CMake 实战

ops/2024/11/14 13:05:59/

我现在项目的目录结构如下
project_root/
├── CMakeLists.txt
├── main.cpp 主函数
├── third_part/
│ ├── CMakeLists.txt # 总的 third_part CMakeLists.txt
│ ├── json/
│ │ ├── CMakeLists.txt # json 的 CMakeLists.txt
│ │ └── json.hpp
│ ├── spdlog/
│ │ ├── CMakeLists.txt # spdlog 的 CMakeLists.txt
│ │ ├── include/
│ │ │ └── spdlog/ # spdlog 的头文件
│ │ └── libspdlog.a # spdlog 静态库
│ ├── httplib/
│ │ ├── CMakeLists.txt # httplib 的 CMakeLists.txt
│ │ ├── httplib.cpp
│ │ └── httplib.h
│ └── inireader/
│ ├── CMakeLists.txt # INIReader 的 CMakeLists.txt
│ ├── ini.c
│ ├── ini.h
│ ├── INIReader.cpp
│ └── INIReader.h
├── basic/ # 业务基础代码
│ ├── CMakeLists.txt
│ ├── include/
│ ├── logic1.cpp
│ └── logicxxx.cpp

也即主函数,基础代码,第三方库。
第三方库有多种形式:
json :只有一个头文件
spdlog:有一个静态库和一个头文件目录
httplib:有一个头文件和源码文件
inireader:有两个头文件和两个源码文件

需要实现如下目标:

  1. 各个模块描述自己模块需要有哪些内容需要编译,哪些接口暴露出去。如果其他模块要使用本模块,只需用一行命令申明即可。编译时会自动链接这个模块,以及把模块的接口加入到头文件路径。
  2. third_part整个4个第三方库为一个库。其他模块只需要用一行命令导入third_part模块就能使用4个第三方库的功能。
    下面介绍各个目录下的CMakeLists.txt

CMakeLists

顶层

cmake_minimum_required(VERSION 3.10)  # cmake 版本最低为3.10
project(server)  # 设置工程名为serverset(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)  #把动态库放在build目录下的lib目录。
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)  #把静态库放在build目录下的lib目录
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)  #把可执行文件放在build目录下的bin目录# 设置 C++ 标准
set(CMAKE_CXX_STANDARD 11)   # 设置C++标准
add_compile_definitions(SPDLOG_COMPILED_LIB)  # 添加编译器宏定义,即g++ -DSPDLOG_COMPILED_LIB,这个是spdlog要求的,这个库是日志库,哪里都用得到,所以在全局添加这个宏定义。# 读 子目录 third_part 和basic
add_subdirectory(third_part)  #引入子目录third_part的内容
add_subdirectory(basic) #引入子目录basic的内容add_executable(server main.cpp)  # 编译可执行文件,源文件只有一个erver.cpp,可执行文件名为server# 指定链接的库
target_link_libraries(server basic third_part mysqlcppconn)  # 指明 可执行文件依赖的模块,有本工程的basic模块和third_part模块,还有系统提供的mysqlcppconn模块。这个就是目标2

顶层配置了整个项目的信息,所以看起来多,但其实去掉注释也不多。引用别的模块很简单,就一个target_link_libraries加模块名,就完成引用了。

third_part

add_subdirectory(json)
add_subdirectory(httplib)
add_subdirectory(INIReader)
add_subdirectory(spdlog)add_library(third_part INTERFACE)
target_link_libraries(third_part INTERFACE json httplib INIReader spdlog)

显示指出需要引入哪些子文件夹的内容。
然后申明本模块的名称,以及本模块整合了哪些模块。别的模块只需要target_link_librairies third_part模块就可以使用这些第三方库,无需操心头文件在哪里,这个第三方库以什么方式提供。
这个就是目标2的实现。

httplib

add_library(httplib STATIC httplib.cc)
target_include_directories(httplib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

httplib是本模块的模块名,这里和目录名同名,和目录名同名不是强制的。

STATIC 表示本模块将以一个静态库的形式呈现。对应的还有SHARED。以动态库形式呈现。
以及INTERFACE,以只头文件(header-only)形式呈现。

PUBLIC:当前模块和使用该模块的模块都会使用的头文件
对应的还有:
INTERFACE:当前模块不会使用的头文件
PRIVATE:只有当前模块会使用的头文件

申明本模块的名称,本模块涉及的源文件。以及本模块的头文件。PUBLIC意味着直接或者间接引用本模块的模块,都能找到本模块的头文件。
这个就是目标1的实现。他告诉了cmake本模块如何编译链接。以及本模块哪些内容是需要暴露给其他模块的。

INIReader

add_library(INIReader STATIC ini.c INIReader.cpp)
target_include_directories(INIReader PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

同httplib

Spdlog

这个模块是一个静态库,所以有不同

add_library(spdlog STATIC IMPORTED GLOBAL) # 申明为global才能被全局发现
set_target_properties(spdlog PROPERTIESIMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/libspdlog.a)  #指明静态库的位置
set_target_properties(spdlog PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}/include)  # 告诉外界这个静态库的头文件,让外界能够发现这个模块的头文件。

IMPORTED 告诉cmake这个库是从外部引入的,不需要生成任何规则来构建这个库。直接使用现成的。spdlog是那个被导入的库在本项目的别名。此后,在本项目中,都用这个别名指代那个外部导入的库。

GLOBAL 默认情况下,IMPORTED的库只能在当前目录以及子目录可见,GLOBAL可以拓展可见范围为全局。

json

add_library(json INTERFACE)
target_include_directories(json INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})

只有头文件,则用INTERFACE
INTERFACE:当前模块不会使用的头文件
PRIVATE:只有当前模块会使用的头文件
PUBLIC:当前模块和使用该模块的模块都会使用的头文件

basic

file(GLOB SOURCES "*.cpp")
add_library(basic STATIC ${SOURCES})
target_include_directories(basic PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_link_libraries(basic third_part)

basic下的所有.cpp文件都是需要编译的,第一条指令可以把当前目录下所有的.cpp文件列出来放到SOURCES变量中。
GLOB用于以列出符合指定模式的文件。
GLOB_RECURSE类似,但是他会列出子目录的。


http://www.ppmy.cn/ops/133291.html

相关文章

用 PHP或Python加密字符串,用iOS解密

可以使用对称加密算法(如 AES)来加密和解密字符串。对称加密适合这种跨平台加密解密的需求,因为可以使用相同的密钥和算法在不同的编程语言和系统之间进行加密和解密。 下面展示如何使用 Python 或 PHP 进行加密,然后用 iOS (Swi…

Unity学习笔记(2):场景绘制

文章目录 前言开发环境场景资源导入Unity2d 瓦片功能更改游戏视图缩放比例 叠层Tilemap如何分层 总结 前言 我也算是跨行学Unity。我希望学了这个东西能有用吧。对以后的工作的要求,时薪高。唉,先学着好了。不知道以后的行情是如何,但是上位…

探索LINQ在C#中的应用:从基本查询到数据联接

LINQ(语言集成查询)是微软为.NET框架开发的一种强大功能,于2007年作为C# 3.0和Visual Basic .NET 9.0的一部分引入。LINQ的诞生旨在提供一种一致且直观的方式来查询和操作数据,无论数据来源是内存中的集合、数据库还是XML文档。 …

【测试框架篇】单元测试框架pytest(1):环境安装和配置

一、pytest简介 Pytest是Python的一种单元测试框架,与Python自带的unittest测试框架类似,但是比 unittest框架使用起来更简洁,效率更高。 二、pytest特点 Pytest是一个非常成熟的Python测试框架,主要特点有以下几点: 非常容易…

DAY59||并查集理论基础 |寻找存在的路径

并查集理论基础 并查集主要有两个功能&#xff1a; 将两个元素添加到一个集合中。判断两个元素在不在同一个集合 代码模板 int n 1005; // n根据题目中节点数量而定&#xff0c;一般比节点数量大一点就好 vector<int> father vector<int> (n, 0); // C里的一…

C++开发基础之使用librabbitmq库实现RabbitMQ消息队列通信

1. 前言 RabbitMQ是一个流行的开源消息队列系统&#xff0c;支持多种消息协议&#xff0c;广泛用于构建分布式系统和微服务架构。可以在不同应用程序之间实现异步消息传递。在本文中&#xff0c;我们将熟悉如何使用C与RabbitMQ进行消息通信。 2. 准备工作 在 Windows 平台上…

docker构建jdk11

# 建立一个新的镜像文件&#xff0c;配置模板&#xff1a;新建立的镜像是以centos为基础模板 # 因为jdk必须运行在操作系统之上 FROM centos:7.9.2009# 作者名 MAINTAINER yuanhang# 创建一个新目录来存储jdk文件 RUN mkdir /usr/local/java#将jdk压缩文件复制到镜像中&#…

LinkedList和单双链表。

java中提供了双向链表的动态数据结构 --- LinkedList&#xff0c;它同时也实现了List接口&#xff0c;可以当作普通的列表来使用。也可以自定义实现链表。 单向链表&#xff1a;一个节点本节点数据下个节点地址 给定两个有序链表的头指针head1和head2&#xff0c;打印两个链表…