cmake 常用方法自我总结
目录
1. 编译一个库依赖另一个库
2. 把某一个CMakeLists.txt中变量设为整个工程中任意CMakeLists.txt都可以访问
3. 枚举目录下所有匹配文件
4. 拷贝文件
5. 解决方案下分Header Files,Source Files目录
6. 依赖头文件(附加依赖项)
7. install
8. 生成库、执行文件
9. 生成debug/release版本判读
10. 编译工程命令
11. 设置默认 C++ 标准
12. 工程示例
13. 指定字符集
14. 注意
15. Cmake设置宏,VS中使用
16. 参考
1. 编译一个库依赖另一个库
最近在做C++项目时,当编译A库得时候,A依赖B库,所以要先生成B库,然后把
B库的lib设置到A库中,一旦工程新建,就要把前面操作过程都执行下,挺繁琐。
cmake里面可以通过 “target_link_libraries” 这个方法来设置,如下:
target_link_libraries(pcb debug ${OpenCV_LIBS} common)
pcb库依赖opencv,common库,当我们这样设置的时候,在pcb工程属性中就可以看到自动设置好了依赖,如下图所示:
最关键的是,当我点击生成pcb库的时候,其会先自动生成common.lib库,然后再生成pcb库,也就是说,cmake会自动判断依赖项,并根据依赖项依次生成,非常方便便捷。
生成的库,还依赖别的生成库,或者依赖别的已有库,这时使用 target_link_libraries 命令,这个命令target_link_libraries一定要放到 add_library 或 add_executable 后面,不然会有问题。
2. 把某一个CMakeLists.txt中变量设为整个工程中任意CMakeLists.txt都可以访问
set(NEED_Lib_Path /xxx/xxx/opencv.lib CACHE STRING INTERNAL)
set命令中的 CACHE STRING INTERNAL 这几个参数就是把变量 NEED_Lib_Path 设为全局都可以访问
3. 枚举目录下所有匹配文件
当想把一个文件夹下所有文件都放到一个变量时,可以通过 file 和 set 一起使用,如下:
file(GLOB NEED_Lib_Dir xxx/xxx/lib/Release/*.lib)
set(NEED_Lib_Path ${NEED_Lib_Dir } CACHE STRING INTERNAL)
file命令通过GLOB参数,把xxx/xxx/lib/Release目录下所有后缀为 .lib 的文件全部以绝对路径放到变量 NEED_Lib_Dir 中。
接着通过set命令中的 CACHE STRING INTERNAL 这几个参数,把 NEED_Lib_Path 设为了全局,在整个工程中的CMakeLists.txt都可以访问整个参数。
4. 拷贝文件
file(COPY ${Debug_OpenCV_Bin} DESTINATION Debug)
这个命令是把变量 Debug_OpenCV_Bin 拷贝到此工程的 Debug 目录下
5. 解决方案下分Header Files,Source Files目录
为了更好的显示文件,需要对.h和.cpp进行分目录,如下图所示:
通过如下命令:
file(GLOB HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h ${CPP_H_CRYPTOPP_PATH}/*.h)
source_group("Header Files" FILES ${HEADERS})
aux_source_directory(src/ SOURCES)
1.先通过file的GLOB把所有文件放到变量HEADERS中
2.通过 source_group 把 HEADERS 变量中的内容放到 “Header Files” 目录中
3.那 aux_source_directory 这是 cmake 命令自动把 .cpp全部放到 “Source Files” 中,这个不需要我们再创建这个目录
6. 依赖头文件(附加依赖项)
通过如下命令,可以把好多不同路径下include都加到工程里,下面加了4个路径的include到工程中
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/ ${COMMON_LIB_PATH} ${DEBUG_NCNN_INCLUDE_PATH} ${DEBUG_CRYPTOPP_INCLUDE_PATH})
7. install
当我们点击install,会自动把需要提供给别人的库和头文件,lib都生成好,且自动输出一个目录下,效果如下图所示:
我当前是需要pcb这个库导出,所以 install 命令是写在 pcb 这个目录下的 CMakeLists.txt 中,命令如下:
set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/install" CACHE STRING "The path to use for make install" FORCE)
set(PCB_OUT_PUT_INCULDE ${CMAKE_CURRENT_SOURCE_DIR}/include/pcb.h)
install(FILES ${PCB_OUT_PUT_INCULDE} DESTINATION include)
install(TARGETS pcb LIBRARY DESTINATION CMAKE_INSTALL_PREFIX)
1.第一行的 set 以及里面内容是通用的,应该就默认这么写
2.第二行中是设置了PCB_OUT_PUT_INCULDE 为需要导出的 .h 文件
3.第三行通过 install 和 参数 FILES 把 .h 文件导出到 DESTINATION 路径下,这个 DESTINATION 参数也是默认的
4.通过 install 和 参数 TARGETS 把 pcb 的 lib 和 dll 导出到 DESTINATION 路径下。这里会把 pcb.lib 导出到 lib 目录,pcb.dll 导出到 bin 目录。pcb 后面跟的参数 “LIBRARY” 也是默认的
8. 生成库、执行文件
1.生成库
通过如下命令可以生成库,这里的 SHARED 是动态库,即 .dll,也可以改为 STATIC 生成 静态库,即 .lib。后面跟的 ${SOURCES} ${HEADERS} 是生成pcb库对应的源文件和头文件
add_library(pcb SHARED ${SOURCES} ${HEADERS})
2.生成执行文件,即 .exe
add_executable命令第一个参数是生成的执行文件名,后面是 ${DIR_LIB_SRCS} 源文件,这里依赖的头文件通过命令 include_directories 设置
add_executable(test ${DIR_LIB_SRCS})
9. 生成debug/release版本判读
通过如下命令可以判断生成debug版本,还是release版本
if(CMAKE_CONFIGURATION_TYPES AND (CMAKE_CONFIGURATION_TYPES STREQUAL "Debug"))
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/ ${COMMON_LIB_PATH} ${DEBUG_NCNN_INCLUDE_PATH} ${DEBUG_CRYPTOPP_INCLUDE_PATH})
target_link_libraries(pcb debug ${OpenCV_LIBS} ${DEBUG_NCNN_LIB_PATH} ${DEBUG_CRYPTOPP_LIB_PATH} common)
else()
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/ ${COMMON_LIB_PATH} ${RELEASE_NCNN_INCLUDE_PATH} ${RELEASE_CRYPTOPP_INCLUDE_PATH})
target_link_libraries(pcb optimized ${OpenCV_LIBS} ${RELEASE_NCNN_LIB_PATH} ${RELEASE_CRYPTOPP_LIB_PATH} common)
endif()
在生成cmake的时候可以在命令行输入:-D CMAKE_CONFIGURATION_TYPES:STRING=Debug 这样CMakeLists.txt 中就会自动判断是debug,还是release
10. 编译工程命令
cmake .. -A x64 -D CMAKE_CONFIGURATION_TYPES:STRING=Debug
11. 设置默认 C++ 标准
通过在顶级目录的CMakeLists.txt中设置,就可以达到下图效果
set(CMAKE_CXX_STANDARD 17)
12. 工程示例
1. 下图是我的工程示例,顶级必须设置的是下图右边红色框内容,顶级目录我基本设置一些路径,这样别人只需要修改这个 CMakeLists.txt 就可以了。这里我就把source加到工程中,因为代码都在source文件夹下
2. source目录下的内容如下:
3. 构建好的工程如下图所示:
4. 附一张 test 的 CMakeLists.txt 内容图以及命令
project(test)
set(OpenCV_DIR ${OpenCV_PATH})
#opencv
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
set(COMMON_INCLUDE ${CMAKE_CURRENT_SOURCE_DIR}/../common/include/)
# this is add C/C++ -> COMMON -> ADD INCLUDE
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/ ${COMMON_INCLUDE})
# 将当前目录下所有源码文件添加到变量DIR_LIB_SRCS
file(GLOB DIR_LIB_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
# 递归
# file(GLOB_RECURSE DIR_LIB_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h )
file(GLOB DIR_LIB_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h)
source_group("Header Files" FILES ${DIR_LIB_HEADERS})
message("Debug_OpenCV_Bin: ${Debug_OpenCV_Bin}")
file(COPY ${Debug_OpenCV_Bin} DESTINATION Debug)
file(COPY ${Release_OpenCV_Bin} DESTINATION Release)
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/../pcb/include/pcb.h DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/include)
link_directories(${JIANJU_OUT_PUT_INCULDE})
add_executable(test ${DIR_LIB_SRCS})
target_link_libraries(test ${OpenCV_LIBS} pcb)
13. 指定字符集
默认Visual Studio是使用 “使用多字节字符集”, 当某个工程需要使用 “使用 Unicode 字符集”,则在此CMakeLists.txt中加入如下,就可以指定设置 “使用 Unicode 字符集”,如下及下图所示:
add_definitions(-DUNICODE -D_UNICODE)
14. 注意
1. 有时候明明方法对,就是执行不对,比如message也显示不对变量,这个时候需要把之前生成的工程目录下所有文件全部删了,重新生成,这个时候就对了。
2. 生成的库,还依赖别的生成库,或者依赖别的已有库,这时使用 target_link_libraries 命令,这个命令target_link_libraries一定要放到 add_library 或 add_executable 后面,不然会有问题。
15. Cmake设置宏,VS中使用
有时需要通过宏定义来判断是否执行某个方法,这时候可以在cmake中传参数,然后在CMakeLists.txt中判断,并把参数设置到 visual studio 工程中
如下,我需要在 VS 代码中判断是否定义了宏 “SAVEXML”,顶层 CMakeLists.txt 中添加如下代码
if (SAVE STREQUAL XML)
add_definitions(-DSAVEXML)
endif()
cmake在编译的时候,传入参数:
cmake .. -A x64 -D CMAKE_CONFIGURATION_TYPES:STRING=Debug -DSAVE=XML
-DSAVE=XML 则为传入 CMakeLists.txt 的参数,接着在 VS 代码中添加如下判断:
#ifdef SAVEXML
std::cout << "save xml" << std::endl;
#else
std::cout << "not save xml" << std::endl;
#endif // SAVEXML
效果展示,如下是添加了-DSAVE=XML
如下是没有添加-DSAVE=XML,效果展示:
同时在项目属性中也可以看到,有 SAVEXML 宏定义,如下图所示:
仔细对比添加和没有添加对VS代码中影响,可以发现,添加了,则 #ifdef SAVEXML 代码高亮,没有添加的则灰色
16. 参考
1. cmake:在 CMake 生成的 VS2015 工程中保持源码文件的目录组织_cmake source_group_OceanStar的学习笔记的博客-CSDN博客
2.CMake定义宏的方式_cmake 宏定义_风闲1217的博客-CSDN博客
3.CMake通过外部传参执行不同逻辑的方案比如瑞芯微(1126)地平线(horizon)-CSDN博客