今天翻到一篇不错的技术分享,看完之后自己也琢磨了一下,把思路梳理记录下来。
🎬 个人主页:艾莉丝努力练剑
❄专栏传送门:《C语言》《数据结构与算法》《C/C++干货分享&学过程记录》
《Linux操作系统编程详解》《笔试/面试常见算法:从基础到进阶》《Python干货分享》
⭐️为天地立心,为生民立命,为往圣继绝学,为万世开太平
🎬 艾莉丝的简介:
这篇目录
1.3 sdk/CMakeLists.txt 完整正确代码1.4 关键依赖宏:CPPHTTPLIB_OPENSSL_SUPPORT1.5 编译与安装完整 shell 操作流程1.6 常见报错与排错- 1.6.1 报错:
OpenSSL::SSL target was not found - 1.6.2 cmake 警告:
cmake_minimum_required should be called prior to project() - 1.6.3 权限拒绝 Permission denied
- 1.6.4 GLOB_RECURSE 新增源码不编译
1 ~> ChatSDK CMake 构建静态库完整实现
1.1 业务目标
- 将 ChatSDK 编译为Linux 静态库(
.a),对外交付产物为:头文件 + 静态库文件。 - 通过
make install将库与头文件安装至系统目录/usr/local,实现全局可被其他项目直接引用。 - SDK 目录结构
sdk
├─ CMakeLists.txt # SDK的CMake构建脚本
├─ include # 对外头文件
│ ├─ util
│ ├─ ChatGPTProvider.h
│ ├─ ChatSDK.h
│ ├─ common.h
│ ├─ DataManager.h
│ ├─ DeepSeekProvider.h
│ ├─ GeminiProvider.h
│ ├─ LLMManager.h
│ ├─ LLMProvider.h
│ ├─ OllamaLLMProvider.h
│ └─ SessionManager.h
└─ src # 实现源文件
├─ util
├─ ChatGPTProvider.cpp
├─ ChatSDK.cpp
├─ DataManager.cpp
├─ DeepSeekProvider.cpp
├─ GeminiProvider.cpp
├─ LLMManager.cpp
├─ OllamaLLMProvider.cpp
└─ SessionManager.cpp
1.2 两种源文件管理方式
1.2.1 手动枚举源文件
- 原理:在
add_executable / add_library中显式罗列全部.cpp源码。 - 优点:编译文件清单清晰可控。
- 缺点:新增
.cpp源文件必须手动修改 CMakeLists.txt 添加,遗忘会导致新增文件不参与编译。
add_executable(testLLM
testLLM.cpp
../sdk/src/util/myLog.cpp
../sdk/src/DeepSeekProvider.cpp
../sdk/src/ChatGPTProvider.cpp
../sdk/src/GeminiProvider.cpp
../sdk/src/OllamaLLMProvider.cpp
../sdk/src/DataManager.cpp
../sdk/src/SessionManager.cpp
../sdk/src/LLMManager.cpp
../sdk/src/ChatSDK.cpp
)
1.2.2 file (GLOB_RECURSE) 自动收集源码
- 原理:递归遍历指定目录,通配符匹配后缀文件,存入 CMake 变量。
留意:GLOB 不会监测磁盘文件变更,新增源文件要重新执行cmake ..才会被识别。
# 递归收集src目录所有cpp源文件
file(GLOB_RECURSE SDK_SOURCES "src/*.cpp")
# 递归收集include目录所有h头文件
file(GLOB_RECURSE SDK_HEADERS "include/*.h")
1.3 sdk/CMakeLists.txt 完整正确代码
# CMake最低版本约束,必须放在文件最开头
cmake_minimum_required(VERSION 3.10)
# 项目定义
project(ai_chat_sdk)
# SDK名称变量
set(SDK_NAME "ai_chat_sdk")
# C++标准配置
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 构建类型:Release发布版本
set(CMAKE_BUILD_TYPE Release)
# 递归收集源码与头文件
file(GLOB_RECURSE SDK_SOURCES "src/*.cpp")
file(GLOB_RECURSE SDK_HEADERS "include/*.h")
# 生成静态库 STATIC代表静态库
add_library(${SDK_NAME} STATIC
${SDK_SOURCES}
${SDK_HEADERS}
)
# 设置编译产物输出目录
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/build)
# 头文件搜索路径 PUBLIC:使用者也会继承该头文件路径
target_include_directories(${SDK_NAME} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include
)
# HTTPS支持宏定义,启用cpp‑httplib的OpenSSL能力
target_compile_definitions(${SDK_NAME} PUBLIC
CPPHTTPLIB_OPENSSL_SUPPORT
)
# 查找OpenSSL依赖
find_package(OpenSSL REQUIRED)
# 第三方库搜索路径
link_directories(/usr/local/lib)
# 链接依赖库
target_link_libraries(${SDK_NAME}
jsoncpp
fmt
spdlog
sqlite3
OpenSSL::SSL
OpenSSL::Crypto
)
########## install安装规则 make install执行时生效 ##########
# 安装静态库 ARCHIVE专门用于静态库
install(TARGETS ${SDK_NAME}
ARCHIVE DESTINATION lib
)
# 批量安装头文件,复制到/usr/local/include/ai_chat_sdk
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/
DESTINATION include/ai_chat_sdk
FILES_MATCHING PATTERN "*.h"
)
- 关键字说明
add_library(xxx STATIC):构建静态库,产物lib${SDK_NAME}.a。
target_include_directories PUBLIC:本库编译、外部用者编译均可看到该头文件目录;PRIVATE 仅本项目内部生效。target_compile_definitions PUBLIC:宏定义会传递给链接本 SDK 的上层项目。install TARGETS ... ARCHIVE DESTINATION lib:静态库安装到${CMAKE_INSTALL_PREFIX}/lib,默认CMAKE_INSTALL_PREFIX=/usr/local。install DIRECTORY:批量复制 include 下全部.h到系统 include 子目录。
1.4 关键依赖宏:CPPHTTPLIB_OPENSSL_SUPPORT
- cpp‑httplib 库,默认仅支持 HTTP;开启该宏,才会引入 OpenSSL 头文件,启用 HTTPS 能力。
- 源码逻辑:
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT分支内才会#include。 - 宏必须通过
target_compile_definitions定义,不能写在代码内。
1.5 编译与安装完整 shell 操作流程
# 进入sdk源码目录
cd sdk
# 创建构建目录
mkdir build
cd build
# cmake解析构建脚本
cmake ..
# 编译生成静态库libai_chat_sdk.a
make
# 安装到系统目录,修改/usr/local需要root权限
sudo make install
- 安装完成产物位置
/usr/local/lib/libai_chat_sdk.a
- 头文件:
/usr/local/include/ai_chat_sdk/
1.6 常见报错与排错
1.6.1 报错:OpenSSL::SSL target was not found
- 根因:
find_package(OpenSSL REQUIRED)调用缺失,找不到导入目标OpenSSL::SSL。 - 修复:CMake 脚本中添加
find_package(OpenSSL REQUIRED),放在用OpenSSL::SSL之前。
1.6.2 cmake 警告:cmake_minimum_required should be called prior to project()
- 根因:
cmake_minimum_required()写在了project()之后。 - 修复:文件第一行必须写 cmake_minimum_required,再写 project 指令。
1.6.3 权限拒绝 Permission denied
- 现象:直接
make install写/usr/local失败。 - 解决方案:使用
sudo make install提升权限执行安装。
1.6.4 GLOB_RECURSE 新增源码不编译
- 根因:file (GLOB_RECURSE 仅 cmake 解析阶段扫描一次磁盘,后续新增文件不会自动检测。
- 修复:新增源文件后重新执行
cmake ..,再执行 make。
1.7 SDK 对外使用说明
- 其他开发者使用该 ChatSDK:
- 创建 build 目录执行
cmake .. && make && sudo make install。 - 使用者项目直接
#include,链接ai_chat_sdk即可。
1.8 核心概念补充
1.8.1 PUBLIC / PRIVATE / INTERFACE
属性作用域PRIVATE仅当前库编译时生效,不会传递给链接者PUBLIC当前库 + 所有链接该库的上层项目均生效INTERFACE仅链接该库的上层项目生效,本库编译不生效
1.8.2 install 参数释义
ARCHIVE DESTINATION lib:专门对应静态库(.a)。LIBRARY DESTINATION lib:专门对应动态库(.so/.dylib)。RUNTIME DESTINATION bin:可执行程序、Windows 下 dll。CMAKE_INSTALL_PREFIX:安装根目录,默认/usr/local,cmake 可通过-DCMAKE_INSTALL_PREFIX=xxx修改安装路径。
1.8.3 静态库本质
- Linux 静态库
.a本质是.o目标文件归档包;链接阶段完整复制库内代码到最终可执行文件。 - 优点:部署简单,运行时不依赖外部库文件;缺点:可执行文件体积大,库更新要重新编译链接上层程序。
结尾
uu们,本文的内容到这里就全部结束了,艾莉丝在这里再次
艾莉丝努力练剑
C/C++ & Linux 底层探索者 | 一个正在努力练剑的技术博主
👀 【关注】 跟随我一起深耕技术领域,见证每一次成长。
❤️
【点赞】 让优质内容被更多人看见,让知识传递更有力量。
⭐
【收藏】 把核心知识点存好,在要时随时查、随时用。
💬
【评论】 分享你的经验或疑问,评论区一起交流避坑!
不要忘记给博主“一键四连”哦!
“今日练剑达成!”
“技术之路难免有困惑,但同行的人会让前进更有方向。”
结语:希望对学Linux相关内容的uu有所帮助,不要忘记给博主“一键四连”哦!
往期回顾:
🗡博主在这里放了一只小狗,大家看完了摸摸小狗放松一下吧!🗡
>
૮₍ ˶ ˊ ᴥ ˋ˶₎ა
今天的内容大概就这些,实际开发中大家还会遇到更多细节,欢迎留言分享自己的经验。
评论 (0)
暂无评论