CMake学习笔记

CMake学习笔记

一、   CMake基础知识

1.1     CMake编译原理

CMake是一种跨平台编译工具,比make更为高级,使用起来要方便得多。CMake主要是编写CMakeLists.txt文件,然后用cmake命令将CMakeLists.txt文件转化为make所需要的makefile文件,最后用make命令编译源码生成可执行程序或共享库(so(shared object))。因此CMake的编译基本就两个步骤:

1. cmake

2. make

CMake指向CMakeLists.txt所在的目录,例如cmake .. 表示CMakeLists.txt在当前目录的上一级目录。cmake后会生成很多编译的中间文件以及makefile文件,所以一般建议新建一个新的目录,专门用来编译,例如

mkdir build

cd build

cmake ..

make

make根据生成makefile文件,编译程序。

1.2     使用Cmake编译程序

我们编写一个关于C/C++程序项目,即hello world,以此理解整个CMake编译的过程。

1.1.1准备程序文件

假设文件层级目录结构如下:

├── build

├── CMakeLists.txt

├── include

│    └──helloworld.h

└── src

        ├──helloworld.c

        └──main.c

头文件helloworld.h,如下所示:

#ifndef HELLOWORLD_H

#define HELLOWORLD_H

void hello_world ();

#endif

 

源文件helloworld.c,如下所示:

#include<stdio.h>

#include "../inc/helloworld.h"

void hello_world ()

{

    printf("hello world");

}

  main.c主函数,如下所示:

#include <stdio.h>

#include "../inc/helloworld.h"

int main(int argc, char** argv)

{

    hello_world();

    return 0;

}

 

1.1.2编写CMakeLists.txt

接下来编写CMakeLists.txt文件,该文件放在和src,include的同级目录,实际方哪里都可以,只要里面编写的路径能够正确指向就好了。CMakeLists.txt文件,如下所示: CMakeLists.txt主要包含以上的7个步骤,具体的意义,请阅读相应的注释。

#1.cmake verson,指定cmake版本

cmake_minimum_required(VERSION 3.2)

#2.project name,指定项目的名称,一般和项目的文件夹名称对应

# 这条指令会自动创建两个变量:

#<project name>_BINARY_DIR(二进制文件保存路径)   

#<project name>_SOURCE_DIR(源代码路径)

#Cmake 系统也帮助我们预定义了

#PROJECT_BINARY_DIR和PROJECT_SOURCE_DIR其值与上述对应相等

PROJECT(helloworld)

#3.head file path,头文件目录

INCLUDE_DIRECTORIES(include)

#4.source directory,源文件目录

AUX_SOURCE_DIRECTORY(src DIR_SRCS)

#5.set environment variable,设置环境变量,编译用到的源文件全部都要放到这里,否则编译能够通过,但是执行的时候会出现各种问题,比如"symbol lookup error xxxxx , undefined symbol"

SET(HELLOWORLD ${DIR_SRCS})

#6.add executable file,添加要编译的可执行文件

ADD_EXECUTABLE(${PROJECT_NAME} ${HELLOWORLD})

#7.add link library,添加可执行文件所需要的库,比如我们用到了libm.so(命名规则:lib+name+.so),就添加该库的名称

TARGET_LINK_LIBRARIES(${PROJECT_NAME} m)

 

1.1.3编译和运行程序

准备好了以上的所有材料,接下来,就可以编译了,由于编译中出现许多中间的文件,因此最好新建一个独立的目录build,在该目录下进行编译,编译步骤如下所示:

mkdir build

cd build

cmake ..

make

操作后,在build目录下生成helloworld

二、   CMake常用指令总结       

2.1         常用指令

INCLUDE_DIRECTORIES( "dir1" "dir2" ... )

头文件路径,相当于编译器参数 -Idir1 -Idir2

LINK_DIRECTORIES("dir1" "dir2")

库文件路径。注意:由于历史原因,相对路径会原样传递给链接器。尽量使用FIND_LIBRARY而避免使用这个。

AUX_SOURCE_DIRECTORY( “sourcedir” variable)

收集目录中的文件名并赋值给变量

ADD_EXECUTABLE

可执行程序目标

ADD_LIBRARY

库目标

ADD_CUSTOM_TARGET

自定义目标

ADD_DEPENDENCIES( target1 t2 t3 )

目标target1依赖于t2 t3

ADD_DEFINITIONS( "-Wall -ansi")

本意是供设置 -D... /D... 等编译预处理需要的宏定义参数,对比 REMOVE_DEFINITIONS()

TARGET_LINK_LIBRARIES( target-name lib1 lib2 ...)

设置单个目标需要链接的库

LINK_LIBRARIES( lib1 lib2 ...)

设置所有目标需要链接的库

SET_TARGET_PROPERTIES( ... )

设置目标的属性 OUTPUT_NAME, VERSION, ....

MESSAGE(...)

用于打印信息

INSTALL( FILES “f1” “f2”DESTINATION . )

DESTINATION 相对于 ${CMAKE_INSTALL_PREFIX}

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

设置变量值

LIST( APPEND|INSERT|LENGTH|GET| REMOVE_ITEM|REMOVE_AT|SORT ...)

列表操作

STRING( TOUPPER|TOLOWER|LENGTH| SUBSTRING|REPLACE|REGEX ...)

字符串操作

SEPARATE_ARGUMENTS( VAR )

转换空格分隔的字符串到列表

FILE( WRITE|READ|APPEND|GLOB| GLOB_RECURSE|REMOVE|MAKE_DIRECTORY ...)

文件操作

FIND_FILE

注意 CMAKE_INCLUDE_PATH

FIND_PATH

注意 CMAKE_INCLUDE_PATH

FIND_LIBRARY

注意 CMAKE_LIBRARY_PATH

FIND_PROGRAM

FIND_PACKAGE

注意 CMAKE_MODULE_PATH

EXEC_PROGRAM( bin [work_dir] ARGS <..> [OUTPUT_VARIABLE var] [RETURN_VALUE var] )

执行外部程序

OPTION( OPTION_VAR “description” [initial value] )

2.2         常用指令说明

2.2.1       常用路径

CMAKE_SOURCE_DIR

PROJECT_SOURCE_DIR

<projectname>_SOURCE_DIR

这三个变量指代的内容是一致的,是工程顶层目录

CMAKE_BINARY_DIR

PROJECT_BINARY_DIR

<projectname>_BINARY_DIR

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

CMAKE_CURRENT_SOURCE_DIR

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

CMAKE_CURRRENT_BINARY_DIR

如果是in-source编译,它跟CMAKE_CURRENT_SOURCE_DIR一致,如果是out-of-source 编译,他指的是target编译目录

CMAKE_CURRENT_LIST_FILE

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

CMAKE_BUILD_TYPE

控制 Debug 和 Release 模式的构建

CMAKE_INCLUDE_PATH

配合 FIND_FILE() 以及 FIND_PATH() 使用。如果头文件没有存放在常规路径(/usr/include, /usr/local/include等),则可以通过这些变量就行弥补。如果不使用 FIND_FILE 和 FIND_PATH的话,CMAKE_INCLUDE_PATH,没有任何作用。

CMAKE_LIBRARY_PATH

配合 FIND_LIBRARY() 使用。否则没有任何作用

CMAKE_MODULE_PATH

cmake 为上百个软件包提供了查找器(finder):FindXXXX.cmake

当使用非cmake自带的finder时,需要指定finder的路径,这就是CMAKE_MODULE_PATH,配合 FIND_PACKAGE()使用

CMAKE_INSTALL_PREFIX

控制make install是文件会安装到什么地方。默认定义是/usr/local 或 %PROGRAMFILES%

BUILD_SHARED_LIBS

如果不进行设置,使用ADD_LIBRARY且没有指定库类型,默认编译生成的库是静态库。

UNIX

在所有的类UNIX平台为TRUE,包括OS X和cygwin

WIN32

在所有的win32平台为TRUE,包括cygwin

2.2.2       常用指令说明

  •                   PROJECT(工程名字)

这条指令会自动创建两个变量:

<projectname>_BINARY_DIR(二进制文件保存路径)

<projectname>_SOURCE_DIR(源代码路径)

cmake系统也帮助我们预定义了PROJECT_BINARY_DIR和

PROJECT_SOURCE_DIR其值与上述对应相等

  •                   SET(变量名 变量值)

SET(VAR [VALUE] [CACHE TYPEDOCSTRING [FORCE]])

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

SET(SRC_LIST main.c)

例:

SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)更改

生成的可执行文件路径

SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)更改生成

的库文件路径

  •                    MESSAGE

MESSAGE([SEND_ERROR | STATUS | FATAL_ERROR] “message to display” …)

向终端输出用户定义的信息或变量的值

SEND_ERROR, 产生错误,生成过程被跳过

STATUS, 输出前缀为-的信息

FATAL_ERROR, 立即终止所有cmake过程

  •                   ADD_EXECUTABLE

ADD_EXECUTABLE(可执行文件名 生成该可执行文件的源文件)

例:

ADD_EXECUTABLE(hello ${SRC_LIST})

说明:SRC_LIST变量中的源文件需要编译出名为hello的可执行文件

  •                     ADD_SUBDIRECTORY

ADD_SUBDIRECTORY(src_dir [binary_dir] [EXCLUDE_FROM_ALL])

向当前工程添加存放源文件的子目录,并可以指定中间二进制和目标二进制的存放位置

  •                    EXCLUDE_FROM_ALL

含义:将这个目录从编译过程中排除

  •                    ADD_LIBRARY

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

生成动态静态库

例:

ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})

  •                    SET_TARGET_PROPERTIES

设置目标的一些属性来改变它们构建的方式。

SET_TARGET_PROPERTIES(target1 target2 ...PROPERTIES prop1 value1

prop2 value2 ...)

为一个目标设置属性。该命令的语法是列出所有你想要变更的文件,然后提供你想要设置的值。你能够使用任何你想要的属性/值对,并且在随后的代码中调用GET_TARGET_PROPERTY命令取出属性的值。

  •                     INSTALL

INSTALL(TARGETS hellohello_static LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)

INSTALL(FILES hello.h DESTINATIONinclude/hello)

  •                     TARGET_LINK_LIBRARIES

设置目标要连接库文件的名称

TARGET_LINK_LIBRARIES(target library1 <debug | optimized> library2 ..)

TARGET_LINK_LIBRARIES(main hello) # 连接libhello.so库

TARGET_LINK_LIBRARIES(main libhello.a)

TARGET_LINK_LIBRARIES(main libhello.so)

  •                      环境变量

使用$ENV{NAME}指令就可以调用系统的环境变量

  •                     FILE指令

文件操作指令,基本语法为:

file(WRITE filename "message to write"... )

file(APPEND filename "message to write"... )

file(READ filename variable [LIMIT numBytes] [OFFSET offset] [HEX])

  WRITE选项将会写一条消息到名为filename的文件中。如果文件已经存在,该命令会覆盖已有的文件;如果文件不存在,它将创建该文件。

  APPEND选项和WRITE选项一样,将会写一条消息到名为filename的文件中,只是该消息会附加到文件末尾。

  READ选项将会读一个文件中的内容并将其存储在变量里。读文件的位置从offset开始,最多读numBytes个字节。如果指定了HEX参数,二进制代码将会转换为十六进制表达方式,并存储在变量里。

  STRINGS将会从一个文件中将一个ASCII字符串的list解析出来,然后存储在variable变量中。文件中的二进制数据会被忽略。回车换行符会被忽略。它也可以用在Intel的Hex和Motorola的S-记录文件;读取它们时,它们会被自动转换为二进制格式。可以使用NO_HEX_CONVERSION选项禁止这项功能。LIMIT_COUNT选项设定了返回的字符串的最大数量。LIMIT_INPUT设置了从输入文件中读取的最大字节数。LIMIT_OUTPUT设置了在输出变量中存储的最大字节数。LENGTH_MINIMUM设置了要返回的字符串的最小长度;小于该长度的字符串会被忽略。LENGTH_MAXIMUM设置了返回字符串的最大长度;更长的字符串会被分割成不长于最大长度的字符串。NEWLINE_CONSUME选项允许新行被包含到字符串中,而不是终止它们。REGEX选项指定了一个待返回的字符串必须满足的正则表达式。典型的使用方式是:

  •                    INCLUDE指令

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

INCLUDE(file1 [OPTIONAL])

INCLUDE(module [OPTIONAL])

OPTIONAL参数的作用是文件不存在也不会产生错误。

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

索这个模块并载入。

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

  •                    FIND_系列指令主要包含一下指令:

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

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

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

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

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

VAR变量代表包含这个文件的路径。

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

VAR变量代表包含这个程序的全路径。

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

用来调用预定义在CMAKE_MODULE_PATH下的Find<name>.cmake模块,你也可以自己

定义Find<name>模块,通过SET(CMAKE_MODULE_PATH dir)将其放入工程的某个目录

中供工程使用

  •                    OPTION

OPTION提供一个用户可以任选的选项。语法如下

OPTION (<option_variable> "help string describing option"

            [initial value])

OPTION提供选项让用户选择是 ON 或者 OFF ,如果没有提供初始化值,使用OFF。也就是说默认的值是OFF。

但是请注意:这个OPTION命令和你本地是否存在编译缓存的关系很大。

所以,如果你有关于OPTION的改变,那么请你务必清理 CMakeCache.txt 和 CMakeFiles 文件夹。

还有,请使用标准的 [initial value] 值 ON 或者 OFF。

  •                    CONFIGURE_FILE

CONFIGURE_FILE的作用是让普通文件也能使用CMake中的变量。

也就是说代码文件中可以使用CMake中的变量。

语法如下:

CONFIGURE_FILE (<input> <output>

                    [COPYONLY] [ESCAPE_QUOTES] [@ONLY]

                    [NEWLINE_STYLE [UNIX|DOS|WIN32|LF|CRLF] ])

拷贝一个 <input>(输入文件) 文件到 <output> (输出文件),并且替换输入文件中被 @VAR@ 或者 ${VAR} 引用的变量值。每一个变量将被替换成当前的变量值(注:CMake中的变量值)或者空串当变量未定义。

COPYONLY

只拷贝文件,不进行任何的变量替换。这个选项在指定了 NEWLINE_STYLE 选项时不能使用(无效)。

ESCAPE_QUOTES

躲过任何的反斜杠(C风格)转义。

    注:躲避转义,比如你有个变量在CMake中是这样的

    SET(FOO_STRING "\"foo\"")

    那么在没有 ESCAPE_QUOTES 选项的状态下,通过变量替换将变为 ""foo"",如果指定了 ESCAPE_QUOTES 选项,变量将不变。

@ONLY

    限制变量替换,让其只替换被 @VAR@ 引用的变量(那么 ${VAR} 格式的变量将不会被替换)。这在配置 ${VAR} 语法的脚本时是非常有用的。

####################分享时代,分享学习#####################

编者水平有限,文中难免存在错误,望指出,谢谢!

文中部分内容属于转载其他人的研究成果,在此表示感谢!

#######################################################

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值