> 文章列表 > cmake 常用方法自我总结

cmake 常用方法自我总结

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 SAVEXMLstd::cout << "save xml" << std::endl;
#elsestd::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博客