为什么不在 CMake 中使用 "include_directories"?
Why not use "include_directories" in CMake?
看了一些关于CMake的视频,大家建议不要用include_directories
,改用target_include_directories
。但是我不明白这个推荐背后的真正原因是什么?
主要有3个原因
- 将包含目录的范围限制为仅那些需要它们的目标
- 允许修改一个目标而无需更新其他项目的 cmake 逻辑
- 允许更轻松地重用项目作为更大项目的一部分
限制包含目录的范围
目标是将包含目录的可见性降至最低。如果在执行 include_directories
后使用 add_subdirectory
,则从子目录或子目录的后代创建的所有目标都会看到添加了 include_directories
.
的包含目录
subdir/CMakeLists.txt
add_library(subdir_lib ...)
...
CMakeLists.txt
add_subdirectory(subdir)
...
include_directories(some_include_dir)
对
include_directories(some_include_dir)
...
add_subdirectory(subdir)
可能很难看出 2 个 CMakeLists.txt
文件之间的区别,尤其是当 2 个命令之间有很多逻辑时;这使得这种逻辑难以维护。
“继承”/易于重组
使用 target_include_directories
还可以更轻松地提供 link 需要包含目录的库的目标。通过 include_directories
添加的包含目录不能自动用于 linking 目标,但是使用 target_include_directories(... PUBLIC ...)
这很容易实现。 include_directories
不适用于从目录创建的目标,这些目录不是在包含该命令的子目录中创建的。
示例项目
- 图书馆
A
- 库
B
需要库 A
; B
的 public headers 使用 public 包含来自 A
- 图书馆
C
不使用A
或B
文件系统:
.
|---A
| |---include
| | |---- A
| | |---- a.hpp
| |
| |--- a.cpp
|
|---B
| |---include
| | |---- B
| | |---- b.hpp
| |
| |--- b.cpp
|
|---C
| |---include
| | |---- C
| | |---- c.hpp
| |
| |--- c.cpp
|
|---CMakeLists.txt
现在您需要授予 B
,而不是 C
访问 A
的 headers。使用 target_link_libraries
这是微不足道的,但是使用 include_directories
你需要注意 CMakeLists.txt
中 add_subdirectory
的顺序
CMakeList.txt
add_subdirectory(A)
add_subdirectory(B)
add_subdirectory(C)
A/CMakeLists.txt
add_library(A ...)
target_include_directories(A PUBLIC include)
B/CMakeLists.txt
add_library(B ...)
target_include_directories(B PUBLIC include)
target_link_libraries(B PUBLIC A) # quite simple to provide access to A's include dir to linking libs using PUBLIC here, if required
C/CMakeLists.txt
add_library(C ...)
target_include_directories(C PUBLIC include)
现在假设您要将目录 A
重命名为 AB
。您需要做的就是重命名文件系统上的目录,并在 CMakeLists.txt
.
中将 add_subdirectory(A)
替换为 add_subdirectory(AB)
或者假设您想要使用库 B
和 C
作为更大项目的一部分:如果您使用 target_include_directories
而不是 include_directories
,是使用 add_subdirectory
添加包含顶层 CMakeLists.txt
的目录,您需要做的就是使用 target_link_libraries(NewTarget PRIVATE B C)
来访问所有必需的包含目录,而不是使用
add_subdirectory(OriginalProject)
include_directories(OriginalProject/B/include)
include_directories(OriginalProject/C/include)
include_directories(OriginalProject/A/include) # did you remember this one is needed by B?
add_executable(NewTarget ...)
看了一些关于CMake的视频,大家建议不要用include_directories
,改用target_include_directories
。但是我不明白这个推荐背后的真正原因是什么?
主要有3个原因
- 将包含目录的范围限制为仅那些需要它们的目标
- 允许修改一个目标而无需更新其他项目的 cmake 逻辑
- 允许更轻松地重用项目作为更大项目的一部分
限制包含目录的范围
目标是将包含目录的可见性降至最低。如果在执行 include_directories
后使用 add_subdirectory
,则从子目录或子目录的后代创建的所有目标都会看到添加了 include_directories
.
subdir/CMakeLists.txt
add_library(subdir_lib ...)
...
CMakeLists.txt
add_subdirectory(subdir)
...
include_directories(some_include_dir)
对
include_directories(some_include_dir)
...
add_subdirectory(subdir)
可能很难看出 2 个 CMakeLists.txt
文件之间的区别,尤其是当 2 个命令之间有很多逻辑时;这使得这种逻辑难以维护。
“继承”/易于重组
使用 target_include_directories
还可以更轻松地提供 link 需要包含目录的库的目标。通过 include_directories
添加的包含目录不能自动用于 linking 目标,但是使用 target_include_directories(... PUBLIC ...)
这很容易实现。 include_directories
不适用于从目录创建的目标,这些目录不是在包含该命令的子目录中创建的。
示例项目
- 图书馆
A
- 库
B
需要库A
;B
的 public headers 使用 public 包含来自A
- 图书馆
C
不使用A
或B
文件系统:
.
|---A
| |---include
| | |---- A
| | |---- a.hpp
| |
| |--- a.cpp
|
|---B
| |---include
| | |---- B
| | |---- b.hpp
| |
| |--- b.cpp
|
|---C
| |---include
| | |---- C
| | |---- c.hpp
| |
| |--- c.cpp
|
|---CMakeLists.txt
现在您需要授予 B
,而不是 C
访问 A
的 headers。使用 target_link_libraries
这是微不足道的,但是使用 include_directories
你需要注意 CMakeLists.txt
add_subdirectory
的顺序
CMakeList.txt
add_subdirectory(A)
add_subdirectory(B)
add_subdirectory(C)
A/CMakeLists.txt
add_library(A ...)
target_include_directories(A PUBLIC include)
B/CMakeLists.txt
add_library(B ...)
target_include_directories(B PUBLIC include)
target_link_libraries(B PUBLIC A) # quite simple to provide access to A's include dir to linking libs using PUBLIC here, if required
C/CMakeLists.txt
add_library(C ...)
target_include_directories(C PUBLIC include)
现在假设您要将目录 A
重命名为 AB
。您需要做的就是重命名文件系统上的目录,并在 CMakeLists.txt
.
add_subdirectory(A)
替换为 add_subdirectory(AB)
或者假设您想要使用库 B
和 C
作为更大项目的一部分:如果您使用 target_include_directories
而不是 include_directories
,是使用 add_subdirectory
添加包含顶层 CMakeLists.txt
的目录,您需要做的就是使用 target_link_libraries(NewTarget PRIVATE B C)
来访问所有必需的包含目录,而不是使用
add_subdirectory(OriginalProject)
include_directories(OriginalProject/B/include)
include_directories(OriginalProject/C/include)
include_directories(OriginalProject/A/include) # did you remember this one is needed by B?
add_executable(NewTarget ...)