CMake 使用教程 (三)

本文介绍了如何在CMake中制作静态库和动态库,包括在CMakeLists.txt文件中使用add_library命令,以及在Linux和Windows环境下库文件的命名规则。同时,文章详细讲解了指定库输出路径的方法,以及如何链接静态库和动态库,包括使用link_libraries和target_link_libraries命令。此外,还提到了链接动态库时处理找不到库文件问题的解决方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.0.0 制作动态库或静态库

有些时候我们编写的源代码并不需要将他们编译生成可执行程序,而是生成一些静态库或动态库提供给第三方使用,下面来讲解在 cmake 中生成这两类库文件的方法。

1.0.1 制作静态库

在 cmake 中,如果要制作静态库,需要使用的命令如下:

add_library(库名称 STATIC 源文件1 [源文件2] ...) 

在 Linux 中,静态库名字分为三部分:lib+ 库名字 +.a,此处只需要指定出库的名字就可以了,另外两部分在生成该文件的时候会自动填充。
在 Windows 中虽然库名和 Linux 格式不同,但也只需指定出名字即可。
下面有一个目录,需要将 src 目录中的源文件编译成静态库,然后再使用:

.
├── build
├── CMakeLists.txt
├── include           # 头文件目录
│   └── head.h
├── main.cpp          # 用于测试的源文件
└── src               # 源文件目录
    ├── add.cpp
    ├── div.cpp
    ├── mult.cpp
    └── sub.cpp

根据上面的目录结构,可以这样编写 CMakeLists.txt 文件:

cmake_minimum_required(VERSION 3.0)
project(CALC)
include_directories(${PROJECT_SOURCE_DIR}/include)
file(GLOB SRC_LIST "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
add_library(calc STATIC ${SRC_LIST})

这样最终就会生成对应的静态库文件 libcalc.a。

1.0.2 制作动态库

在 cmake 中,如果要制作动态库,需要使用的命令如下:

add_library(库名称 SHARED 源文件1 [源文件2] ...) 

在 Linux 中,动态库名字分为三部分:lib+ 库名字 +.so,此处只需要指定出库的名字就可以了,另外两部分在生成该文件的时候会自动填充。
在 Windows 中虽然库名和 Linux 格式不同,但也只需指定出名字即可。
根据上面的目录结构,可以这样编写 CMakeLists.txt 文件:

cmake_minimum_required(VERSION 3.0)
project(CALC)
include_directories(${PROJECT_SOURCE_DIR}/include)
file(GLOB SRC_LIST "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
add_library(calc SHARED ${SRC_LIST})

这样最终就会生成对应的动态库文件 libcalc.so

1.0.3 指定输出的路径

方式 1 - 适用于动态库

对于生成的库文件来说和可执行程序一样都可以指定输出路径。由于在Linux下生成的动态库默认是有执行权限的,所以可以按照生成可执行程序的方式去指定它生成的目录:

cmake_minimum_required(VERSION 3.0)
project(CALC)
include_directories(${PROJECT_SOURCE_DIR}/include)
file(GLOB SRC_LIST "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
# 设置动态库生成路径
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
add_library(calc SHARED ${SRC_LIST})

对于这种方式来说,其实就是通过 set 命令给 EXECUTABLE_OUTPUT_PATH 宏设置了一个路径,这个路径就是可执行文件生成的路径。

方式 2 - 都适用

由于在 Linux 下生成的静态库默认不具有可执行权限,所以在指定静态库生成的路径的时候就不能使用 EXECUTABLE_OUTPUT_PATH 宏了,而应该使用 LIBRARY_OUTPUT_PATH,这个宏对应静态库文件和动态库文件都适用。

cmake_minimum_required(VERSION 3.0)
project(CALC)
include_directories(${PROJECT_SOURCE_DIR}/include)
file(GLOB SRC_LIST "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
# 设置动态库/静态库生成路径
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
# 生成动态库
#add_library(calc SHARED ${SRC_LIST})
# 生成静态库
add_library(calc STATIC ${SRC_LIST})

1.1.0 包含库文件

在编写程序的过程中,可能会用到一些系统提供的动态库或者自己制作出的动态库或者静态库文件,cmake 中也为我们提供了相关的加载动态库的命令。

1.1.1 链接静态库

src
├── add.cpp
├── div.cpp
├── main.cpp
├── mult.cpp
└── sub.cpp

现在我们把上面 src 目录中的 add.cpp、div.cpp、mult.cpp、sub.cpp 编译成一个静态库文件 libcalc.a
测试目录结构如下:

$ tree 
.
├── build
├── CMakeLists.txt
├── include
│   └── head.h
├── lib
│   └── libcalc.a     # 制作出的静态库的名字
└── src
    └── main.cpp

4 directories, 4 files

在 cmake 中,链接静态库的命令如下:
link_libraries( […])
参数 1:指定出要链接的静态库的名字
可以是全名 libxxx.a
也可以是掐头(lib)去尾(.a)之后的名字 xxx
参数 2-N:要链接的其它静态库的名字
如果该静态库不是系统提供的(自己制作或者使用第三方提供的静态库)可能出现静态库找不到的情况,此时可以将静态库的路径也指定出来:

link_directories(<lib path>)

这样,修改之后的 CMakeLists.txt 文件内容如下:

cmake_minimum_required(VERSION 3.0)
project(CALC)
# 搜索指定目录下源文件
file(GLOB SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
# 包含头文件路径
include_directories(${PROJECT_SOURCE_DIR}/include)
# 包含静态库路径
link_directories(${PROJECT_SOURCE_DIR}/lib)
# 链接静态库
link_libraries(calc)
add_executable(app ${SRC_LIST})

添加了第 8 行的代码,就可以根据参数指定的路径找到这个静态库了。

1.1.2 链接动态库

在程序编写过程中,除了在项目中引入静态库,好多时候也会使用一些标准的或者第三方提供的一些动态库,关于动态库的制作、使用以及在内存中的加载方式和静态库都是不同的,在此不再过多赘述,如有疑惑请参考
在 cmake 中链接动态库的命令如下:

target_link_libraries(
    <target> 
    <PRIVATE|PUBLIC|INTERFACE> <item>... 
    [<PRIVATE|PUBLIC|INTERFACE> <item>...]...)

target:指定要加载动态库的文件的名字

  • 该文件可能是一个源文件
  • 该文件可能是一个动态库文件
  • 该文件可能是一个可执行文件
    PRIVATE|PUBLIC|INTERFACE:动态库的访问权限,默认为 PUBLIC
  • 如果各个动态库之间没有依赖关系,无需做任何设置,三者没有没有区别,一般无需指定,使用默认的 PUBLIC 即可。
  • 动态库的链接具有传递性,如果动态库 A 链接了动态库 B、C,动态库 D 链接了动态库 A,此时动态库 D 相当于也链接了动态库 B、C,并可以使用动态库 B、C 中定义的方法。
target_link_libraries(A B C)
target_link_libraries(D A)
  • PUBLIC:在 public 后面的库会被 Link 到前面的 target 中,并且里面的符号也会被导出,提供给第三方使用。
  • PRIVATE:在 private 后面的库仅被 link 到前面的 target 中,并且终结掉,第三方不能感知你调了啥库
  • INTERFACE:在 interface 后面引入的库不会被链接到前面的 target 中,只会导出符号。
    链接系统动态库
    动态库的链接和静态库是完全不同的:
  • 静态库会在生成可执行程序的链接阶段被打包到可执行程序中,所以可执行程序启动,静态库就被加载到内存中了。
  • 动态库在生成可执行程序的链接阶段不会被打包到可执行程序中,当可执行程序被启动并且调用了动态库中的函数的时候,动态库才会被加载到内存。
    因此,在 cmake 中指定要链接的动态库的时候,应该将命令写到生成了可执行文件之后:
cmake_minimum_required(VERSION 3.0)
project(TEST)
file(GLOB SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
# 添加并指定最终生成的可执行程序名
add_executable(app ${SRC_LIST})
# 指定可执行程序要链接的动态库名字
target_link_libraries(app pthread)

在 target_link_libraries(app pthread) 中:

  • app: 对应的是最终生成的可执行程序的名字
  • pthread:这是可执行程序要加载的动态库,这个库是系统提供的线程库,全名为
    libpthread.so,在指定的时候一般会掐头(lib)去尾(.so)。

链接第三方动态库
现在,自己生成了一个动态库,对应的目录结构如下:

$ tree 
.
├── build
├── CMakeLists.txt
├── include
│   └── head.h            # 动态库对应的头文件
├── lib
│   └── libcalc.so        # 自己制作的动态库文件
└── main.cpp              # 测试用的源文件

3 directories, 4 files

假设在测试文件 main.cpp 中既使用了自己制作的动态库 libcalc.so 又使用了系统提供的线程库,此时 CMakeLists.txt 文件可以这样写:

cmake_minimum_required(VERSION 3.0)
project(TEST)
file(GLOB SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
include_directories(${PROJECT_SOURCE_DIR}/include)
add_executable(app ${SRC_LIST})
target_link_libraries(app pthread calc)

在第六行中,pthread、calc 都是可执行程序 app 要链接的动态库的名字。当可执行程序 app 生成之后并执行该文件,会提示有如下错误信息:

$ ./app 
./app: error while loading shared libraries: libcalc.so: cannot open shared object file: No such file or directory

这是因为可执行程序启动之后,去加载 calc 这个动态库,但是不知道这个动态库被放到了什么位置,所以就加载失败了,在 CMake 中可以在生成可执行程序之前,通过命令指定出要链接的动态库的位置,指定静态库位置使用的也是这个命令:

link_directories(path)

所以修改之后的 CMakeLists.txt 文件应该是这样的:

cmake_minimum_required(VERSION 3.0)
project(TEST)
file(GLOB SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
# 指定源文件或者动态库对应的头文件路径
include_directories(${PROJECT_SOURCE_DIR}/include)
# 指定要链接的动态库的路径
link_directories(${PROJECT_SOURCE_DIR}/lib)
# 添加并生成一个可执行程序
add_executable(app ${SRC_LIST})
# 指定要链接的动态库
target_link_libraries(app pthread calc)

通过 link_directories 指定了动态库的路径之后,在执行生成的可执行程序的时候,就不会出现找不到动态库的问题了。

温馨提示:使用 target_link_libraries 命令就可以链接动态库,也可以链接静态库文件。

标题基于SpringBoot+Vue的社区便民服务平台研究AI更换标题第1章引言介绍社区便民服务平台的研究背景、意义,以及基于SpringBoot+Vue技术的研究现状和创新点。1.1研究背景与意义分析社区便民服务的重要性,以及SpringBoot+Vue技术在平台建设中的优势。1.2国内外研究现状概述国内外在社区便民服务平台方面的发展现状。1.3研究方法与创新点阐述本文采用的研究方法和在SpringBoot+Vue技术应用上的创新之处。第2章相关理论介绍SpringBoot和Vue的相关理论基础,以及它们在社区便民服务平台中的应用。2.1SpringBoot技术概述解释SpringBoot的基本概念、特点及其在便民服务平台中的应用价值。2.2Vue技术概述阐述Vue的核心思想、技术特性及其在前端界面开发中的优势。2.3SpringBoot与Vue的整合应用探讨SpringBoot与Vue如何有效整合,以提升社区便民服务平台的性能。第3章平台需求分析与设计分析社区便民服务平台的需求,并基于SpringBoot+Vue技术进行平台设计。3.1需求分析明确平台需满足的功能需求和性能需求。3.2架构设计设计平台的整体架构,包括前后端分离、模块化设计等思想。3.3数据库设计根据平台需求设计合理的数据库结构,包括数据表、字段等。第4章平台实现与关键技术详细阐述基于SpringBoot+Vue的社区便民服务平台的实现过程及关键技术。4.1后端服务实现使用SpringBoot实现后端服务,包括用户管理、服务管理等核心功能。4.2前端界面实现采用Vue技术实现前端界面,提供友好的用户交互体验。4.3前后端交互技术探讨前后端数据交互的方式,如RESTful API、WebSocket等。第5章平台测试与优化对实现的社区便民服务平台进行全面测试,并针对问题进行优化。5.1测试环境与工具介绍测试
### CLion 中使用 CMake教程 #### 1. 初步了解 CMake 和 CLion 集成 CMake 是一种跨平台的构建系统生成器,能够为不同的开发环境生成相应的构建文件。在 CLion 中,CMake 被深度集成到 IDE 中,当创建一个新的 C++ 项目时,CLion 自动会生成 `CMakeLists.txt` 文件作为项目的构建配置文件[^1]。 #### 2. 创建新项目并初始化 CMake 在 CLion 中新建一个 C++ 项目时,IDE 就会在项目根目录下自动创建 `CMakeLists.txt` 文件。该文件包含了基本的 CMake 构建指令,例如设置最低支持的 CMake 版本 (`cmake_minimum_required`)、定义项目名称 (`project`) 和添加可执行目标 (`add_executable`) 等[^1]。 以下是典型的初始 `CMakeLists.txt` 文件的内容: ```cmake cmake_minimum_required(VERSION 3.20) # 设置所需的最小 CMake 版本 project(MyProject LANGUAGES CXX) # 定义项目名和使用的编程语言 set(CMAKE_CXX_STANDARD 17) # 设置 C++ 标准 (如 C++17) add_executable(main main.cpp) # 添加可执行目标及其对应的源文件 ``` #### 3. 配置 CMake 环境 为了使 CLion 正常运行 CMake,需要确保本地已安装 CMake 并将其路径正确配置到 CLion 的 Settings 中。具体步骤如下: - 打开 **Settings -> Build, Execution, Deployment -> Toolchains**。 - 确认已经选择了合适的编译器(如 MinGW 或 MSVC),并确认 CMake 工具已被正确加载[^2]。 #### 4. 修改和更新 CMakeLists.txt 随着项目的复杂度增加,可能需要向 `CMakeLists.txt` 文件中添加更多内容,比如引入外部库或管理多个子模块间的依赖关系。以下是一些常见的场景: ##### a. 引入第方库 通过 Conan 等包管理工具可以简化第方库的引入过程。例如,假设我们需要使用 POCO 库,则可以在 `conanfile.txt` 中声明需求,并让 CMake 自动生成必要的配置文件[^5]。 示例 `CMakeLists.txt` 增强版: ```cmake find_package(Poco REQUIRED) # 查找 POCO 库 include_directories(${Poco_INCLUDE_DIRS}) # 包含头文件路径 target_link_libraries(main ${Poco_LIBRARIES}) # 链接库 ``` ##### b. 复杂工程结构的支持 对于由多个子模块组成的大型工程项目,可以通过嵌套的方式组织各个组件的关系。例如,某些模块负责提供静态/动态链接库,另一些则专注于业务逻辑实现。这种情况下,合理设计 `CMakeLists.txt` 至关重要[^3]。 示例多层架构下的 `CMakeLists.txt` 结构化方式: ```cmake # 主目录下的顶层描述 add_subdirectory(libs) # 加载 lib 子目录中的所有模块 add_subdirectory(applications) # 加载 app 子目录中的应用入口程序 ``` #### 5. 清理缓存与重载项目 如果修改了 `CMakeLists.txt` 文件或者调整了其他相关参数后发现效果未生效,可能是由于旧的构建数据干扰所致。此时可通过手动删除 `.idea/cmake-build-*` 目录再触发刷新解决此类问题[^4]。 --- ### 总结 以上介绍了如何在 CLion 下高效地运用 CMake 来管理和构建 C++ 项目的基础流程及相关技巧。无论是简单的单文件练习还是复杂的分布式协作开发模式,掌握好这些核心概念都将极大提升工作效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

houxian1103

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值