我使用库类型创建了一个具有一些嵌套库依赖项的项目OBJECT
。这样做的动机是为了避免静态库的链接顺序问题。
我有一个简单的目录结构如下:
\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 bar\n\xe2\x94\x82 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 bar.c\n\xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 bar.h\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 foo\n\xe2\x94\x82 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 foo.c\n\xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 foo.h\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 main.c\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 CMakeLists.txt\n
Run Code Online (Sandbox Code Playgroud)\nfoo
取决于bar
,并且main
取决于foo
。例如,
酒吧.c
\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 bar\n\xe2\x94\x82 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 bar.c\n\xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 bar.h\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 foo\n\xe2\x94\x82 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 foo.c\n\xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 foo.h\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 main.c\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 CMakeLists.txt\n
Run Code Online (Sandbox Code Playgroud)\nfoo.c
\n#include "bar.h"\n\n#include <stdio.h>\n\nvoid bar(void) {\n printf("woot woot\\n");\n}\n
Run Code Online (Sandbox Code Playgroud)\n主程序
\n#include "foo.h"\n\n#include "bar.h"\n\nvoid foo(void) {\n bar();\n}\n
Run Code Online (Sandbox Code Playgroud)\nCMakeLists.txt
\n#include "foo.h"\n\nint main() {\n foo();\n return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n我的期望是,当它链接到它时myexe
,它会继承bar
依赖关系foo
。然而,事实似乎并非如此。编译代码时,main.o
仅链接到foo.o
,因此存在对 的未定义引用bar
。但是,如果我将库类型更改为 ,OBJECT
则STATIC
一切正常。为什么会出现这种情况?
对象库不能以这种方式链接。您必须直接(非传递)链接到对象库才能获取其对象文件。正如文档中所说,
对象库可以“链接”到其他对象库以获得使用要求,但由于它们没有链接步骤,因此不会对它们的对象文件执行任何操作。[...] 换句话说,当对象库出现在目标的
INTERFACE_LINK_LIBRARIES
属性中时,它们将被视为接口库,但是当它们出现在目标的LINK_LIBRARIES
属性中时,它们的对象文件也将包含在链接中。
不过,我同意这违背了一切理由。
target_link_libraries(INTERFACE)
但是,从 3.21 开始,您可以通过生成器表达式手动传播对象文件$<TARGET_OBJECTS>
(这样做在早期版本中存在错误,并且偶数黑客也target_sources
可以在早期版本中使用)。
请注意,这有点像黑客,因为有些情况会失败。值得注意的是,如果库目标公开链接到此类目标,则目标文件将再次传播。所以……要小心。
不过,这里是示例构建的更正版本:
cmake_minimum_required(VERSION 3.21)
project(myproj LANGUAGES C ASM)
set(CMAKE_C_STANDARD 11 CACHE STRING "The C standard to use")
option(CMAKE_C_STANDARD_REQUIRED "Enforce strict C standard selection" ON)
option(CMAKE_C_EXTENSIONS "Allow compiler-specific C extensions" OFF)
# build bar
add_library(bar OBJECT bar/bar.c)
target_include_directories(
bar PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/bar>"
)
# build foo, depends on bar
add_library(foo OBJECT foo/foo.c)
target_include_directories(
foo PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/foo>"
)
target_link_libraries(foo PUBLIC bar "$<TARGET_OBJECTS:bar>")
# build executable, depends on foo
add_executable(myexe main.c)
target_link_libraries(myexe PRIVATE foo)
Run Code Online (Sandbox Code Playgroud)
在命令行中:
$ cmake -G Ninja -S . -B build
...
$ cmake --build build -- -nv
[1/4] /usr/bin/cc -I/path/to/bar -std=c11 -MD -MT CMakeFiles/bar.dir/bar/bar.c.o -MF CMakeFiles/bar.dir/bar/bar.c.o.d -o CMakeFiles/bar.dir/bar/bar.c.o -c /path/to/bar/bar.c
[2/4] /usr/bin/cc -I/path/to/foo -I/path/to/bar -std=c11 -MD -MT CMakeFiles/foo.dir/foo/foo.c.o -MF CMakeFiles/foo.dir/foo/foo.c.o.d -o CMakeFiles/foo.dir/foo/foo.c.o -c /path/to/foo/foo.c
[3/4] /usr/bin/cc -I/path/to/foo -I/path/to/bar -std=c11 -MD -MT CMakeFiles/myexe.dir/main.c.o -MF CMakeFiles/myexe.dir/main.c.o.d -o CMakeFiles/myexe.dir/main.c.o -c /path/to/main.c
[4/4] : && /usr/bin/cc CMakeFiles/foo.dir/foo/foo.c.o CMakeFiles/myexe.dir/main.c.o -o myexe CMakeFiles/bar.dir/./bar/bar.c.o && :
Run Code Online (Sandbox Code Playgroud)