前段时间遇到一个小问题,后来发现这是个挺常见的坑,顺手整理一篇笔记。
🎬 个人主页:艾莉丝努力练剑
❄专栏传送门:《C语言》《数据结构与算法》《C/C++干货分享&学过程记录》
《Linux操作系统编程详解》《笔试/面试常见算法:从基础到进阶》《Python干货分享》
⭐️为天地立心,为生民立命,为往圣继绝学,为万世开太平
🎬 艾莉丝的简介:
文章目录
- 1 ~> ChatServer项目CMake构建实战
- 1.1 项目背景与构建前置要求
- 1.2 CMakeLists.txt编写、错误修正与完整可用代码
- 1.2.1 原始素材中存在的典型错误
- 1.2.2 修正做好完整CMakeLists.txt
- 1.3.1 link_directories
- 1.3.2 target_link_libraries 链接库规则
- 1.3.3 构建类型 CMAKE_BUILD_TYPE
- 1.3.4 target_compile_definitions
1 ~> ChatServer项目CMake构建实战
1.1 项目背景与构建前置要求
- 项目:
AIChatServer,C++聊天服务器项目,依赖自研SDK静态库与第三方开源库 - 编译前置条件
main.cpp、ChatServer.cpp业务源码开发
- 自研SDK静态库
libai_chat_sdk.a已经编译安装至/usr/local/lib - 系统预先部署依赖库:OpenSSL、jsoncpp、fmt、spdlog、gflags、sqlite3
- CMake最低版本要求:3.10,C++标准采用C++17
- 采用外部构建(out‑of‑source build),创建独立
build编译目录,避免编译产物污染源码目录
1.2 CMakeLists.txt编写、错误修正与完整可用代码
1.2.1 原始素材中存在的典型错误
1. 变量名拼写错误:CHAKE_*系列,正确前缀为CMAKE_
2. target_link_libraries错误填写静态库全名libai_chat_sdk,‑l链接器参数不要前缀lib与后缀.a
3. 重复添加链接库gflags
4. 依赖库OpenSSL现代CMake规范使用导入目标OpenSSL::SSL、OpenSSL::Crypto
5. link_directories作用:指定静态库搜索路径,必须写在add_executable之前,对后续target生效
6. EXECUTABLE_OUTPUT_PATH旧变量,现代CMake推荐使用CMAKE_RUNTIME_OUTPUT_DIRECTORY
1.2.2 修正做好完整CMakeLists.txt
# 指定CMake最低版本
cmake_minimum_required(VERSION 3.10)
# 定义项目名称
project(AIChatServer)
# 设置C++编译标准 C++17
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 设置默认构建类型,调试使用Debug;发布版本编译改为Release
set(CMAKE_BUILD_TYPE Debug)
# 设置静态库搜索路径,必须放置在add_executable之前
link_directories(/usr/local/lib)
# 生成可执行程序,指定项目源码文件
add_executable(AIChatServer
main.cpp
ChatServer.cpp
)
# 设置可执行文件输出目录,输出至build目录下
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
# 查找系统OpenSSL依赖库
find_package(OpenSSL REQUIRED)
# 添加编译宏定义,启用cpp‑httplib的OpenSSL HTTPS支持
target_compile_definitions(AIChatServer PRIVATE CPPHTTPLIB_OPENSSL_SUPPORT)
# 链接所有依赖库
# 自研静态库ai_chat_sdk,不要写lib前缀,不要写.a后缀
target_link_libraries(AIChatServer
ai_chat_sdk # 自研SDK静态库 libai_chat_sdk.a
jsoncpp
fmt
spdlog
gflags
OpenSSL::SSL
OpenSSL::Crypto
sqlite3
)
1.3 CMake关键指令原理梳理
1.3.1 link_directories
- 功能:告诉链接器去哪里搜索静态/动态库文件
- 语法:
link_directories(目录路径) - 重要注意事项
- 现代CMake优先使用
find_package导入目标,link_directories多用于本地自定义静态库 - 示例:
link_directories(/usr/local/lib),用于读取安装到此路径下自研静态库
1.3.2 target_link_libraries 链接库规则
- Linux下静态库命名规范:
libxxx.a、动态库libxxx.so - CMake填写规则:只写中间库名
xxx,CMake自动补全lib前缀,传递‑lxxx给gcc链接器 - 错误案例:静态库文件
libai_chat_sdk.a,写libai_chat_sdk→ 传递参数‑llibai_chat_sdk,链接器查找liblibai_chat_sdk.a,文件不存在直接报错 - 报错信息识别:
cannot find -llibai_chat_sdk: No such file or directory,就是库名多写lib前缀导致
1.3.3 构建类型 CMAKE_BUILD_TYPE
Debug:调试模式,开启调试符号‑g,不做代码优化,开发调试阶段使用Release:发布模式,开启代码优化,去除调试符号,正式上线发布编译使用- 修改方法:修改CMakeLists内
CMAKE_BUILD_TYPE变量,或者cmake命令行传入参数‑DCMAKE_BUILD_TYPE=Release
1.3.4 target_compile_definitions
- 作用:为指定编译目标添加预编译宏
- 示例:
CPPHTTPLIB_OPENSSL_SUPPORT,开启http‑lib库的SSL HTTPS能力,没有该宏会无法启用HTTPS
1.4 完整编译流程(外部构建 out‑of‑source build)
1.4.1 创建构建目录并进入
# 在ChatServer源码目录下创建build文件夹
mkdir -p build
cd build
1.4.2 执行CMake配置
# cmake .. 代表读取上一级目录的CMakeLists.txt,生成Makefile构建脚本
cmake ..
- 成功输出标志:
Configuring done、Generating done,生成Makefile与CMake缓存文件 - 失败场景:依赖库缺失(OpenSSL未安装等),
find_package会直接报错终止配置
1.4.3 执行编译链接
make
1. 编译阶段:把.cpp源码编译为.o目标文件
2. 链接阶段:把目标文件 + 所有指定静态/动态库合并,生成最终可执行文件AIChatServer
3. 成功标志:[100%] Built target AIChatServer,可执行文件生成在build目录
1.5 高频踩坑问题与排错方案
1.5.1 链接报错:找不到自定义静态库
- 报错:
cannot find -lxxx: No such file or directory排查步骤
ls /usr/local/lib/libai_chat_sdk.a,确认库文件已经部署
2. 确认link_directories(/usr/local/lib)写在add_executable之前
3. target_link_libraries库名不要写lib前缀,不要写.a后缀
4. 如果特殊情况,强制指定完整库文件:‑l:libai_chat_sdk.a
1.5.2 编译通过,链接阶段报符号未定义
- 现象:编译cpp源文件正常,链接报类、函数未定义(举个例子日志器、ChatSDK相关符号找不到)
- 根因:没有链接自研SDK静态库,或者静态库编译ABI不匹配(Debug/Release模式不一致,C++标准不一致)
- 解决方案:确认
target_link_libraries加入自研库,确认SDK库编译C++标准、构建类型和当前项目完全一致
1.5.3 头文件找不到
- 解决方案:使用
include_directories()或者target_include_directories()添加头文件搜索路径
# 推荐现代写法,仅对AIChatServer目标生效
target_include_directories(AIChatServer PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/../sdk/include
)
1.6 Release发布版本编译
两种方法切换Release模式
1. 修改CMakeLists.txt:set(CMAKE_BUILD_TYPE Release),重新执行cmake … && make
2. 命令行传入参数,不修改文件
cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
make
1.7 补充CMake概念拓展面试要点
- 外部构建(out‑of‑source):编译产物全部放到build,源码目录保持干净,是工业界标准做法,禁止在源码目录直接执行cmake
- PRIVATE/PUBLIC/INTERFACE
- PUBLIC:当前目标 + 依赖本目标的其他target都会生效
- INTERFACE:仅依赖本目标的target生效,自身不生效
find_package(OpenSSL REQUIRED):REQUIRED代表找不到库直接终止CMake配置,不会静默失败link_directories的缺点:全局生效,现代CMake优先使用导入目标(举个例子OpenSSL::SSL),导入目标自带库路径、头文件路径,不要手动配置link_directories
结尾
uu们,本文的内容到这里就全部结束了,艾莉丝在这里再次
艾莉丝努力练剑
C/C++ & Linux 底层探索者 | 一个正在努力练剑的技术博主
👀 【关注】 跟随我一起深耕技术领域,见证每一次成长。
❤️
【点赞】 让优质内容被更多人看见,让知识传递更有力量。
⭐
【收藏】 把核心知识点存好,在要时随时查、随时用。
💬
【评论】 分享你的经验或疑问,评论区一起交流避坑!
不要忘记给博主“一键四连”哦!
“今日练剑达成!”
“技术之路难免有困惑,但同行的人会让前进更有方向。”
结语:希望对学Linux相关内容的uu有所帮助,不要忘记给博主“一键四连”哦!
往期回顾:
🗡博主在这里放了一只小狗,大家看完了摸摸小狗放松一下吧!🗡
>
૮₍ ˶ ˊ ᴥ ˋ˶₎ა
今天的内容大概就这些,实际开发中大家还会遇到更多细节,欢迎留言分享自己的经验。
评论 (0)
暂无评论