一. 简介
前面几篇文章学习了CMakeLists.txt语法中前面几篇文章学习了CMakeLists.txt语法中部分常用命令。文章如下:
CMakeLists.txt语法规则:部分常用命令说明一-CSDN博客
CMakeLists.txt语法规则:部分常用命令说明二-CSDN博客
CMakeLists.txt语法规则:部分常用命令说明三-CSDN博客
本文继续学习 CMakeLists.txt语法中两个常用命令:target_include_directories命令 和 target_link_libraries命令。
二. CMakeLists.txt语法规则:部分常用命令
target_include_directories命令 和 target_link_libraries命令
target_include_directories
命令为指定目标设置头文件搜索路径。
target_link_libraries
命令为指定目标设置链接库文件。
这听起来跟
include_directories
和
link_libraries
命令有着相同的作用,确实如此,它们的
功能的确相同,但是在一些细节方面却有不同。
target_include_directories
和
target_link_libraries
命令定义如下所示:
target_include_directories(<target> [SYSTEM] [BEFORE]
<INTERFACE|PUBLIC|PRIVATE> [items1...]
[<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
target_link_libraries(<target>
<PRIVATE|PUBLIC|INTERFACE> <item>...
[<PRIVATE|PUBLIC|INTERFACE> <item>...]...)
这俩命令都有一个相同的参数
<target>
目标,这个目标指的就是譬如
add_executable
、
add_library
命令所创建的目标。
首 先 对 于
target_include_directories
命 令 来 说 ,
SYSTEM
、
BEFORE
这 两 个 选 项 与
include_directories
命令中
SYSTEM
、
BEFORE
选项的意义相同。
如果使用
SYSTEM
选项,会把指定目录当成系统的搜索目录。
通过
BEFORE
选项可显式指定添加到列表的前面。
我们重点关注的是 INTERFACE|PUBLIC|PRIVATE 这三个选项有何不同?
通过一个示例向大家说明,譬如工程目录结构如下所示:
调用关系:
根据以上工程,我们对
INTERFACE
、
PUBLIC
、
PRIVATE
三个关键字进行说明:
PRIVATE
:
私有的。
main.c
程序调用了
libhello_world.so
。生成
libhello_world.so
时,只在
hello_world.c 中包含了
hello.h
,
libhello_world.so
对外的头文件:
hello_world.h
头文件中不包含
hello.h
。
而且
main.c
不会调用
hello.c
中的函数,或者说
main.c
不知道
hello.c
的存在,它只知道
libhello_world.so
的存在;
那么在
hello_world/CMakeLists.txt
中应该写入:
target_link_libraries(hello_world PRIVATE hello)
target_include_directories(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
提供的功能,但是
main.c
需要使用
libhello.so
中的功能。
那么在
hello_world/CMakeLists.txt
中应该写入:
target_link_libraries(hello-world INTERFACE hello)
target_include_directories(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
中应该写入:
target_link_libraries(hello-world PUBLIC hello)
target_include_directories(hello-world PUBLIC hello)
对于
target_include_directories命令
来说,这些关键字用于指示
何时
需要传递给目标的
包含目录列表
,指定了
包含目录列表
的使用范围(
scope
):
⚫
当使用
PRIVATE
关键字修饰时,意味着
包含目录列表
仅用于当前目标;
⚫
当使用
INTERFACE
关键字修饰时,意味着
包含目录列表
不用于当前目标、只能用于依赖该目标的其它目标,也就是说
cmake
会将
包含目录列表
传递给当前目标的依赖目标;
⚫
当使用
PUBLIC
关键字修饰时,这就是以上两个的集合,
包含目录列表
既用于当前目标、也会传递给当前目标的依赖目标。
对于
target_link_libraries命令
亦是如此,只不过
包含目录列表
换成了
链接库列表
。
譬如:
target_link_libraries(hello_world INTERFACE hello)
:
表示目标
hello_world
不需要链接
hello
库,但是对
于
hello_world
目标的依赖目标(依赖于
hello_world
的目标)它们需要链接
hello
库。
以上便是对 INTERFACE、PUBLIC、PRIVATE 这三个关键字的概括性理解,所以整出这几个关键 字主要还是为了控制包含目录列表或链接库列表的使用范围,这就是 target_include_directories、
target_link_libraries 命令与 include_directories、link_libraries 命令的不同之处。
target_include_directories() 功能与 target_link_libraries()的功能完全可以使用 include_directories()、link_libraries()来实现。
但是笔者强烈建议大家使用 target_include_directories()和 target_link_libraries()。为什么?保持清晰!
include_directories()
、
link_libraries()
是针对当前源码中的所有目标,并且还会向下传递(譬如通过
add_subdirectory
加载子源码时,也会将其传递给子源码)。
在一个大的工程当中,这通常不规范、有时还
会编译出现错误、混乱,所以我们应尽量使用
target_include_directories()
和
target_link_libraries()
,保持整个
工程的目录清晰。
下一篇文章继续学习 CMakeLists.txt语法的一个常用命令: message命令。