一、cmake简介
CMake是一个开源的跨平台工具系列,主要用于构建、测试和打包软件。 它使用平台无关的配置文件来控制软件的编译过程,并能够生成适用于不同编译器环境的项目文件,如Makefile或Visual Studio项目文件。CMake由Kitware公司创建,旨在满足开源项目如ITK和VTK对跨平台构建环境的需求。CMake的主要功能包括多文件编译、管理外部依赖、代码模块化和编译结果的安装等,使得开发人员可以在多个平台上无缝衔接,提高开发效率。
我们编写CMakeLists.txt(区分大小写)文件,通过cmake命令生成makefile文件,再使用make命令生成目标文件。
二、Cmake安装
通过输入下列命令查看cmake版本来判断是否安装cmake
cmake --version
若没有安装,则输入如下命令进行安装
sudo apt install cmake
三、Cmake使用
1.注释
#hello 是单行注释符。
#[[hello]] 是多行注释。
2.CMakeLists.txt基本构成的三行命令
cmake_minimum_required此命令是指定要求最低的cmake版本。
project()此命令是定义工程名字
add_executable(hello helloworld.cpp)此命令第一个参数是定义生成的可执行文件的文件名,后面的参数是需要执行的源文件,这些源文件可以用分号隔开也可以用空格隔开。
cmake_minimum_required(VERSION 3.0)# 要求最低cmake版本
project(cmake_learning)#定义工程名字
add_executable(hello helloworld.cpp)
3.Cmake基本使用步骤
执行 cmake CMakeLists.txt文件所在位置 代码示例如下
cmake . #CMakeLists.txt文件在本级目录下
执行上述命令后文件夹会多出一些文件,然后输入make,执行makefile文件,就会生成我们add_executable函数所指定的可执行文件。
执行hello文件,则helloworld.cpp成功执行。
我们可以在同级重新建立一个build目录,进入build目录执行cmake .. 命令,那么生成的这些文件会全部都在build目录中,不会污染环境。
4.set命令的使用
a.set设置变量
set变量中的值默认为字符串类型,set给变量赋值的基本语法为set(变量名 值1,值2),那么我们用变量代替helloworld.cpp,我们的代码就可变为
cmake_minimum_required(VERSION 3.0)# 要求最低cmake版本
project(cmake_learning)#定义工程名字
set(MY_CPP helloworld.cpp)
add_executable(hello ${MY_CPP})
b.set指定c++使用标准
set(CMAKE_CXX_STANDARD 11) #c++11标准
也可以在执行cmake命令时-DCMAKE_CXX_STANDARD=11
c.set指定可执行文件的输出路径
第一个参数EXECUTABLE_OUTPUT_PATH 第二个参数是路径(若路径不存在,系统会自动创造)
set(HOME /home/june/Linux_learning/cmake_learning)
set(EXECUTABLE_OUTPUT_PATH ${HOME}/build)
5.搜索文件
方法一
使用aux_source_directory(路径,变量)函数(不支持递归)可以将指定路径下的所有源文件都寻找出来添加至变量中。
aux_source_directory(/home/june/Linux_learning/cmake_learning,PATH)
${PROJECT_SOURCE_DIR}、${CMAKE_CURRENT_SOURCE_DIR}:cmake 后所跟目录
方法二
file(GLOB_RECURSE PATH2 ${PROJECT_SOURCE_DIR} /*.cpp)
参数一GLOB:扫描本目录;
GLOB_RECURSE:递归扫描本目录;
参数二 变量:用来存储搜到的文件名
参数三 路径
参数四 文件格式
6.搜索头文件
使用include_directories(头文件路径)函数添加头文件
7.制作库文件
动态库名称 lib+动态库名+.so
静态库名称 lib+静态库名+.a
使用add_library函数制作库文件,第一个参数是库名,第二个指定动态库或静态库,动态库为shared,静态库为static,第三个参数为源文件,可以为多个
add_library(mylib STATIC helloworld.cpp)
set(LIBRARY_OUTPUT_PATH /home/june)
上述命令可以指定库文件生成路径
8.链接静态库
使用link_libraries(静态库名)函数来链接静态库,参数直接填静态库名即可,若是多个,也可直接写入。若链接的静态库是自定义的,则还需要链接静态库路径,多个路径用空格间隔开。经测试,这两行代码无先后顺序。
link_directories() #指定静态库路径
link_libraries() #链接静态库
若使用静态库,静态库和可执行文件都会被打包至可执行文件当中,而动态库则不会。
9.链接动态库
要连接动态库,则需要使用target_link_libraries()函数,其中,第一个参数为要加载动态库的文件的名称,该文件可以是动态库,也可以是可执行文件,也可以是源文件。之后所跟参数为需要链接的动态库。
动态库的访问权限:public,private interface;下图是权限比较
public权限库可以被无限链接;
private权限库只能被链接一次;
interface权限它不为目标自身定义任何东西,只为其他链接到它的目标定义(类似于接口);
链接动态库命令如下,该命令要放在exe命令之后,默认权限为public;自定义动态库需指定路径,指定路径方法在静态库模块;
target_link_libraries(hello mylib)
10.日志输出
使用message函数进行控制台打印信息,其中遇到fatal_error会终止程序,其他状态不会影响执行。
message("this is importent error")
message(STATUS "this is not importent error")
message(FATAL_ERROR "this is fatal error")
11.变量操作
a.追加
使用set命令,将变量名1和变量名2合并至变量名 set(变量名 ${变量名1} ${变量名2}),该命令是将从第二个变量开始的所有字符串拼接,然后赋值给第一个变量,若第一个变量存在值,则会被覆盖。
使用list命令,使用append参数。list函数会在SRC之后追加字符串,SRC中有字符串就会在之后追加而不会被覆盖。,list在底层拼接每个字符串会用分号连接,打印不会显示;
list(APPEND SRC ${MY_CPP} ${PATH2})
b.移除字符串
使用list中remove_item参数来删除字符串,上面所说在拼接时每个字符串在底层是用分号隔开的,故在删除时,我们要输出一个完整的字符串项,list第二个参数为要删除字符串的变量,第三个此参数为要删除的字符串。
list(REMOVE_ITEM MY_CPP "helloworld.cpp")
12.list其他操作
a.list获取字符串长度
将第二个变量中字符串的长度赋值给第三个变量(以字符串的形式),获取的字符串长度其实是字符串个数而不是实际的字符数。实际上获取的是list(变量一)中的元素个数。
list(LENGTH MY_CPP new_val)
b.list获取指定索引值
将指定索引中的值赋给新的变量中,可以指定多个索引。
list(GET MY_CPP 1 2 new_val2)
c.使用连接符连接list中的元素
用指定的连接符来链接list的值,并将其赋值给新的变量。
list(JOIN MY_CPP "lianjie" new_val3)
d.使用list查找指定元素
使用find参数,在变量一中查找值,将其索引返回new_val4中,若不存在则返回-1;
list(FIND MY_CPP "helloworld.cpp" new_val4)
e.使用list在指定位置插入元素
使用insert参数,在指定索引位置插入元素,可以插入多个元素
list(INSERT MY_CPP 2 "hello" "hello1")
13.cmake中自定义宏
利用add_definitions命令添加宏,此功能可以控制有些代码是否需要执行(#ifdef DEBUG)。宏的名字前需要加-D宏名。
add_definitions(-DDEBUG)
14.cmake嵌套
每个子目录都可以有一个CMakeLists文件,父节点定义的变量可以被子节点使用,而反之则不行。在父节点的CMakeLists文件中使用如下代码添加子目录中有CMakeLists文件的目录。
add_subdirectory(子目录路径)
最终我们只需要cmake父节点的cmake。
15.静态库中链接其他库
a.静态库链接静态库
方法与链接静态库相似,代码如下。
link_libraries(静态库名)
link_directories(静态库路径)
b.静态库链接动态库
与链接动态库操作相同,在指定动态库命令之后,并生成静态库.
target_link_libraries(静态库名 动态库名)