cmake 编译教程

一、只有一个源文件的程序编译

首先在当前目录下创建两个文件
hello.cpp
CMakeLists.txt (注意CMakeLists大小写,不要写错了)
cpp 复制代码
cmake_minimum_required (VERSION 2.8)
 
project (learn_cmake)
 
add_executable(hello hello.cpp)
  • 第一行意思是cmake最低版本要求2.8,
  • 第二行是本项目的工程名
  • 第三行:第一个变量:要生成的可执行文件名为hello,后面的参数是需要的依赖。
接着在当前目录下执行 cmake . 接着会发现目录下多生成了一些文件,例如Makefile,然后使用GNU make命令来编译程序,会生成可执行程序。

二、同一目录下多个源文件

此时在当前目录新增两个依赖,并mian函数的执行需要依赖这两个文件

add.cpp

add.h

只需要在CMakeLists.txt中添加所依赖的.cpp文件,编译步骤和上面相同。

cpp 复制代码
cmake_minimum_required (VERSION 2.8)
 
project (learn_cmake)
 
add_executable(hello hello.cpp myadd.cpp)

三、同一目录下很多源文件

如果同一目录下有无穷多源文件,那么一个一个添加就很慢了。此时可以使用cmake中的函数存储这些源文件

aux_source_directory(dir var)

他的作用是把dir目录中的所有源文件都储存在var变量中

然后需要用到源文件的地方用 变量var来取代

此时 CMakeLists.txt 可以这样优化

cpp 复制代码
cmake_minimum_required(VERSION 2.8)

project(learn_cmake)

aux_source_directory(. SRC_LIST)

add_executable(hello ${SRC_LIST})

四、头文件在别的文件夹

对于集中的头文件,CMake提供了一个很方便的函数

include_directories ( dir )

他的作用是 自动去dir 目录下寻找头文件,相当于 gcc中的 gcc -I dir

此时 CMakeLists.txt 可以这样优化

cpp 复制代码
cmake_minimum_required(VERSION 2.8)

project(learn_cmake)

aux_source_directory(. SRC_LIST)

include_directories(./inc_dir)

add_executable(hello ${SRC_LIST})

五、头文件源文件分离,并含有多个文件夹

假如说当前的工程目录是这样的,头文件和源文件分离,并含有多个文件夹

此时 CMakeLists.txt 可以这样优化

cpp 复制代码
cmake_minimum_required(VERSION 2.8)

project(learn_cmake)

aux_source_directory(src_dir1 SRC_LIST1)
aux_source_directory(src_dir2 SRC_LIST2)
aux_source_directory(main_dir MAIN_DIR)

include_directories(./inc_dir1 ./inc_dir2)

add_executable(hello ${SRC_LIST1} ${SRC_LIST2} ${MAIN_DIR})

六、生成动态库和静态库

假如说当前的项目目录是这样的

  • inc目录下存放头文件
  • src目录下存放源文件
  • lib目录下存放生成的库
  • build目录下存放构建项目相关的文件,如CMakeLists.txt。而稍后我们也在这个目录下执行cmake和make

此时 CMakeLists.txt 可以这样优化

cpp 复制代码
cmake_minimum_required(VERSION 2.8)

project(learn_lib)

#整合源文件
aux_source_directory(${PROJECT_BINARY_DIR}/../src SRC_LIST)

#引入头文件路径
include_directories(${PROJECT_BINARY_DIR}/../inc)

#生成静态库或者动态库 参数1:生成的库的名称 参数2:静态或动态 参数3:生成库所需要的源文件
add_library(func_shared SHARED ${SRC_LIST})
add_library(func_static STATIC ${SRC_LIST})

#设置最终生成的库的名称
set_target_properties(func_shared PROPERTIES OUTPUT_NAME "myfunc")
set_target_properties(func_static PROPERTIES OUTPUT_NAME "myfunc")

#设置生成的库的路径
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/../lib)

开始编译:

  1. 在build目录下执行 cmake .
  2. 在build目录下执行 make
  3. 查看lib目录下是否生成库文件,

出现库文件就算编译成功

七、链接库文件

库文件目录结构如下:

  • lib目录下存放静态库和动态库
  • main_src目录下存放main函数相关的源文件
  • bin目录存放项目生成的可执行文件

此时 CMakeLists.txt 可以这样写

cpp 复制代码
cmake_minimum_required(VERSION 2.8)

project(learn_lib)

#整合源文件
aux_source_directory(${PROJECT_BINARY_DIR}/../main_src MAIN_SRC)

#引入头文件路径
include_directories(${PROJECT_BINARY_DIR}/../inc)

#生成静态库或者动态库 参数1:生成的库的名称 参数2:静态或动态 参数3:生成库所需要的源文件
add_library(func_shared SHARED ${SRC_LIST})
add_library(func_static STATIC ${SRC_LIST})

#设置最终生成的库的名称
set_target_properties(func_shared PROPERTIES OUTPUT_NAME "myfunc")
set_target_properties(func_static PROPERTIES OUTPUT_NAME "myfunc")

#设置生成的库的路径
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/../lib)

#查找库文件 第一个参数:存储查找到的库文件 第二个参数:要查找的库文件 第三个参数:要查找的目录
find_library(FUNC_LIB myfunc ${PROJECT_BINARY_DIR}/../lib)

#设置可执行文件生成到哪里
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/../bin)

add_executable(hello ${MAIN_SRC})

target_link_libraries(hello ${FUNC_LIB})

八、如何选择动态库和静态库

选择生成动态库(Dynamic Link Library,DLL 在 Windows 上,Shared Object,.so 在 Unix/Linux 上,或 Dynamic Library,.dylib 在 macOS 上)还是静态库(Library Archive,.a 或 .lib)主要取决于以下几个因素:

动态库的优点:

  1. 资源占用: 动态库在多个程序间共享相同的代码,可以节省系统内存和磁盘空间,因为不需要为每个使用该库的应用程序复制整个库。
  2. 更新方便: 更新动态库时,所有依赖它的应用程序都会自动使用新版本,无需重新编译或分发应用程序。
  3. 模块化: 动态库可以更容易地实现模块化编程,允许在运行时加载或卸载库,增强程序的灵活性和扩展性。
  4. 性能: 尽管启动时可能需要一些额外的时间来解析动态库中的符号,但在频繁调用的情况下,动态链接可能会更快,因为它避免了静态链接中的冗余代码。

静态库的优点:

  1. 部署简单: 使用静态库的程序是自包含的,不需要在目标机器上存在额外的库文件。
  2. 可靠性: 不会受到"依赖地狱"问题的影响,即不会因为缺少动态库或者动态库版本不匹配而导致程序崩溃。
  3. 安全性: 避免了由于动态库被恶意替换而导致的安全风险。
  4. 兼容性: 特别是在嵌入式系统或资源受限的环境中,静态链接可以确保软件的完整性和最小化依赖。

选择策略:

  • 如果库的使用者需要减少最终可执行文件的分发复杂度,或者目标平台资源有限,静态库可能是更好的选择。
  • 如果库需要在多个应用之间共享,或者希望简化库的更新流程,动态库更为合适。
相关推荐
Code哈哈笑7 分钟前
【C++ 学习】多态的基础和原理(10)
java·c++·学习
Aurora_th14 分钟前
树与图的深度优先遍历(dfs的图论中的应用)
c++·算法·深度优先·图论·dfs·树的直径
消失的旧时光-194314 分钟前
kotlin的密封类
android·开发语言·kotlin
A_cot18 分钟前
Redis 的三个并发问题及解决方案(面试题)
java·开发语言·数据库·redis·mybatis
学步_技术18 分钟前
Python编码系列—Python原型模式:深克隆与高效复制的艺术
开发语言·python·原型模式
alden_ygq24 分钟前
GCP容器镜像仓库使用
java·开发语言
sysin.org41 分钟前
VMware ESXi 7.0U3q macOS Unlocker 集成驱动版更新 OEM BIOS 2.7 支持 Windows Server 2025
windows·macos·esxi·bios·oem·网卡驱动·nvme驱动
苹果酱05671 小时前
一文读懂SpringCLoud
java·开发语言·spring boot·后端·中间件
Eoneanyna1 小时前
QT设置git仓库
开发语言·git·qt
shuxianshrng1 小时前
大气网格化精细化监管监测系统
大数据·服务器·windows·经验分享