CMake学习心得
不知道抽什么风,突然想起要学学CMake了,不学不知道,一学吓一跳,CMake功能真心强大,有各种寻找库包的支持,而且适合对跨平台打包
CMake Variables
1. cmake_source_dir
vs project_source_dir
可以首先看看stackoverflow上的一个回答, 这两个变量有些细微的区别,cmake_source_dir
的确指向CMakeLists.txt被定义的那个顶层目录,而project_source_dir
指向的是CMakeLists.txt含有的那个最近的project()命令的目录
举个例子说吧,比如有一个顶层项目,名称为Outer,它含有一个子目录,该子目录有它自己的项目Inner,Outer的CMakeLists.txt内容为
project(Outer)
add_subdirectory(Inner)
Inner的CMakeLists.txt内容为
project(Inner)
这两个CMakeLists文件中,两个CMakeLists.txt的cmake_source_dir
都指向Outer的源目录,但Outer的project_source_dir
也指向Outer的源目录,Inner的project_source_dir
指向Inner的源目录(含有project()), 这两个变量的区别与其他PROJECT_<var>
和CMAKE_<var>
一致.
2. find_package
在CMake官网浏览时才发现,原来CMake支持多个库包的搜索,再也不用为这些库包做些额外的include操作了,比如FindOpenGL、FindOpenCL、FindVulkan等,可以在官网cmake-modules查看,或者你可以通过执行命令
cmake --help-module-list
查看,在Ubuntu上一般都在/usr/local/share/cmake/Modules
目录
具体使用可以见CMake-Wiki-How to find library, 这里做简单介绍
2.1 如何使用CMake官方支持find的库
先考虑一个例子,现在要用bzip2库,编译器需要知道bzlib.h文件在哪,链接器需要知道bzip2库在哪(假如是动态链接,windows平台会找libbz2.dll,Unix平台会找libbz2.so),如何去Find呢?下面是CMakeLists.txt内容
cmake_minimum_required(VERSION 2.8)
project(helloworld)
add_executable(helloworld hello.c)
find_package (BZip2)
if (BZIP2_FOUND)
include_directories(${BZIP_INCLUDE_DIRS})
target_link_libraries (helloworld ${BZIP2_LIBRARIES})
endif (BZIP2_FOUND)
通过include_directories
及target_link_libraries
的使用,就可以来查系统上的bzlib.h及bzip2库了
2.2 如何使用CMake官方暂时不支持find的库
假设你想使用LibXML++库,但CMake没有一个libXML++的find模块,但你在网上google到一个文件FindLibXML++.cmake, 在CMakeLists.txt里可以写
find_package(LibXML++ REQUIRED)
include_directories(${LibXML++_INCLUDE_DIRS})
set(LIBS ${LIBS} ${LibXML++_LIBRARIES})
如果这个包可选, 你可以省略REQUIRED
关键字,可以通过boolean变量LibXML++_FOUND
看是否有被found, 然后
target_link_libraries(exampleProgram ${LIBS})
为了让这起作用,还要将FindLibXML++.cmake文件放在CMake模块路径下,
当前的CMake那边走不通,自然需要我们这边在project里设置路径,在project根目录,创建一个路径为cmake/Modules/文件夹,而后把FindLibXML++.cmake放在该文件夹下,根目录的CMakeLists.txt里包含如下代码
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
这样CMake将自动的去find.
3. find_path & find_library
分别用来寻找头文件和库文件的路径
4. source_group
之前遇到用CMake构建VS项目,得到的VS项目缺少头文件列表信息,这个命令可以用来干这事,参考Listing header files in Visual Studio C++ project generated by cmake, 官方对该命令source_group解释
5. file
该命令可以对文件做许多操作,如重命名、移除、新建目录, 例如,使用正则表达式将同后缀的文件名打包
file(GLOB MODULES_HEADER "${CMAKE_SOURCE_DIR}/*.h" "${CMAKE_SOURCE_DIR}/vulkan/*.h")
小功能
CMake保证项目目录结构
通过source_group
的应用,保证源目录及头文件目录,均显示在生成的目录结构中
set(ALL_FILES
src/SomeClass.cpp
include/SomeClass.h
...)
add_library(MyLibrary ${ALL_FILES})
foreach(FILE ${ALL_FILES})
get_filename_component(PARENT_DIR "${FILE}" PATH)
# skip src or include and changes /'s to \\'s
string(REGEX REPLACE "(\\./)?(src|include)/?" "" GROUP "${PARENT_DIR}")
string(REPLACE "/" "\\" GROUP "${GROUP}")
# group into "Source Files" and "Header Files"
if ("${FILE}" MATCHES ".*\\.cpp")
set(GROUP "Source Files\\${GROUP}")
elseif("${FILE}" MATCHES ".*\\.h")
set(GROUP "Header Files\\${GROUP}")
endif()
source_group("${GROUP}" FILES "${FILE}")
endforeach()
set_property
set_property()
在特定作用于下设置多种属性
exclude file or folder
解决方案
aux_source_directory(src _srcFiles)
list(REMOVE_ITEM _srcFiles "src/f4.cpp")
推荐阅读
- 递归添加子目录