工作后开发内容都是在Linux系统下完成,cmake使用比较频繁,找到一篇很不错的CMake笔记。
记录下来方便自己查阅。
1.CMake介绍
CMake是一种跨平台的编译配置工具,它可以在不同的平台下基于同样的源代码文件生成对应的工程文件。例如Makefile和VS工程. 使用CMake的流程如下:
①编写CMakeLists.txt
②执行cmake PATH或ccmake PATH生成Makefile
③使用make进行编译
CMakeLists.txt的语法较为简单,由命令、注释和空格组成,其中命令是不区分大小写的,符号#后面的内容被认为是注释,命令由命令名称、小括号和参数组成,参数之间使用空格进行间隔。
2.示例一:编译单个文件
- 工程目录如下
./Demo1
|
+--main.cpp
现在有一个源文件main.cpp,程序里面包含一个函数power,main中调用了它,在同目录下编写CMakeLists.txt文件。
main.cpp
#include <stdio.h>
#include <stdlib.h>
/**
* power - Calculate the power of number.
* @param base: Base value.
* @param exponent: Exponent value.
*
* @return base raised to the power exponent.
*/
double power(double base, int exponent)
{
int result = base;
int i;
if (exponent == 0) {
return 1;
}
for(i = 1; i < exponent; ++i){
result = result * base;
}
return result;
}
int main(int argc, char *argv[])
{
if (argc < 3){
printf("Usage: %s base exponent \n", argv[0]);
return 1;
}
double base = atof(argv[1]);
int exponent = atoi(argv[2]);
double result = power(base, exponent);
printf("%g ^ %d is %g\n", base, exponent, result);
return 0;
}
CMakeLists.txt
# CMake最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo1)
# 指定生成目标
add_executable(Demo main.cpp)
上面的CMakeLists.txt文件出现如下命令:
-
cmake_minimum_required
:表示指定运行此配置文件所需的CMake的最低版本 -
project
:参数值Demo1,表示此项目的名称是Demo1 -
add_executable
:将名为main.cpp的文件编译成一个名为Demo的可执行文件
在当前目录执行cmake .
cmake就会根据平台自动生成工程文件,未报错就继续执行make
,生成可执行文件。
- 运行可执行文件
-
指定DEBUG模式
也可以在CMakeLists.txt文件中添加以下代码来指定DEBUG模式.
set(CMAKE_BUILD_TYPE Debug)
①修改CMakeLists.txt文件
②终端执行make clean
③将CMakeCache.txt文件删除,重新进行cmake .
CMAKE_BUILD_TYPE
1.可选值包括
Debug:用于在没有优化的情况下,使用带有调试符号构建库或可执行文件
Release:用于构建的优化的库或可执行文件,不包含调试符号
RelWithDebInfo:由于构建较少的优化库或可执行文件,包含调试符号MinSizeRel:用于不增加目标代码大小的优化方式,来构建或可执行文件
2.使用方法set(CMAKE_BUILD_TYPE "Debug")
# CMakeLists.txt中指定
或者cmake .. -D CMAKE_BUILD_TYPE=“Debug”
# 生成时命令行指定
3.示例二:编译同个目录下多个文件
- 工程目录如下,把power函数单独写进一个MathFunctions.c的源文件中
./Demo2
|
+--main.cpp
|
+--MathFunctions.cpp
|
+--MathFunctions.h
main.cpp
#include <stdio.h>
#include <stdlib.h>
#include "MathFunctions.h"
int main(int argc, char *argv[])
{
if (argc < 3){
printf("Usage: %s base exponent \n", argv[0]);
return 1;
}
double base = atof(argv[1]);
int exponent = atoi(argv[2]);
double result = power(base, exponent);
printf("%g ^ %d is %g\n", base, exponent, result);
return 0;
}
MathFunctions.cpp
/**
* power - Calculate the power of number.
* @param base: Base value.
* @param exponent: Exponent value.
*
* @return base raised to the power exponent.
*/
double power(double base, int exponent)
{
int result = base;
int i;
if (exponent == 0) {
return 1;
}
for(i = 1; i < exponent; ++i){
result = result * base;
}
return result;
}
MathFunctions.h
#ifndef POWER_H
#define POWER_H
extern double power(double base, int exponent);
#endif
CMakeLists.txt
# CMake最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo2)
# 指定生成目标
add_executable(Demo main.cpp MathFunctions.cpp)
此时CMakeLists.txt修改只是在add_executable
命令中增加了一个MathFunctions.cc,如果源文件太多,可以使用aux_source_directory命令。
aux_source_directory()
该命令会查找指定目录下的所有源文件,然后把结果存进指定变量名,通过${variable}来使用变量。
aux_source_directory( <dir> <variable>)
修改CMakeLists.txt如下:
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo2)
# 查找目录下的所有源文件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)
# 指定生成目标
add_executable(Demo ${DIR_SRCS})
4.示例三:编译多个目录下多个文件
- 工程目录如下,将MathFunctions.h和MathFunctions.cc文件移动到单独的Math目录下。
./Demo3
|
+--main.cpp
|
+--math/
|
+--MathFunctions.cpp
|
+--MathFunctions.h
需要在根目录和math下各建立一个CMakeLists.txt文件,先将math目录下的文件编译成静态库再由main函数调用。
只需要将示例二源码中main.cpp引用路径由#include "MathFunctions.h"
改为#include "math/MathFunctions.h"
即可。
根目录中的CMakeLists.txt
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo3)
# 查找目录下的所有源文件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)
# 添加 math 子目录
add_subdirectory(math)
# 指定生成目标
add_executable(Demo ${DIR_SRCS})
# 添加链接库
target_link_libraries(Demo MathFunctions)
使用命令add_subdirectory
指明项目包含一个子目录math,这样math目录下的CMakeList.txt 和源代码也会被处理。使用命令 target_link_librarys
指明可执行文件main需要链接一个名为MathFunctions的链接库。
add_subdirectory()
target_link_librarys()
add_library()
子目录中的CMakeLists.txt
# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_LIB_SRCS 变量
aux_source_directory(. DIR_LIB_SRCS)
# 指定生成 MathFunctions 链接库
add_library (MathFunctions ${DIR_LIB_SRCS})
使用命令add_library
将src目录中的源文件编译为静态链接库
。
5.示例四:通过CMake自定义编译选项
CMake允许为项目增加编译选项,从而根据用户的环境和需求选择最合适的编译方案。
例如,可以把MathFunctions库设为一个可选的库,如果该选项为ON,就是用该库的数学函数来进行计算,否则就调用标准库中的数学函数库。
- 工程目录如下
./Demo4
|
+--main.cpp
|
+--config.h.in
|
+--CMakeLists.txt
|
+--math/
|
+--MathFunctions.cpp
|
+--MathFunctions.h
|
+--CMakeLists.txt
①修改根目录下的CMakeLists.txt
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo4)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# 是否使用自己的 MathFunctions 库
option (USE_MYMATH
"Use provided math implementation" ON)
# 加入一个配置头文件,用于处理 CMake 对源码的设置
configure_file (
"${PROJECT_SOURCE_DIR}/config.h.in"
"${PROJECT_BINARY_DIR}/config.h"
)
# 是否加入 MathFunctions 库
if (USE_MYMATH)
include_directories ("${PROJECT_SOURCE_DIR}/math")
add_subdirectory (math)
set (EXTRA_LIBS ${EXTRA_LIBS} MathFunction)
endif (USE_MYMATH)
# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)
# 指定生成目标
add_executable (Demo ${DIR_SRCS})
target_link_libraries (Demo ${EXTRA_LIBS})
- 其中
configure_file
命令用于加入一个配置文件config.h,这个文件由CMake从config.h.in生成,通过这样的机制,可以通过预定义一些参数和变量来控制代码的生成 -
option
命令添加了一个USE_MYMATH选项,并且默认值是ON -
if (USE_MYMATH)
根据USE_MYMATH变量的值决定是否使用math目录下的MathFunctions库 - option选项必须放置在coufibure_file 前,否则会按照没有定义USE_MYMATH来生成config.h
configure_file()
configure_file(<input> <output>
[COPYONLY] [ESCAPE_QUOTES] [@ONLY]
[NEWLINE_STYLE [UNIX|DOS|WIN32|LF|CRLF] ])
复制一份输入文件到输出文件,替换输入文件中被@VAR@或者${VAR}引用的变量值。
configure_file的其他选项:
COPYONLY:只拷贝文件,不进行任何的变量替换。这个选项在指定了NEWLINE_STYLE选项时不能使用(无效)。
ESCAPE_QUOTES:躲过任何的反斜杠(C风格)转义。
@ONLY:限制变量替换,让其只替换被@VAR@引用的变量(那么 ${VAR}格式
的变量将不会被替换)。这在配置${VAR}语法的脚本时是非常有用的。
NEWLINE_STYLE style:指定输出文件中的新行格式。UNIX和LF的新行是\n,DOS和WIN32和CRLF的新行格式是\r\n。这个选项在指定了COPYONLY选项时不能使用(无效)。
通常情况下,输入文件以.h.in为后缀,输出文件以.h为后缀。
eg.
configure_file(src/translations.qrc ${CMAKE_CURRENT_BINARY_DIR} COPYONLY) # f=复制src文件夹下的translations.qrc文件到编译的目录下
修改main.cpp文件
让其根据USE_MYMATH的预定义值来决定调用标准库还是MathFunctions库
#include <stdio.h>
#include <stdlib.h>
#include <config.h>
#ifdef USE_MYMATH
#include <MathFunctions.h>
#else
#include <math.h>
#endif
int main(int argc, char *argv[])
{
if (argc < 3){
printf("Usage: %s base exponent \n", argv[0]);
return 1;
}
double base = atof(argv[1]);
int exponent = atoi(argv[2]);
#ifdef USE_MYMATH
printf("Now we use our own Math library. \n");
double result = power(base, exponent);
#else
printf("Now we use the standard library. \n");
double result = pow(base, exponent);
#endif
printf("%g ^ %d is %g\n", base, exponent, result);
return 0;
}
上面的程序引用了一个config.h
,config.h控制是否定义了USE_MYMATH
config.h由config.h.in生成。
config.h.in
#cmakedefine USE_MYMATH
我们要做的第一步是在顶层的CMakeLists.txt文件中添加该选项
CMake会自动根据CMakeLists配置文件中的设置生产config.h文件。
使用CMake进行编译即可得到使用MYMATH的编译版本,修改CMakeLists.txt中的USE_MYMATH为OFF即可使用库函数中的函数。
测试如下:
①CMakeLists.txt中的USE_MYMATH为ON
使用cmake .后生成的config.h
运行结果:
①CMakeLists.txt中的USE_MYMATH为OFF
使用cmake .后生成的config.h
运行结果:
6.示例五:CMake指定安装规则
CMake也可以指定安装规则,可以通过在产生Makefile后使用make install
。
首先在math/CMakeLists.txt的结尾添加下面两行:
# 指定 MathFunctions库的安装路径
install (TARGETS MathFunctions DESTINATION bin)
install (FILES MathFunctions.h DESTINATION include)
上面的代码指明了MathFunctions库的安装路径,之后修改根目录的CMakeLists文件,在末尾添加下面几行:
# 指定安装路径
install (TARGETS Demo DESTINATION bin)
install (FILES "${PROJECT_BINARY_DIR}/config.h"
DESTINATION include)
通过上面的设置,生成的Demo文件和MathFunctions函数库。libMathFunctions.o将会被复制到/usr/local/bin中,而MathFunctions.h和生成的config.h文件将会被复制到/usr/local/include中。
PS:这里需要加权限sudo进行make install,否则会失败
cmake .
sudo make install
这里的/usr/local是默认安装目录,可以通过修改CMAKE_INSTALL_PREFIX变量的值来制定安装目录。
7.支持gdb
8.添加环境检查
9.添加版本号
10.生成安装包
11.导入第三方库
在CMake中导入第三方库可以通过include_directories
和link_directories
设置第三方库的路径,然后使用target_link_libraries
进行链接。
12.链接本地库文件
官方推荐使用find_library
获得库绝对目录然后接target_link_libraries
。
find_library(VI_LIB vi ./vi/lib)
target_link_libraries(${PROJECT_NAME} ${VI_LIB})
13.
14.CMake 复制文件方法
http://t.zoukankan.com/JoyPoint-p-11629521.html
FILE-COPY
ADD_CUSTOM_COMMAND
ADD_CUSTOM_TARGET
15.关于CPack打包
https://blog.csdn.net/lqzer/article/details/125238748
16.关于install的用法
install用于指定在安装时运行的规则。它可以用来安装很多内容,可以包括目标二进制、动态库、静态库以及文件、目录、脚本等。
https://blog.csdn.net/qq_38410730/article/details/102837401
# 1.安装的文件夹
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/biz_sdk/lib/linux_lib/ DESTINATION lib)
# 2.安装的文件
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/config.json DESTINATION ./)
# 3.安装的动态链接库(库的软链接也会拷贝过去)
install(FILES ${PROJECT_SOURCE_DIR}/lib/libFormatConversion.so DESTINATION lib)
17.set_target_properties
set_target_properties(
Thirdlib
PROPERTIES IMPORTED_LOCATION
${CMAKE_CURRENT_SOURCE_DIR}/jniLibs/libThirdlib.so
)
# 举例
set_target_properties(
MVS
PROPERTIES IMPORTED_LOCATION
${MVS_SOURCE_DIR}/lib/64/libMvCameraControl.so
)
18.set_property
https://blog.csdn.net/sinat_31608641/article/details/123834265
在指定域中设置一个命名属性
set_property(<GLOBAL |
DIRECTORY [dir] |
TARGET [target1 [target2 ...]] |
SOURCE [src1 [src2 ...]] |
TEST [test1 [test2 ...]] |
CACHE [entry1 [entry2 ...]]>
[APPEND][APPEND_STRING]
PROPERTY <name>[value1 [value2 ...]])
在某个域中对零个或多个对象设置一个属性。第一个参数决定该属性设置所在的域。它必须为下面中的其中之一:
GLOBAL域是唯一的,并且不接特殊的任何名字。
DIRECTORY域默认为当前目录,但也可以用全路径或相对路径指定其他的目录(前提是该目录已经被CMake处理)。
TARGET域可命名零或多个已经存在的目标。
SOURCE域可命名零或多个源文件。注意:源文件属性只对在相同目录下的目标是可见的(CMakeLists.txt)。
TEST域可命名零或多个已存在的测试。
CACHE域必须命名零或多个已存在条目的cache.
必选项PROPERTY后面紧跟着要设置的属性的名字。其他的参数用于构建以分号隔开的列表形式的属性值。如果指定了APPEND选项,则指定的列表将会追加到任何已存在的属性值当中。如果指定了APPEND_STRING选项,则会将值作为字符串追加到任何已存在的属性值。
举例:
set_property(TARGET hikcamera_client PROPERTY POSITION_INDEPENDENT_CODE ON)
其中POSITION_INDEPENDENT_CODE ON
表示编译成动态库。
19.CMAKE_PREFIX_PATH
https://www.cnblogs.com/Fitanium/p/16181605.html文章来源:https://www.toymoban.com/news/detail-600217.html
20.GLOB和GLOB_RECURSE
file
的一个作用是生成目录列表。文章来源地址https://www.toymoban.com/news/detail-600217.html
// 添加当前目录下的所有c文件列表到lib_srcs变量中
file(GLOB lib_srcs *.c)
// 添加当前目录及其子目录下的所有c文件列表到lib_srcs变量中
file(GLOB_RECURSE lib_srcs *.c)
到了这里,关于Cmake笔记记录的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!