CMake 教程

CMake 概述

CMake是一个跨平台的编译(Build)工具,可以用简单的语句来描述所有平台的编译过程。

CMake 常见的宏

后面会用到,先在前面做个记录

功能
PROJECT_SOURCE_DIR 使用cmake命令后紧跟的目录,一般是工程的根目录
PROJECT_BINARY_DIR 执行cmake命令的目录
CMAKE_CURRENT_SOURCE_DIR 当前处理的CMakeLists.txt所在的路径
CMAKE_CURRENT_BINARY_DIR target 编译目录
EXECUTABLE_OUTPUT_PATH 重新定义目标二进制可执行文件的存放位置
LIBRARY_OUTPUT_PATH 重新定义目标链接库文件的存放位置
PROJECT_NAME 返回通过PROJECT指令定义的项目名称
CMAKE_BINARY_DIR 项目实际构建路径,假设在build目录进行的构建,那么得到的就是这个目录的路径

CMake 使用

注释

  • 注释行
    CMake 使用 #进行注释,可以放在任何位置
    # 这是一个 CMakeLists.txt 文件
    cmake_minimum_required(VERSION 3.0.0)
    
  • 注释块
    CMake 使用 #[[ ]]进行块注释
    #[[这是一个 CMakeLists.txt 文件。
    这是一个 CMakeLists.txt 文件
    这是一个 CMakeLists.txt 文件]]
    cmake_minimum_required(VERSION 3.0.0)
    

CMake测试

  • 文件结构
    leon@leon:prj1$ tree
    .
    ├── CMakeLists.txt
    ├── build
    └── src
        ├── main.cpp
        └── operator
            ├── add.cpp
            ├── add.hpp
            ├── sub.cpp
            └── sub.hpp
    
    3 directories, 6 files
    
  • CMakeLists.txt
    cmake_minimum_required(VERSION 3.0)
    
    project(CALC)
    
    include_directories(src)
    
    add_executable(app src/main.cpp src/operator/add.cpp src/operator/sub.cpp)
    
    对上面用到的CMake语句的解释
    • cmake_minimum_required
      指定使用的 cmake 的最低版本。 可选,非必须,如果不加可能会有警告
    • project
      定义工程名称,并可指定工程的版本、工程描述、web主页地址、支持的语言(默认情况支持所有语言),如果不需要这些都是可以忽略的,只需要指定出工程名字即可。
      # PROJECT 指令的语法是:
      project(<PROJECT-NAME> [<language-name>...])
      project(<PROJECT-NAME>
           [VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]
           [DESCRIPTION <project-description-string>]
           [HOMEPAGE_URL <url-string>]
           [LANGUAGES <language-name>...])
      
    • include_directories
      将给定的目录添加到编译器用于搜索包含文件的目录中。相对路径被解释为相对于当前源目录。
      # include_directories 指令的语法是:
      include_directories([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...])
      
      BEFORE | AFTER:可选参数,它们用于指定包含目录的添加顺序。如果使用AFTER修饰符,那么添加的目录将会放在已有包含目录的后面;如果使用BEFORE修饰符,那么添加的目录将会放在已有包含目录的前面。默认情况下,新的包含目录会放在已有目录的后面。
      SYSTEM:是一个可选的修饰符,用于指定所包含的目录是系统级别的目录。当使用SYSTEM修饰符时,编译器会将这些目录视为系统级别的头文件目录,这意味着编译器不会产生关于这些目录的警告信息。
    • add_executable
      定义工程会生成一个可执行程序
      # 源文件名可以是一个也可以是多个,如有多个可用空格或;间隔
      add_executable(可执行程序名 源文件名称)
      
  • 编译效果


    image.png

进一步优化CMakeLists.txt

  • 定义变量

    # SET 指令的语法是:
    # [] 中的参数为可选项, 如不需要可以不写
    SET(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])
    

    VAR : 变量名称
    VALUE : 变量值
    例如将所有的源文件都存储到同一个变量中

    SET(SRC_LIST  src/main.cpp src/operator/add.cpp src/operator/sub.cpp)
    add_executable(app  ${SRC_LIST})
    
  • 指定C++标准

    #增加-std=c++11
    set(CMAKE_CXX_STANDARD 11)
    #增加-std=c++14
    set(CMAKE_CXX_STANDARD 14)
    #增加-std=c++17
    set(CMAKE_CXX_STANDARD 17)
    
    #增加-std=c++11
    cmake CMakeLists.txt文件路径 -DCMAKE_CXX_STANDARD=11
    #增加-std=c++14
    cmake CMakeLists.txt文件路径 -DCMAKE_CXX_STANDARD=14
    #增加-std=c++17
    cmake CMakeLists.txt文件路径 -DCMAKE_CXX_STANDARD=17
    
  • 指定可执行文件输出路径
    在CMake中指定可执行程序输出的路径,也对应一个宏,叫做EXECUTABLE_OUTPUT_PATH,它的值还是通过set命令进行设置:

    # 如果这个路径中的子目录不存在,会自动生成,无需自己手动创建
    set(HOME /mnt/d/workspace/code/cmaketest/prj1)
    set(EXECUTABLE_OUTPUT_PATH ${HOME}/workspace)
    
  • 文件搜索
    如果项目中的可执行文件太多,手动添加太过繁琐
    方式一
    在 CMake 中使用aux_source_directory 命令可以查找某个路径下的所有源文件,命令格式为

    aux_source_directory(< dir > < variable >)
    

    dir:要搜索的目录
    variable:将从dir目录下搜索到的源文件列表存储到该变量中
    方式二
    在 CMake 中使用file命令可以查找某个路径下的所有源文件,命令格式为:

    file(GLOB/GLOB_RECURSE 变量名 要搜索的文件路径和文件类型)
    

    GLOB: 将指定目录下搜索到的满足条件的所有文件名生成一个列表,并将其存储到变量中。
    GLOB_RECURSE:递归搜索指定目录,将搜索到的满足条件的文件名生成一个列表,并将其存储到变量中。

  • 使用文件搜索对上面使用的CMakeLists.txt进行改造

    cmake_minimum_required(VERSION 3.0)
    
    project(CALC)
    
    include_directories(src)
    
    set(HOME /mnt/d/workspace/code/cmaketest/prj1)
    set(EXECUTABLE_OUTPUT_PATH ${HOME}/workspace)
    
    file(GLOB_RECURSE SRC_LIST ${HOME}/src/*.cpp)
    add_executable(app ${SRC_LIST})
    

制作静态库

  • 语法
    add_library(库名称 STATIC 源文件1 [源文件2] ...) 
    
    在Linux中,静态库名字分为三部分:lib+库名字+.a,此处只需要指定出库的名字就可以了,另外两部分在生成该文件 的时候会自动填充。
  • 测试制作静态库
    文件结构
    .
    ├── CMakeLists.txt
    ├── build
    ├── src
    │   ├── main.cpp
    │   └── operator
    │       ├── add.cpp
    │       ├── add.hpp
    │       ├── sub.cpp
    │       └── sub.hpp
    └── workspace
        └── app
    
    4 directories, 7 files
    
    CMakeLists.txt
    cmake_minimum_required(VERSION 3.0)
    
    project(CALC)
    set(CMAKE_CXX_STANDARD 11)
    
    include_directories(src)
    
    set(HOME /mnt/d/workspace/code/cmaketest/prj1)
    set(EXECUTABLE_OUTPUT_PATH ${HOME}/workspace)
    
    file(GLOB_RECURSE SRC_LIST ${HOME}/src/operator/*.cpp)
    # add_executable(app ${SRC_LIST})
    add_library(calc STATIC ${SRC_LIST})
    
    这样最终就会生成对应的静态库文件libcalc.a。

制作动态库

  • 语法

    add_library(库名称 SHARED 源文件1 [源文件2] ...) 
    

    在Linux中,动态库名字分为三部分:lib+库名字+.so,此处只需要指定出库的名字就可以了,另外两部分在生成该文件的时候会自动填充。

  • 测试制作动态库
    文件结构

    .
    ├── CMakeLists.txt
    ├── build
    ├── src
    │   ├── main.cpp
    │   └── operator
    │       ├── add.cpp
    │       ├── add.hpp
    │       ├── sub.cpp
    │       └── sub.hpp
    └── workspace
        └── app
    
    4 directories, 7 files
    

    CMakeLists.txt

    cmake_minimum_required(VERSION 3.0)
    project(CALC)
    set(CMAKE_CXX_STANDARD 11)
    include_directories(src)
    set(HOME /mnt/d/workspace/code/cmaketest/prj1)
    set(EXECUTABLE_OUTPUT_PATH ${HOME}/workspace)
    file(GLOB_RECURSE SRC_LIST ${HOME}/src/operator/*.cpp)
    # add_executable(app ${SRC_LIST})
    add_library(calc SHARED ${SRC_LIST})
    

    这样最终就会生成对应的静态库文件libcalc.so。

设置库文件生成路径

  • 方式1
    对于生成的库文件来说和可执行程序一样都可以指定输出路径。由于在Linux下生成的动态库默认是有执行权限的,所以可以按照生成可执行程序的方式去指定它生成的目录
    set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
    
  • 方式2
    由于在Linux下生成的静态库默认不具有可执行权限,所以在指定静态库生成的路径的时候就不能使用EXECUTABLE_OUTPUT_PATH宏了,而应该使用LIBRARY_OUTPUT_PATH,这个宏对应静态库文件和动态库文件都适用。
    set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
    

同时生成静态库和动态库

文件结构

.
├── CMakeLists.txt
├── build
├── lib
├── src
│   ├── main.cpp
│   └── operator
│       ├── add.cpp
│       ├── add.hpp
│       ├── sub.cpp
│       └── sub.hpp
└── workspace

5 directories, 6 files

CMakeLists.txt

cmake_minimum_required(VERSION 3.0)

project(CALC)
set(CMAKE_CXX_STANDARD 11)

include_directories(src)

set(HOME /mnt/d/workspace/code/cmaketest/prj1)
set(LIBRARY_OUTPUT_PATH ${HOME}/lib) 
file(GLOB_RECURSE SRC_LIST src/operator/*.cpp)


add_library(calc_shared SHARED ${SRC_LIST})
add_library(calc_static STATIC ${SRC_LIST})
set_target_properties(calc_shared PROPERTIES OUTPUT_NAME "calc")
set_target_properties(calc_static PROPERTIES OUTPUT_NAME "calc")
  • set_target_properties
    用于重新定义库的输出名称,如果不使用set_target_properties也可以,那么库的名称就是add_library里面定义的名称,只是连续两次使用add_library指定库名称时,这个名称不可以相同,而set_target_properties可以将库名称设置为相同,只是最终生成的库文件的后缀不同(.so .a),这样相对来说好看一点

CMake链接库文件

CMake链接静态库和动态库的区别

  • 链接静态库
    静态库会在生成可执行程序的链接阶段被打包到可执行程序中,所以可执行程序启动,静态库就被加载到内存中了。
  • 链接动态库
    动态库在生成可执行程序的链接阶段不会被打包到可执行程序中,当可执行程序被启动并且调用了动态库中的函数的时候,动态库才会被加载到内存。因此,在cmake中指定要链接的动态库的时候,应该将命令写到生成了可执行文件之后

CMake链接静态库

  • 语法
    link_libraries(<static lib> [<static lib>...])
    
    <static lib>:指定出要链接的静态库的名字。可以是全名 libxxx.a,也可以是掐头(lib)去尾(.a)之后的名字 xxx
    [<static lib>...]:要链接的其它静态库的名字。
    如果该静态库不是系统提供的(自己制作或者使用第三方提供的静态库)可能出现静态库找不到的情况,此时可以将 静态库的路径也指定出来:
    link_directories(<lib path>)
    

CMake链接动态库

  • 语法
    target_link_libraries(
        <target> 
        <PRIVATE|PUBLIC|INTERFACE> <item>... 
        [<PRIVATE|PUBLIC|INTERFACE> <item>...]...)
    
    target:指定要加载动态库的文件的名字
    该文件可能是一个源文件
    该文件可能是一个动态库文件
    该文件可能是一个可执行文件
    PRIVATE|PUBLIC|INTERFACE:动态库的访问权限,默认为PUBLIC
    如果该动态库不是系统提供的(自己制作或者使用第三方提供的静态库)可能出现动态库找不到的情况,此时可以将 动态库的路径也指定出来:
    link_directories(<lib path>)
    

测试库文件链接

  • 静态库
    文件结构

    .
    ├── CMakeLists.txt
    ├── build
    ├── lib
    │   └── libcalc.a
    ├── src
    │   ├── main.cpp
    │   └── operator
    │       ├── add.cpp
    │       ├── add.hpp
    │       ├── sub.cpp
    │       └── sub.hpp
    └── workspace
    5 directories, 8 files
    

    测试链接静态库,在编译时没有用到operator文件夹中的cpp文件

    CMakeLists.txt

    cmake_minimum_required(VERSION 3.0)
    
    project(CALC)
    set(CMAKE_CXX_STANDARD 11)
    
    include_directories(src)
    
    set(HOME /mnt/d/workspace/code/cmaketest/prj1)
    set(EXECUTABLE_OUTPUT_PATH ${HOME}/workspace)
    # 这里只用mainc.cpp
    file(GLOB_RECURSE SRC_LIST src/main.cpp)
    link_directories(${HOME}/lib)
    link_libraries(calc)
    add_executable(app ${SRC_LIST})
    
  • 动态库
    文件结构

    .
    ├── CMakeLists.txt
    ├── build
    ├── lib
    │   └── libcalc.so
    ├── src
    │   ├── main.cpp
    │   └── operator
    │       ├── add.cpp
    │       ├── add.hpp
    │       ├── sub.cpp
    │       └── sub.hpp
    └── workspace
    5 directories, 8 files
    

    测试链接静态库,在编译时没有用到operator文件夹中的cpp文件

    CMakeLists.txt

    cmake_minimum_required(VERSION 3.0)
    
    project(CALC)
    set(CMAKE_CXX_STANDARD 11)
    
    include_directories(src)
    
    set(HOME /mnt/d/workspace/code/cmaketest/prj1)
    set(EXECUTABLE_OUTPUT_PATH ${HOME}/workspace)
    # 这里只用mainc.cpp
    file(GLOB_RECURSE SRC_LIST src/main.cpp)
    link_directories(${HOME}/lib)
    link_libraries(calc)
    add_executable(app ${SRC_LIST})
    
  • 通过find_library搜索库文件
    find_library则是一个更基本的方法,用于在系统中搜索特定的库文件。它不依赖于库提供的CMake配置文件,而是直接查找库文件。使用find_library时,需要手动指定库文件路径、头文件路径等。find_library更适合于较小或没有CMake配置文件的库。

    • 语法
      find_library (<VAR> name [path1 path2 ...])
      
      find_library ( <VAR> name | NAMES name1 [name2 ...] [NAMES_PER_DIR] [HINTS [path | ENV var]... ] [PATHS [path | ENV var]... ] [PATH_SUFFIXES suffix1 [suffix2 ...]] [DOC "cache documentation string"] [NO_CACHE] [REQUIRED] [NO_DEFAULT_PATH] [NO_PACKAGE_ROOT_PATH] [NO_CMAKE_PATH] [NO_CMAKE_ENVIRONMENT_PATH] [NO_SYSTEM_ENVIRONMENT_PATH] [NO_CMAKE_SYSTEM_PATH] [CMAKE_FIND_ROOT_PATH_BOTH | ONLY_CMAKE_FIND_ROOT_PATH | NO_CMAKE_FIND_ROOT_PATH] )
      
      • <VAR> 用于存储该命令执行的结果,也就是找到的库的全路径(包含库名
        1. <var>可以是普通变量(需要指定NO_CACHE选项),也可以是缓存条目(意味着会存放在CMakeCache.txt中,不删除该文件或者用set重新设置该变量,其存储的值不会再刷新);
        2. 当库能被找到,<var>会被存放正常的库路径,当库未被找到,<var>中存放的值为"<var>-NOTFOUND"。只要<var>中的值不是"<var>-NOTFOUND",那么即使多次调用find_library,<var>也不会再刷新;
      • name 用于指定待查找的库名称,库名称可以使用全称,例如libmymath.a(优先会当成全名搜索);也可以不带前缀(例如前缀lib)和后缀(例如Linux中的.so、.a,Mac中的.dylib等),直接使用mymath。
      • path 用于指定库的查找的路径
    • 使用find_library链接测试
      文件结构
      .
      ├── CMakeLists.txt
      ├── build
      ├── lib
      │   ├── libcalc.a
      │   └── libcalc.so
      ├── src
      │   ├── main.cpp
      │   └── operator
      │       ├── add.cpp
      │       ├── add.hpp
      │       ├── sub.cpp
      │       └── sub.hpp
      └── workspace
      
      5 directories, 8 files
      
      CMakeLists.txt 链接静态库
      cmake_minimum_required(VERSION 3.0)
      project(CALC)
      set(CMAKE_CXX_STANDARD 11)
      
      include_directories(src)
      
      set(HOME /mnt/d/workspace/code/cmaketest/prj1)
      set(EXECUTABLE_OUTPUT_PATH ${HOME}/workspace)
      ## 这里只用mainc.cpp
      file(GLOB SRC_LIST src/*.cpp)
      find_library(CALC_LIB libcalc.a ${HOME}/lib)
      link_libraries(${CALC_LIB})
      add_executable(app ${SRC_LIST})
      
      CMakeLists.txt 链接动态库
      cmake_minimum_required(VERSION 3.0)
      project(CALC)
      set(CMAKE_CXX_STANDARD 11)
      
      include_directories(src)
      
      set(HOME /mnt/d/workspace/code/cmaketest/prj1)
      set(EXECUTABLE_OUTPUT_PATH ${HOME}/workspace)
      ## 这里只用mainc.cpp
      file(GLOB SRC_LIST src/*.cpp)
      find_library(CALC_LIB libcalc.so ${HOME}/lib)
      add_executable(app ${SRC_LIST})
      target_link_libraries(${CALC_LIB})
      
      使用find_library可以在cmake的时候判断需要的库文件是否存在,如果不存在会直接报错。如下图所示
      image.png

CMake日志

  • 语法
    message([STATUS|WARNING|AUTHOR_WARNING|FATAL_ERROR|SEND_ERROR] "message to display" ...)
    
    (无) :重要消息
    STATUS :非重要消息
    WARNING:CMake 警告, 会继续执行
    AUTHOR_WARNING:CMake 警告 (dev), 会继续执行
    SEND_ERROR:CMake 错误, 继续执行,但是会跳过生成的步骤
    FATAL_ERROR:CMake 错误, 终止所有处理过程

变量操作

  • 拼接
    set 拼接

    set(变量名 ${变量名1} ${变量名2} ...)
    

    关于上面的命令其实就是将从第二个参数开始往后所有的字符串进行拼接,最后将结果存储到第一个参数中,如果第一个参数中原来有数据会对原数据就行覆盖。

    list 拼接

    list(APPEND <list> [<element> ...])
    

    list命令的功能比set要强大,字符串拼接只是它的其中一个功能,所以需要在它第一个参数的位置指定出我们要做的操作,APPEND表示进行数据追加,后边的参数和set就一样了。

    在CMake中,使用set命令可以创建一个list。一个在list内部是一个由分号;分割的一组字符串。例如,set(var a b c d e)命令将会创建一个list:a;b;c;d;e,但是最终打印变量值的时候得到的是abcde

    set(tmp1 a;b;c;d;e)
    set(tmp2 a b c d e)
    message(${tmp1})
    message(${tmp2})
    
  • 移除
    用途:对于一些需要编写成为动态库或者静态库的代码,一般是不需要main函数的,可以通过remove移除该函数所在文件

    list(REMOVE_ITEM <list> <value> [<value> ...])
    

宏定义

在进行程序测试的时候,我们可以在代码中添加一些宏定义,通过这些宏来控制这些代码是否生效。如下所示

#include <stdio.h>
#define NUMBER  3

int main()
{
  int a = 10;
#ifdef DEBUG
  printf("我是一个程序猿, 我不会爬树...\n");
#endif
  for(int i=0; i<NUMBER; ++i)
  {
      printf("hello, GCC!!!\n");
  }
  return 0;
}

在CMake中可以通过add_definitions命令来添加宏。语法如下

add_definitions(-D宏名称)

CMake配置交叉编译工具链

在CMakeLists 同级目录下新建一个 toolchain.cmake 文件,在这个文件里加上如下内容

# 指定目标系统
set(CMAKE_SYSTEM_NAME Linux)
# 指定目标平台
set(CMAKE_SYSTEM_PROCESSOR arm)
 
# 指定交叉编译工具链的根路径
set(CROSS_CHAIN_PATH /path/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf)
# 指定C编译器
set(CMAKE_C_COMPILER "${CROSS_CHAIN_PATH}/bin/arm-linux-gnueabihf-gcc")
# 指定C++编译器
set(CMAKE_CXX_COMPILER "${CROSS_CHAIN_PATH}/bin/arm-linux-gnueabihf-g++")

编译时指定

cmake .. -DCMAKE_TOOLCHAIN_FILE=../toolchain.cmake

CMAKE_BUILD_TYPE

CMAKE_BUILD_TYPE 是 CMake 中一个用于指定构建类型的内置变量。在使用 CMake 构建项目时,可以使用这个变量来指定编译器使用的编译选项和构建类型。
CMAKE_BUILD_TYPE的默认值是空字符串, 可以使用命令查看

cmake --system-information | grep CMAKE_BUILD_TYPE
leon@leon:build$ cmake --system-information | grep CMAKE_BUILD_TYPE
CMAKE_BUILD_TYPE == ""
CMAKE_BUILD_TYPE ""
CMAKE_BUILD_TYPE:STRING=
  • 系统预定义可选值
    Debug:这个构建类型启用了调试信息,并且通常关闭了优化,以便于程序员调试和定位问题。编译出的代码可能运行较慢,但包含了详细的调试信息(例如变量的值、函数调用栈等)。
    ReleaseRelease 构建类型启用了各种优化选项,以提高代码的性能和运行速度。
    RelWithDebInfo:这个构建类型类似于 Release,但是同时包含了一些调试信息,例如函数名和行号等,以便在出现问题时进行调试。
    MinSizeRel :这个构建类型旨在最小化可执行文件的尺寸,因此关闭了大部分的调试和优化选项
  • 工作原理
    CMAKE_BUILD_TYPE的取值会影响程序的编译和链接
    具体来说,cmake中预定义了一批格式为:
    CMAKE_<LANGUAGE>_FLAGS_<CONFIG>的变量
    代表不同的构建类型,比如 DebugReleaseRelWithDebInfo、MinSizeRel 等。这些变量用于设置 C 和 C++ 编译器的选项。当设置了 CMAKE_BUILD_TYPE 后,对应的 下的编译器选项就会被应用
    可以通过cmake --system-information | grep CMAKE_CXX_FLAGS来打印出当前cmake版本预定义的变量值:
    CMAKE_CXX_FLAGS == ""
    CMAKE_CXX_FLAGS_DEBUG == "-g"
    CMAKE_CXX_FLAGS_MINSIZEREL == "-Os -DNDEBUG"
    CMAKE_CXX_FLAGS_RELEASE == "-O3 -DNDEBUG"
    CMAKE_CXX_FLAGS_RELWITHDEBINFO == "-O2 -g -DNDEBUG"
    CMAKE_CXX_FLAGS ""
    CMAKE_CXX_FLAGS_DEBUG "-g"
    CMAKE_CXX_FLAGS_DEBUG_INIT " -g"
    CMAKE_CXX_FLAGS_INIT "  "
    CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG"
    CMAKE_CXX_FLAGS_MINSIZEREL_INIT " -Os -DNDEBUG"
    CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG"
    CMAKE_CXX_FLAGS_RELEASE_INIT " -O3 -DNDEBUG"
    CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -DNDEBUG"
    CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT " -O2 -g -DNDEBUG"
    CMAKE_CXX_FLAGS:STRING=
    CMAKE_CXX_FLAGS_DEBUG:STRING=-g
    CMAKE_CXX_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG
    CMAKE_CXX_FLAGS_RELEASE:STRING=-O3 -DNDEBUG
    CMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG
    //ADVANCED property for variable: CMAKE_CXX_FLAGS
    CMAKE_CXX_FLAGS-ADVANCED:INTERNAL=1
    //ADVANCED property for variable: CMAKE_CXX_FLAGS_DEBUG
    CMAKE_CXX_FLAGS_DEBUG-ADVANCED:INTERNAL=1
    //ADVANCED property for variable: CMAKE_CXX_FLAGS_MINSIZEREL
    CMAKE_CXX_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
    //ADVANCED property for variable: CMAKE_CXX_FLAGS_RELEASE
    CMAKE_CXX_FLAGS_RELEASE-ADVANCED:INTERNAL=1
    //ADVANCED property for variable: CMAKE_CXX_FLAGS_RELWITHDEBINFO
    CMAKE_CXX_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 
    
  • 编译时指定
    cmake .. -DCMAKE_BUILD_TYPE=Release
    

文章参考

写的很好
CMake 保姆级教程(上) | 爱编程的大丙 (subingwen.cn)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容