CMake Tutorial & Example
Tutorial
CMakeLists用于告诉CMake我们要对这个目录下的文件做什么事情
cmake 的特点主要有:
1,开放源代码,使用类 BSD 许可发布。http://cmake.org/HTML/Copyright.html
2,跨平台,并可生成 native 编译配置文件,在 Linux/Unix 平台,生成 makefile,在苹果平台,可以生成 xcode,在 Windows 平台,可以生成 MSVC 的工程文件。
3,能够管理大型项目,KDE4 就是最好的证明。
4,简化编译构建过程和编译过程。Cmake 的工具链非常简单:cmake+make。
5,高效虑,按照 KDE 官方说法,CMake 构建 KDE4 的 kdelibs 要比使用 autotools 来构建 KDE3.5.6 的 kdelibs 快 40%,主要是因为 Cmake 在工具链中没有 libtool。
6,可扩展,可以为 cmake 编写特定功能的模块,扩充 cmake 功能
T1 cmake中一些预定义变量
常用
PROJECT_SOURCE_DIR 工程的根目录
PROJECT_BINARY_DIR 运行cmake命令的目录,通常是${PROJECT_SOURCE_DIR}/build
CMAKE_INCLUDE_PATH 环境变量,非cmake变量
CMAKE_LIBRARY_PATH 环境变量
CMAKE_CURRENT_SOURCE_DIR 当前处理的CMakeLists.txt所在的路径
CMAKE_CURRENT_BINARY_DIR target编译目录
使用ADD_SURDIRECTORY(src bin) 可以更改此变量的值
SET(EXECUTABLE_OUTPUT_PATH <新路径>)并不会对此变量有影响,只是改变了最终目标文件的存储路径
CMAKE_CURRENT_LIST_FILE 输出调用这个变量的CMakeLists.txt的完整路径
CMAKE_CURRENT_LIST_LINE 输出这个变量所在的行
CMAKE_MODULE_PATH 定义自己的cmake模块所在的路径
SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake),然后可以用INCLUDE命令来调用自己的模块
EXECUTABLE_OUTPUT_PATH 重新定义目标二进制可执行文件的存放位置
LIBRARY_OUTPUT_PATH 重新定义目标链接库文件的存放位置
PROJECT_NAME 返回通过PROJECT指令定义的项目名称
CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS 用来控制IF ELSE语句的书写方式
系统信息
CMAKE_MAJOR_VERSION cmake主版本号,如2..6中的2
CMAKE_MINOR_VERSION cmake次版本号,如2..6中的8
CMAKE_PATCH_VERSION cmake补丁等级,如2..6中的6
CMAKE_SYSTEM 系统名称,例如Linux-2.6.
CAMKE_SYSTEM_NAME 不包含版本的系统名,如Linux
CMAKE_SYSTEM_VERSION 系统版本,如2.6.22
CMAKE_SYSTEM_PROCESSOR 处理器名称,如i686
UNIX 在所有的类UNIX平台为TRUE,包括OS X和cygwin
WIN32 在所有的win32平台为TRUE,包括cygwin
开关选项
BUILD_SHARED_LIBS 控制默认的库编译方式。如果未进行设置,使用ADD_LIBRARY时又没有指定库类型,默认编译生成的库都是静态库 (可在t3中稍加修改进行验证)
CMAKE_C_FLAGS 设置C编译选项
CMAKE_CXX_FLAGS 设置C++编译选项
CMAKE_BUILD_TYPE 设置编译模式 None:編譯器預設值 Debug:產生除錯資訊 Release:進行執行速度最佳化
T2 cmake常用命令
基本语法规则:
cmake变量使用${}方式取值,但是在IF控制语句中是直接使用变量名
环境变量使用$ENV{}方式取值,使用SET(ENV{VAR} VALUE)赋值
指令(参数1 参数2…) 参数使用括弧括起,参数之间使用空格或分号分开。
部分常用命令列表:
PROJECT
PROJECT(projectname [CXX] [C] [Java])
指定工程名称,并可指定工程支持的语言。支持语言列表可忽略,默认支持所有语言 SET
SET(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])
定义变量(可以定义多个VALUE,如SET(SRC_LIST main.c util.c reactor.c)) MESSAGE
MESSAGE([SEND_ERROR | STATUS | FATAL_ERROR] “message to display” …)
向终端输出用户定义的信息或变量的值
SEND_ERROR, 产生错误,生成过程被跳过
STATUS, 输出前缀为—的信息
FATAL_ERROR, 立即终止所有cmake过程 ADD_EXECUTABLE
ADD_EXECUTABLE(bin_file_name ${SRC_LIST})
生成可执行文件 ADD_LIBRARY
ADD_LIBRARY(libname [SHARED | STATIC | MODULE] [EXCLUDE_FROM_ALL] SRC_LIST)
生成动态库或静态库
SHARED 动态库
STATIC 静态库
MODULE 在使用dyld的系统有效,若不支持dyld,等同于SHARED
EXCLUDE_FROM_ALL 表示该库不会被默认构建 SET_TARGET_PROPERTIES
设置输出的名称,设置动态库的版本和API版本 CMAKE_MINIMUM_REQUIRED
CMAKE_MINIMUM_REQUIRED(VERSION version_number [FATAL_ERROR])
声明CMake的版本要求 ADD_SUBDIRECTORY
ADD_SUBDIRECTORY(src_dir [binary_dir] [EXCLUDE_FROM_ALL])
向当前工程添加存放源文件的子目录,并可以指定中间二进制和目标二进制的存放位置
EXCLUDE_FROM_ALL含义:将这个目录从编译过程中排除 SUBDIRS
deprecated,不再推荐使用
(hello sample)相当于分别写ADD_SUBDIRECTORY(hello),ADD_SUBDIRECTORY(sample) INCLUDE_DIRECTORIES
INCLUDE_DIRECTORIES([AFTER | BEFORE] [SYSTEM] dir1 dir2 … )
让CMake找到我的头文件, 向工程添加多个特定的头文件搜索路径,路径之间用空格分隔,
如果路径包含空格,可以使用双引号将它括起来,默认的行为为追加到当前头文件搜索路径的后面。有如下两种方式可以控制搜索路径添加的位置:
CMAKE_INCLUDE_DIRECTORIES_BEFORE,通过SET这个cmake变量为on,可以将添加的头文件搜索路径放在已有路径的前面
通过AFTER或BEFORE参数,也可以控制是追加还是置前 LINK_DIRECTORIES
LINK_DIRECTORIES(dir1 dir2 …)
添加非标准的共享库搜索路径 TARGET_LINK_LIBRARIES
TARGET_LINK_LIBRARIES(target lib1 lib2 …)
为target添加需要链接的共享库 ADD_DEFINITIONS
向C/C++编译器添加-D定义
ADD_DEFINITIONS(-DENABLE_DEBUG -DABC),参数之间用空格分隔
ADD_DEPENDENCIES
ADD_DEPENDENCIES(target-name depend-target1 depend-target2 …)
定义target依赖的其他target,确保target在构建之前,其依赖的target已经构建完毕 AUX_SOURCE_DIRECTORY
AUX_SOURCE_DIRECTORY(dir VAR)
发现一个目录下所有的源代码文件并将列表存储在一个变量中
把当前目录下的所有源码文件名赋给变量DIR_HELLO_SRCS EXEC_PROGRAM
EXEC_PROGRAM(Executable [dir where to run] [ARGS <args>][OUTPUT_VARIABLE <var>] [RETURN_VALUE <value>])
用于在指定目录运行某个程序(默认为当前CMakeLists.txt所在目录),通过ARGS添加参数,通过OUTPUT_VARIABLE和RETURN_VALUE获取输出和返回值,如下示例
# 在src中运行ls命令,在src/CMakeLists.txt添加
EXEC_PROGRAM(ls ARGS "*.c" OUTPUT_VARIABLE LS_OUTPUT RETURN_VALUE LS_RVALUE)
IF (not LS_RVALUE)
MESSAGE(STATUS "ls result: " ${LS_OUTPUT}) # 缩进仅为美观,语法无要求
ENDIF(not LS_RVALUE)
INCLUDE
INCLUDE(file [OPTIONAL]) 用来载入CMakeLists.txt文件
INCLUDE(module [OPTIONAL])用来载入预定义的cmake模块
OPTIONAL参数的左右是文件不存在也不会产生错误
可以载入一个文件,也可以载入预定义模块(模块会在CMAKE_MODULE_PATH指定的路径进行搜索)
载入的内容将在处理到INCLUDE语句时直接执行 FIND_
FIND_FILE(<VAR> name path1 path2 …)
VAR变量代表找到的文件全路径,包含文件名 FIND_LIBRARY(<VAR> name path1 path2 …)
VAR变量代表找到的库全路径,包含库文件名
FIND_LIBRARY(libX X11 /usr/lib)
IF (NOT libx)
MESSAGE(FATAL_ERROR "libX not found")
ENDIF(NOT libX)
FIND_PATH(<VAR> name path1 path2 …)
VAR变量代表包含这个文件的路径 FIND_PROGRAM(<VAR> name 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)将其放入工程的某个目录供工程使用
IF
语法:
IF (expression)
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
...
ELSE (expression)
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
...
ENDIF (expression) # 一定要有ENDIF与IF对应
IF (expression), expression不为:空,0,N,NO,OFF,FALSE,NOTFOUND或<var>_NOTFOUND,为真
IF (not exp), 与上面相反
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 dir) 当dir是目录时,为真
IF (DEFINED var) 如果变量被定义,为真
IF (var MATCHES regex) 此处var可以用var名,也可以用${var}
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 (WIN32)
MESSAGE(STATUS “This is windows.”)
ELSE (WIN32)
MESSAGE(STATUS “This is not windows”)
ENDIF (WIN32)
上述代码用来控制在不同的平台进行不同的控制,但是,阅读起来却并不是那么舒服,ELSE(WIN32)之类的语句很容易引起歧义。
可以SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS ON)
这时候就可以写成:
IF (WIN32)
ELSE ()
ENDIF ()
配合ELSEIF使用,可能的写法是这样:
IF (WIN32)
#do something related to WIN32
ELSEIF (UNIX)
#do something related to UNIX
ELSEIF(APPLE)
#do something related to APPLE
ENDIF (WIN32)
WHILE
其真假判断条件可以参考IF指令
WHILE(condition)
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
...
ENDWHILE(condition)
FOREACH
FOREACH指令的使用方法有三种形式:
1.列表
语法:
FOREACH(loop_var arg1 arg2 ...)
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
...
ENDFOREACH(loop_var)
示例:
AUX_SOURCE_DIRECTORY(. SRC_LIST)
FOREACH(F ${SRC_LIST})
MESSAGE(${F})
ENDFOREACH(F)
2.范围
语法:
FOREACH(loop_var RANGE total)
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
...
ENDFOREACH(loop_var)
示例:
从0到total以1为步进
FOREACH(VAR RANGE )
MESSAGE(${VAR})
ENDFOREACH(VAR)
输出:
012345678910 3.范围和步进
语法:
FOREACH(loop_var RANGE start stop [step])
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
...
ENDFOREACH(loop_var)
从start开始到stop结束,以step为步进,
注意:直到遇到ENDFOREACH指令,整个语句块才会得到真正的执行。
FOREACH(A RANGE )
MESSAGE(${A})
ENDFOREACH(A)
输出:
cmake中如何生成动态库和静态库
参考ADD_LIBRARY和SET_TARGET_PROPERTIES用法 cmake中如何使用动态库和静态库(查找库的路径) 参考INCLUDE_DIRECTORIES, LINK_DIRECTORIES, TARGET_LINK_LIBRARIES用法
t4示例使用动态库或静态库
t5示例如何使用cmake预定义的cmake模块(以FindCURL.cmake为例演示)
t6示例如何使用自定义的cmake模块(编写了自定义的FindHELLO.cmake)
注意读t5和t6的CMakeLists.txt和FindHELLO.cmake中的注释部分 cmake中如何指定生成文件的输出路径 如上ADD_SUBDIRECTORY的时候指定目标二进制文件输出路径(推荐使用下面这种)
使用SET命令重新定义EXECUTABLE_OUTPUT_PATH和LIBRARY_OUTPUT_PATH变量来指定最终的二进制文件的位置
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
上面的两条命令通常紧跟ADD_EXECUTABLE和ADD_LIBRARY,与其写在同一个CMakeLists.txt即可
cmake中如何增加编译选项 使用变量CMAKE_C_FLAGS添加C编译选项
使用变量CMAKE_CXX_FLAGS添加C++编译选项
使用ADD_DEFINITION添加 cmake中如何增加头文件路径 参考INCLUDE_DIRECTORIES命令用法 cmake中如何在屏幕上打印信息 参考MESSAGE用法 cmake中如何给变量赋值 参考SET和AUX_SOURCE_DIRECTORY用法 建议:在Project根目录先建立build,然后在build文件夹内运行cmake ..,这样就不会污染源代码, 如果不想要这些自动生成的文件了,只要简单的删除build文件夹就可以
e.g 1.0
# 声明要求的 cmake 最低版本
cmake_minimum_required( VERSION 2.8 ) # 声明一个 cmake 工程
project( HelloSLAM ) # 设置编译模式 None:編譯器預設值 Debug:產生除錯資訊 Release:進行執行速度最佳化
set( CMAKE_BUILD_TYPE "Debug" ) # 添加一个库:hello库
#静态库.a :每次被调用都生成一个副本 在build里生成的是 libhello_static.a
add_library( hello_static libHelloSLAM.cpp )
#共享库.so :不论被调用几次都只有一个副本 在build里生成的是 libhello_shared.so
add_library( hello_shared SHARED libHelloSLAM.cpp )
# 添加一个可执行程序useHello
# 语法:add_executable( 程序名 源代码文件 )
add_executable( HelloSLAM useHello.cpp )
# 将库文件链接到可执行程序HelloSLAM上
target_link_libraries( HelloSLAM hello_shared )
e.g 1.1
1.添加Eigen头文件
Eigen通过apt-get安装之后,我们要怎么使用这个依赖库呢?
Eigen有一点很奇怪,Eigen库只有头文件,所以我们在CMakeLists.txt中是不需要写target_link_libraries,
因为我们是通过apt安装的,所以很容易的知道Eigen库的位置就是在/usr/include/eigen3
#添加头文件
include_directories("/usr/include/eigen3")
因为我们已经知道Eigen具体的位置,就不用使用find_package来寻找了,虽然有些粗暴,但是简单有效。
2.添加Pangolin依赖
Pangolin的安装也很简单,功能主要就是做三维的可视化显示,主要依赖库是OpenGL,通过apt也很好安装。
find_package(Pangolin) include_directories(${Pangolin_INCLUDE_DIRS}) add_executable(project_name filename.cpp) target_link_libraries(project_name ${Pangolin_LIBRARIES})
3.添加Sophus依赖
Sophus实际上是Eigen库的扩展模块,Eigen中虽然有几何模块,但是没有提供李代数的支持,所以Sophus算是一个比较好的李代数库,安装参考之前博文。
find_package(Sophus REQUIRED)
include_directories(${Sophus_INCLUDE_DIRS})
add_executable(project_name project_name.cpp)
target_link_libraries(project_name ${Sophus_LIBRARIES})
4.添加OpenCV依赖
OpenCV经常会出现版本不兼容的问题,LZ同时安装了OpenCV2和OpenCV3两个版本,所以在CMakeLists.txt要指定OpenCV的版本。
#指定OpenCV的版本是3.
find_package(OpenCV 3.1 REQUIRED) include_directories(${OpenCV_INCLUDE_DIRS}) add_executable(project_name filename.cpp) target_link_libraries(project_name ${OpenCV_LIBS})
添加OpenCV要注意一个问题,大小写!很重要!大小写!
5.添加PCL依赖
这个点云库在SLAM应用中还是蛮重要的,通常情况下好像也都有安装,安装很简单,这里还是讲一下CMakeLists.txt中怎么写:
find_package(PCL REQUIRED COMPONENT common io) include_directories(${PCL_INCLUDE_DIRS}) add_definitions(${PCL_DEFINITIONS}) target_link_libraries(project_name ${PCL_LIBRARIES})
6.添加Ceres依赖
Ceres是Google出品的一个优化库,安装编译都在LZ之前写过一个SLAM安装大全里都有。因为Ceres不是常用的库,所以需要添加一个cmake_modules。
#这行代码就是添加查找Ceres的一个文件
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake_modules) find_package(Ceres REQUIRED) include_directories(${CERES_INCLUDE_DIRS}) target_link_libraries(project_name ${CERES_LIBRARIES})
7添加G2O的依赖
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake_modules) find_package(G2O REQUIRED) include_directories(${G20_INCLUDE_DIRS}) target_link_libraries(project_name g2o_core g2o_stuff)
CMake Tutorial & Example的更多相关文章
- CMake Tutorial
1.最简实例 使用cmake的最简实例是由一个源程序文件生成一个可执行文件.例如由下述C++源程序文件生成可执行文件tutorial. main.cpp #include<iostream> ...
- ubuntu 16.04 上编译和安装C++机器学习工具包mlpack并编写mlpack-config.cmake | tutorial to compile and install mplack on ubuntu 16.04
本文首发于个人博客https://kezunlin.me/post/1cd6a04d/,欢迎阅读最新内容! tutorial to compile and install mplack on ubun ...
- [cmake] Basic Tutorial
Basic Project The most basic porject is an executable built from source code file. CMakeLists.txt cm ...
- CMake使用教程
转自 RichardXG 原文 CMake使用教程 CMake是一个比make更高级的编译配置工具,它可以根据不同平台.不同的编译器,生成相应的Makefile或者vcproj项目. 通过编写CMak ...
- CMake入门指南-编译教程
CMake是一个比make更高级的编译配置工具,它可以根据不同平台.不同的编译器,生成相应的Makefile或者vcproj项目.通过编写CMakeLists.txt,可以控制生成的Makefile, ...
- CMake入门指南
原文地址:http://www.cnblogs.com/sinojelly/archive/2010/05/22/1741337.html CMake是一个比make更高级的编译配置工具,它可以根据不 ...
- CMake Intro - CMakeLists.txt
Notes: directory structure: cmake, cmake/Tutorial, cmake/Tutorial/MathLibs 1. File lists in cmake/ ...
- 基于Cmake+QT+VS的C++项目构建开发编译简明教程
目录 一.工具下载与安装 1. Qt 2. Visual Studio 2015 3. Cmake 二.C++及Qt项目构建 1. 基于VS构建Qt项目 2. ...
- CMake 用法导览
Preface : 本文是CMake官方文档CMake Tutorial (http://www.cmake.org/cmake/help/cmake_tutorial.html) 的翻译.通过一个样 ...
随机推荐
- 0x40二分法
二分模板一共有两个,分别适用于不同情况.算法思路:假设目标值在闭区间[l, r]中, 每次将区间长度缩小一半,当l = r时,我们就找到了目标值. 版本1 在单调递增序列a中查找>=x的数中最小 ...
- ffmpeg处理RTMP流媒体的命令大全
最近浏览国外网站时候发现,翻译不准确的敬请谅解. 1.将文件当做直播送至live ffmpeg -re -i localFile.mp4 -c copy -f flv rtmp://server/li ...
- 2017.10.25 Java List /ArrayList 三种遍历方法
java list三种遍历方法性能比较 学习java语言list遍历的三种方法,顺便测试各种遍历方法的性能,测试方法为在ArrayList中插入记录,然后遍历ArrayList,测试代码如下: pac ...
- grep的使用
http://www.eguidedog.net/linux-tutorial/05-grep.php grep apple fruitlist.txt:在fruitlist.txt中查找apple字 ...
- service 入门
https://www.cnblogs.com/keguangqiang/p/3663086.html#undefined
- 将TIF格式批量转换成jpg或png格式(C#自制软件)
此项目基于.net framework 4.0 全选tif,拖进去,等待,完成. so easy... 链接:https://pan.baidu.com/s/1uCDhAT0uHRjdy4g557wK ...
- Ray-AABB交叉检测算法
最近在解决三维问题时,需要判断线段是否与立方体交叉,这个问题可以引申为:射线是否穿过立方体AABB. 在3D游戏开发中碰撞检测普遍采用的算法是轴对齐矩形边界框(Axially Aligned ...
- 第3章 如何用DAP仿真器下载程序—零死角玩转STM32-F429系列
第3章 如何用DAP仿真器下载程序 集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/firege ...
- jquery操作DOM 元素(3)
.detach() 从DOM 中去掉所匹配的元素. .detach([selector]) selector 一个选择表达式将需要移除的从匹配的元素中过滤出来. $("p").de ...
- cordova-plugin-themeablebrowser 0.2.17 "ThemeableBrowser"ionic跳转外链插件在ios中heardBar会遮住内容的bug
ionic+angular的app项目中需要在App打开一个外部的url链接,用了这个插件发现在iPhone手机中会出现toolbar挡住url页面内容 解决方法: 在原有基础上加上statusBar ...