CMake 基本常用语法 CMakeLists.txt

CMake 语法

Hello, World

cmake_minimum_required(VERSION 3.5) # 指定CMake的版本
project(hello-world) # 项目名称
add_executable(hello helloworld.cpp) # 创建一个可执行程序

基本语法

文件编码-Encoding

官方说明文档:文件编码

  1. 在3.0以下的版本,CMake文件必须使用7-bit的ASCII编码,在3.0以后可以使用UTF-8编码
  2. 文件的换行符必须使用\n\r\n

注释-Comments

官方说明文档:Comments1
官方说明文档:Comments2

单行注释

test # comment

多行注释

# 最简单的多行注释
test #[[comment]]
# 注释两边的`=`个数要相等
test #[={len}[comment]={len}]

字符串

官方说明文档:字符串

  1. 字符串的格式为"string"

  2. 对于多行字符串,可以在行尾添加\来忽略换行符

    ### Example-1
    message("12
    34")
    # 12
    # 34
    ### Example-2
    message("12\
    34")
    # 1234
    
  3. 使用[={len}[string]={len}]来可以禁止字符串转义;左右两边的=个数需要相等

    ### Example-1
    message([=[string\n]=])
    # string\n
    ### Example-2
    message("string\n")
    # string
    #
    ### Example-3
    message([==[string]=]) # ERROR: 左右两边的=个数不相等
    ### Example-4
    message([=[string]==]) # ERROR: 左右两边的=个数不相等
    ### Example-5
    message([==========[string]==========]) # OK: 左右两边的=个数相等
    # string
    

设置变量-set

官方说明文档:设置变量

set(<variable> <value>
       [[CACHE <type> <docstring> [FORCE]] | PARENT_SCOPE])
  1. 设置普通变量

    set(var0 "string")
    
  2. 设置数组

    扫描二维码关注公众号,回复: 10756309 查看本文章
    set(arr0 "item0;item0;item2")
    set(arr1 item0 item1 item2)
    set(arr2 ${arr0} ${arr1})
    set(arr3 "${arr0};${arr1}")
    # 使用'\ '来转义空格
    set(arr4 item0 item1\ item2)
    foreach(item ${arr4})
    	message(${item})
    endforeach()
    # item0
    # item1 item2
    # 使用'\;'来转义分号
    set(arr5 "item0;item0\;item2")
    foreach(item ${arr5})
    	message(${item})
    endforeach()
    # item0
    # item1;item2
    
  3. 设置环境变量

    set($ENV{TEST_ENV_VARIABLE} 233)
    

取消设置变量-unset

官方说明文档:取消设置变量

unset(<variable> [CACHE | PARENT_SCOPE])
  • 将变量、缓存变量或环境变量改为未定义状态

变量引用-${var}

官方说明文档:变量引用

  1. 变量通过${}来引用

    set(var 233)
    message(${var})
    # 233
    
  2. 变量可以嵌套引用

    set(inner 666)
    set(outer_233 233)
    set(outer_666 666)
    set(id "bb")
    set(outer_666_aa "666 aa")
    set(outer_666_bb "666 bb")
    message(${outer_${inner}})
    # 666
    message(${outer_${inner}_${id}})
    ## 666 bb
    
  3. 变量可以在引号表达式中使用

    set(var 233)
    message("current var is ${var}")
    # 233
    
  4. 使用环境变量,通过$ENV{环境变量名}即可获取

    message("$ENV{PATH}")
    # LIKE: C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1\bin;......
    

条件表达式-if

官方说明文档:条件表达式

关键字

  • if()/elseif()/else()/endif()

结构

if(expression)
    [statement]
elseif(expression)
    [statement]
elseif(expression)
    [statement]
else()
    [statement]
endif()

真值

  • 1ONYESTRUEY非0数字
  • 不区分大小写

假值

  • 0OFFNOFALSENIGNORENOTFOUND空字符串以-NOTFOUND结尾的变量
  • 不区分大小写

逻辑表达式

  • NOT:逻辑非

    if (NOT <expr>)
    
  • AND:逻辑与

    if (<expr0> AND <expr1>)
    
  • OR:逻辑或

    if (<expr0> OR <expr1>)
    

判断函数或宏的返回值

  • 如果返回值为真值,则表达式为

    if (COMMAND <command>)
    

判断编译目标是否存在

  • 如果目标是通过add_executableadd_libraryadd_custom_target来创建的,则表达式为

    if (TARGET <target>)
    

文件和目录相关

  • 判断文件或者目录是否存在:如果文件或者目录存在,则表达式为

    if (EXISTS path-to-file-or-directory)
    
  • 比较两个文件哪个更新:如果file1file2更新,则表达式为

    if (file1 IS_NEWER_THAN file2)
    
  • 判断目标是不是目录

    if (IS_DIRECTORY path-to-directory)
    
  • 判断目标是不是符号链接

    if (IS_SYMLINK file-name)
    
  • 判断路径是不是绝对路径

    if (IS_ABSOLUTE path)
    

值比较

  • 小于,variable或string必须能解析成数字才可以比较

    if (<variable|string> LESS <variable|string>)
    
  • 大于,variable或string必须能解析成数字才可以比较

    if (<variable|string> GREATER <variable|string>)
    
  • 等于,variable或string必须能解析成数字才可以比较

    if (<variable|string> EQUAL <variable|string>)
    

字符串比较

  • 小于,按照字典序比较

    if (<variable|string> STRLESS <variable|string>)
    
  • 大于,按照字典序比较

    if (<variable|string> STRGREATER <variable|string>)
    
  • 等于,按照字典序比较

    if (<variable|string> STREQUAL <variable|string>)
    

版本比较

  • 版本号格式 major[.minor[.patch[.tweak]]]

  • 小于

    if (<variable|string> VERSION_LESS <variable|string>)
    
  • 大于

    if (<variable|string> VERSION_GREATER <variable|string>)
    
  • 等于

    if (<variable|string> VERSION_EQUAL <variable|string>)
    

判断变量是否定义

  • 判断变量是否定义,macro的参数不是变量

    if (DEFINED <variable>)
    

正则匹配

  • 判断变量或字符串是否匹配正则表达式

    if (<variable|string> MATCHES regex)
    

循环-loop

foreach

官方说明文档:foreach

  • 类型1:参数可以是元素或者是数组

    foreach(loop_var arg1 arg2 ...)
        COMMAND1(ARGS ...)
        COMMAND2(ARGS ...)
        ...
    endforeach(loop_var)
    
  • 类型2:for range

    # 从start开始,到stop,每次增加step步,start,stop,step都是整数
    foreach(loop_var RANGE start stop [step])
    # total是一个整数,相当于foreach(loop_var RANGE 0 total 1)
    foreach(loop_var RANGE total)
    
  • 类型3:for in lists/items

    foreach(loop_var IN [LISTS [list1 [...]]]
                           [ITEMS [item1 [...]]])
    
    • foreach(loop_var IN LISTS list1 list2 ...)可以用foreach(loop_var ${list1} ${list2} ...)代替
    • foreach(loop_var IN ITEMS item1 item2 ...)可以用foreach(loop_var ${item1} ${item2} ...)代替

while

官方说明文档:while

while(condition)
    COMMAND1(ARGS ...)
    COMMAND2(ARGS ...)
    ...
endwhile(condition)

continue & break

官方说明文档:continue
官方说明文档:break

continue()
break()

函数/宏-function/macro

函数-function

官方说明文档:函数

function(<name> [<arg1> ...])
    <commands>
endfunction()
  • ARGC:输入的参数个数
  • ARGN:输入的参数
  • ARGV0,ARGV1…ARGVN:参数

function是独立的作用域,在function内定义的变量外部是访问不了的,需要通过set(var PARENT_SCOPE)来向外暴露变量

宏-macro

官方说明文档:宏

macro(<name> [<arg1> ...])
    <commands>
endmacro()
  • 宏的参数不能通过ARGCARGNARGV{IDX}来获取
  • 宏内定义的变量的作用域在父级

作用域

官方说明文档:作用域

  • 全局层:定义在cache中,整个项目可见
  • 目录层:在当前CMakeLists.txt内
  • 函数层:定义在function内,函数内可见
  • 全局层<目录层<函数层;会优先使用当前层内变量,如果没有,或到父级找,但被修改的变量不会先父级传递

创建executable/library

add_executable

官方说明文档:add_executable

# 创建可执行程序
add_executable(<name> [source1] [source2 ...])

add_library

官方说明文档:add_library

# 创建动态库/静态库
add_library(<name> [STATIC|SHARED|MODULE] [source1] [source2 ...])
# 从外部导入动态库/静态库
add_library(<name> <SHARED|STATIC|MODULE|OBJECT|UNKNOWN> IMPORTED [GLOBAL])

链接库

  • 导入动态链接库(Windows)

    set(target "example")
    add_library(${target} SHARED IMPORTED)
    set_property(TARGET ${target} APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
    set_target_properties(${target} PROPERTIES
      IMPORTED_IMPLIB_DEBUG   "${_IMPORT_PREFIX}/path/to/libexampled.lib"
      IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/path/to/libexampled.dll"
    )
    set_property(TARGET ${target} APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
    set_target_properties(${target} PROPERTIES
      IMPORTED_IMPLIB_RELEASE   "${_IMPORT_PREFIX}/path/to/libexample.lib"
      IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/path/to/libexample.dll"
    )
    
  • 导入静态链接库(Windows)

    set(target "example")
    add_library(${target} SHARED IMPORTED)
    set_property(TARGET ${target} APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
    set_target_properties(${target} PROPERTIES
      IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/path/to/libexampled.lib"
    )
    set_property(TARGET ${target} APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
    set_target_properties(${target} PROPERTIES
      IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/path/to/libexample.lib"
    )
    
  • 导入动态链接库(Linux/Unix)

    set(target "example")
    add_library(${target} SHARED IMPORTED)
    set_property(TARGET ${target} APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
    set_target_properties(${target} PROPERTIES
      IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/path/to/libexampled.so"
    )
    set_property(TARGET ${target} APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
    set_target_properties(${target} PROPERTIES
      IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/path/to/libexample.so"
    )
    
  • 导入静态链接库(Linux/Unix)

    set(target "example")
    add_library(${target} SHARED IMPORTED)
    set_property(TARGET ${target} APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
    set_target_properties(${target} PROPERTIES
      IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/path/to/libexampled.a"
    )
    set_property(TARGET ${target} APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
    set_target_properties(${target} PROPERTIES
      IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/path/to/libexample.a"
    )
    

名称前缀/后缀

  • 设置输出可执行程序/库的名称前缀/后缀

    set_target_properties(target1 target2 ...
                          PROPERTIES prop1 value1
                          prop2 value2 ...)
    
    set_target_properties(${module_name} PROPERTIES
        PREFIX "lib" # 前缀
        <CONFIG>_POSTFIX "d" # 后缀,可以分DEBUG/RELEASE版本
    )
    

链接-link

link_libraries

官方说明文档:link_libraries

link_libraries([item1 [item2 [...]]]
               [[debug|optimized|general] <item>] ...)

target_link_libraries

官方说明文档:target_link_libraries

target_link_libraries(<target> ... <item>... ...)

MSVC编译器设置源文件为UTF-8编码

add_compile_options("$<$<C_COMPILER_ID:MSVC>:/source-charset:utf-8>")
add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/source-charset:utf-8>")

设置C++版本

# C++11/C++0x
set(CMAKE_CXX_STANDARD 11)
if (CMAKE_VERSION VERSION_LESS "3.1")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
endif ()
# C++14/C++1y
set(CMAKE_CXX_STANDARD 14)
if (CMAKE_VERSION VERSION_LESS "3.1")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
endif ()
# C++17/C++1z
set(CMAKE_CXX_STANDARD 17)
if (CMAKE_VERSION VERSION_LESS "3.1")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1z")
endif ()
# C++20/C++2a
set(CMAKE_CXX_STANDARD 20)
if (CMAKE_VERSION VERSION_LESS "3.1")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++2a")
endif ()

平台判断

if(WIN32)
    add_definitions(-DPLATFORM_WINDOWS=1)
    set(PLATFORM_WINDOWS 1)
    add_definitions(-D_CRT_SECURE_NO_WARNINGS)
elseif(APPLE)
    if(IOS)
        add_definitions(-DPLATFORM_IOS=1)
        set(PLATFORM_IOS 1)
    elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
        add_definitions(-DPLATFORM_OSX=1)
        set(PLATFORM_OSX 1)
    endif()
elseif(ANDROID)
    add_definitions(-DPLATFORM_ANDROID=1)
    set(PLATFORM_ANDROID 1)
elseif(UNIX)
    add_definitions(-DPLATFORM_LINUX=1)
    set(PLATFORM_LINUX 1)
    
    execute_process(COMMAND bash "-c" "cat /etc/*-release" RESULT_VARIABLE rv OUTPUT_VARIABLE out)
    if (${rv})
    	message(FATAL_ERROR "command execute error")
    else()
        if (out MATCHES ".*Ubuntu.*")
        	add_definitions(-DPLATFORM_UBUNTU=1)
        	set(PLATFORM_UBUNTU 1)
        elseif(out MATCHES ".*CentOS.*")
        	add_definitions(-DPLATFORM_CENTOS=1)
        	set(PLATFORM_CENTOS 1)
        else()
        	message("Unknown Linux Branch")
        endif()
    endif()
else()
    add_definitions(-DPLATFORM_UNKNOWN=1)
    set(PLATFORM_UNKNOWN 1)

    message(WARNING "Unknown Platform")
    message(WARNING "Unknown Platform")
    message(WARNING "Unknown Platform")
endif()

find_package

官方说明文档:find_package

find_package(<PackageName> [version] [EXACT] [QUIET] [MODULE]
             [REQUIRED] [[COMPONENTS] [components...]]
             [OPTIONAL_COMPONENTS components...]
             [NO_POLICY_SCOPE])
  • OpenCV

    # - OpenCV_LIBS                     : The list of libraries to link against.
    # - OpenCV_INCLUDE_DIRS             : The OpenCV include directories.
    # - OpenCV_COMPUTE_CAPABILITIES     : The version of compute capability
    # - OpenCV_VERSION                  : The version of this OpenCV build: "3.4.1"
    # - OpenCV_VERSION_MAJOR            : Major version part of OpenCV_VERSION: "3"
    # - OpenCV_VERSION_MINOR            : Minor version part of OpenCV_VERSION: "4"
    # - OpenCV_VERSION_PATCH            : Patch version part of OpenCV_VERSION: "1"
    
    find_package(OpenCV 3.0 REQUIRED COMPONENTS core imgproc imgcodecs)
    if (OpenCV_FOUND)
    	include_directories(${OpenCV_INCLUDE_DIRS})
    	target_link_libraries(target ${OpenCV_LIBS})
    endif()
    

install

官方说明文档:install

message

官方说明文档:message

message([<mode>] "message to display" ...)
  • FATAL_ERROR:错误,会停止配置和生成
  • SEND_ERROR:错误,继续处理,但不会生成
  • WARNING:警告
  • NOTICE:默认
  • STATUS:状态
发布了8 篇原创文章 · 获赞 0 · 访问量 54

猜你喜欢

转载自blog.csdn.net/q345911572/article/details/105250633