cmake教程

全栈工程师开发手册 (作者:栾鹏)
架构系列文章

基本使用

一、 基本使用

安装:下载二进制包后可直接解压使用

从源码安装则执行命令:./bootstrap; make; make install——尝试执行bootstrap失败

使用:cmake dir_path,生成工程文件或makefile文件

二、 概念
out-of-source build,与in-source build相对,即将编译输出文件与源文件放到不同目录中;

三、 基本结构

1,依赖CMakeLists.txt文件,项目主目标一个,主目录中可指定包含的子目录;

2,在项目CMakeLists.txt中使用project指定项目名称,add_subdirectory添加子目录

3,子目录CMakeLists.txt将从父目录CMakeLists.txt继承设置(TBD,待检验)

cmake基本语法

Cmake的输入是在源码目录下的CMakeLists.txt文件。这个文件可以用include或者 add_subdirectory 命令增加入其它的输入文件。

语法

CMakeList.txt文件是由注释、命令和空白字符组成。

注释是由 # 开始,到行结尾。

命令是由:命令名、(、空格分隔的参数、)组成。

例如:command (args….)

上面的command可以是一个命令名;或者是一个宏;也可以是一个函数名。

args是以空格分隔的参数例表(如果参数中包含空格,则要加双引号)

除了用于分隔参数的空白字符(空格、换行号、tabs)都是被忽略不计的。任何包含在双引号中的字符都做为一个参数。一个反斜杠用于转换码。

命令名是大小写不敏感的。

字符串(string)和字符串列表(lists)

CMake的基本数据类型是字符串(string)。CMake也支持由字符串组成的字符串列表。字符串列表可以由;或空格分隔的组成。例如:下面设置变量var是等效的。

set(var a;b;c)

set(var a b c)

字符串列表可以用 foreach命令叠代(iterated)或list命令操作。

变量

CMake支持简单的变量:字符串或字符串列表。用${VAR} 语法得到变量的引用。

可以用一个set命令把一个字符串列表设置为一个变量,然后把这个变量传递给需要传递多参数的函数。例如:

set(Foo a b c)

command(${Foo})

上面两行等效 command(a b c)

如果你想传把一个字符串列表做为一个单独的参数传递给函数,用双引号包含它。例如:

Command(“${Foo}”)

等效于:command(“a b c”)

环境变量:

用$ENV{VAR}得到环境变量的引用

设置环境变量:

Set(ENV{VAR} /home)

程序流控制

CMake提供三种程序流控制结构:

1、 条件声明:if

# some_command will be called if the variable's value is not:
# empty, 0, N, NO, OFF, FALSE, NOTFOUND, or -NOTFOUND. 
if(var) 
   some_command(...) 
endif(var)

2、 循环控制:foreach 和 while

set(VAR a b c) 
  # loop over a, b,c with the variable f 
foreach(f ${VAR}) 
    message(${f}) 
endforeach(f)

3、 程序定义:宏或函数(函数在CMake2.6以后的版本才支持)。函数建立本地范围内的变量,宏用于全局范围内。

# define a macro hello 
macro(hello MESSAGE)
    message(${MESSAGE})
endmacro(hello) 
# call the macro with the string "hello world" 
hello("hello world") 
# define a function hello 
function(hello MESSAGE)
    message(${MESSAGE}) 
endfunction(hello)

函数可以返回,可以用 return()命令返回。如果要从函数中返回值,只能通过参数返回:

set命令中 PARENT_SCOPE表示传递给函数调用者所拥有的变量

引号、字符串和escapes

一个用双引号包含的字符串,是这个字符串的字面含义。一个字符串能包含多行。例如:

set (MY_STRING "this is a string with a
  newline in
  it")

也能在字符串中用转义字符

set (VAR "
   hello 
  world 
  ")
message ( "\${VAR} = ${VAR}")
  # prints out
  ${VAR} = 
    hello 
    world

标准C的转义字符被支持

message("\n\thello world")
# prints out 
hello world
message(hell"o")   -> prints hell"o"
message(hell"o")   -> prints hell"o" 
message(hell\"o\")  -> prints hell"o"

引号必须是匹配的

message(hell"o)   -> produces this error:
Parse error. Function missing ending ")". 
Instead found unterminated string with text "o) 
". 

    message(hell\"o) -> prints hell"o

正则表达式

一些CMake命令(如if和 string),能使用正则表达式或使用正则表达式作为参数。一个简单的形式,一个正则表达式用于在一个序列的字符串中精确查找一个字符。然而在大多时候,一个精确查找是不知道的或者只是匹配最前或者最后字符。所以这里用正则表达式进行不同的转换。Cmake标准是可被描述的。这个描述是基于开源的正则表达式类(Texas Instruments)。

^ 匹配一行或一字符串开头
$匹配一行或一字符串结尾
.匹配单一字符或一个新行
 [ ]匹配括号中的任一字符
[^ ] 匹配不在括号内的任一字符
[-] 匹配指定范围内的字符
* 匹配0次或多次
+ 匹配一次或多次
? 匹配0次或一次
()保存匹配的表达式并用随后的替换它

CMAKE进阶

内部变量

CMAKE_C_COMPILER:指定C编译器

CMAKE_CXX_COMPILER:

CMAKE_C_FLAGS:编译C文件时的选项,如-g;也可以通过add_definitions添加编译选项

EXECUTABLE_OUTPUT_PATH:可执行文件的存放路径

LIBRARY_OUTPUT_PATH:库文件路径

CMAKE_BUILD_TYPE::build 类型(Debug, Release, …),CMAKE_BUILD_TYPE=Debug

BUILD_SHARED_LIBS:Switch between shared and static libraries

内置变量的使用:

在CMakeLists.txt中指定,使用set

cmake命令中使用,如cmake -DBUILD_SHARED_LIBS=OFF

命令

project (HELLO) #指定项目名称,生成的VC项目的名称;

使用${HELLO_SOURCE_DIR}表示项目根目录

include_directories:指定头文件的搜索路径,相当于指定gcc的-I参数

include_directories (${HELLO_SOURCE_DIR}/Hello)  #增加Hello为include目录

link_directories:动态链接库或静态链接库的搜索路径,相当于gcc的-L参数

link_directories (${HELLO_BINARY_DIR}/Hello)     #增加Hello为link目录

add_subdirectory:包含子目录

add_subdirectory (Hello)

add_executable:编译可执行程序,指定编译,好像也可以添加.o文件

add_executable (helloDemo demo.cxx demo_b.cxx)   #将cxx编译成可执行文件——

add_definitions:添加编译参数

add_definitions(-DDEBUG)将在gcc命令行添加DEBUG宏定义;
add_definitions( “-Wall -ansi –pedantic –g”)

target_link_libraries:添加链接库,相同于指定-l参数

target_link_libraries(demo Hello) #将可执行文件与Hello连接成最终文件demo

add_library:

add_library(Hello hello.cxx)  #将hello.cxx编译成静态库如libHello.a

add_custom_target:

message( status|fatal_error, “message”):

set_target_properties( … ): lots of properties… OUTPUT_NAME, VERSION, …

link_libraries( lib1 lib2 …): All targets link with the same set of libs

实例:

先制作makefile文件 以便以后运行

CMakeLists.txt文件内容如下:

cmake_minimum_required(VERSION 3.10)
project(cpptensorflow)
set(CMAKE_CXX_STANDARD 11)
link_directories(/home/lp/projects/safety/tensorflow_c/tensorflow_cpp/tensorflow)
include_directories(
        /home/lp/projects/safety/tensorflow_c/tensorflow-master/tensorflow
        /home/lp/projects/safety/tensorflow_c/tensorflow-master/tensorflow/bazel-genfiles
        /home/lp/projects/safety/tensorflow_c/tensorflow-master/tensorflow/bazel-bin/tensorflow
        /home/lp/projects/safety/tensorflow_c/eigen3
)
add_executable(cpptensorflow main.cpp ann_model_loader.h model_loader_base.h ann_model_loader.cpp)
target_link_libraries(cpptensorflow tensorflow_cc tensorflow_framework)

其中 link_directories为指定优先搜索库的路径,也就是.so文件的路径 默认搜索 /usr/local/lib目录,
该目录下有很多.so目录 include_directories为包含的unclude目录.
add_executable参数为要生成的可执行文件的文件名, 要编译的cpp/h文件
target_link_libraries为在lib目录下(包含系统lib目录/usr/local/lib和手动添加目录link_directories,)要包含的.so文件名.其中去掉文件名前面的lib字符串 当多个库存在依赖时,依赖库要写在后面 如果你添加了目标库,但是没有添加目标库的依赖库,就会报错,这个时候你需要将缺少的库也添加到target_link_libraries里面
注意:库的名称是.so文件的文件名去掉前面的lib字符串

在 linux 平台下使用 CMake 生成 Makefile 并编译的流程如下:

编写 CMake 配置文件 CMakeLists.txt 。

执行命令 cmake PATH 或者 ccmake PATH 生成 Makefile, 其中, PATH 是 CMakeLists.txt 所在的目录。
其中ccmake 和 cmake 的区别在于前者提供了一个交互式的界面。

使用 make 命令进行编译。

在CMakeLists.txt目录下执行

mkdir  build   
cd  build
cmake ..
make 

这样就可以生成可执行文件了

cmake 添加头文件目录,链接动态、静态库

1, 添加头文件目录INCLUDE_DIRECTORIES

语法:

include_directories([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...])

例如:
include_directories(../../../thirdparty/comm/include)

它相当于g++选项中的-I参数的作用,也相当于环境变量中增加路径到CPLUS_INCLUDE_PATH变量的作用。

2, 添加需要链接的库文件目录LINK_DIRECTORIES

语法:

link_directories(directory1 directory2 ...)

它相当于g++命令的-L选项的作用,也相当于环境变量中增加LD_LIBRARY_PATH的路径的作用。

示例:
link_directories("/home/server/third/lib")

3, 查找库所在目录FIND_LIBRARY

A short-hand signature is:

find_library (<VAR> name1 [path1 path2 ...])
The general signature is:

find_library (
          <VAR>
          name | NAMES name1 [name2 ...] [NAMES_PER_DIR]
          [HINTS path1 [path2 ... ENV var]]
          [PATHS path1 [path2 ... ENV var]]
          [PATH_SUFFIXES suffix1 [suffix2 ...]]
          [DOC "cache documentation string"]
          [NO_DEFAULT_PATH]
          [NO_CMAKE_ENVIRONMENT_PATH]
          [NO_CMAKE_PATH]
          [NO_SYSTEM_ENVIRONMENT_PATH]
          [NO_CMAKE_SYSTEM_PATH]
          [CMAKE_FIND_ROOT_PATH_BOTH |
           ONLY_CMAKE_FIND_ROOT_PATH |
           NO_CMAKE_FIND_ROOT_PATH]
         )

示例:

FIND_LIBRARY(RUNTIME_LIB rt /usr/lib  /usr/local/lib NO_DEFAULT_PATH)

cmake会在目录中查找,如果所有目录中都没有,值RUNTIME_LIB就会被赋为NO_DEFAULT_PATH
 

4, 添加需要链接的库文件路径LINK_LIBRARIES

语法:

link_libraries(library1 <debug | optimized> library2 ...)
# 直接是全路径
link_libraries(“/home/server/third/lib/libcommon.a”)
# 下面的例子,只有库名,cmake会自动去所包含的目录搜索
link_libraries(iconv)

# 传入变量
link_libraries(${RUNTIME_LIB})
# 也可以链接多个
link_libraries("/opt/MATLAB/R2012a/bin/glnxa64/libeng.so" "/opt/MATLAB/R2012a/bin/glnxa64/libmx.so")

可以链接一个,也可以多个,中间使用空格分隔.

5, 设置要链接的库文件的名称TARGET_LINK_LIBRARIES

语法:

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

# 以下写法都可以: 
target_link_libraries(myProject comm)       # 连接libhello.so库,默认优先链接动态库
target_link_libraries(myProject libcomm.a)  # 显示指定链接静态库
target_link_libraries(myProject libcomm.so) # 显示指定链接动态库

# 再如:
target_link_libraries(myProject libcomm.so)  #这些库名写法都可以。
target_link_libraries(myProject comm)
target_link_libraries(myProject -lcomm)

6,为工程生成目标文件

语法:

add_executable(<name> [WIN32] [MACOSX_BUNDLE]
               [EXCLUDE_FROM_ALL]
               source1 [source2 ...])

简单的例子如下:

add_executable(demo
        main.cpp
)

7, 最后贴一个完整的例子


cmake_minimum_required (VERSION 2.6)

INCLUDE_DIRECTORIES(../../thirdparty/comm)

FIND_LIBRARY(COMM_LIB comm ../../thirdparty/comm/lib NO_DEFAULT_PATH)
FIND_LIBRARY(RUNTIME_LIB rt /usr/lib  /usr/local/lib NO_DEFAULT_PATH)

link_libraries(${COMM_LIB} ${RUNTIME_LIB})

ADD_DEFINITIONS(
-O3 -g -W -Wall
 -Wunused-variable -Wunused-parameter -Wunused-function -Wunused
 -Wno-deprecated -Woverloaded-virtual -Wwrite-strings
 -D__WUR= -D_REENTRANT -D_FILE_OFFSET_BITS=64 -DTIXML_USE_STL
)


add_library(lib_demo
        cmd.cpp
        global.cpp
        md5.cpp
)

link_libraries(lib_demo)
add_executable(demo
        main.cpp
)

# link library in static mode
target_link_libraries(demo libuuid.a)

另外,使用cmake生成makefile之后,make edit_cache可以编辑编译选项。

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页
实付 29.90元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值