CMake系列:问题解决点滴记录

Posted 岬淢箫声

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CMake系列:问题解决点滴记录相关的知识,希望对你有一定的参考价值。

文章目录

1. CMake点滴记录

1.1. 如何理解、使用CMake多配置编译系统

  1. 常见错误

    以Debug和Release配置有不同的宏定义为例,如下所示:

    if(NOT DEFINED CMAKE_BUILD_TYPE)
        add_definitions(-DDEBUG)
    else()
        add_definitions(-DRELEASE)
    endif()
    
  2. 问题现象

    1. 按Debug运行Configure后Release配置没有 RELEASE宏定义,按Release运行Configure后Debug配置没有 DEBUG宏定义。
    2. 每次运行 cmake -B命令只能看到一个宏定义
  3. 正确做法

    add_definitions(
         $<$<CONFIG:DEBUG>:-DDEBUG> 
         $<$<CONFIG:RELEASE>:-DRELEASE>
     )
    

    或者

    add_definitions($<IF:$<CONFIG:DEBUG>,-DDEBUG,-DRELEASE>)
    
  4. CMake的最少Configure原则

    以下典型的情况不运行Configure:

    1. 项目配置没有改变
    2. CMake运行环境没有改变:操作系统版本、编译器版本等等
    3. 不是准备版本发布
  5. CMake统一原则

    同一个项目只有同一步CMakeLists.txt,应对不同的编译器、不同的操作系统。

  6. cmake if指令应该什么时候使用

    1. 不同的编译器有不同的编译选项,比如MSVC和GCC
    2. 不同的目标平台有不同的编译选项,比如Windows和Linux
  7. 活学活用

    CI只需要验证Debug配置环境可运行:cmake -B build -DCMAKE_BUILD_TYPE=Debug,Release同理。
    CI只需要验证Debug编译结果可运行:cmake --build build --config Debug -j 16,Release同理。

  8. CMake淘汰的用法

    项目属性+配置名的做法已被逐步淘汰。举例如下:

    set(COMPILE_DEFINITIONS_DEBUG   DEBUG)   # 3.23版本已不起作用
    set(COMPILE_DEFINITIONS_RELEASE RELEASE) # 3.23版本已不起作用
    set_target_properties($PROJECT_NAME PROPERTIES 
        LIBRARY_OUTPUT_NAME_DEBUG   testd
        LIBRARY_OUTPUT_NAME_RELEASE test
    )
    

1.2. 判断环境变量是否存在

方法1:

if(NOT DEFINED ENVQt5_DIR)
    message(FATAL_ERROR "environment variable Qt5_DIR is required.")
else()
    message("---- Qt5_DIR is set to " $ENVQt5_DIR)
endif()

方法2:

if("$ENVQt5_DIR" STREQUAL "")
    message(FATAL_ERROR "environment variable Qt5_DIR is required.")
else()
    message("---- Qt5_DIR is set to " $ENVQt5_DIR)
endif()

1.3. VS调试不用windeployqt

像Qt Creator一样调试

set_property(TARGET LTFocus PROPERTY VS_DEBUGGER_ENVIRONMENT "PATH=$ENVQt5_DIR/bin")
set_property(TARGET LTFocus PROPERTY VS_DEBUGGER_WORKING_DIRECTORY "$EXECUTABLE_OUTPUT_PATH")

1.4. Debug与Release输出不同名称的编译结果

set_property(TARGET LTFocus PROPERTY DEBUG_POSTFIX "d")

1.5. CMake不用手动添加源代码

举例:

file(GLOB SRCS *.h *.cpp *.ui *.rc *.qrc)
add_executable($PROJECT_NAME $SRCS)

GLOB换成 GLOB_RECURSE,结果包含子目录下的代码文件。

1.6. CMake在Windows上生成没有控制台的程序

方法1:

if(MSVC)
   add_executable($PROJECT_NAME WIN32 $SRCS)
endif()

方法2:

if(MSVC)
   add_link_options(/SUBSYSTEM:WINDOWS)
endif()

1.7. CMake添加编译生成事件

set(EXE_DIR $CMAKE_SOURCE_DIR/$CMAKE_BUILD_TYPE/)
cmake_path(NATIVE_PATH EXE_DIR EXE_DIR)
add_custom_command(TARGET $PROJECT_NAME POST_BUILD 
   COMMAND copy test.* $EXE_DIR /Y
   WORKING_DIRECTORY $CMAKE_BINARY_DIR/$CMAKE_BUILD_TYPE)
  1. POST_BUILD指编译成功后,PRE_BUILD指编译成功前。
  2. EXE_DIR最后面的杠是必须的,因为copy命令不判断复制来源是目录还是文件。如果末尾没有杠且复制目的地不存在同名目录,copy就会在目的地创建与目录同名的文件,然后复制失败。
  3. cmake_path的作用是转换路径分隔符,copy命令不支持Linux风格的路径。

1.8. VS项目设置UNICODE

这里有个坑,常见错误的做法

add_compile_definitions(UNICODE _UNICODE)

正确的做法

add_definitions(-DUNICODE -D_UNICODE)

add_definitions的每个宏定义须添加-D前缀,add_compile_definitions的每个宏定义不需要前缀。最终执行的编译命令,所有的宏都有 -D/D前缀。

1.9. 一个子项目的属性如何传递到另一个子项目

CMake中变量的作用域是自上而下的,一个下层项目的属性传递给另一个子项目的属性,如果没有上下级关系,则需要通过 set_propertyget_property指令实现。对于整个CMake项目树结构,需先添加 set_property的下级项目,后添加 get_property的下级项目。

1.10. CMake使用Qt MOC、界面和资源文件

方法1:打开CMake支持Qt的自动化设置,把Qt资源以代码形式直接添加到项目

set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)
add_executable($PROJECT_NAME *.qrc *.ui)

方法2:按Qt资源命名规则生成代码,把生成代码添加到项目。下面代码以UI文件为例。

file(GLOB UI_SOURCES *.ui)
qt5_wrap_ui(UI_SOURCES $UI_GENERATED)
foreach(UI_SRC $UI_GENERATED)
    cmake_path(GET UI_SRC PARENT_PATH UI_DIR)
    include_directories($UI_DIR)
endforeach()

1.11. CMake多编译器支持

方法1:直接设置编译器路径

set(CMAKE_SYSTEM_NAME QNX)

set(arch gcc_ntoarmv7le)

set(CMAKE_C_COMPILER qcc)
set(CMAKE_C_COMPILER_TARGET $arch)
set(CMAKE_CXX_COMPILER QCC)
set(CMAKE_CXX_COMPILER_TARGET $arch)

set(CMAKE_SYSROOT $ENVQNX_TARGET) 

方法2:利用CMake的探测机器。以VC为例,CMake运行环境存在 %VCINSTALLDIR%,则CMake能自动找到 cl编译器,进而确认编译器版本和特性。VCINSTALLDIR环境变量是Visual Studio提供的 vcvarsall.bat提供的。典型的环境初始化代码:

@echo off
title Visual Studio 2019 Development Kit
set WORKDIR=%cd%
set Qt5_DIR=C:\\Qt\\Qt5.14.0\\5.14.0\\msvc2017_64
set GENERATOR=Visual Studio 16 2019
call "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Auxiliary\\Build\\vcvarsall.bat" x64
call "%Qt5_DIR%\\bin\\qtenv2.bat"
set PATH=%PATH%;C:\\Qt\\qtcreator-7.0.2\\bin;C:\\Program Files\\CMake\\bin
cd /d "%WORKDIR%"
cmd /k echo OK!

CMake能探测以默认选项安装的开发工具,比如VS安装到C盘,则即使不设置环境变量,CMake也能找到VC编译器。

1.12 关闭链接警告

CMake v3.24.3

代码add_link_options(/IGNORE:4099,4098)不起作用,
代码set_target_properties($PROJECT_NAME PRIVATE LINK_FLAGS "/IGNORE:4099,4098")可正常关闭链接警告。

1.13 有空格的宏定义不是字符串类型

错误的做法:add_compile_definitions(GC_API="__host__ __device__")。实际结果是代码多了一个字符串类型的宏定义,不能作用于NVIDIA GPU函数修饰符。正确做法是使用转义字符把空格转义,即:add_compile_definitions(GC_API=__host__\\ __device__)

1.14 版本号转十六进制整数

project(Test1DLL VERSION 2.1.3.1)
math(EXPR AOI_INT_VER "$PROJECT_VERSION_MAJOR<<24|$PROJECT_VERSION_MINOR<<16|$PROJECT_VERSION_PATCH<<8|$PROJECT_VERSION_TWEAK" OUTPUT_FORMAT HEXADECIMAL)
add_compile_definitions(Test1DLL_EXPORTS AOI_PF_VER="$PROJECT_VERSION" AOI_INT_VER=$AOI_INT_VER)

1.15 CMake文件读写操作

    write_file($LIBRARY_OUTPUT_DIRECTORY/Test1/makelib.cmd "@echo off")
    write_file($LIBRARY_OUTPUT_DIRECTORY/Test1/makelib.cmd "title libTest1 release tool by zhtqs8@163.com" APPEND)
    write_file($LIBRARY_OUTPUT_DIRECTORY/Test1/makelib.cmd "set CA7ZIP=C:\\\\Program Files\\\\7-Zip\\\\7z.exe" APPEND)
    write_file($LIBRARY_OUTPUT_DIRECTORY/Test1/makelib.cmd "set CVER=$PROJECT_VERSION" APPEND)
    write_file($LIBRARY_OUTPUT_DIRECTORY/Test1/makelib.cmd "if not exist \\"%CA7ZIP%\\" echo 7-zip is required. && goto end" APPEND)
    write_file($LIBRARY_OUTPUT_DIRECTORY/Test1/makelib.cmd "\\"%CA7ZIP%\\" a \\"libTest1%CVER%.zip\\" libTest12.0.dll libTest12.0.lib libTest12.0.pdb libTest12.0*.md ../../src/test1/Test1DevCommon.h ../../src/test2/Test1Dev.h ../../src/test3/Test1Common.h" APPEND)
    write_file($LIBRARY_OUTPUT_DIRECTORY/Test1/makelib.cmd ":end" APPEND)
    write_file($LIBRARY_OUTPUT_DIRECTORY/Test1/makelib.cmd "pause" APPEND)
作者:岬淢箫声
邮箱:zhtqs8@163.com
来源:https://caowei.blog.csdn.net/article/details/129088446

以上是关于CMake系列:问题解决点滴记录的主要内容,如果未能解决你的问题,请参考以下文章

[记录点滴] 一个解决Lua 随机数生成问题的办法

点滴记录——在Ubuntu 14.04中使SublimeText 3支持中文输入法

python学习点滴记录-Day01

windows使用记录---2019.8月补丁更新后出现windows7系列UEFI无法启动解决办法

记录点滴,厚积薄发!

C++学习--点滴记录001