库标题和#define
我不确定要搜索什么.如果这很简单,请原谅.但让我概述一下场景,看看有什么答案.
I wasn't sure what to search for for this one. So excuse me if this is simple. But let me outline the scenario and see what answers are out there.
假设我有一个定义如下结构的库:
Let's say I have a library which defines a structure like this:
struct Example {
int a;
#if B_ENABLED
int b;
#endif
};
此头文件作为整个库安装的一部分进行安装.我的问题是,如果我的库定义了 B_ENABLED,它将具有包含这两个变量的结构.但是如果我的应用程序也没有定义它.然后它会将标头解释为定义一个只有一个成员的结构.
This header gets installed as a part of the library's installation as a whole. My question here is that if my library defines B_ENABLED it will have a structure with these two variables included. However if my application does not define this as well. Then it will interpret the header as defining a struct with only one member.
处理这个问题的最好方法是生成某种选项"标头,其中包括库构建中指定的所有#defines?
Is the best way to handle this just to generate some kind of "options" header which would include all of the #defines that were specified in the library build?
我的库使用 CMAKE 构建.因此,针对此的 CMAKE 解决方案是额外的功劳 =D.
My library builds with CMAKE. So a CMAKE solution for this is extra credit =D.
推荐答案
Solution #1 (configure + install)
在头文件中包含 config.hpp
文件(即 foo.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
指令:
input file config.hpp.in
use special cmakedefine
directive:
#ifndef CONFIG_HPP_
#define CONFIG_HPP_
#cmakedefine FOO_DEBUG
#endif // CONFIG_HPP_
请注意,当您在其他项目中使用已安装的库时:
Note that when you use installed library in other project:
- 您仍然需要为库指定包含目录
- 如果您的库有依赖项,您需要手动链接它们
- 你不能有 2 个配置文件(调试/发布)
安装(导出...)命令可以保存有关使用库的所有信息(又名使用要求:包括定义、链接库、配置等):
install(EXPORT ...) command can hold all information about using library (aka usage requirements: including definitions, linked library, configuration etc):
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
):
Installing such project will produce files (CMAKE_DEBUG_POSTFIX
is 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
命令(需要配置,参见 configure_package_config_file):
Include FooTargets.cmake
file to import installed library to project. For example using find_package
command (need config, see configure_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
添加到发布构建类型 - 定义
FOO_DEBUG=1
添加到调试构建类型
- path to
include/Foo.hpp
automatically added to compiler options - dependend library
pthread
is automatically added toprog
linker option - definition
FOO_DEBUG=0
added to Release build type - definition
FOO_DEBUG=1
added to Debug build type
So excuse me if this is simple
它不是 (:
问题的根源在于ODR(C++ Standard 2011, 3.2 [basic.def.ord],第 3 页):
The root of the problem is ODR (C++ Standard 2011, 3.2 [basic.def.ord], p.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
恕我直言,好的通用解决方案仍然不存在.使用带有导入配置的 CMake可以部分帮助一点,但在某些情况下,您仍然会收到链接器错误(例如,如果您使用用 gcc
编译的库,默认情况下链接到 libstdcxx
,并尝试使用 clang
编译器将其链接到项目,该编译器链接到 libcxx
).使用 工具链 文件可以解决其中一些问题(并非全部,仍然).请参阅示例.
IMHO good general solution still not exists. Using CMake with imported configuration
can partially helps a little bit, but in some cases you still will get linker errors
(for example if you use library compiled with gcc
, which linked to libstdcxx
by default,
and try to link it to project with clang
compiler, which linked to libcxx
).
Some of this problems (not all, still) can be solved using toolchain files.
See examples.
- CMake 教程
- 导出/导入目标
- 使用 Qt 和 Boost 的现代 CMake莉>
相关文章