cmake学习之target_指令学习
[TOC]
概述
文章转自:https://zhuanlan.zhihu.com/p/82244559
target_include_directories():指定目标包含的头文件路径。官方文档:https://cmake.org/cmake/help/v3.15/command/target_include_directories.html?highlight=target_include_directories
target_link_libraries():指定目标链接的库。官方文档:https://cmake.org/cmake/help/v3.15/command/target_link_libraries.html?highlight=target_link_libraries
target_compile_options():指定目标的编译选项。官方文档:https://cmake.org/cmake/help/v3.15/command/target_compile_options.html#command:target_compile_options
目标 由 add_library() 或 add_executable() 生成。
这三个指令类似,这里以 target_include_directories() 为例进行讲解。
指令讲解
target_include_directories()
测试工程目录结构:
1 | cmake-test/ 工程主目录,main.c 调用 libhello-world.so |
关键字用法说明:
PRIVATE:私有的。生成 libhello-world.so时,只在 hello_world.c 中包含了 hello.h,libhello-world.so 对外的头文件——hello_world.h 中不包含 hello.h。而且 main.c 不会调用 hello.c 中的函数,或者说 main.c 不知道 hello.c 的存在,那么在 hello-world/CMakeLists.txt 中应该写入:
1 | target_link_libraries(hello-world PRIVATE hello) |
INTERFACE:接口。生成 libhello-world.so 时,只在libhello-world.so 对外的头文件——hello_world.h 中包含 了 hello.h, hello_world.c 中不包含 hello.h,即 libhello-world.so 不使用 libhello.so 提供的功能,只使用 hello.h 中的某些信息,比如结构体。但是 main.c 需要使用 libhello.so 中的功能。那么在 hello-world/CMakeLists.txt 中应该写入:
1 | target_link_libraries(hello-world INTERFACE hello) |
PUBLIC:公开的。PUBLIC = PRIVATE + INTERFACE。生成 libhello-world.so 时,在 hello_world.c 和 hello_world.h 中都包含了 hello.h。并且 main.c 中也需要使用 libhello.so 提供的功能。那么在 hello-world/CMakeLists.txt 中应该写入:
1 | target_link_libraries(hello-world PUBLIC hello) |
实际上,这三个关键字指定的是目标文件依赖项的使用范围(scope)或者一种传递(propagate)。官方说明
include_directories()
target_include_directories()
的功能完全可以使用 include_directories()
实现。但是我还是建议使用 target_include_directories()
。为什么?保持清晰!
include_directories(header-dir)
是一个全局包含,向下传递。什么意思呢?就是说如果某个目录的 CMakeLists.txt 中使用了该指令,其下所有的子目录默认也包含了header-dir
目录。
上述例子中,如果在顶层的 cmake-test/CMakeLists.txt 中加入:
1 | include_directories(hello-world) |
那么整个工程的源文件在编译时都会增加:
1 | -I hello-world -I hello-world/hello -I hello-world/world ... |
各级子目录中无需使用 target_include_directories()
或者 include_directories()
了。如果此时查看详细的编译过程(make VERBOSE=1
)就会发现编译过程是一大坨,很不舒服。
当然了,在最终子目录的 CMakeLists.txt 文件中,使用 include_directories()
和 target_include_directories()
的效果是相同的。