在使用 CMake 构建项目时,管理路径和链接库是非常重要的。CMake 提供了多个命令来设置头文件路径、库文件路径及链接库。其中,include_directories
、link_directories
和 link_libraries
是最常用的三个命令。它们的作用分别是:设置头文件搜索路径、设置库文件搜索路径以及指定需要链接的库文件。
1. include_directories
功能
include_directories
用于指定编译阶段头文件的搜索路径。
用法
include_directories(path1 path2 ...)
- 作用阶段:编译阶段。
- 作用对象:头文件(如
.h
或.hpp
)。 - 作用范围:默认全局,影响当前 CMakeLists.txt 文件中所有的目标。
影响
告诉编译器在查找 #include
的头文件时,除了默认路径,还可以从指定路径中查找。
示例
include_directories(${CMAKE_SOURCE_DIR}/include)
add_executable(my_target main.cpp)
在上述示例中,main.cpp
可以通过 #include
使用 ${CMAKE_SOURCE_DIR}/include
下的头文件。
现代替代方案
在现代 CMake 中,推荐使用目标作用域的 target_include_directories
,以精确控制头文件路径的作用范围。
target_include_directories(my_target PUBLIC ${CMAKE_SOURCE_DIR}/include)
2. link_directories
功能
link_directories
用于指定链接阶段库文件的搜索路径。
用法
link_directories(directory1 directory2 ...)
- 作用阶段:链接阶段。
- 作用对象:库文件(如
.so
、.a
、.lib
等)。 - 作用范围:全局,影响当前 CMakeLists.txt 文件中所有的目标。
影响
告诉链接器在查找目标库文件时,除了默认路径,还可以从指定路径中查找。
示例
link_directories(${CMAKE_SOURCE_DIR}/libs)
add_executable(my_target main.cpp)
target_link_libraries(my_target my_library)
在上述示例中,链接器会在 ${CMAKE_SOURCE_DIR}/libs
中查找名为 my_library
的库文件。
注意事项
- 仅指定库的搜索路径,并不会直接将库文件链接到目标。
- 如果可能,优先使用绝对路径或通过
find_package
指定库。
现代替代方案
建议直接在 target_link_libraries
中使用库的完整路径,避免使用 link_directories
。
3. link_libraries
功能
link_libraries
用于指定全局或局部范围的链接库。
用法
link_libraries(library1 library2 ...)
- 作用阶段:链接阶段。
- 作用对象:库文件(如
.so
、.a
、.lib
等)。 - 作用范围:
- 全局:直接使用
link_libraries
,会影响当前 CMakeLists.txt 中定义的所有目标。 - 局部:通过作用域关键字限制作用范围(例如
PUBLIC
、PRIVATE
)。
- 全局:直接使用
影响
在链接目标时,自动添加指定的库文件。
示例
link_libraries(my_library)
add_executable(target1 main.cpp)
add_executable(target2 other.cpp)
上述代码中,my_library
会被自动添加到 target1
和 target2
的链接阶段。
局部范围控制
可以通过作用域关键字限制库的作用范围:
link_libraries(PUBLIC my_library)
现代替代方案
现代 CMake 更推荐直接使用 target_link_libraries
,为目标精确设置所需的库。
target_link_libraries(my_target PRIVATE my_library)
三者的区别
命令 | 作用 | 作用阶段 | 作用范围 | 现代替代方案 |
---|---|---|---|---|
include_directories | 指定头文件搜索路径 | 编译阶段 | 默认全局 | target_include_directories |
link_directories | 指定库文件搜索路径 | 链接阶段 | 默认全局 | 避免使用,直接指定完整路径 |
link_libraries | 为所有后续目标指定链接库 | 链接阶段 | 默认全局或局部作用域 | target_link_libraries |
如何选择正确的命令?
-
优先使用目标作用域命令
- 如果仅需对单个目标进行设置,直接使用
target_include_directories
和target_link_libraries
。 - 避免全局命令(如
link_libraries
和include_directories
),以减少潜在的冲突。
- 如果仅需对单个目标进行设置,直接使用
-
尽量避免使用
link_directories
- 在现代 CMake 中,直接通过
target_link_libraries
指定库的完整路径更安全。 - 如果必须使用,请确保路径唯一并清晰。
- 在现代 CMake 中,直接通过
-
控制依赖传播
- 通过
PRIVATE
、PUBLIC
和INTERFACE
等关键字明确依赖的传播规则。
- 通过
示例:完整的现代 CMake 使用方式
cmake_minimum_required(VERSION 3.20)
project(MyProject)# 指定头文件和库的路径
set(MY_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/include)
set(MY_LIBRARY_DIR ${CMAKE_SOURCE_DIR}/libs)
set(MY_LIBRARY my_library)# 定义目标
add_executable(my_target main.cpp)# 为目标设置头文件路径
target_include_directories(my_target PRIVATE ${MY_INCLUDE_DIR})# 直接设置库文件
target_link_libraries(my_target PRIVATE ${MY_LIBRARY_DIR}/${MY_LIBRARY})
总结
include_directories
用于头文件路径,link_directories
用于库文件路径,而link_libraries
用于全局设置链接库。- 在现代 CMake 中,更推荐使用目标作用域的命令如
target_include_directories
和target_link_libraries
。 - 避免全局命令可以提高配置的可维护性和可读性。