库标头和#define
Library headers and #define
我不知道该为这个搜索什么。如果这很简单,请原谅。但让我概述一下这个场景,看看答案是什么。
假设我有一个库,它定义了这样一个结构:
struct Example {
int a;
#if B_ENABLED
int b;
#endif
};
此标头将作为库整体安装的一部分进行安装。我的问题是,如果我的库定义B_ENABLED,它将具有包含这两个变量的结构但是如果我的应用程序没有对此进行定义。然后它将把头解释为定义一个只有一个成员的结构。
处理这一问题的最佳方法是否只是生成某种"选项"标头,其中包括库构建中指定的所有#定义?
我的库是用CMAKE构建的。因此,CMAKE的解决方案是额外信贷=D。
解决方案#1(配置+安装)
在头文件(即foo.hpp
)中包含config.hpp
文件:
#ifndef FOO_HPP_
#define FOO_HPP_
#include "config.hpp" // FOO_DEBUG
class Foo {
public:
int result() const;
private:
int a_;
#ifdef FOO_DEBUG
int b_;
#endif // FOO_DEBUG
};
#endif // FOO_HPP_
config.hpp
是configure_file命令的输出:
configure_file(config.hpp.in "${PROJECT_BINARY_DIR}/config/config.hpp")
include_directories("${PROJECT_BINARY_DIR}/config")
install(FILES Foo.hpp "${PROJECT_BINARY_DIR}/config/config.hpp" DESTINATION include)
输入文件config.hpp.in
使用特殊的cmakedefine
指令:
#ifndef CONFIG_HPP_
#define CONFIG_HPP_
#cmakedefine FOO_DEBUG
#endif // CONFIG_HPP_
请注意,当您在其他项目中使用已安装的库时:
- 您仍然需要为库指定include目录
- 如果你的库有依赖项,你需要手动链接它们
- 不能有2个配置文件(调试/发布)
解决方案#2(推荐导出/导入目标)
install(EXPORT…)命令可以保存有关使用库的所有信息(又名使用要求:包括定义、链接库、配置等):
add_library(Foo Foo.cpp Foo.hpp)
# Target which used Foo will be compiled with this definitions
target_compile_definitions(Foo PUBLIC $<$<CONFIG:Release>:FOO_DEBUG=0>)
target_compile_definitions(Foo PUBLIC $<$<CONFIG:Debug>:FOO_DEBUG=1>)
# This directory will be used as include
target_include_directories(Foo INTERFACE "${CMAKE_INSTALL_PREFIX}/include")
# This library will be linked
target_link_libraries(Foo PUBLIC pthread)
# Regular install
install(FILES Foo.hpp DESTINATION include)
# Install with export set
install(TARGETS Foo DESTINATION lib EXPORT FooTargets)
install(EXPORT FooTargets DESTINATION lib/cmake/Foo)
安装这样的项目会产生文件(CMAKE_DEBUG_POSTFIX
就是d
):
include/Foo.hpp
lib/libFoo.a
lib/libFood.a
lib/cmake/Foo/FooTargets-debug.cmake
lib/cmake/Foo/FooTargets-release.cmake
lib/cmake/Foo/FooTargets.cmake
包括FooTargets.cmake
文件以将已安装的库导入到项目中。例如,使用find_package
命令(需要配置,请参阅config_package_config_file):
add_executable(prog main.cpp)
find_package(Foo REQUIRED) # import Foo
target_link_libraries(prog Foo)
注意:
自动添加到编译器选项的include/Foo.hpp
路径
pthread
自动添加到prog
链接器选项FOO_DEBUG=0
添加到Release构建类型FOO_DEBUG=1
添加到调试生成类型基本原理
So excuse me if this is simple
它不是(:
问题的根源是ODR(C++标准2011,3.2[basic.def.ord],第3页):
Every program shall contain exactly one definition of every non-inline function
or variable that is odr-used in that program; no diagnostic required. The
definition can appear explicitly in the program, it can be found in the
standard or a user-defined library
IMHO良好的通用解决方案仍然不存在。将CMake与导入的配置一起使用可以提供部分帮助,但在某些情况下,仍然会出现链接器错误(例如,如果使用使用默认链接到libstdcxx
的gcc
编译的库,并尝试使用链接到libcxx
的clang
编译器将其链接到项目)。其中一些问题(并非全部)可以使用工具链文件解决。请参见示例。
相关
- CMake教程
- 导出/导入目标
- Qt和Boost的现代CMake
- 与C代码相比,为什么C++代码不需要"#define _POSIX_C_SOURCE 200809L"?
- 以下 C++ 代码用于 -> "#define idiv(a, b) (((a) + (b) / 2) / (b))" 是什么?
- 如何以静态代码分析友好的方式使用 #define 防护?
- C++相当于整数的 #define
- #define Dbg(fmt,..) (0) 是什么意思? 警告:表达式无效
- 在C++中使用变量而不是"#define"来指定数组大小是不是一种糟糕的做法?(C错误:在文件范围内
- 我们可以用 C 语言嵌套 #define 和 #if 吗?
- 如何将旧的 C 样式 #define 映射与现代C++进行调整?
- 找不到 #define 的函数定义
- "#define X X"是什么意思?
- 使用 constexpr 替换 #define 和 #ifdef 进行条件编译
- 野牛/flex:计算器将双精度值解释为整数,所以我添加了 YYSTYPE 双精度 #define 但我有多个编译错误
- 如何解决C++中声纳库贝静态代码分析错误"Explicitly define the missing copy constructor, move constructor .."
- c中 #define 的不足
- 使用 [#define & #ifdef] 跨文件激活代码块
- 如何避免#define语法的变量重新声明
- 使用 GCC 对 C 文件进行部分预处理(不删除 "define" 指令)
- 使用 #define 声明函数
- #define 宏中的括号失败
- 初始化在类类型 #define 中定义的非静态成员数组,不带默认 ctor