cmake的安装使用常用命令介绍以及一些常用配置
Posted 非晚非晚
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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_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++编译选项
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})
以上是关于cmake的安装使用常用命令介绍以及一些常用配置的主要内容,如果未能解决你的问题,请参考以下文章