CMake 实战

我现在项目的目录结构如下
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)  # 设置工程名为server

set(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 PROPERTIES
                        IMPORTED_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类似,但是他会列出子目录的。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值