欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

CMake学习记录

程序员文章站 2022-07-15 16:44:35
...

参考文章:CMake Practice

PROJECT

PROJECT(projectname [CXX] [C] [JAVA])

PROJECT用于定义工程名称,该指令隐式的定义了两个cmake变量:_BINARY_DIR、_source_DIR

cmake预定义PROJECT_BINARY_DIR和PROJECT_SOURCE_DIR与上面两个cmake变量一致

SET

SET(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])

用于定义变量

SET(SRC_LIST main.c t1.c t2.c)

MESSAGE

MESSAGE([SEND_ERROR | STATUS | FATAL_ERROR] "message to display")
类型 含义
SEND_ERROR 产生错误,生成过程被跳过
STATUS 输出前缀为–的信息
FATAL_ERROR 立即终止所有cmake过程

ADD_EXECUTABLE

ADD_EXECUTABLE(hello ${SRC_LSIT})

生成一个文件名为hello的可执行文件,相关源文件是SRC_LIST中定义的源文件列表

变量

使用${}应用变量,是cmake应用变量的方式

在cmake中使用IF控制语句,变量是直接使用变量名引用不许要使{}。若使用{}去应用变量,IF判断的是${}所代表的值得变量,必定不存在

  1. 使用${}方式取值,在IF控制语句中直接使用变量名
  2. 指令(参数1 参数2)
  3. 指令大小写无关,参数和变量大小写相关。推荐指令使用大写指令

ADD_SUBDIRECTORY

ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL])

该指令用于向当前工程添加存放源文件的子目录,并可以将制定中间二进制和目标二进制存放的位置。EXCLUDE_FROM_ALL参数含义是将这个目录从编译过程中排除,比如example,可能需要工程构建完成之后,在进入example目录单独进行构建

ADD_SUBDIRECTORY

ADD_SUBDIRECTORY(src bin)

将src子目录加入工程,并制定编译输出(包含编译中间结果)路径为bin目录。如果bin目录不指定编译结果将放在build/src目录,指定bin目录之后,相当于在编译时将src重命名为bin,所有中间结果和目标二进制都将存放在bin目录

LIBRARY_OUTPUT_PATH/EXECUTABLE_OUTPUT_PATH

SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)

EXECUTABLE_OUTPUT_PATH->二进制文件输出目录
LIBRARY_OUTPUT_PATH->库文件输出目录
可以通过SET重新定义

这两条志林卸载build目录下的CMakeList.txt还是build/src目录下CMakeList.txt,写在src目录下,原则是在哪里ADD_EXECUTABLE或者ADD_LIBRARY,需要改变目标存放路径,就在哪里加入上述定义

INSTALL

INSTALL(TARGET targets...
        [[ARCHIVE|LIBRARY|RUNTIME]
                    [DESTINATION <dir>]
                    [PERMISSIONS permissions...]
                    [CONFIGURATIONS
                            [DEBUG|RELEASE|...]]
                    [COMPONENT <component>]
                    [OPTIONAL]
                    ] [...])

参数中的TARGETS后面跟的是通过ADD_EXECUTABLE或者ADD_LIBRARY定义的目标文件,可以是可执行二进制、动态库、静态库

目标类型也有对应的三种

类型 含义
ARCHIVE 静态库
LIBRARY 动态库
RUNTIME 可执行目标二进制

DESTINATION指定了安装的路径,如果路径以/开头,指的是绝对路径,这时候CMAKE_INSTALL_PREFIX其实无效了。
希望使用CMAKE_INSTALL_PREFIX定义安装路径就要写成相对路径,即不要以/开头安装后的路径是
CMAKE_INSTALL_PREFIX/<DESTINATION定义的路径>

示例

INSTALL(TARGETS myrun mylib mystaticlib...
        ARCHIVE DESTINATION libstatic
        LIBRARY DESTINATION lib
        RUNTIME DESTINATION bin

安装普通文件

INSTALL(FILES files... DESTINATION <dir>
        [PERMISSIONS permissions...]
        [CONFIGURATIONS [Debug|Release|...]]
        [COMPONENT <component>]
        [RENAME <name>]
        [OPTIONAL])

用于安装一般文件,并可以指定访问权限,文件名是此指令所在路径下的相对路径。如果默认不定权限PERMISSIONS,安装后的权限为:
OWNER_WRITE、OWNER_READ、GROUP_READ和WORLD_READ,即644权限

非目标文件的可执行程序安装(脚本)

INSTALL(PROGRAMS files... DESTINATION <dir>
        [PERMISSIONS permissions...]
        [CONFIGURATIONS [Debug|Release|...]]
        [COMPONENT <component>]
        [RENAME <name>]
        [OPTIONAL])

安装后权限为:
OWNER_EXECUTE,GROUP_EXECUTE和WORLD_EXECUTE,即权限为755

目录安装

INSTALL(DIRECTORY dirs... DESTINATION <dir>
        [FILE_PERMISSIONS permissions...]
        [DIRECTORY_PERMISSIONS permissions...]
        [USE_SOURCE_PERMISSIONS]
        [CONFIGURATIONS [Debug|Release|...]]
        [COMPONENT <component>]
        [[PATTERN <pattern> | REGEX <regex>]
        [EXCLUDE] [PERMISSIONS permissions...]] [...])

DIRECTORY后面连接的所在Source目录的相对路径,注意abc和abc/有很大区别。
如果目录名不以/结尾,那么这个目录将被安装为目标路径下的abc,如果目标名以/结尾,代表将这个目录中的内容安装到目标路径,但不包括这个目录本身。

PATTERN使用正则表达式进行过滤,PERMISSIONS用于指定PATTERN过滤后的文件权限。

示例

INSTALL(DIRECTORY ions scripts DESTINATION share/myproj
        PATTERN "CVS" EXCLUDE
        PATTERN "scripts/*"
        PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ)

将icons目录安装到/share/myproj,将scripts/中的内容安装到/share/myproj
不包含CVS目录,对于scripts/*文件指定权限为OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ

CMAKE脚本执行

INSTALL([[SCRIPT <file>] [CODE <code>]] [...])
  • SCRIPT参数用于在安装时调用cmake脚本文件(也就是.cmake文件)
  • CODE参数用于执行CMAKE指令,必须以双引号括起来。
INSTALL(CODE "MESSAGE(\"SSample install message.\")");

静态库与动态库

ADD_LIBRARY(libname [SHARED|STATIC|MOUDULE] [EXCLUDE_FROM_ALL] source1 source2 ...sourceN)

三种类型的库

类型 含义
SHARED 动态库
STATIC 静态库
MODULE 在使用dyld的系统有效,如果不支持dyld,则被当做SHARED对待

EXCLUDE_FROM_ALL参数的意思是这个库不会被默认构建,除非有其他的组件依赖或者手工构建

SET_TARGET_PROPERTIES

SET_TARGET_PROPERTIES(target1 target2 ... PROPERTIES prop1 value1 prop2 value2 ...)

这条指令可以用来设置输出的名称,对于动态库,还可以用来指定动态库的版本和API版本

SET_TARGET_PROPERTIES(hello_static PROPERTIES OUTPUT_NAME "hello")

SET_TARGET_PROPERTIES(hello PROPERTIES CLEAN_DIRECT_OUTPUT 1)
SET_TARGET_PROPERTIES(hello_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
SET_TARGET_PROPERTIES(hello PROPERTIES VERSION 1.2 SOVERSION 1)

GET_TARGET_PROPERTIE

GET_TARGET_PROPERTIE(VAR target property)

获取属性

示例

GET_TARGET_PROPERTY(hellooutput hello_static OUTPUT_NAME)

message(STATUS "hello_static output name:"${hellooutput})

使用外部共享库

INCLUDE_DIRECTORIES([AFTER|BEFORE] [SYSTEM] dir1 dir2)
LINK_DIRECTORIES(dir1 dir2 ...)
TARGET_LINK_LIBRARIES(target lib1 <debug | optimized> lib2 ...)

CMAKE常用变量和使用环境变量

CMAKE_BINARY_DIR/PROJECT_BINARY_DIR/_BINARY_DIR

这三个变量只带的内容是一致的,如果是in source编译,就指的是工程顶层目录,如果是out-of-source编译,指的是工程编译发生的目录。

CMAKE_SOURCE_DIR/PROJECT_SOURCE_DIR/_SOURCE_DIR

这三个变量指代内容一致,不论采用何种编译方式,都是顶层目录。

CMAKE_CURRENT_SOURCE_DIR

指当前处理的CMakeLists.txt所在的路径

CMAKE_CURRENT_BINARY_DIR

如果是in-source编译,它跟CMAKE_CURRENT_SOURCE_DIR一致,如果是out-of_source编译,指target编译目录。
使用ADD_SUBDIRECTORY(src bin)可以改变这个变量的值

使用SET(EXECUTABLE_OUTPUT_PATH dir)并不会对这个变量造成影响,仅仅改变了最终目标存放的路径

CMAKE_CURRENT_LIST_FILE

输出调用该变量的CMakeLists.txt的完整路径

CMAKE_CURRENT_LIST_LINE

输出这个变量所在CMakeLists.txt文件所在行

CAMKE_MODULE_PATH

定义自己的cmake模块所在的路径。如果工程比较复杂,可能会编写cmake模块,这些cmake模块是随工程发布的,为了让cmake在处理CMakeLists时找到这些模块,需要通过SET指令,将自己的cmake模块路径设置一下。

LIBRARY_OUTPUT_PATH/EXECUTABLE_OUTPUT_PATH

重新定义最终结果的存放目录

PROJECT_NAME

输出PROJECT定义的项目名称

cmake调用环境变量

使用$ENV{NAME}指令调用环境变量
设置环境变量的方式

SET($ENV{var} value)

CMAKE_INCLUDE_CURRENT_DIR

自动添加CMAKE_CURRENT_BINARY_DIR和CMAKE_CURRENT_SOURCE_DIR到当前处理的CMakeLists.txt。相当于在每个CMakeLists.txt中加入:

INLCUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})

CMAKE_INCLUDE_DIRECTORIES_BEFORE

将工程提供的头文件目录是中至于系统头文件目录之前,当定义的头文件确实和系统发生冲突时可以提供帮助

系统信息

  1. CMAKE_MAJOR_VERSION
  2. CMAKE_MINOR_VERSION
  3. CMAKE_PATCH_VERSION
  4. CMAKE_SYSTEM 系统信息
  5. CMAKE_SYSTEM_NAME 系统名称
  6. CMAKE_SYSTEM_VERSION 系统版本
  7. CMAKE_SYSTEM_PROCESSOR 处理器
  8. UNIX 在类UNIX系统上为true,包括OSX和cygwin
  9. WIN32 所有win32平台为true,摆阔cygwin

开关选项

  1. CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS,用来控制IF ELSE语句的书写方式
  2. BUILD_SHARED_LIBS这个开关用来控制默认的编译方式,如果不进行设置,使用ADD_LIBRARY并没有指定库类型的情况下,默认编译生成静态库
  3. CMAKE_C_FLAGS,设置C编译选项,可以通过ADD_DEFINITIONS()添加
  4. CMAKE_CXX_FLAGS,设置C++编译选项,可以通过ADD_DEFINITIONS()添加

cmake常用指令

ADD_DEFINITIONS

向C/C + + 编译器添加-D定义,比如:

ADD_DEFINITIONS(-DENABLE_DEBUG -DADC)

参数之间空格分割。

如果代码中定义了

#ifdef ENABLE_DEBUG
#endif

这个代码块就会生效。

如果要添加其他编译开关,可以通过CMAKE_C_FLAGS变量和CMAKE_CXXFLAGS变量设置。

ADD_DEPEDENCIES

定义target依赖的其他target,确保在编译target之前,其他target已经被构建

ADD_DEPEDENCIES(target-name depend_target1 depend-target2 ...)

ADD_EXECUTABLE、ADD_LIBRARY、ADD_SUBDIRECTORY

前面以介绍

ADD_TEST与ENABLE_TESTING指令

ENABLE_TESTING指令用于控制Makefile是否构建test目标,涉及工程所有目录。语法简单,没有任何参数,ENABLE_TESTING(),一般情况这个指令放在工程的主CmakeLists.txt中

ADD_TEST指令的语法是:

ADD_TEST(testname Exename arg1 arg2)

testname是自定义的test名称,Exename可以是构建的目标文件也可以是外部脚本等等。后面连接产地给可执行文件的参数。如果没有在同一个CMakeLists.txt中打开ENABLE_TESTING()指令,任何ADD_TEST都是无效的。

之前helloworld例子,可以在工程主CMakeLists.txt中添加

ADD_TEST(mytest ${PROJECT_BINARY_DIR}/bin/main)
ENABLE_TESTING()

生成Makefile之后,可以运行make test进行测试

AUX_SOURCE_DIRECTORY

AUX_SOURCE_DIRECTORY(dir VARIABLE)

作用是发现一个目录下所有的源代码文件并将列表存储在一个变量中,这个指令临时被用来自动构建源文件列表。因为目前cmake还不能自动发现新添加的源文件。

AUX_SOURCE_DIRECTORY(. SRC_LIST)
ADD_EXECUTABLE(main ${SRC_LIST})

CMAKE_MINIMUM_REQUIRED

CMAKE_MINIMUM_REQUIRED(VERSION versionNumber [FATAL_ERROR])
CMAKE_MINIMUM_REQUIRED(VERSION 2.5 FATAL_ERROR)

如果cmake版本小于2.5,则出现严重错误,整个过程终止。

EXEC_PROGRAM

在CMakeLists.txt处理过程中执行命令,并不会在生成的Makefile中执行。具体做法为:

EXEC_PROGRAM(Executable [directory in which to run]
                [ARGS <arguments to executable>]
                [OUTPUT_VIRABLE <var>]
                [RETURN_VALUE <var>])

用于在指定的目录运行某个程序,通过ARGS添加参数,如果要获取输出和返回值,可以通过
OUTPUT_VIRABLE和**RETURN_VALUE分别定义两个变量。

该指令可以在CMakeLists.txt处理过程中支持任何指令,比如根据系统情况去修改代码文件等等。

e.g:在src目录执行ls命令,并将返回值保存下来,在src/CMakeLists.txt文件中添加

EXEC_PROGRAM(ls ARGS "*.c" OUTPUT_VIRABLE LS_OUTPUT RETURN_VALUE LS_RVALUE)
IF(not LS_RVALUE)
MESSAGE(STATUS "ls result: " ${LS_OUTPUT})
ENDIF(not LS_RVALUE)

在cmake生成Makefile的过程中,执行ls命令,如果返回值为0,则说明成功执行,并且输出 ls *.c的结果。

FILE

FILE(WRITE filname "messgae to write" ...)
FILE(APPEND filename "message to wirte" ...)
FILE(READ filename variable)
FILE(GLOB variable [RELATIVE path] [globbing expressions] ...)
FILE(GLOB_RECURSE variable [RELATIVE path] [globbing expressions] ...)
FILE(REMOVE [directory]...)
FILE(REMOVE_RECUSE [directory] ...)
FILE(RELATIVE_PATH varibale directory file)
FILE(TO_CMAKE_PATH path result)
FILE(TO_NATIVE_PATH path result)

INCLUDE

用来载入CMakeLists.txt文件,也用于载入预定义的cmake模块

INCLUDE(file1 [OPTIONAL])
INCLUDE(module [OPTIONAL])
OPTIONAL参数的作用是文件不存在也不会产生错误

可以指定载入一个文件,如果定义的是一个模块,那么将在CMAKE_MODULE_PATH中搜寻这个模块并载入

载入的内容将在处理到INCLUDE语句时直接执行

INSTALL

见前述

FIND_指令

FIND_系列指令主要包含以下

FIND_FILE

FIND_FILE(<VAR> name1 path1 path2 ...)

VAR变量代表找到的文件路径,包含文件名

FIND_LIBRARY

FIND_LIBRARY(<VAR> name1 path1 path2 ...)

VAR表示找到的库全路径,包含文件名

FIND_PATH

FIND_PATH(<VAR> name1 path1 path2 ...)

VAR表示包含这个文件的路径

FIND_PROGRAM

FIND_PROGRAM(<VAR> name1 path1 path2 ...)

VAR表示包含这个程序的全路径

FIND_PACKAGE

FIND_PACKAGE(<name> [major.minor] [QUIET] [NO_MODULE]
                [[REQUIRED|COMPONENTS] [components ...]])

用来调用预定义在CMAKE_MODULE_PATH的Find.cmake模块,也可以自己定义Find模块,通过**SET(CMAKE_MODULE_PATH dir)将其放入工程的某个目录*工程使用。

FIND_LIBRARY(libX X11 /usr/lib)
IF(NOT libX)
MESSAGE(FATAL_ERROR "libX not found")
ENDIF(NOT libX)

控制指令

IF

IF(expression)
    #Then section
    COMMAND1(ARGS ...)
    ...
    COMMANDN(ARGS ...)
ELSE(expression)
    #Else section
    COMMAND1(ARGS ...)
    ...
    COMMANDN(ARGS ...)
ENDIF(expression)

还有个指令是ELSEIF,凡是出现IF的地方一定要有对应的ENDIF。出现ELSEIF的地方,ENDIF是可选的

表达式(expression)的使用方法

IF(var),如果变量不是:空,0,N,NO,OFF,FLASE,NOTFOUND或_NOTFOUND时表达式为真

IF(NOT var) 与上述条件相反

IF(var1 AND var2),当两个变量都为真时为真

IF(var1 OR var2),或

IF(COMMAND cmd) 给定cmd确实是命令并可以调用是为真。

IF(EXISTS dir)或者IF(EXISTS file),当目录名或者文件名存在时为真

IF(file1 IS_NEWER_THAN file2),当file1比file2新,或者file1/file2其中有一个不存在时为真,文件名使用完整路径。

IF(IS_DIRECTORY dirname),当dirname为目录时,为真。

IF(variable MATCHES regex)
IF(STRING MATCHES regex)
当给定的变量或者字符串能够匹配正则表达式regex 时为真

IF("hello" MATCHES "ell")
MESSAGE("true")
ENDIF("hello" MATCHES "ell")

IF(variable LESS number)
IF(string LESS number)
IF(variable GREATER number)
IF(string GREATER number)
IF(variable EQUAL number)
IF(string EQUAL number)
数字比较表达式

IF(variable STRLESS string)
IF(string STRLESS string)
IF(variable STRGREATER string)
IF(string STRGREATER string)
IF(variable STREQUAL string)
IF(string STREQUAL string)
按照字母序的排列进行比较

IF(DEFINED variable) 如果定义的变量被定义,为真

IF(WIN32)
    MESSAGE(STATUS "this is windows")
ELSE(WIN32)
    MESSAGE(STATUS "this is not windows")
ENDIF(WIN32)

ELSE(WIN32)容易引起歧义

推荐使用CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS开关

IF(WIN32)
#do something windows
ELSEIF(UNIX)
#do something unix
ELSEIF(APPLE)
#do something related to APPPLE
ENDIF(WIN32)

WHILE

WHILE(condition)
    COMMAND1(ARGS ...)
    COMMAND2(ARGS ...)
    ...
ENDWHILE(condition)

FOREACH

列表

FOREACH(loop_var arg1 arg2)
    COMMAND1(ARGS ...)
    COMMAND2(ARGS ...)
ENDFOREACH(loop_var)
AUC_SOURCE_DIRECTORY(. SRC_LIST)
FOREACH(F ${SRC_LIST})
    MESSAGE(${F})
ENDFOREACH(F)

范围

FOREACH(loop_var RANGE total)
ENDFOREACH(loop_var)
FOREACH(VAR RANGE 10)
MESSAGE(${VAR})
ENDFOREACH(VAR)

范围和步进

FOREACH(loop_var RANGE start stop [step])
ENDFOREACH(loop_var)
FOREACH(VAR RANGE 5 15 3)
MESSAGE(${VAR})
ENDFOREACH(VAR)

Cmake交叉编译

# this one is important
SET(CMAKE_SYSTEM_NAME Linux)
#this one not so much
SET(CMAKE_SYSTEM_VERSION 1)

# specify the cross compiler
SET(CMAKE_C_COMPILER   /opt/eldk-2007-01-19/usr/bin/ppc_74xx-gcc)
SET(CMAKE_CXX_COMPILER /opt/eldk-2007-01-19/usr/bin/ppc_74xx-g++)

# where is the target environment 
SET(CMAKE_FIND_ROOT_PATH  /opt/eldk-2007-01-19/ppc_74xx /home/alex/eldk-ppc74xx-inst)

# search for programs in the build host directories
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# for libraries and headers in the target directories
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)


~/src$ cd build
~/src/build$ cmake -DCMAKE_TOOLCHAIN_FILE=~/Toolchain-eldk-ppc74xx.cmake ..
相关标签: CMake