Cmake笔记记录

工作后开发内容都是在Linux系统下完成,cmake使用比较频繁,找到一篇很不错的CMake笔记。
记录下来方便自己查阅。

目录

  • 1.CMake介绍
  • 2.示例一:编译单个文件
    • CMAKE_BUILD_TYPE
  • 3.示例二:编译同个目录下多个文件
    • aux_source_directory()
  • 4.示例三:编译多个目录下多个文件
    • add_subdirectory()
    • target_link_librarys()
    • add_library()
  • 5.示例四:通过CMake自定义编译选项
    • configure_file()
  • 6.示例五:CMake指定安装规则
  • 7.支持gdb
  • 8.添加环境检查
  • 9.添加版本号
  • 10.生成安装包
  • 11.导入第三方库
  • 12.链接本地库文件
  • 13.
  • 14.CMake 复制文件方法
    • FILE-COPY
    • ADD_CUSTOM_COMMAND
    • ADD_CUSTOM_TARGET
  • 15.关于CPack打包
  • 16.关于install的用法
  • 17.set_target_properties
  • 18.set_property
  • 19.CMAKE_PREFIX_PATH
  • 20.GLOB和GLOB_RECURSE

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 
#include 

/**
 * 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,生成可执行文件。
Cmake笔记记录_第1张图片

  • 运行可执行文件
    在这里插入图片描述
  • 指定DEBUG模式
    也可以在CMakeLists.txt文件中添加以下代码来指定DEBUG模式.
set(CMAKE_BUILD_TYPE Debug)

①修改CMakeLists.txt文件
Cmake笔记记录_第2张图片
②终端执行make clean
③将CMakeCache.txt文件删除,重新进行cmake .
Cmake笔记记录_第3张图片

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

Cmake笔记记录_第4张图片
main.cpp

#include 
#include 
#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

Cmake笔记记录_第5张图片
①修改根目录下的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 
#include 
#include 

#ifdef USE_MYMATH
  #include 
#else
  #include 
#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
Cmake笔记记录_第6张图片
运行结果:
Cmake笔记记录_第7张图片
CMakeLists.txt中的USE_MYMATH为OFF
在这里插入图片描述
使用cmake .后生成的config.h
Cmake笔记记录_第8张图片
运行结果:
Cmake笔记记录_第9张图片

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笔记记录_第10张图片
cmake .
sudo make install
Cmake笔记记录_第11张图片

这里的/usr/local是默认安装目录,可以通过修改CMAKE_INSTALL_PREFIX变量的值来制定安装目录。

7.支持gdb

8.添加环境检查

9.添加版本号

10.生成安装包

11.导入第三方库

在CMake中导入第三方库可以通过include_directorieslink_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

20.GLOB和GLOB_RECURSE

file的一个作用是生成目录列表。

// 添加当前目录下的所有c文件列表到lib_srcs变量中
file(GLOB lib_srcs *.c)

// 添加当前目录及其子目录下的所有c文件列表到lib_srcs变量中
file(GLOB_RECURSE lib_srcs *.c)

你可能感兴趣的:(C++,Linux,cmake)