CMAKE如何编译具有不同标志的静态/对象库

Posted

技术标签:

【中文标题】CMAKE如何编译具有不同标志的静态/对象库【英文标题】:CMAKE How to compile static/object library with different flags 【发布时间】:2018-04-23 11:15:04 【问题描述】:

问题:2 个可执行文件,1 个带有 if/defs 的核心库

UPD2 在 Ľubomír Carik 的帮助下

每个可执行文件都设置自己的预处理器标志 一开始,创建库的目标

add_library(common_library STATIC $__SOURCES $__HEADERS)

common_library 代码(即静态库,自带cmake文件)有预处理条件

#if defined(MY_DEFINE_1)
// specific code #1 
#elif defined (MY_DEFINE_2)
// specific code #2 
#else
// error
#endif

我在使用 CMake 来准备这样的配置时遇到问题。库没有看到定义。 第一个可执行文件(自己的 cmake):

target_compile_definitions(common_library PRIVATE -DMY_DEFINE_1)
add_executable(BINARY_1  $bin1_sources   )
add_dependencies(BINARY_1 common_library)

第二个可执行文件(自己的 cmake):

target_compile_definitions(common_library PRIVATE -DMY_DEFINE_2)
add_executable(BINARY_2  $bin2_sources   )
add_dependencies(BINARY_2 common_library)

但是 common_library 只构建一次,有 2 个定义。它应该为每个二进制文件单独构建。

【问题讨论】:

您的标题是关于 STATIC 库的,您的代码是指 OBJECT 库(TARGET_OBJECTS 属性),而您的文字说明 SHARED 库 (... which will build shared library 2 times)。您实际使用哪种类型的库? “共享”我的意思是,代码是共享的。静态或对象,我不知道,什么会起作用。很抱歉造成混乱 【参考方案1】:

由于您尝试更改库上的编译器标志,因此您需要多次构建该库。您现在正在做的是多次更改库上的标志,这就是为什么您在构建中看到两组编译器定义的原因。

解决问题的最简单方法是创建两个库条目,每个条目都有自己的标志。这是我能想到的最小的例子:

project("sample"
    LANGUAGES
        C
)

add_library(lib1 STATIC foo.c)
target_compile_definitions(lib1
    PRIVATE -DCOND=1
)
add_library(lib2 STATIC foo.c)
target_compile_definitions(lib2
      PRIVATE -DCOND=0
)

我的foo.c 看起来像这样:

#if COND
#warning "case 1"
#else
#warning "case 2"
#endif

void foo()  

构建看起来像这样:

$ make
Scanning dependencies of target lib1
[ 25%] Building C object CMakeFiles/lib1.dir/foo.o
/tmp/so/static-lib/foo.c:2:2: warning: #warning "case 1" [-Wcpp]
 #warning "case 1"
  ^~~~~~~
[ 50%] Linking C static library liblib1.a
[ 50%] Built target lib1
Scanning dependencies of target lib2
[ 75%] Building C object CMakeFiles/lib2.dir/foo.o
/tmp/so/static-lib/foo.c:4:2: warning: #warning "case 2" [-Wcpp]
 #warning "case 2"
  ^~~~~~~
[100%] Linking C static library liblib2.a
[100%] Built target lib2

如果大部分库代码都相同,您可以通过使用三个库来限制编译时间(例如,真正通用的代码,然后是只包含条件编译内容的库)。

【讨论】:

谢谢,我终于找到了相同的解决方案。【参考方案2】:

您应该使用target_compile_options 和target_compile_definitions 而不是全局“add_definitions”。并为 library_1 和 library_2 设置不同的定义。

【讨论】:

好的,它有帮助,我只需将 OBJECT 更改为 STATIC 我必须取消标记答案,因为它有效,但是......奇怪。最后,我在库中都有定义。它只构建了 1 次,带有两个标志。 是的,我现在看到了,您的更改。当您将下一个定义添加到同一个目标时,它就像添加一样。您需要 2 个目标,即 2 个具有不同目标名称的库(又名 common_library1 和 common_library2)。请不要将 CMakeList.txt 文件作为命令序列。 CMake 将生成项目文件,这些文件过着自己的生活。 你应该创建 lib1 和 lib2,然后是 binary1 和 binary2 目标,然后你可以使用“target_link_libraries”将 lib1 链接到 app1(而不是冗余的 add_dependencies)等。

以上是关于CMAKE如何编译具有不同标志的静态/对象库的主要内容,如果未能解决你的问题,请参考以下文章

CMake:具有多个项目的静态库

在 CMake 中使用本地编译器标志

如何使用cmake生成基于静态库的动态链接库

使用 cmake 如何静态链接一些库和动态链接其他库?

gdbserver 找不到静态库课程

使用 CMAKE 编译具有不同标志的相同文件