当前位置: 首页 > news >正文

CMake

CMake

我们先建立几个文件:

//head.h
#pragma once

int add(int val1, int val2);

int sub(int val1, int val2);
//add.cpp
#include "head.h"

int add(int val1, int val2)
{
    return val1 + val2;
}
//sub.cpp
#include "head.h"

int sub(int val1, int val2)
{
    return val1 - val2;
}
//main.cpp
#include <iostream>
#include "head.h"

int main()
{
    std::cout << add(10, 20) << std::endl;
    std::cout << sub(20, 10) << std::endl;
    return 0;
}

那么,我们怎么用cmake呢?

首先,先创建一个名叫CMakeLists.txt的文件,再在里面添加如下内容:

cmake_minimum_required(VERSION 3.23)
project(test)
add_executable(main main.cpp add.cpp sub.cpp)

这样一个最基本的cmake文件就写好了。

下面来解释一下这3个命令分别是啥意思:

1、cmake_minimum_required(VERSION 3.23):这个命令就是指定使用cmake的最低版本。

2、project(test):定义工程名称,还可以有其他选项,这些选项是可选的。

3、add_executable(main main.cpp add.cpp sub.cpp):生成一个可执行程序,这个命令里面的格式为:第一个参数是生成的可执行文件名,后面跟着生成这个可执行文件所需要的文件,每个文件之间可以用空格分隔也可以使用分号分隔。

add_executable(main main.cpp add.cpp sub.cpp)如果觉得这么写太麻烦了还有另一种方式:

cmake支持变量:

set(SRC_LIST main.cpp add.cpp sub.cpp):这条指令相当于将这些.cpp文件赋值给名叫SRC_LIST的变量。

add_executable(main ${SRC_LIST}):使用上面这个变量

指定C++标准

有两种方式。

一、在CMakeLists.txt文件中通过set指定标准:

set(CMAKE_CXX_STANDARD 11)

二、在cmake命令后带上参数:-DCMAKE_CXX_STANDARD=11

指定输出路径

在cmake中指定可执行程序输出的路径:

set(HOME /home/ubuntu/test-cmake)
set(EXECUTABLE_OUTPUT_PATH ${HOME})

推荐使用绝对路径,如果该路径的子目录不存在,CMake会帮我们自动生成,无需自己手动创建。

使用cmake编译项目

格式:cmake [options] <path-to-source>

cmake . # CMakeLists.txt 文件所在路径
make

如果CMakeLists.txt在/home/xxx/code/C/目录下,而你当前所在的目录是/home/xxx/code/C/aa,则使用cmake ..make

需要注意的是,如果CMakeLists.txt所在的路径如果存在CMakeCache.txt CMakeFiles cmake_install.cmake Makefile这些文件,cmake ..命令是不会重新生成的,

搜索文件

两种方式:

1、aux_source_directory(${PROJECT_SOURCE_DIR} SRC)

其中,PROJECT_SOURCE_DIR是一个宏,它就是cmake命令后跟的路径,也就是CMakeLists.txt所在的路径,而SRC是一个变量,这个函数相当于把CMakeLists.txt所在路径中所有的文件赋值给SRC变量。

2、file(GLOB SRC ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)

这个函数和aux_source_directory函数是一样的,只不过参数不同,这个函数第一个参数是是否对路径进行递归搜索,如果不递归搜索,那就GLOB,如果选择递归就GLOB_RECURSE,第二个参数是搜索到的文件存储到哪,这里就是存储到SRC变量中,第三个参数就是要搜索的文件路径以及文件类型,CMAKE_CURRENT_SOURCE_DIR是一个宏,它和PROJECT_SOURCE_DIR是一样的,都是CMakeLists.txt所在的路径,后面是文件类型,该例子中是搜索CMakeLists.txt所在的路径中所有.cpp为后缀的文件。

指定头文件路径

假设现在有这么一种场景,我创建了两个目录,一个include目录,存放头文件的,另一个目录src存放源文件的,文件还是最上面那4个文件:head.h add.cpp sub.cpp main.cpp,而我的CMakeLists.txt文件是这样的:

cmake_minimum_required(VERSION 3.31)
project(test)
# set(SRC_LISTS main.cpp add.cpp sub.cpp)
# aux_source_directory(${PROJECT_SOURCE_DIR} SRC)
file(GLOB  SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
set(CMAKE_CXX_STANDARD 11)
set(EXECUTABLE_OUTPUT_PATH /home/zqq/code/C/CMake_test/aa/bb)
add_executable(main ${SRC})

我执行cmake命令之后,再执行make发现报错了,说是找不到头文件,这个很简单,直接在源文件中修改包含头文件的路径就可以了,但是,如果源文件有很多呢,难道也是一个一个改吗,cmake提供了一个函数可以帮助我们指定头文件的路径:include_directories(${PROJECT_SOURCE_DIR}/include),这个函数里面的参数就不需要过多解释了,就是存放头文件的目录。

制作库文件

add_library(cale STATIC ${SRC})

首先先补充下前提知识:在windows中,静态库文件后缀是.lib,动态库后缀是.dll,而在Linux中,静态库文件格式为libXXX.a,动态库文件格式为libXXX.so

在上面这个函数中,第一个参数是去掉前缀后缀的库文件名称,比如上面的例子中,在Linux环境下生成的库文件是libcale.a,为什么是.a呢,那时因为后面这个参数,第二个参数取决于你想生成的是静态库还是动态库,静态库为STATIC,动态库则为SHARED,第三个参数就是生成的库文件所需要的文件,这个SRC变量就是上面指定头文件路径中CMakeLists.txt里面的SRC变量。

指定库文件输出路径

我们可以通过set函数设置LIBRARY_OUTPUT_PATH为指定生成的路径,这个宏对应的就是库文件生成路径,如果是生成动态库还可以使用EXECUTABLE_OUTPUT_PATH这个宏,因为动态库有可执行权限,但是还是不建议使用这个宏,因为不明确生成的到底是可执行程序还是动态库文件。

举例:

set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib) # 如果后面路径不存在则会自动创建。

如果不指定生成的路径,那它就会默认生成到当前构建目录。

链接静态库文件

link_libraries(cale),这个函数里面的参数可以是静态库文件的全称,即libXXX.a,也可以是去掉前缀后缀之后的文件名。

如果这个静态库文件不在当前目录,还需要指定静态库文件所在的目录,用到的函数:link_directories(${PROJECT_SOURCE_DIR}/lib),里面的参数就是静态库文件所在路径。

链接动态库文件

target_link_libraries(main cale),第一个参数是指定要加载的库的名字,当然也不是说只能是库文件,也可以是可执行文件或者源文件,第二个参数是public,其实在第一个参数后面跟着的参数格式是:[public/private/interface] [file],默认是[public],所以没写,后面跟着编译时要用到的库文件,我这个例子中main在编译时需要链接libcale.so或者libcale.a库。

下面是关于public/private/interfac分别代表什么意思:

target_link_libraries(a b c)

以下这个属性添加在b、c前面

public:代表如果有一个库d依赖a,那么d能访问到b、c

private:代表如果有一个库d依赖a,那么d不能访问到b、c

interfaceb、c不会被链接到a中,只会导出符号。

在cmake中打印日志信息

用到的函数是message(),里面有两个参数,第一个是日志等级,如果不写默认最高等级,还有其他等级:

STATUS:非重要信息。

WARNING:CMake警告,会继续执行。

AUTHOR_WARNING:CMake警告(dev),会继续执行。

SEND_ERROR:CMake错误,但是会继续执行,但是会跳过生成的步骤。

FATAL_ERROR:CMake错误,终止所有处理过程。

字符串相关操作

1、追加list(APPEND SRC hello world),往SRC变量中追加helloworld字符串。

2、移除list(REMOVE_ITEM SRC ${PROJECT_SOURCE_DIR}/src/add.cpp),在SRC中移除${PROJECT_SOURCE_DIR}/src/add.cpp)文件,注意,这里的移除需要绝对路径,单独一个文件名是不行的。

(其他字符串操作我就不赘述了,偷了点懒)。

自定义宏

//test.cpp
#include <iostream>
#define NUMBER 3

int main()
{
#ifdef DEBUG
    std::cout << "这是一条调试信息" << std::endl;
#endif
    for (int i = 0; i < NUMBER; ++i)
    {
        std::cout << "hello world" << std::endl;
    }
    return 0;
}
# CMakeLists.txt
cmake_minimum_required(VERSION 3.23)
project(test)
add_executable(test test.cpp)

执行cmakemake命令后,执行可执行程序,得到的结果是3行hello world,这个当然毋庸置疑,想要输出这是一条调试信息也很简单,直接在源文件中添加宏就可以了,但是如果源文件很多呢,一个一个添加太麻烦,我们可以直接在CMakeLists.txt中操作:

# 添加宏
add_definitions(-DDEBUG)

函数里面的参数首先前面需要加上-D之后跟着宏,中间不需要空格。

嵌套的CMake

在一个目录中有一个CMakeLists.txt,还有一个目录,这个目录里面又有一个CMakeLists.txt文件,嵌套使用的函数:add_subdirectory(),里面参数是子目录名称。

相关文章:

  • 多线程与并发编程 面试专题
  • SQLAlchemy系列教程:批量插入数据
  • React Vue 项开发中组件封装原则及注意事项
  • 几个金融衍生产品:
  • 浙江大学第四讲:DeepSeek模型优势:算力、成本角度解读(含PPT及直播回放)(文末附链接下载)
  • 【时时三省】(C语言基础)输入输出的概念
  • 【原创】MCP服务介绍使用MCP实现类Manus Agent
  • SpaceSense Systems 借助桂花网解决方案实现工业设备预测性维护与状态监测升级
  • Docker基础命令说明
  • 算法刷题整理合集(一)
  • 人工智能-周志华ML版|系列习题参考答案与综合测试目录
  • c# 查找相似颜色算法
  • 个人学习编程(3-13) 刷题2
  • 深度学习环境配置指令大全
  • MAE:Masked Autoencoders Are Scalable Vision Learners——论文学习
  • 深度学习 bert与Transformer的区别联系
  • 手绘板工具:基于python以及pyqt5实现的手绘白板
  • 基于Redis+AOP+Lua脚本实现一个服务器限流机制
  • 【RTSP】客户端(二):SDP解析
  • MySQL再次基础 向初级工程师迈进
  • 网站关键字及说明/厦门人才网唯一官网
  • 莆田网站建设创意/政府免费培训面点班
  • 微信做淘宝优惠券但网站是怎么建设但/一站式网络推广服务
  • 网站建设用苹果系统与liunx/网站优化外包找谁
  • 长春网站优化公司/最热门的短期培训课程
  • 已有网站做百度推广/优化王