【问题标题】:Propagate CMake target definition to linked library将 CMake 目标定义传播到链接库
【发布时间】:2021-01-15 22:33:26
【问题描述】:

我有一个包含多个目标 releasetest 的项目,该项目链接到一个静态库,该库可以使用 TEST 宏进行编译。

假设我希望构建我的 release 目标而不使用 TEST 宏,并且使用定义的宏构建 test 目标,但该宏必须传播到链接的反对库。

在我的主要CMakeLists.txt 中,我创建了目标并使用target_compile_definitions(mytest PUBLIC TEST) 定义了该宏,但显然库core 无法识别它。

项目树如下:

.
├── CMakeLists.txt
├── core
│   ├── CMakeLists.txt
│   ├── inc
│   │   ├── core_comp1.h
│   │   └── core_comp2.h
│   └── src
│       ├── core_comp1.c
│       └── core_comp2.c
├── lib
│   ├── CMakeLists.txt
│   ├── inc
│   │   ├── ext_comp1.h
│   │   └── ext_comp2.h
│   └── src
│       ├── ext_comp1.c
│       └── ext_comp2.c
├── main.c
├── README.md
└── test.c

./CMakeLists.txt如下:

cmake_minimum_required(VERSION 3.10)

# set the project name
project(cmake_test)

# add the subdirectories
add_subdirectory(core)
add_subdirectory(lib)

# define my targets
set(MY_TARGETS myexe mytest)

# create and link against the libs
foreach(target ${MY_TARGETS})
    add_executable(${target})
    target_link_libraries(${target} PRIVATE core ext)
endforeach(target ${MY_TARGETS})

# add target specific sources
target_sources(myexe  PRIVATE main.c)
target_sources(mytest PRIVATE test.c)

# define the TEST macro for mytest
target_compile_definitions(mytest PUBLIC TEST)

./core/CMakeLists.txt 库文件夹有:

add_library(core
    ${CMAKE_CURRENT_SOURCE_DIR}/src/core_comp1.c
    ${CMAKE_CURRENT_SOURCE_DIR}/src/core_comp2.c
)

target_include_directories(core PUBLIC 
    ${CMAKE_CURRENT_SOURCE_DIR}/inc
)

target_link_libraries(core PRIVATE ext)

myexe的输出,release target是正确的:

Running the release executable
Original core_comp1_display

虽然mytest 不正确:

Running the test executable
Original core_comp1_display

应该是:

Running the test executable
Test core_comp1_display

我已将项目推送到 GitLab,cmake-library-test

myexe 目标的编译给出如下:

[build] [9/12   8% :: 0.032] /usr/bin/gcc  -I../../core/inc -I../../lib/inc -g -MD -MT CMakeFiles/myexe.dir/lib/src/ext_comp2.c.o -MF CMakeFiles/myexe.dir/lib/src/ext_comp2.c.o.d -o CMakeFiles/myexe.dir/lib/src/ext_comp2.c.o -c ../../lib/src/ext_comp2.c
[build] [9/12  16% :: 0.034] /usr/bin/gcc  -I../../core/inc -I../../lib/inc -g -MD -MT CMakeFiles/myexe.dir/core/src/core_comp2.c.o -MF CMakeFiles/myexe.dir/core/src/core_comp2.c.o.d -o CMakeFiles/myexe.dir/core/src/core_comp2.c.o -c ../../core/src/core_comp2.c
[build] [9/12  25% :: 0.039] /usr/bin/gcc  -I../../lib/inc -g -MD -MT lib/CMakeFiles/mylib.dir/src/ext_comp2.c.o -MF lib/CMakeFiles/mylib.dir/src/ext_comp2.c.o.d -o lib/CMakeFiles/mylib.dir/src/ext_comp2.c.o -c ../../lib/src/ext_comp2.c
[build] [9/12  33% :: 0.041] /usr/bin/gcc  -I../../lib/inc -g -MD -MT lib/CMakeFiles/mylib.dir/src/ext_comp1.c.o -MF lib/CMakeFiles/mylib.dir/src/ext_comp1.c.o.d -o lib/CMakeFiles/mylib.dir/src/ext_comp1.c.o -c ../../lib/src/ext_comp1.c
[build] [10/12  41% :: 0.043] /usr/bin/gcc  -I../../core/inc -I../../lib/inc -g -MD -MT CMakeFiles/myexe.dir/lib/src/ext_comp1.c.o -MF CMakeFiles/myexe.dir/lib/src/ext_comp1.c.o.d -o CMakeFiles/myexe.dir/lib/src/ext_comp1.c.o -c ../../lib/src/ext_comp1.c
[build] [10/12  50% :: 0.046] /usr/bin/gcc  -I../../core/inc -g -MD -MT core/CMakeFiles/core.dir/src/core_comp2.c.o -MF core/CMakeFiles/core.dir/src/core_comp2.c.o.d -o core/CMakeFiles/core.dir/src/core_comp2.c.o -c ../../core/src/core_comp2.c
[build] [10/12  58% :: 0.049] /usr/bin/gcc  -I../../core/inc -g -MD -MT core/CMakeFiles/core.dir/src/core_comp1.c.o -MF core/CMakeFiles/core.dir/src/core_comp1.c.o.d -o core/CMakeFiles/core.dir/src/core_comp1.c.o -c ../../core/src/core_comp1.c
[build] [11/12  66% :: 0.054] /usr/bin/gcc  -I../../core/inc -I../../lib/inc -g -MD -MT CMakeFiles/myexe.dir/main.c.o -MF CMakeFiles/myexe.dir/main.c.o.d -o CMakeFiles/myexe.dir/main.c.o -c ../../main.c
[build] [11/12  75% :: 0.058] /usr/bin/gcc  -I../../core/inc -I../../lib/inc -g -MD -MT CMakeFiles/myexe.dir/core/src/core_comp1.c.o -MF CMakeFiles/myexe.dir/core/src/core_comp1.c.o.d -o CMakeFiles/myexe.dir/core/src/core_comp1.c.o -c ../../core/src/core_comp1.c
[build] [11/12  83% :: 0.110] : && /usr/bin/cmake -E rm -f lib/libmylib.a && /usr/bin/ar qc lib/libmylib.a  lib/CMakeFiles/mylib.dir/src/ext_comp1.c.o lib/CMakeFiles/mylib.dir/src/ext_comp2.c.o && /usr/bin/ranlib lib/libmylib.a && :
[build] [11/12  91% :: 0.119] : && /usr/bin/cmake -E rm -f core/libcore.a && /usr/bin/ar qc core/libcore.a  core/CMakeFiles/core.dir/src/core_comp1.c.o core/CMakeFiles/core.dir/src/core_comp2.c.o && /usr/bin/ranlib core/libcore.a && :
[build] [12/12 100% :: 0.147] : && /usr/bin/gcc -g  CMakeFiles/myexe.dir/main.c.o CMakeFiles/myexe.dir/core/src/core_comp1.c.o CMakeFiles/myexe.dir/core/src/core_comp2.c.o CMakeFiles/myexe.dir/lib/src/ext_comp1.c.o CMakeFiles/myexe.dir/lib/src/ext_comp2.c.o -o myexe  core/libcore.a  lib/libmylib.a && :
[build] Build finished with exit code 0

mytest的编译给:

[build] [9/12   8% :: 0.035] /usr/bin/gcc  -I../../core/inc -g -MD -MT core/CMakeFiles/core.dir/src/core_comp2.c.o -MF core/CMakeFiles/core.dir/src/core_comp2.c.o.d -o core/CMakeFiles/core.dir/src/core_comp2.c.o -c ../../core/src/core_comp2.c
[build] [9/12  16% :: 0.045] /usr/bin/gcc -DTEST -I../../core/inc -I../../lib/inc -g -MD -MT CMakeFiles/mytest.dir/lib/src/ext_comp1.c.o -MF CMakeFiles/mytest.dir/lib/src/ext_comp1.c.o.d -o CMakeFiles/mytest.dir/lib/src/ext_comp1.c.o -c ../../lib/src/ext_comp1.c
[build] [9/12  25% :: 0.047] /usr/bin/gcc -DTEST -I../../core/inc -I../../lib/inc -g -MD -MT CMakeFiles/mytest.dir/lib/src/ext_comp2.c.o -MF CMakeFiles/mytest.dir/lib/src/ext_comp2.c.o.d -o CMakeFiles/mytest.dir/lib/src/ext_comp2.c.o -c ../../lib/src/ext_comp2.c
[build] [9/12  33% :: 0.049] /usr/bin/gcc -DTEST -I../../core/inc -I../../lib/inc -g -MD -MT CMakeFiles/mytest.dir/core/src/core_comp2.c.o -MF CMakeFiles/mytest.dir/core/src/core_comp2.c.o.d -o CMakeFiles/mytest.dir/core/src/core_comp2.c.o -c ../../core/src/core_comp2.c
[build] [9/12  41% :: 0.049] /usr/bin/gcc  -I../../core/inc -g -MD -MT core/CMakeFiles/core.dir/src/core_comp1.c.o -MF core/CMakeFiles/core.dir/src/core_comp1.c.o.d -o core/CMakeFiles/core.dir/src/core_comp1.c.o -c ../../core/src/core_comp1.c
[build] [10/12  50% :: 0.052] /usr/bin/gcc -DTEST -I../../core/inc -I../../lib/inc -g -MD -MT CMakeFiles/mytest.dir/test.c.o -MF CMakeFiles/mytest.dir/test.c.o.d -o CMakeFiles/mytest.dir/test.c.o -c ../../test.c
[build] [10/12  58% :: 0.056] /usr/bin/gcc -DTEST -I../../core/inc -I../../lib/inc -g -MD -MT CMakeFiles/mytest.dir/core/src/core_comp1.c.o -MF CMakeFiles/mytest.dir/core/src/core_comp1.c.o.d -o CMakeFiles/mytest.dir/core/src/core_comp1.c.o -c ../../core/src/core_comp1.c
[build] [10/12  66% :: 0.065] /usr/bin/gcc  -I../../lib/inc -g -MD -MT lib/CMakeFiles/mylib.dir/src/ext_comp2.c.o -MF lib/CMakeFiles/mylib.dir/src/ext_comp2.c.o.d -o lib/CMakeFiles/mylib.dir/src/ext_comp2.c.o -c ../../lib/src/ext_comp2.c
[build] [10/12  75% :: 0.069] /usr/bin/gcc  -I../../lib/inc -g -MD -MT lib/CMakeFiles/mylib.dir/src/ext_comp1.c.o -MF lib/CMakeFiles/mylib.dir/src/ext_comp1.c.o.d -o lib/CMakeFiles/mylib.dir/src/ext_comp1.c.o -c ../../lib/src/ext_comp1.c
[build] [11/12  83% :: 0.127] : && /usr/bin/cmake -E rm -f core/libcore.a && /usr/bin/ar qc core/libcore.a  core/CMakeFiles/core.dir/src/core_comp1.c.o core/CMakeFiles/core.dir/src/core_comp2.c.o && /usr/bin/ranlib core/libcore.a && :
[build] [11/12  91% :: 0.139] : && /usr/bin/cmake -E rm -f lib/libmylib.a && /usr/bin/ar qc lib/libmylib.a  lib/CMakeFiles/mylib.dir/src/ext_comp1.c.o lib/CMakeFiles/mylib.dir/src/ext_comp2.c.o && /usr/bin/ranlib lib/libmylib.a && :
[build] [12/12 100% :: 0.168] : && /usr/bin/gcc -g  CMakeFiles/mytest.dir/test.c.o CMakeFiles/mytest.dir/core/src/core_comp1.c.o CMakeFiles/mytest.dir/core/src/core_comp2.c.o CMakeFiles/mytest.dir/lib/src/ext_comp1.c.o CMakeFiles/mytest.dir/lib/src/ext_comp2.c.o -o mytest  core/libcore.a  lib/libmylib.a && :
[build] Build finished with exit code 0

很明显core_comp*.cext_comp*.c是在没有-DTEST的情况下编译的

使用建议的INTERFACE关键字,将标志-DTEST传入所有文件,编译如下:

[build] [5/6  16% :: 0.024] /usr/bin/gcc -DTEST -I../../core/inc -I../../lib/inc -g -MD -MT CMakeFiles/mytest.dir/core/src/core_comp2.c.o -MF CMakeFiles/mytest.dir/core/src/core_comp2.c.o.d -o CMakeFiles/mytest.dir/core/src/core_comp2.c.o -c ../../core/src/core_comp2.c
[build] [5/6  33% :: 0.025] /usr/bin/gcc -DTEST -I../../core/inc -I../../lib/inc -g -MD -MT CMakeFiles/mytest.dir/lib/src/ext_comp2.c.o -MF CMakeFiles/mytest.dir/lib/src/ext_comp2.c.o.d -o CMakeFiles/mytest.dir/lib/src/ext_comp2.c.o -c ../../lib/src/ext_comp2.c
[build] [5/6  50% :: 0.038] /usr/bin/gcc -DTEST -I../../core/inc -I../../lib/inc -g -MD -MT CMakeFiles/mytest.dir/lib/src/ext_comp1.c.o -MF CMakeFiles/mytest.dir/lib/src/ext_comp1.c.o.d -o CMakeFiles/mytest.dir/lib/src/ext_comp1.c.o -c ../../lib/src/ext_comp1.c
[build] [5/6  66% :: 0.041] /usr/bin/gcc -DTEST -I../../core/inc -I../../lib/inc -g -MD -MT CMakeFiles/mytest.dir/core/src/core_comp1.c.o -MF CMakeFiles/mytest.dir/core/src/core_comp1.c.o.d -o CMakeFiles/mytest.dir/core/src/core_comp1.c.o -c ../../core/src/core_comp1.c
[build] [5/6  83% :: 0.058] /usr/bin/gcc -DTEST -I../../core/inc -I../../lib/inc -g -MD -MT CMakeFiles/mytest.dir/test.c.o -MF CMakeFiles/mytest.dir/test.c.o.d -o CMakeFiles/mytest.dir/test.c.o -c ../../test.c
[build] [6/6 100% :: 0.134] : && /usr/bin/gcc -g  CMakeFiles/mytest.dir/test.c.o CMakeFiles/mytest.dir/core/src/core_comp1.c.o CMakeFiles/mytest.dir/core/src/core_comp2.c.o CMakeFiles/mytest.dir/lib/src/ext_comp1.c.o CMakeFiles/mytest.dir/lib/src/ext_comp2.c.o -o mytest   && :
[build] Build finished with exit code 0

coremylib 库现在是透明的,目标 myexemytest 实际上认为库源是“他们的”

【问题讨论】:

  • @KamilCuk 使用target_link_libraries(core PRIVATE mytest) 将导致错误Attempt to add link library "mytest" to target "core" which is not built in this directory
  • 堆栈溢出的要求相关代码应该包含问题帖子中,而不仅仅是链接。请将您的代码(至少CMakeLists.txt)添加到问题帖子中。另请参阅How to Ask
  • @Tsyvarev 指出,我添加了 2 个主要的 CMakeLists.txt
  • 好吧,您显示的代码绝对不足以理解问题,但是根据链接的 repo,Original core_comp1_displayTest core_comp1_display 行是由依赖于的 core 库输出的TEST 宏的值。您将core 库链接到testrelease 可执行文件,并希望库输出不同 行。这根本不可能:您的core构建一次,因此只有单个输出 是可能的。此输出是在您构建库本身时确定的,而不是在您与它链接时确定的。
  • 您可以创建单独的库(例如core_testcore_release)并将它们相应地链接到testrelease。或者您可以在打印行的core_comp1_display 函数中添加一个参数,因此testrelease 可执行文件可以使用不同的参数调用此函数。您可以在core 库中创建一些变量,而不是函数的参数,并为testrelease 提供一种为此变量设置值的方法。

标签: cmake


【解决方案1】:

实现类似行为的一种方法是使用接口库并通过target_sources() 将源文件添加到接口库。

这实际上并没有将定义传播到库,而是将源带到消费目标。需要确定并且仅通过 PRIVATE 依赖此库,否则将为每个后续依赖项编译源代码。

我不鼓励这种解决方案,但我以前需要它,所以想分享一下。

./CMakeLists.txt

cmake_minimum_required(VERSION 3.17)
project(example)

add_subdirectory(lib)

add_executable(my_exe main.c)
target_link_libraries(my_exe PRIVATE my_lib) 

add_executable(my_test main.c)
target_link_libraries(my_test PRIVATE my_lib) 
target_compile_definitions(my_test PRIVATE TEST) 

./main.c

#include <stdio.h>

const char * get_string();

int main(int argc, char *argv[]) {
    printf("The message is \"%s\"\n", get_string());
    return 0;
}

lib/CMakeLists.txt

add_library(my_lib INTERFACE)
target_sources(my_lib INTERFACE message.c)

lib/message.c

#ifdef TEST
const char * get_string(){
    return "The test string";
}
#else
const char * get_string(){
    return "The normal string";
}
#endif

【讨论】:

  • 你的想法行得通!唯一需要注意的是,它们不再被视为库,并且源是使用接口库的目标的一部分
  • > 唯一需要注意的是,它们不再被视为库,并且源是使用接口库的目标的一部分 正确它不再是一个独立的库。你可以为每个版本使用一个中间库,但如果你走这条路,你可能最好按照 Tsyvarev 的建议做,从一开始就制作 2 个库。如果您发现自己经常使用此解决方案,则可能值得投资于其他使代码可测试的方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多