Cmake基础知识及项目构建

目录

1.Cmake简介

2.Cmake指令的使用

2.1CMakeLists.txt

2.2cmake命令和make命令

2.3Cmake项目的基本结构

2.4set指令

2.5cmake中的宏定义

2.6搜索文件

2.6.1aux_source_directory命令

2.6.2file命令

2.7包含头文件

2.8制作静态库或动态库

2.8.1制作静态库

2.8.2制作动态库

2.8.3指定输出路径

2.9包含库文件

2.9.1链接静态库

2.9.2链接动态库

3.嵌套的Cmake

3.1目录结构

3.2节点关系

3.3添加子目录

3.4问题分析及解决

3.4.1根目录

3.4.2calc目录

3.4.3sort目录

3.4.4test1目录

3.4.5test2目录

3.5完结撒花

4.参考内容链接


1.Cmake简介

Cmake是一个跨平台的项目构建工具,能够自动化生成本地化的Makefile和工程文件,最后通过make编译即可,因此可以将Cmake看成是一款自动生成Makefile的工具。

图1-1 编译流程

图1-1中表示使用不同方式构建项目的流程:

  • 蓝色虚线表示使用makefile构建项目的过程
  • 红色实线表示使用cmake构建项目的过程

CMake的优点:

  • 跨平台
  • 能够管理大型项目
  • 简化编译构建过程和编译过程
  • 可扩展:可以为 cmake 编写特定功能的模块,扩充 cmake 功能

2.Cmake指令的使用

2.1CMakeLists.txt

#指定使用cmake的最低版本
cmake_minimum_required(VERSION 3.0)
#指定工程的名称
project(CALC)
#生成可执行程序,基本语法为add_executable(可执行程序名 源文件名称)
add_executable(app add.c div.c main.c mult.c sub.c)

2.2cmake命令和make命令

若将CMakeLists、源文件、头文件放在同一目录下,其结构如下:

├── add.c
├── CMakeLists.txt
├── div.c
├── head.h
├── main.c
├── mult.c
└── sub.c

在当前路径下执行cmake命令后,目录中生成了一些新文件,如下所示:

├── add.c
├── CMakeCache.txt         # new add file
├── CMakeFiles             # new add dir
├── cmake_install.cmake    # new add file
├── CMakeLists.txt
├── div.c
├── head.h
├── main.c
├── Makefile               # new add file
├── mult.c
└── sub.c

可以看到新生成的文件中包含有一个makefile文件,若此时执行make命令,则可生成所需的可执行程序,如下所示:

├── add.c
├── app					# 生成的可执行程序
├── CMakeCache.txt
├── CMakeFiles
├── cmake_install.cmake
├── CMakeLists.txt
├── div.c
├── head.h
├── main.c
├── Makefile
├── mult.c
└── sub.c

2.3Cmake项目的基本结构

从2.2节可以看到通过cmake 命令make命令生成了makefile文件以及可执行程序,它们和CMakeLists.txt、源文件、头文件都放在了一起,如果项目较大就会显得过于混乱,因此为了便于管理和维护,将上述文件放入对应的目录下。

├── bin               # 执行make命令后,生成的可执行程序的存放路径
│   ├── app           # 可执行程序
├── build             # cmake执行目录,存放执行cmake命令后生成的makefile等文件
│   ├── CMakeCache.txt
│   ├── CMakeFiles
│   ├── cmake_install.cmake
│   └── Makefile
├── CMakeLists.txt    # 注意C、M、L为大写,Lists的s不要漏写
├── include           # 头文件目录
│   └── head.h        # 头文件
└── src               # 源文件目录
    ├── add.cpp       # 源文件
    ├── div.cpp       # 源文件
    ├── mult.cpp      # 源文件
    ├── sub.cpp       # 源文件
    └── main.cpp      # 用于测试的源文件

2.4set指令

在2.1节CMakeLists.txt中生成可执行文件时有5个源文件

add_executable(app add.c div.c main.c mult.c sub.c)

可通过set指令将这5个源文件赋予一个变量

# SET指令基本语法SET(VAR [VALUE]
# VAR:变量名
# VALUE:变量值
set(SRC_LIST add.c div.c main.c mult.c sub.c)
add_executable(app  ${SRC_LIST})

2.5cmake中的宏定义

EXECUTABLE_OUTPUT_PATH:可执行程序存放位置,放在bin文件夹中

PROJECT_SOURCE_DIR:一般是工程的根目录

CMAKE_CURRENT_SOURCE_DIR:当前处理的CMakeLists.txt所在的路径

2.6搜索文件

2.6.1aux_source_directory命令

# 基本语法 aux_source_directory(< dir > < variable >)
# dir:要搜索的目录
# variable:从dir目录下搜索源文件列表存储到该变量中
# 搜索 src 目录下的源文件,存储到变量SRC_LIST中
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/src SRC_LIST)
# 生成可执行程序
add_executable(app  ${SRC_LIST})

2.6.2file命令

# 基本语法file(GLOB/GLOB_RECURSE 变量名 要搜索的文件路径和文件类型)
# 搜索头文件
file(GLOB MAIN_HEAD ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h)
# 搜索源文件
file(GLOB MAIN_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)

2.7包含头文件

为了在编译源文件的时候,能够找到与源文件对应的头文件,使得编译顺利通过,需要在CMakeLists.txt中设置包含头文件的目录。

# PROJECT_SOURCE_DIR对应的宏参照2.5节,一般为工程根目录
# include为头文件目录
include_directories(${PROJECT_SOURCE_DIR}/include)

2.8制作静态库或动态库

若我们编写的源文件不需要编译生成可执行程序,可以生成静态库或动态库供第三方使用,以下为制作这两种库文件的方法。

2.8.1制作静态库

# 基本语法add_library(库名称 STATIC 源文件1 [源文件2] ...) 
# 将SRC_LIST变量中所表示的源文件生成静态库文件
# STATIC表示静态库,SHARED表示动态库
add_library(calc STATIC ${SRC_LIST})

在Linux中,静态库名字分为三部分:lib+库名字+.a,此处只需要指定出库的名字就可以了,另外两部分在生成该文件的时候会自动填充。

因此add_library(calc STATIC ${SRC_LIST})生成的对应的静态库文件为libcalc.a

2.8.2制作动态库

# 基本语法add_library(库名称 SHARED 源文件1 [源文件2] ...) 
add_library(calc SHARED ${SRC_LIST})

在Linux中,动态库名字分为三部分:lib+库名字+.so,此处只需要指定出库的名字就可以了,另外两部分在生成该文件的时候会自动填充。

因此add_library(calc SHARED ${SRC_LIST})生成的对应的静态库文件为libcalc.so

2.8.3指定输出路径

使用LIBRARY_OUTPUT_PATH宏,指定库文件的生成路径

# 设置动态库/静态库生成路径
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
# 生成动态库(在lib目录下)
#add_library(calc SHARED ${SRC_LIST})
# 生成静态库(在lib目录下)
add_library(calc STATIC ${SRC_LIST})

2.9包含库文件

在编写程序过程中,会使用到库文件,下面对库文件的加载进行说明。

2.9.1链接静态库

若静态库不是系统提供的(自己制作或第三方提供的),可能会出现静态库找不到的情况,因此需指定静态库的路径。

# 包含静态库路径
link_directories(${PROJECT_SOURCE_DIR}/lib)
# 链接静态库
link_libraries(calc)
add_executable(app ${SRC_LIST})

2.9.2链接动态库

# 基本语法
target_link_libraries( <target> )
# <target>为指定要加载的库文件的名字
# 该文件可能是一个源文件、静态库/动态库文件或可执行文件

动态库的链接和静态库是完全不同的:

  • 静态库会在生成可执行程序的链接阶段被打包到可执行程序中,所以可执行程序启动,静态库就被加载到内存中了。
  • 动态库在生成可执行程序的链接阶段不会被打包到可执行程序中,当可执行程序被启动并且调用了动态库中的函数的时候,动态库才会被加载到内存

因此,在指定要链接的动态库的时候,应该将命令写到生成了可执行文件之后,如下所示:

# 添加并指定最终生成的可执行程序名
add_executable(app ${SRC_LIST})
# 指定可执行程序要链接的动态库名字(此处为pthread)
target_link_libraries(app pthread)

3.嵌套的Cmake

通过Cmake管理大型项目时,若只使用一个CMakeLists.txt,将会使这个文件变得非常复杂,因此为便于管理和维护,为每一个源码目录都添加一个CMakeLists.txt。

3.1目录结构

├── build
├── calc
│   ├── add.cpp
│   ├── CMakeLists.txt
│   ├── div.cpp
│   ├── mult.cpp
│   └── sub.cpp
├── CMakeLists.txt
├── include
│   ├── calc.h
│   └── sort.h
├── sort
│   ├── CMakeLists.txt
│   ├── insert.cpp
│   └── select.cpp
├── test1
│   ├── calc.cpp
│   └── CMakeLists.txt
└── test2
    ├── CMakeLists.txt
    └── sort.cpp
include目录头文件目录
calc目录包含计算相关的4个源文件,对应的头文件为include目录中的calc.h
sort目录包含排序相关的2个源文件,对应的头文件为include目录中的sort.h
test1目录测试目录,对计算相关的算法进行测试
test2目录测试目录,对排序相关的算法进行测试

3.2节点关系

嵌套的 CMake 是一个树状结构,最顶层的 CMakeLists.txt 是根节点,其次都是子节点。

CMakeLists.txt 文件变量作用域的一些信息:

  • 根节点CMakeLists.txt中的变量全局有效
  • 父节点CMakeLists.txt中的变量可以在子节点中使用
  • 子节点CMakeLists.txt中的变量只能在当前节点中使用

3.3添加子目录

建立父子节点之间的关系

# 基本语法add_subdirectory(source_dir)
# 添加子目录
add_subdirectory(calc)
add_subdirectory(sort)
add_subdirectory(test1)
add_subdirectory(test2)

3.4问题分析及解决

将calc目录和sort目录中的源文件生成为库文件,供test1目录和test2目录中的测试文件使用。

3.4.1根目录

在根目录中的CMakeLists.txt文件中完成两件事:定义全局变量和添加子目录。具体如下:

cmake_minimum_required(VERSION 3.0)
project(test)
# 定义变量
# 静态库生成的路径
set(LIB_PATH ${CMAKE_CURRENT_SOURCE_DIR}/lib)
# 测试程序生成的路径
set(EXEC_PATH ${CMAKE_CURRENT_SOURCE_DIR}/bin)
# 头文件目录
set(HEAD_PATH ${CMAKE_CURRENT_SOURCE_DIR}/include)
# 静态库的名字
set(CALC_LIB calc)
set(SORT_LIB sort)
# 可执行程序的名字
set(APP_NAME_1 test1)
set(APP_NAME_2 test2)
# 添加子目录
add_subdirectory(calc)
add_subdirectory(sort)
add_subdirectory(test1)
add_subdirectory(test2)

3.4.2calc目录

calc 目录中的 CMakeLists.txt文件具体如下:

cmake_minimum_required(VERSION 3.0)
project(CALCLIB)
aux_source_directory(./ SRC)
include_directories(${HEAD_PATH})
set(LIBRARY_OUTPUT_PATH ${LIB_PATH})
add_library(${CALC_LIB} STATIC ${SRC})

3.4.3sort目录

sort 目录中的 CMakeLists.txt文件具体如下:

cmake_minimum_required(VERSION 3.0)
project(SORTLIB)
aux_source_directory(./ SRC)
include_directories(${HEAD_PATH})
set(LIBRARY_OUTPUT_PATH ${LIB_PATH})
add_library(${SORT_LIB} SHARED ${SRC})

3.4.4test1目录

test1 目录中的 CMakeLists.txt文件具体如下:

cmake_minimum_required(VERSION 3.0)
project(CALCTEST)
aux_source_directory(./ SRC)
include_directories(${HEAD_PATH})
link_directories(${LIB_PATH})
link_libraries(${CALC_LIB})
set(EXECUTABLE_OUTPUT_PATH ${EXEC_PATH})
add_executable(${APP_NAME_1} ${SRC})

3.4.5test2目录

test2 目录中的 CMakeLists.txt文件具体如下:

cmake_minimum_required(VERSION 3.0)
project(SORTTEST)
aux_source_directory(./ SRC)
include_directories(${HEAD_PATH})
set(EXECUTABLE_OUTPUT_PATH ${EXEC_PATH})
link_directories(${LIB_PATH})
add_executable(${APP_NAME_2} ${SRC})
target_link_libraries(${APP_NAME_2} ${SORT_LIB})

3.4.6构建项目

上述步骤完成后,开始构建项目,进入到根节点目录的build 目录中,执行cmake 命令,build目录中具体如下:

build
├── calc                  # 目录
├── CMakeCache.txt        # 文件
├── CMakeFiles            # 目录
├── cmake_install.cmake   # 文件
├── Makefile              # 文件
├── sort                  # 目录
├── test1                 # 目录
└── test2                 # 目录

build目录下执行make命令

图中显示在lib目录下生成了静态库libcalc.a和动态库libsort.so,在bin目录下生成了可执行程序test1和test2。

bin/
├── test1
└── test2
lib/
├── libcalc.a
└── libsort.so

3.5完结撒花

4.参考内容链接

具体内容请参考如下链接:

Cmake保姆级教程(上):Cmake的基本使用

Cmake保姆级教程(下):嵌套的Cmake

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值