文章目录
一、CMake常用变量
在 CMake 中,有许多常见的变量可用于配置和管理构建过程。以下是一些常见的变量,包括当前源码路径:
CMAKE_SOURCE_DIR
:当前 CMakeLists.txt 所在的源码目录的根路径。CMAKE_BINARY_DIR
:构建目录的根路径,即构建生成的可执行文件、库和其他构建输出的存放位置。CMAKE_CURRENT_SOURCE_DIR
:当前处理的 CMakeLists.txt 所在的源码目录的路径。CMAKE_CURRENT_BINARY_DIR
:当前处理的 CMakeLists.txt 所在的构建目录的路径。CMAKE_CURRENT_LIST_DIR
:当前处理的 CMakeLists.txt 所在的路径(源码目录或构建目录)。CMAKE_CURRENT_LIST_LINE
:当前正在处理的 CMakeLists.txt 的行号。CMAKE_MODULE_PATH
:一个用于指定额外的 CMake 模块(.cmake 文件)的搜索路径的列表。CMAKE_INCLUDE_CURRENT_DIR
:如果设置为 ON,则在构建过程中自动将当前处理的 CMakeLists.txt 所在的目录添加到包含路径中。CMAKE_LIBRARY_OUTPUT_DIRECTORY
:库文件的输出目录。CMAKE_RUNTIME_OUTPUT_DIRECTORY
:可执行文件的输出目录。
以上是一些常用的 CMake 变量,其中包含了当前源码路径相关的变量。您可以在 CMakeLists.txt 文件中使用这些变量来设置路径、配置目录结构以及管理构建过程中的输出位置。
二、自定义头文件、链接库路径的方法
自定义头文件路径
可以使用 include_directories
命令来指定自定义的头文件路径。该命令会将指定的路径添加到编译器的头文件搜索路径中。
powershell
include_directories(path/to/include/dir)
你可以多次调用 include_directories 命令,以添加多个头文件路径。
自定义链接库路径
可以使用 link_directories
命令来指定自定义的链接库路径。该命令会将指定的路径添加到链接器的库搜索路径中。
powershell
link_directories(path/to/library/dir)
你可以多次调用 link_directories 命令,以添加多个链接库路径。
需要注意的是,尽量避免在 CMake 中使用 include_directories 和 link_directories 命令来处理第三方库的头文件和链接库路径
。更好的做法是使用 find_package 命令或编写 Find 模块来查找和链接第三方库,这样可以更好地管理依赖关系和跨平台兼容性
。
另一种实现的命令
另外,对于特定的库 ,你还可以使用 target_include_directories
命令和 target_link_directories
命令,将自定义的头文件路径和链接库路径应用于特定的目标。
powershell
target_include_directories(target_name PUBLIC path/to/include/dir)
target_link_directories(target_name PUBLIC path/to/library/dir)
这样可以确保自定义路径只应用于特定的目标,并使得相关路径不会泄漏到其他目标中
。
通过以上方式,你可以在 CMake 中自定义头文件路径和链接库路径,以满足项目的需求。
两种命令的区别介绍
target_include_directories() 的功能完全可以使用 include_directories() 实现。但是我还是建议使用 target_include_directories()。为什么?保持清晰!
include_directories(header-dir)
是一个全局包含,向下传递
。什么意思呢?就是说如果某个目录的 CMakeLists.txt 中使用了该指令,其下所有的子目录默认也包含了header-dir 目录。
上述例子中,如果在顶层的 cmake-test/CMakeLists.txt 中加入:
powershell
include_directories(hello-world)
include_directories(hello-world/hello)
include_directories(hello-world/world)
那么整个工程的源文件在编译时都会增加:
powershell
-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() 的效果是相同的。
而使用 target_include/link_directories()
每一个目录都是一个模块,目录内部应将对外和对内的头文件进行区分,由模块的调用者决定模块是否被传递(PRIVATE,INTERFACE,PUBLIC)。
测试工程目录结构:
powershell
cmake-test/ 工程主目录,main.c 调用 libhello-world.so
├── CMakeLists.txt
├── hello-world 生成 libhello-world.so,调用 libhello.so 和 libworld.so
│ ├── CMakeLists.txt
│ ├── hello 生成 libhello.so
│ │ ├── CMakeLists.txt
│ │ ├── hello.c
│ │ └── hello.h libhello.so 对外的头文件
│ ├── hello_world.c
│ ├── hello_world.h libhello-world.so 对外的头文件
│ └── world 生成 libworld.so
│ ├── CMakeLists.txt
│ ├── world.c
│ └── world.h libworld.so 对外的头文件
└── main.c
调用关系:
powershell
├────libhello.so
可执行文件────libhello-world.so
├────libworld.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 中应该写入:
powershell
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 提供的功能,只使用 hello.h 中的某些信息,比如结构体。但是 main.c 需要使用 libhello.so 中的功能。那么在 hello-world/CMakeLists.txt 中应该写入:
powershell
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 中应该写入:
powershell
target_link_libraries(hello-world PUBLIC hello)
target_include_directories(hello-world PUBLIC hello)
实际上,这三个关键字指定的是目标文件依赖项的使用范围(scope)或者一种传递(propagate)
。官方说明
可执行文件依赖 libhello-world.so, libhello-world.so 依赖 libhello.so 和 libworld.so。
- main.c 不使用 libhello.so 的任何功能,因此 libhello-world.so 不需要将其依赖 libhello.so 传递给 main.c ,hello-world/CMakeLists.txt 中使用
PRIVATE
关键字;- main.c 使用 libhello.so 的功能,但是libhello-world.so 不使用 ,hello-world/CMakeLists.txt 中使用
INTERFACE
关键字;- main.c 和 libhello-world.so 都使用 libhello.so 的功能 ,hello-world/CMakeLists.txt 中使用
PUBLIC
关键字;
补充阅读:
CMake的链接选项:PRIVATE,INTERFACE,PUBLIC
参考链接:
https://zhuanlan.zhihu.com/p/631823872
https://zhuanlan.zhihu.com/p/82244559
仅作学习记录