Tips for CMake

变量与文件

变量

设置系统环境变量,如设置vcpkg的根目录:

1
set(ENV{VCPKG_ROOT} D:/vcpkg)

参考:stackoverflow

列表

列表追加

1
list(APPEND CMAKE_PREFIX_PATH "C:/Program Files/glew")

文件

保存某文件夹下的所有特定文件,如列出src文件夹下的所有.cpp文件保存在变量source中:

1
2
file(GLOB sources ${CMAKE_SOURCE_DIR}/src/*.cpp)
add_executable(myapp ${sources})

属性设置与定义

组织管理相关设置

添加VS项目筛选器

将项目放在一个Visual Studio筛选器下面,如将所有的测试项目放在tests下面:

1
2
3
set_property(GLOBAL PROPERTY USE_FOLDERS ON)  # 首先打开这个属性
set_property(TARGET test_app_1 PROPERTY FOLDER "tests")
set_property(TARGET test_app_2 PROPERTY FOLDER "tests")

添加VS文件夹

将文件组织在Visual Studio的一个文件夹下,如将CUDA的核函数放在一个单独的叫做CUDA kernels文件夹中

1
source_group("CUDA kernels" FILES ${KERNELS})

添加宏定义

1
2
3
4
set(DATAPATH ${PROJECT_SOURCE_DIR}/data)         # 定义路径变量
add_definitions("-DDATA_PATH=\"${DATAPATH}/\"") # 设置宏DATA_PATH

add_definitions(-DHAVE_OPENCV=1) # 设置宏HAVE_OPENCV且其值为1

添加预处理定义

为特定目标添加预处理定义

1
2
target_compile_definitions(mylib PRIVATE MYLIB_DEF1)  # PRIVATE属性指MYLIB_DEF1只针对mylib有效,且不能传递给依赖mylib的目标
target_compile_definitions(mylib PUBLIC MYLIB_DEF_2) # PUBLIC指MYLIB_DEF2可以传递给依赖mylib的目标

添加链接库

1
2
3
target_link_libraries(mylib PRIVATE mylib_dep1) # mylib_dep1依赖项只在mylib的实现中使用,而没有在其头文件中使用
target_link_libraries(mylib PUBLIC mylib_dep2) # mylib_dep2依赖项在头文件和实现中都有使用
target_link_libraries(mylib INTERFACE mylib_dep3) # mylib_dep3依赖项只在头文件中有使用

通常,如果仅在库的实现中使用了依赖项,而在头文件中没有使用,则应使用带有PRIVATE关键字的target_link_libraries()来指定依赖关系。如果在库的头文件中也使用了依赖项,则应将其指定为PUBLIC依赖项。如果依赖性没有在库的实现使用,只在库的头文件中使用,应该将其指定为INTERFACE依赖项。

添加Debug库后缀

为生成的Debug库添加后缀

1
2
3
4
5
if(WIN32)
set(CMAKE_DEBUG_POSTFIX "d")
endif()
add_library(mylib ${SOURCE_FILES})
set_target_properties(mylib PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})

添加64位库后缀

如果要区分生成的32位与64位库,可以通过下面的方式实现

1
2
3
4
5
6
7
if(CMAKE_SIZEOF_VOID_P EQUAL 4)
set(ARCH_POSTFIX "")
else()
set(ARCH_POSTFIX 64)
endif()

add_library(my_lib${ARCH_POSTFIX} ${SOURCE_FILES})

配置相关设置

链接静态库

根据Debug或者Release模式自动链接静态库,target_link_libraries()提供了debugoptimized参数,可以根据当前具体配置来链接相应的库。==注意==:debugoptimized后面只能紧跟着一个库名称。

1
target_link_libraries(myexe debug ${DBG_LIB} optimized ${REL_LIB} )

参考:cmake: target_link_libraries & stackoverflow

拷贝动态库

Windows平台根据Debug或者Release模式自动拷贝动态库到可执行文件目录下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Copy DLL to binary path in windows
macro(copy_dll target_name dll_path dll_name binary_path)
if (WIN32)
message("copy_dll() called: target_name = ${target_name}; dll_file = ${dll_path}/$<CONFIG>/${dll_name}; binary_path = ${binary_path}/$<CONFIG>/")
set(dll_dbg ${dll_path}/Debug/${dll_name}d.dll)
set(dll_rel ${dll_path}/Release/${dll_name}.dll)
#message("dll_dbg = ${dll_dbg}")
#message("dll_rel = ${dll_rel}")
add_custom_command(TARGET ${target_name} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo "copy $<CONFIG> dll $<IF:$<CONFIG:Debug>,${dll_dbg},${dll_rel}> to ${binary_path}/$<CONFIG>/"
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<IF:$<CONFIG:Debug>,${dll_dbg},${dll_rel}> ${binary_path}/$<CONFIG>/
COMMENT "copy dll for target ${target_name} done"
)
endif (WIN32)
endmacro()

参考:cmakecommands & tool-cmake

输出

输出包含路径

如果想要打印出项目的所有包含路径,使用命令

1
2
3
4
get_property(dirs DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES)
foreach(dir ${dirs})
message(STATUS "dir='${dir}'")
endforeach()

注意:上面方法只能追踪该命令调用前CMakeLists.txt中通过include_directories命令包含的路径。

命令

编译器

指定编译器

1
cmake -DCMAKE_CXX_COMPILER=g++-8 ..

CMake-GUI

指定编译器

如果需要用CMake-GUI生成VS2017的项目,但是使用VS2015的编译器,在下方填写

1
v140

对应的cmake命令是cmake -G "Visual Studio 15 2017" -T v140
另外VS2017对应v141VS2019对应v142

VS Code

Bugs Fix

LNK2026

  1. LNK2026: XXX模块对于SAFESEH映像是不安全的
    解决方法:在add_executableadd_library之前加

    1
    2
    3
    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO")
    set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /SAFESEH:NO")
    set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /SAFESEH:NO")

error C1128

  1. error C1128: 字节数超过对象文件格式限制: 请使用 /bigobj 进行编译
    解决方法:在CMakeLists.txt文件中加上

    1
    add_compile_options(-bigobj)