Administrator
Published on 2024-03-24 / 19 Visits
0
0

CMake基本用法

基本写法示例

环境准备

编译在centos7下,需要先安装相关软件:

yum -y install gcc gcc-c++ automake autoconf libtool make

编写文件

/demo/CMakeLists.txt

# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)

# 项目信息
project (Demo1)

# 指定生成目标
add_executable(Demo main.cc)

/demo/main.cc

#include <stdio.h>
#include <stdlib.h>

double multiplication(double one, double two)
{
    return one*two;
}

int main(int argc, char *argv[])
{
    double one = atof(argv[1]);
    double two = atof(argv[2]);
    double result = multiplication(one, two);
    printf("%g * %g is %g\n", one, two, result);
    return 0;
}

生成

/demo目录下执行:

cmake .

会生成Makefile,CMakeCache.txt,cmake_install.cmake,CMakeFiles,其中Makefile就可以用来构建可执行文件。

由于cmake并没有clean类似的操作,为了避免临时文件和代码混在一起,我们可以在当前目录创建build目录,然后/demo/build执行:

cmake ..

cmake . 命令的详细作用:
扫描源代码:CMake 会扫描当前目录下的源代码文件、目录结构和包含的库依赖关系。
生成配置:CMake 根据扫描结果生成一个名为 CMakeCache.txt(或 CMakeCache.cmake)的缓存文件。这个文件包含了所有检测到的配置信息,如编译器路径、库依赖、生成器类型等。
生成构建系统:CMake 会根据 CMakeLists.txt 文件中的指令和缓存文件中的配置信息,生成适用于当前系统的构建系统。这可能包括 Makefile、Visual Studio 解决方案、Xcode 项目文件等。
确定依赖关系:CMake 会检测项目依赖的库,并尝试找到可用的版本。如果依赖的库不在系统中,CMake 会报错,并要求用户指定库的路径。
设置构建目录:CMake 默认会在当前目录下创建一个名为 build 的子目录,用于存放构建过程中的文件和生成的目标文件。用户也可以通过 -B 选项指定一个不同的构建目录。
启动构建:配置完成后,CMake 通常会提示用户运行构建工具(如 make)来编译和链接项目。如果没有指定生成器,CMake 通常会使用默认的生成器,如 Unix Makefiles。

/demo目录在执行:

make

就可以生成可执行文件Demo,我们可以测试,会输出对应结果:

./Demo 2 2

CMake语法

说明

  • 编写 CMakeLists.txt 文件时使用的语法称为CMake 语法(CMake syntax)或CMake 脚本语言(CMake scripting language)。
  • CMake 语法用于编写 CMakeLists.txt 文件,指导 CMake 如何为项目生成构建系统。
  • CMake 脚本语言包括指令、变量、函数、宏、控制结构等,用于组织和控制项目的构建过程。

基本语法

注释

# 这是一个注释

打印

message("hello world!")

变量

# 设置
set(VARIABLE_NAME hello)
message("使用: ${VARIABLE_NAME}")

# 清空
set(VARIABLE_NAME)
或
unset(VARIABLE_NAME)

上面的称为一般变量,此外还有缓存变量,环境变量,对应的设置和清空方式也不大一样。
清空后的如果再使用(比如message),将整行不会打印。

include_directories

include_directories ("${PROJECT_SOURCE_DIR}/math")
  • 可以将对应的路径应用到当前环境下,c文件在调用时,就可以不指明具体路径。
  • 比如a.c文件同级别有目录math/MathFunctions.h,a.c正常引用头文件需要#include "math/MathFunctions.h",而写了include_directories ("${PROJECT_SOURCE_DIR}/math")则只需要#include "MathFunctions.h"。
  • 可参考:https://blog.csdn.net/sinat_31608641/article/details/121666564

configure_file

configure_file (
  "${PROJECT_SOURCE_DIR}/config.h.in"
  "${PROJECT_BINARY_DIR}/config.h"
  )
  • cmake 中的 configure_file 指令通过读取输入文件中的内容,将 CMakeLists.txt 文件中的变量转变为 C/C++ 中可识别的宏定义,然后存入另一个文件中。
  • 让普通文件,也能使用CMake中的变量,比如CMakeLists.txt中定义set(BUILD_Version 1)
    输入文件中内容为:#define BUILD_Version @BUILD_Version@
    输出文件中就会被转化为:#define BUILD_Version 1
    然后c文件可以使用此h文件进行判断。
    通常情况下,输入文件以.h.in为后缀,输出文件以.h为后缀。
  • 参考:
    https://blog.csdn.net/qq_38410730/article/details/103741579
    https://zhuanlan.zhihu.com/p/436923370

option

option (USE_MYMATH "Use provided math implementation" ON)
  • 定义选项USE_MYMATH,只有ON/OFF,然后在CMakeFiles可以进行条件判断:
if (USE_MYMATH)
 ...
endif (USE_MYMATH)
  • 该定义的值并不能在c代码中读取,为了实现该功能,我们可以配合configure_file,生成一个头文件:
configure_file (
  "${PROJECT_SOURCE_DIR}/config.h.in"
  "${PROJECT_BINARY_DIR}/config.h"
  )

config.h.in内容为:#cmakedefine USE_MYMATH,即如果CMakeFiles没有定义USE_MYMATH(option设置,on代表定义,off代表没定义),则生成的config.h则没有#define USE_MYMATH,我们的c文件就可以进行#ifdef USE_MYMATH进行存在/不存在的判断了。
奇怪的是第一次cmake肯定为config.h没有#define USE_MYMATH,第二次才有,即使option的时候为ON;
使用set(BUILD_Version 1)的方式则正常。

在cmake时,我可以改用ccmake .来运行交互式的界面进行配置的设置,ccmake主要帮助用户设置和调整 CMake 构建系统的参数。

第一次ccmake显示EMPTY CACHE,得执行过cmake命令后,才显示出配置选项,原因是:这通常意味着 CMake 缓存(.cmake 文件)尚未被创建或初始化。缓存文件用于存储 CMake 运行时的配置信息,如编译器路径、生成器类型、依赖项等。在第一次运行 ccmake 之前,如果没有通过 cmake 命令扫描源代码目录并生成缓存,那么 ccmake 就不会显示任何配置选项,因为它们还没有被定义。这就是为什么你需要在运行 ccmake 之前先运行 cmake 命令的原因。


Comment