cmake的一点点初步使用
cmake的一点点初步使用 https://cmake.org/
-------------
cmake打包程序。
1.开源跨平台
2.构建build,测试test,打包软件package sofrware的工具软件.
3.cmake的配置文件简单易懂,不依赖于其他平台的编译器
4.使用cmake配置文件来控制软件的编译过程,生成器generator生成指定项目文件(native makefile,MinGW Makefiles,Ninja,Visual Studio)等等的workspaces。
通过,对应的编译软件,最终编译成目标程序。
cmake命令,在那个目录下执行,就会搜索CMakeLists.txt,并在当前目录下生成相关文件(如果在代码目录执行,会在代码文件目录,会污染代码目录)。
所以一般是,建立build目录,和bin目录,在build目录中执行cmake ..(在上一级目录找CMakeLists.txt), build目录生成处理文件,最终可执行文件在bin中
一 ,简单的cmake
1 先看下目录结构 (-I表示忽略的目录)
$ tree . -I "bin|build|lib|src" . |-- CMakeLists.txt |-- fun1.c |-- fun2.c |-- include | |-- fun1.h | `-- fun2.h `-- test01.c 1 directory, 6 files
# 指定 CMake 的最低版本要求 cmake_minimum_required(VERSION 3.10.0) #定义项目的名称和使用的编程语言 project(code1 VERSION 0.1.0 LANGUAGES C) #指定要生成的可执行文件和其源文件 add_executable(code1 test01.c fun1.c fun2.c)
如果文件夹有很多源码文件总不能一个一个添加吧,这里用到 aux_source_directory(. SRC_LIST)
# 指定 CMake 的最低版本要求 cmake_minimum_required(VERSION 3.10.0) #定义项目的名称和使用的编程语言 project(code1 VERSION 0.1.0 LANGUAGES C) #将当前目录.的所有源码文件保存在SRC_LIST变量中 aux_source_directory(. SRC_LIST) #指定要生成的可执行文件和其源文件 add_executable(code1 ${SRC_LIST})
2 最后在build目录下执行 cmake ..
二 , cmake正规的组织结构
$ tree . . |-- CMakeLists.txt |-- bin |-- build |-- include | |-- fun1.h | `-- fun2.h |-- lib `-- src |-- fun1.c |-- fun2.c `-- test01.c 5 directories, 6 files
# 指定 CMake 的最低版本要求 cmake_minimum_required(VERSION 3.10.0) #定义项目的名称和使用的编程语言 project(code1 VERSION 0.1.0 LANGUAGES C) # bin目录下将来存最终生成的可执行文件 set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) #将当前目录.的src所有源码文件保存在SRC_LIST变量中 aux_source_directory(src SRC_LIST) # 指定头文件目录include include_directories(include) #指定要生成的可执行文件和其源文件 add_executable(code1 ${SRC_LIST})
这里介绍几个cmake的变量, EXECUTABLE_OUTPUT_PATH :可执行文件生成路径;PROJECT_SOURCE_DIR :项目的路径。
set()设置变量;include_directories()设置头文件目录;aux_source_directory()设置源码路径。
三, cmake处理编译动态库静态库
1.创建并处理自制动态库windows下(单个CMakeLists.txt )
$ tree . . |-- CMakeLists.txt |-- build `-- src |-- include | `-- mylib.h |-- lib | |-- module1.cpp | `-- module2.cpp `-- main.cpp
四个文件内容
mylib.h
#pragma once // 跨平台导出宏(Windows 专用) #ifdef _WIN32 #ifdef LIB_BUILDING #define LIB_API __declspec(dllexport) #else #define LIB_API __declspec(dllimport) #endif #else #define LIB_API #endif namespace MOD1 { LIB_API int add(int a, int b); LIB_API int subtract(int a, int b); } namespace MOD2 { LIB_API int add(int a, int b); LIB_API int subtract(int a, int b); }
module1.cpp
#include <iostream> #include "mylib.h" namespace MOD1 { int add(int a, int b) { return a + b; } int subtract(int a, int b) { return a - b; } }
module2.cpp
#include <iostream> #include "mylib.h" namespace MOD2 { int add(int a, int b) { return a + b; } int subtract(int a, int b) { return a - b; } }
main.cpp
#include <iostream> #include "mylib.h" int main(){ std::cout << MOD1::add(1,2)<< std::endl; std::cout << MOD2::add(5,2)<< std::endl; return 0; }
CMakeLists.txt
###项目设置######################### cmake_minimum_required(VERSION 3.10) # 指定最低 CMake 版本 project(MyProject VERSION 1.0) # 定义项目名称和版本 # 设置 C++ 标准 set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 包含头文件路径 include_directories(${PROJECT_SOURCE_DIR}/src/include) ###动态库设置######################### # 创建动态库 add_library(MyLib SHARED src/lib/module1.cpp src/lib/module2.cpp ) # 设置公共头文件路径 target_include_directories(MyLib PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> $<INSTALL_INTERFACE:include> ) # 关键:定义宏**_BUILDING,让头文件知道当前是“构建 DLL” target_compile_definitions(MyLib PRIVATE LIB_BUILDING) # 可选:统一输出目录(更整洁) set_target_properties(MyLib PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib ) ###主程序设置######################### # 找自定库的路径 #find_library(MyLib ${PROJECT_SOURCE_DIR}/lib) # 创建可执行程序 add_executable(MyApp src/main.cpp) # 链接动态库(直接写目标名!CMake 自动处理 .lib 路径) target_link_libraries(MyApp PRIVATE MyLib) # 👇 关键:Windows 下自动复制 .dll 到 .exe 目录 (不添加手动复制dll到可执行程序也可以) if(WIN32) add_custom_command(TARGET MyApp POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:MyLib> # MyLib.dll $<TARGET_FILE_DIR:MyApp> # 目标:MyApp.exe 所在目录 COMMENT "Copying MyLib.dll to MyApp directory" ) endif()
2.创建并处理自制动态库windows下(多个CMakeLists.txt 子工程)
项目结构(推荐) 这种结构清晰、可扩展,适合中小型到大型项目。
MyProject/ ├── CMakeLists.txt # 根 CMake ├── MathLib/ # 动态库模块 │ ├── CMakeLists.txt │ ├── include/MathLib.h │ └── src/MathLib.cpp └── MyApp/ # 主程序 ├── CMakeLists.txt └── main.cpp
第一步:编写动态库代码
MathLib/include/MathLib.h
#pragma once // 跨平台导出宏(Windows 专用) #ifdef _WIN32 #ifdef MATHLIB_BUILDING #define MATHLIB_API __declspec(dllexport) #else #define MATHLIB_API __declspec(dllimport) #endif #else #define MATHLIB_API #endif namespace Math { MATHLIB_API int add(int a, int b); MATHLIB_API int subtract(int a, int b); }
MathLib/src/MathLib.cpp
#include "MathLib.h" namespace Math { int add(int a, int b) { return a + b; } int subtract(int a, int b) { return a - b; } }
第二步:MathLib/CMakeLists.txt(构建 DLL)
# 创建动态库 add_library(MathLib SHARED src/MathLib.cpp ) # 设置公共头文件路径(供 MyApp 使用) target_include_directories(MathLib PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> $<INSTALL_INTERFACE:include> ) # 关键:定义宏,让头文件知道当前是“构建 DLL” target_compile_definitions(MathLib PRIVATE MATHLIB_BUILDING) # 可选:统一输出目录(更整洁) set_target_properties(MathLib PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )
PUBLIC表示:任何链接MathLib的目标,都会自动获得include/路径。
第三步:主程序代码
MyApp/main.cpp
#include <iostream> #include "MathLib.h" // 来自 MathLib/include/ int main() { std::cout << "10 + 5 = " << Math::add(10, 5) << "\n"; std::cout << "10 - 3 = " << Math::subtract(10, 3) << "\n"; return 0; }
第四步:MyApp/CMakeLists.txt(引用 DLL)
# 创建可执行程序 add_executable(MyApp main.cpp) # 链接动态库(直接写目标名!CMake 自动处理 .lib 路径) target_link_libraries(MyApp PRIVATE MathLib) # 👇 关键:Windows 下自动复制 .dll 到 .exe 目录 if(WIN32) add_custom_command(TARGET MyApp POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:MathLib> # 源:MathLib.dll $<TARGET_FILE_DIR:MyApp> # 目标:MyApp.exe 所在目录 COMMENT "Copying MathLib.dll to MyApp directory" ) endif()
$<TARGET_FILE:MathLib>会自动解析为Debug/MathLib.dll或Release/MathLib.dll,完全匹配当前配置!
第五步:根 CMakeLists.txt
cmake_minimum_required(VERSION 3.16) project(MyProject LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 添加子模块 add_subdirectory(MathLib) add_subdirectory(MyApp)
构建步骤(VS2022 + CMake)
方法一:用命令行(推荐)
# 在 MyProject 目录下 mkdir build cd build # 生成 VS2022 项目(x64) cmake .. -G "Visual Studio 17 2022" -A x64 # 构建 Release 版本 cmake --build . --config Release # 运行(自动找到 DLL!) .\Release\MyApp.exe
方法二:用 VS2022 IDE
- 打开 VS2022 → 文件 → 打开 → CMake... → 选择
MyProject/CMakeLists.txt - VS 会自动加载项目
- 顶部选择 x64-Release
- 右键
MyApp→ 设为启动项 - 按 F5 运行!
10 + 5 = 15 10 - 3 = 7
构建后目录结构(build/ 下)
build/ ├── bin/ │ └── Release/ │ ├── MathLib.dll ← 动态库 │ └── MyApp.exe ← 可执行文件(同目录,运行无忧) ├── lib/ │ └── Release/ │ └── MathLib.lib ← 导入库(链接时用) └── MyProject.sln ← VS 解决方案
💡 因为用了
add_custom_command,运行时绝不会报“找不到 MathLib.dll”!
3.使用默认目录下的动态库(环境变量)
#2.使用在连接器默认路径下/lib /usr/lib下的动态库,环境变量 find_library(mysql mysqlclient) #libmysqlclient.so #实际文件名 #设置变量LIBS set(LIBS mysharedlib ${mysql}) #链接动态库 output是主程序名 target_link_libraries(output ${LIBS}) #设置库和可执行文件生成输出路径 ...
4.使用指定目录下的动态库
#3.找自定义路径的动态库(参数一:变量,参数二:名称,参数三:路径) find_library(math sharemath ${PROJECT_SOURCE_DIR}/lib set(LIBS mysharedlib ${mysql} ${math} ) #链接动态库 target_link_libraries(output ${LIBS})
----总结,自制库,环境变量库,指定目录库
#1.自制库(参数一:库名,参数二:类型,参数三:库的路径) add_library(mysharedlib SHARED ${LIB SRC}) # 添加可执行文件add executable(output main.cpp) #2.使用在连接器默认路径下/lib /usr/lib 下的动态库,环境变量中 find_library(mysql mysqlclient) #libmysqlclient.so 库全名 #3.找自定义路径的动态库(参数一:变量,参数二:库名,参数三:库的路径) find_library(math sharemath ${PROJECT SOURCE DIR}/lib) #把所有库都定义到LIBS变量中 set(LIBS mysharedlib ${mysql} ${math} ) # 链接动态库 target_link_libraries(output ${LIBS})
四,cmake 一些问题
1.cmake搜索目录下的所有文件
方法一:使用 file(GLOB_RECURSE ...) 命令
# 定义项目和最低 CMake 版本 cmake_minimum_required(VERSION 3.4.1) project(MySharedLibrary) # 递归搜索 src 目录下的所有 .cpp 文件 file(GLOB_RECURSE SRC_FILES "src/*.cpp") # 创建共享库 add_library(my_shared_lib SHARED ${SRC_FILES})
- 功能:
file(GLOB_RECURSE SRC_FILES "src/*.cpp")会递归搜索src目录及其子目录中的所有.cpp文件,并将结果存储在SRC_FILES变量中。 - 优点:自动收集源文件,避免手动列出每个文件。
- 注意:
GLOB命令在文件列表变化时不会自动触发 CMake 重新配置,建议在开发阶段使用,发布时手动列出文件。
方法二:使用 aux_source_directory 命令
# 定义项目和最低 CMake 版本 cmake_minimum_required(VERSION 3.4.1) project(MySharedLibrary) # 搜索 src 目录下的所有 .cpp 文件 aux_source_directory(src SRC_FILES) # 创建共享库 add_library(my_shared_lib SHARED ${SRC_FILES})
- 功能:
aux_source_directory(src SRC_FILES)会搜索src目录下的所有源文件(包括.cpp),并将结果存储在SRC_FILES变量中。 - 适用场景:适用于源文件位于单一目录的情况。
GLOB关键字: https://www.cnblogs.com/hshy/p/18908613
单官方推荐手动列出源码文件
# 手动列出源文件(简化示例) set(SOURCES src/main.cpp src/utils.cpp src/module1/file1.cpp src/module1/file2.cpp # ... 其他文件 src/moduleN/fileN.cpp ) # 添加可执行文件 add_executable(large_project ${SOURCES})
https://blog.csdn.net/hhltaishuai/article/details/123795718
https://www.runoob.com/cmake/cmake-basic.html
扩展:cake
https://www.bilibili.com/video/BV1nw411C71Z
https://www.bilibili.com/video/BV1EuWKevE23
gcc编译:
https://www.bilibili.com/video/BV192pZeTE9B
使用CMake生成动态链接库(.dll和.so)和静态链接库(.lib和.a)的方法
https://blog.csdn.net/weixin_43325228/article/details/143139745

浙公网安备 33010602011771号