为什么不在 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 需要库 AB 的 public headers 使用 public 包含来自 A
  • 图书馆C不使用AB

文件系统:

.
|---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)

或者假设您想要使用库 BC 作为更大项目的一部分:如果您使用 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 ...)