文章目录
- 一、安装
- 二、cmake编译
- 三、语法
- 1.基本语法
- 2.指令
- (1)PROJECT()
- (2)CMAKE_MINIMUM_REQUIRED()
- (3)SET()
- (4)MESSAGE()
- (5)AUX_SOURCE_DIRECTORY()
- ①基本含义
- ②子目录
- ③可添加多个
- (6)ADD_SUBDIRECTORY
- (7)FIND_PACKAGE()
- (8)INCLUDE_DIRECTORIES()
- (9)ADD_EXECUTABLE()
- (10)TARGET_LINK_LIBRARIES()
- (11)cmake
- 3.总结
- 三、简单的内部构建
- 1.前期准备
- 2.构建CMakeLists.txt
- 3.cmake+make编译
- 四、简单的外部构建
- 1.在工程目录下准备好你的代码构建CMakeLists.txt
- 2.在工程目录下创建一个build文件夹
- 3.进入build进行cmake+make编译
一、安装
sudo apt-get install cmake
安装好后,输入
cmake -version
如果出现了cmake的版本显示,那么说明安装成功
二、cmake编译
cmake的作用就是将在IDE编译器中的编译功能拿出来,可以在终端上完成。类似于vim和文本编辑器。
cmake的编译方式:
- 内部构建(in-source-build)
- 外部构建(out-of-source-build)
两者的区别仅仅是前者将生成的编译文件和源代码、CMakeLists.txt混杂在一起,后者就只是创建了一个文件夹存储生成的编译文件,更好删除编译生成的文件而已(直接删文件夹)。
三、语法
1.基本语法
- 指令是大小写无关的,参数和变量是大小写相关的。但推荐你全部使用大写指令。
- 变量使用
${}
方式取值,但是在 IF 控制语句中是直接使用变量名。
如:${SRC_LIST}
- 指令(参数 1 参数 2…) 参数使用括弧括起,参数之间使用空格或分号分开。
如:ADD_EXECUTABLE(hello main.c func.c)
或者ADD_EXECUTABLE(hello main.c;func.c)
- 注释:
# comment
2.指令
搞清当前目录的意思:
-
CMakeLists.txt
下的.
表示当前目录是CMakeLists.txt
文件所在的目录,而非执行时终端的当前目录。 -
cmake .
这条终端命令是执行时终端的当前目录。
(1)PROJECT()
PROJECT(projectname [CXX] [C] [Java])
总结:定义工程名称,并可指定工程支持的语言。
- 定义工程名称:
如PROJECT(HELLO)
,那么工程的名称就是HELLO
- 支持的语言列表
支持的语言列表是可以忽略的, 默认情况表示支持所有语言。
如指定C++,PROJECT(HELLO CXX)
- 这个指令隐式的定义了四个 cmake 变量:
-
<projectname>_BINARY_DIR
以及<projectname>_SOURCE_DIR
(格式,并非实际的变量)
对于这个工程就是HELLO_BINARY_DIR
和HELLO_SOURCE_DIR
(之后就可以直接使用了这两个变量),使用<projectname>_BINARY_DIR
这个是无效的。 -
PROJECT_BINARY_DIR
和PROJECT_SOURCE_DIR
变量
他们的值分别跟HELLO_BINARY_DIR
与HELLO_SOURCE_DIR
一致。区别是这两个会自动根据工程名字的变化而变化。 - 建议以后直接使用
PROJECT_BINARY_DIR
,PROJECT_SOURCE_DIR
,即使修改了工程名称,也不会影响这两个变量。
如:从HELLO该为WORLD,那么前者就得写成WORLD_BINARY_DIR
和WORLD_SOURCE_DIR
,但后者还是PROJECT_BINARY_DIR
和PROJECT_SOURCE_DIR
。
(2)CMAKE_MINIMUM_REQUIRED()
CMAKE_MINIMUM_REQUIRED(VERSION 3.10)
cmake最低版本
(3)SET()
SET(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])
作用:定义变量的值
比如:
- 如果有多个源文件,也可以定义成:
SET(SRC_LIST main.c t1.c t2.c)
- 可以用
""
来处理包含空格的文件名:SET(SRC_LIST "hello world.cpp")
(建议使用方式) - 使用c++11特性:
set(CMAKE_CXX_FLAGS "${CAMKE_CXX_FLAGS} -std=c++11")
防止出现因为c++11才有的编译错误,比如error: 'to_string' is not a member of 'std'
- 设置编译模式 Build Type:要加引号,不加可能报错。
- Debug模式:
set(CMAKE_BUILD_TYPE "Debug")
- Release模式:
set(CMAKE_BUILD_TYPE "Release")
。更快。
(4)MESSAGE()
MESSAGE([SEND_ERROR | STATUS | FATAL_ERROR] "message to display")
作用:在cmake编译过程中向终端输出用户定义的信息。
- 三种信息类型:
-
SEND_ERROR
:产生错误,生成过程被跳过 -
STATUS
:输出前缀为--
的信息。 -
FATAL_ERROR
:立即终止所有 cmake 过程
- 输出内容:
"hello ${<variant name>}"
比如:
PROJECT(HELLO)
SET(SRC_LIST main.cpp)
MESSAGE(STATUS "The value of HELLO_SOURCE_DIR is${HELLO_SOURCE_DIR}" )
ADD_EXECUTABLE(hello ${SRC_LIST})
ps:引号的作用是保留空格
-
"hello world ${HELLO_SOURCE_DIR}"
:输出为hello world /home
-
hello world ${HELLO_SOURCE_DIR}
:输出为helloworld/home
(5)AUX_SOURCE_DIRECTORY()
①基本含义
AUX_SOURCE_DIRECTORY(dir VARIABLE)
PS:aux表示auxiliary附近的
作用是发现一个目录dir
下所有的源代码文件并将列表存储在一个变量中,这个指令临时被用来自动构建源文件列表。因为目前 cmake 还不能自动发现新添加的源文件。 (本目录为CMakeLists.txt所在的目录)
比如:
AUX_SOURCE_DIRECTORY(. SRC_LIST)
ADD_EXECUTABLE(main ${SRC_LIST})
将本目录下的源代码文件添加到SRC_LIST变量中,再将这些文件编译成生成文件。
②子目录
注意:如果本目录下有子目录,是不会将子目录下的源代码文件添加进去的,得手动打出来。
比如:
# 本目录下的子目录subDir
AUX_SOURCE_DIRECTORY(./subDir SRC_LIST)
③可添加多个
这两个一起添加进入SRL_LIST
,并不是后者覆盖前者。
AUX_SOURCE_DIRECTORY(./src/text SRC_LIST)
AUX_SOURCE_DIRECTORY(./src/serial SRC_LIST)
(6)ADD_SUBDIRECTORY
ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
这个指令用于向当前工程添加存放源文件的子目录,并可以指定中间二进制和目标二进制存放的位置。
- EXCLUDE_FROM_ALL参数的含义
将这个目录从编译过程中排除,比如,工程 的 example,可能就需要工程构建完成后,再进入 example 目录单独进行构建(当然,你 也可以通过定义依赖来解决此类问题)。
比如:
将 src 子目录加入工程,并指定编译输出(包含编译中间结果)路径为bin 目录。
(7)FIND_PACKAGE()
FIND_PACKAGE(<name> [major.minor] [QUIET] [NO_MODULE]
[[REQUIRED|COMPONENTS] [componets...]])
参数:
- REQUIRED 参数
如果使用了这个参数,说明这 个链接库是必备库,如果找不到这个链接库,则工程不能编译。
功能:
只找一个名为name
的包(后面都是修饰条件),所以如果要找多个包,要分多个FIND_PACKAGE()
写。
比如:
- OpenCV3:
find_package(OpenCV REQUIRED)
- ROS:
find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs)
(8)INCLUDE_DIRECTORIES()
include_directories()
功能:链接头文件
描述:可以将要链接的头文件都写在括号里,不用分成多个INCLUDE_DIRECTORIES()写。
比如:
- OpenCV3:
${OpenCV_INCLUDE_DIRS}
- ROS:
${catkin_INCLUDE_DIRS}
(9)ADD_EXECUTABLE()
ADD_EXECUTABLE(hello ${SRC_LIST})
生成可执行文件。
- 相关的源文件是SRC_LIST 中 定义的源文件列表, 你也可以直接写成
ADD_EXECUTABLE(hello main.c ti.c)
。 - 可以写成
ADD_EXECUTABLE(hello main)
cmake 会自动的在本目录查找main.c
或者main.cpp
等,当然,最好不要偷这个懒,以免这个目录确实存在一个main.c
一个main.cpp
- hello是最终要执行的可执行文件:
./hello
(10)TARGET_LINK_LIBRARIES()
TARGET_LINK_LIBRARIES(target library1 <debug | optimized> library2...)
功能:这个必须写在ADD_EXECUTABLE()之后,为生成文件target添加库。
比如:
- OpenCV3:
${OpenCV_LIBS}
- ROS:
${catkin_LIBRARIES}
(11)cmake
这里的目录,因为是这条指令是在终端下编译,所以本目录为终端下的当前目录。
cmake .
:对工作目录(本目录)进行cmake编译cmake ..
:对父目录进行cmake编译
这两个都将生成的编译文件放到本目录下。
3.总结
添加文件的方式
- 手动添加:
set()
SET(SRC_LIST "main.cpp forest.hpp")
ADD_EXECUTABLE(main ${SRC_LIST})
- 自动添加:
AUX_SOURCE_DIRECTORY()
AUX_SOURCE_DIRECTORY(. SRC_LIST)
ADD_EXECUTABLE(main ${SRC_LIST})
三、简单的内部构建
关键步骤就三步:
- 准备好你的代码
- 构建CMakeLists.txt
- cmake+make编译
- MyCode
- main.cpp
- CMakeLists.txt
- build编译生成的东西
1.前期准备
- 先创一个目录
mkdir Code
- 写个main.cpp代码
gedit main.cpp
内容是
#include<iostream>
using namespace std;
int main()
{
cout<<"hello"<<endl;
return 0;
}
2.构建CMakeLists.txt
CMakeLists.txt是告诉cmake该怎么编译你的代码的:要编译什么代码等之类的信息。
- 创建一个CMakeLists.txt文件
gedit CMakeLists.txt
- 内容是
PROJECT(HelloProject)
ADD_EXECUTABLE(hello main.cpp)
3.cmake+make编译
- cmake编译
cmake .
- make编译
make
- 执行
./hello
四、简单的外部构建
关键步骤就三步:
- 在工程目录下准备好你的代码构建CMakeLists.txt
- 在工程目录下创建一个build文件夹
- 进入build进行cmake+make编译
- MyCode
- main.cpp
- CMakeLists.txt
- build
- build编译生成的东西
1.在工程目录下准备好你的代码构建CMakeLists.txt
mkdir MyCode
-
gedit main.cpp
内容同上 -
gedit CMakeLists.txt
内容同上
2.在工程目录下创建一个build文件夹
mkdir build
3.进入build进行cmake+make编译
cd build
-
cmake ..
(代码和CMakeLists.txt都在父目录,只是让编译出的文件在这里生成) make
./hello
参考:
链接:cmake实践 提取码:
979y