cmake的安装、使用、常用命令介绍以及一些常用配置

如果英文水平不错,或者想要深入了解cmake,可以查看官方指令文档。但是对于大部分人来说,如果只是对cmake的要求仅仅为使用的水平,那么这一篇文章已经远远足够了。

0. 安装以及使用介绍

在ubuntu系统下的安装命令如下:

sudo apt install cmake

查看cmake版本:

cmake -version
  • 为什么用cmake

理论上说,任意一个 C++ 程序都可以用 g++ 来编译。但当程序规模越来越大时,一个工程可能有许多个文件夹和里边的源文件,这时输入的编译命令将越来越长。如果仅靠 g++ 命令,我们需要输入大量的编译指令,整个编译过程会变得异常繁琐。在历史上工程师们曾使用 makefile 进行自动编译,但下面要谈的 cmake 比它更加方便。在一个 cmake 工程中,我们会用 cmake 命令生成一个 makefile 文件,然后,用 make命令,根据这个 makefile 文件的内容,编译整个工程。

  • 使用步骤

在CMakeLists.txt同一目录下新建build目录,使用步骤类似于下列命令。

mkdir build
cd build
cmake .. # 在该目录下生成makefile文件
make -j4 # 编译
./YourExecutable #运行

上面的cmake后面接了两个点,表示CMakeLists.txt在上一个目录。也可以不添加build目录,CMakeLists.txt同一目录使用cmake .进行编译,只不过生成的内容太多,影响美观。

这一步骤类似于使用源码安装软件,./YourExecutable运行命令,修改为下列命令:

sudo make install

1. 基本语法规则

  • cmake变量使用${}方式取值,但是在IF控制语句中是直接使用变量名
  • 环境变量使用$ENV{}方式取值,使用SET(ENV{VAR} VALUE)赋值
  • 指令是大小写无关的,参数和变量是大小写相关的。推荐你全部使用大写指令。
  • 指令(参数1 参数2…),参数使用括弧括起,参数之间使用空格或分号分开。
#以ADD_EXECUTABLE指令为例:
ADD_EXECUTABLE(hello main.c func.c)或者
ADD_EXECUTABLE(hello main.c;func.c)
  • 如果文件名或者路径名包含了空格,可以使用双引号将它括起来(不包含空格也可以使用双引号):
SET(SRC_LIST “fu nc.c”)

2. cmake中一些预定义变量

  • PROJECT_BINARY_DIR:运行cmake命令的目录,通常是${PROJECT_SOURCE_DIR}/build

  • EXECUTABLE_OUTPUT_PATH:重新定义目标二进制可执行文件的存放位置

  • LIBRARY_OUTPUT_PATH 重新定义目标链接库文件的存放位置

    SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)#设定可执行文件地址
    SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)#设定输出库地址
    
  • PROJECT_SOURCE_DIR:工程的根目录

  • CMAKE_CURRENT_SOURCE_DIR:当前处理的CMakeLists.txt所在的目录

  • CMAKE_MAJOR_VERSION:cmake主版本号,如2.8.6中的2

  • CMAKE_MINOR_VERSION:cmake次版本号,如2.8.6中的8

  • CMAKE_PATCH_VERSION:cmake补丁等级,如2.8.6中的6

  • CMAKE_SYSTEM:系统名称,例如Linux-2.6.22

  • 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时又没有指定库类型,默认编译生成的库都是静态库。

  • CMAKE_C_FLAGS:设置C编译选项

  • CMAKE_CXX_FLAGS:设置C++编译选项

  • PROJECT_NAME: 工程名。

3. cmake中如何生成动态库和静态库

参考ADD_LIBRARY和SET_TARGET_PROPERTIES用法,t3示例展示了相关用法

4. cmake中如何使用动态库和静态库(查找库的路径)

参考INCLUDE_DIRECTORIES, LINK_DIRECTORIES, TARGET_LINK_LIBRARIES用法

  • t4示例使用动态库或静态库
  • t5示例如何使用cmake预定义的cmake模块(以FindCURL.cmake为例演示)
  • t6示例如何使用自定义的cmake模块(编写了自定义的FindHELLO.cmake)

5. 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)

6. cmake中如何增加编译选项

  • 使用变量CMAKE_C_FLAGS添加C编译选项
  • 使用变量CMAKE_CXX_FLAGS添加C++编译选项
  • 使用ADD_DEFINITION添加

7. cmake中如何增加头文件路径

  • 参考INCLUDE_DIRECTORIES命令用法

8. cmake中如何在屏幕上打印信息

  • 参考MESSAGE用法

9. cmake中如何给变量赋值

  • 参考SET和AUX_SOURCE_DIRECTORY用法

10. 部分常用命令

  • PROJECT:指定工程名称,还可指定工程支持的语言(可忽略)
  • SET:定义变量,可定义多个变量,如下:
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_LIBRARY:生成动态库或静态库
ADD_LIBRARY(libname [SHARED | STATIC | MODULE] [EXCLUDE_FROM_ALL] SRC_LIST) #生成动态、静态库,module等同于shared
# EXCLUDE_FROM_ALL表示该库不会被默认构建
  • SET_TARGET_PROPERTIES:设置动态库的版本和API版本
SET_TARGET_PROPERTIES(hello_static PROPERTIES OUTPUT_NAME "hello")#生成的库名字
# 设置动态库的版本号,这里设置了两个版本号
SET_TARGET_PROPERTIES(hello_shared PROPERTIES VERSION 1.2 SOVERSION 1)
  • CMAKE_MINIMUM_REQUIRED:声明CMake的版本要求
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
  • ADD_SUBDIRECTORY:向当前工程添加存放源文件的子目录

  • SUBDIRS:deprecated,不再推荐使用

  • INCLUDE_DIRECTORIES:向工程添加多个特定的头文件搜索路径

  • LINK_DIRECTORIES:添加非标准的共享库搜索路径

  • TARGET_LINK_LIBRARIES:为target添加需要链接的共享库

  • ADD_DEFINITIONS:向C/C++编译器添加-D定义

  • ADD_DEPENDENCIES:定义target依赖的其他target

  • AUX_SOURCE_DIRECTORY:发现一个目录下所有的源代码文件并将列表存储在一个变量中

  • EXEC_PROGRAM:用于在指定目录运行某个程序(默认为当前CMakeLists.txt所在目录)

  • INCLUDE:载入CmakeList.txt文件或者预定义的cmake模块

INCLUDE(file [OPTIONAL]) #用来载入CMakeLists.txt文件
INCLUDE(module [OPTIONAL])#用来载入预定义的cmake模块
  • FIND_
  • FIND_FILE( name path1 path2 …)

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

  • FIND_LIBRARY( name path1 path2 …)

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

FIND_LIBRARY(libX X11 /usr/lib)
IF (NOT libx)
    MESSAGE(FATAL_ERROR "libX not found")
ENDIF(NOT libX)
  • FIND_PATH( name path1 path2 …)

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

  • FIND_PROGRAM( name path1 path2 …)

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

  • FIND_PACKAGE( [major.minor] [QUIET] [NO_MODULE] [[REQUIRED | COMPONENTS] [componets …]])

用来调用预定义在CMAKE_MODULE_PATH下的Find.cmake模块,你也可以自己定义Find
模块,通过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指令的使用方法有三种形式

形式一:列表

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)

形式二:范围

FOREACH(loop_var RANGE total)
    COMMAND1(ARGS ...)
    COMMAND2(ARGS ...)
    ...
ENDFOREACH(loop_var)
#从0到total以1为步进
FOREACH(VAR RANGE 10)
   MESSAGE(${VAR})
ENDFOREACH(VAR)
#输出:
012345678910

形式三:范围和步进

FOREACH(loop_var RANGE start stop [step])
    COMMAND1(ARGS ...)
    COMMAND2(ARGS ...)
    ...
ENDFOREACH(loop_var)

从start开始到stop结束,以step为步进。**注意:**直到遇到ENDFOREACH指令,整个语句块才会得到真正的执行。

FOREACH(A RANGE 5 15 3)
    MESSAGE(${A})
ENDFOREACH(A)
输出:
581114

11. 常用配置

这里介绍一些常用的配置,也作为以后的参考。

###############################################################
# 基础配置
cmake_minimum_required(VERSION 2.8)# # 声明要求的 cmake 最低版本
project(YourProjectName) # # 声明一个 cmake 工程
set(CMAKE_BUILD_TYPE Release) # 设置编译模式
set(CMAKE_CXX_FLAGS "-std=c++14 -O3") # C++支持的版本
set(OpenCV_DIR /opt/ros/kinetic/share/OpenCV-3.3.1-dev)#手动定义变量,find_package没找到的情况下可以使用

###############################################################
#典型配置
include_directories(/usr/local/include)#找根目录


# OpenCV
find_package(OpenCV REQUIRED)#寻找OpenCV.CMakeLists,以此找到包,并赋值各库相关变量
include_directories(${OpenCV_INCLUDE_DIRS})#添加头文件搜索路径,这样可以在代码中的#include做根目录
#OpenCV_INCLUDE_DIRS是关于find_package的变量

# Ceres
find_package(Ceres REQUIRED)
include_directories(${CERES_INCLUDE_DIRS})

# g2o
find_package(G2O REQUIRED)
include_directories(${G2O_INCLUDE_DIRS})

# Eigen
include_directories("/usr/include/eigen3")

# pcl
find_package(PCL 1.2 REQUIRED)
include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS}) #库地址
add_definitions(${PCL_DEFINITIONS})

add_executable(gaussNewton gaussNewton.cpp)#添加对主函数的可执行文件
target_link_libraries(gaussNewton ${OpenCV_LIBS})  # 添加OpenCV的库,目标链接库

add_executable(ceresCurveFitting ceresCurveFitting.cpp)
target_link_libraries(ceresCurveFitting ${OpenCV_LIBS} ${CERES_LIBRARIES})

add_executable(g2oCurveFitting g2oCurveFitting.cpp)
target_link_libraries(g2oCurveFitting ${OpenCV_LIBS} ${G2O_CORE_LIBRARY} ${G2O_STUFF_LIBRARY})
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

非晚非晚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值