CMake构建学习笔记-SQLite库的构建

发布时间:2026/7/27 20:22:13
CMake构建学习笔记-SQLite库的构建 CMake构建学习笔记-SQLite库的构建一、CMake与SQLite基础概念### 1.1 什么是CMakeCMake是一个跨平台的构建工具它通过CMakeLists.txt文件描述项目的构建过程并生成对应平台的Makefile或项目文件如Visual Studio解决方案。相比直接编写MakefileCMake提供了更简洁、可移植的构建方案特别适合管理依赖关系复杂的C/C项目。### 1.2 什么是SQLiteSQLite是一个轻量级的嵌入式关系数据库引擎它不需要独立的服务器进程数据直接存储在单个磁盘文件中。SQLite的源代码是C语言编写的在嵌入式系统、移动应用和桌面软件中广泛使用。### 1.3 为什么要用CMake构建SQLiteSQLite官方手册推荐直接包含其源代码文件sqlite3.c和sqlite3.h到项目中但这种方式在大型项目或需要跨平台编译时存在弊端- 缺乏灵活的编译选项控制如线程安全、内存分配器- 难以集成到现代CMake项目的依赖管理流程中- 不利于版本管理和自动化构建通过CMake构建SQLite库可以- 使用CMake的option命令控制编译特性- 自动处理平台差异- 生成可复用的库文件静态库或动态库—## 二、从零开始构建SQLite库### 2.1 准备工作首先从SQLite官网下载源代码包sqlite-amalgamation-3450200.zip解压后得到以下核心文件-sqlite3.c合并后的SQLite实现-sqlite3.h头文件-sqlite3ext.h扩展接口头文件可选### 2.2 创建基础的CMakeLists.txt在解压目录下创建CMakeLists.txt文件这是CMake构建的核心cmake# CMakeLists.txt - 基础版本cmake_minimum_required(VERSION 3.10)project(SQLite3 VERSION 3.45.2 LANGUAGES C)# 定义库目标从单个源文件编译静态库add_library(sqlite3 STATIC sqlite3.c)# 指定头文件路径当前目录target_include_directories(sqlite3 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})# 启用线程安全支持默认开启target_compile_definitions(sqlite3 PRIVATE SQLITE_THREADSAFE1 # 1表示线程安全0表示单线程)# 设置输出目录set_target_properties(sqlite3 PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)### 2.3 构建与测试在终端中执行以下命令bashmkdir build cd buildcmake ..cmake --build . --config Release构建成功后会在build/lib目录下生成libsqlite3.aLinux或sqlite3.libWindows。—## 三、高级用法定制编译选项### 3.1 为什么需要定制选项SQLite提供了大量编译时选项来优化不同场景-SQLITE_DEFAULT_CACHE_SIZE默认缓存大小-SQLITE_ENABLE_FTS5启用全文搜索-SQLITE_OMIT_LOAD_EXTENSION禁用扩展加载### 3.2 增强版CMakeLists.txt以下代码展示了如何使用CMake的option命令暴露编译选项cmake# CMakeLists.txt - 高级版本cmake_minimum_required(VERSION 3.15)project(SQLite3 VERSION 3.45.2 LANGUAGES C)# 编译选项 option(SQLITE_ENABLE_THREADS 启用线程安全 ON) # 默认开启option(SQLITE_ENABLE_FTS5 启用全文搜索5 OFF) # 默认关闭option(SQLITE_OMIT_LOAD_EXTENSION 禁用扩展加载 OFF) # 默认允许加载# 库目标定义 add_library(sqlite3 STATIC sqlite3.c)target_include_directories(sqlite3 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})# 条件编译定义 # 根据选项添加预处理器定义if(SQLITE_ENABLE_THREADS) target_compile_definitions(sqlite3 PRIVATE SQLITE_THREADSAFE1)else() target_compile_definitions(sqlite3 PRIVATE SQLITE_THREADSAFE0)endif()if(SQLITE_ENABLE_FTS5) target_compile_definitions(sqlite3 PRIVATE SQLITE_ENABLE_FTS5)endif()if(SQLITE_OMIT_LOAD_EXTENSION) target_compile_definitions(sqlite3 PRIVATE SQLITE_OMIT_LOAD_EXTENSION)endif()# 输出配置 set_target_properties(sqlite3 PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib # 设置C标准SQLite需要C99以上 C_STANDARD 99 C_STANDARD_REQUIRED ON)# 安装规则可选 install(TARGETS sqlite3 ARCHIVE DESTINATION lib LIBRARY DESTINATION lib)install(FILES sqlite3.h sqlite3ext.h DESTINATION include)### 3.3 使用自定义选项构建现在可以通过-D参数控制编译特性bashmkdir build_fts5 cd build_fts5cmake .. -DSQLITE_ENABLE_FTS5ON -DSQLITE_ENABLE_THREADSOFFcmake --build .这样生成的库将包含FTS5全文搜索功能但禁用线程安全。—## 四、集成SQLite到其他项目### 4.1 作为外部依赖使用创建另一个项目MyApp在它的CMakeLists.txt中引用SQLite库cmake# MyApp/CMakeLists.txtcmake_minimum_required(VERSION 3.10)project(MyApp LANGUAGES CXX)# 指定SQLite库路径set(SQLITE3_DIR ../sqlite3-build CACHE PATH SQLite3构建目录)# 导入已构建的库add_library(sqlite3 STATIC IMPORTED)set_target_properties(sqlite3 PROPERTIES IMPORTED_LOCATION ${SQLITE3_DIR}/lib/libsqlite3.a INTERFACE_INCLUDE_DIRECTORIES ${SQLITE3_DIR}/../sqlite3-src)# 创建应用程序目标add_executable(myapp main.cpp)# 链接SQLitetarget_link_libraries(myapp PRIVATE sqlite3)### 4.2 验证集成的C示例创建main.cpp测试数据库操作cpp// main.cpp - 测试SQLite数据库操作#include iostream#include sqlite3.hint main() { sqlite3* db nullptr; char* errMsg nullptr; // 1. 打开数据库如果不存在则创建 int rc sqlite3_open(test.db, db); if (rc ! SQLITE_OK) { std::cerr 无法打开数据库: sqlite3_errmsg(db) std::endl; return 1; } // 2. 创建表 const char* createSQL CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, age INTEGER );; rc sqlite3_exec(db, createSQL, nullptr, nullptr, errMsg); if (rc ! SQLITE_OK) { std::cerr SQL错误: errMsg std::endl; sqlite3_free(errMsg); } else { std::cout 表创建成功 std::endl; } // 3. 插入数据 const char* insertSQL INSERT INTO users (name, age) VALUES (张三, 25);; rc sqlite3_exec(db, insertSQL, nullptr, nullptr, errMsg); if (rc ! SQLITE_OK) { std::cerr 插入失败: errMsg std::endl; sqlite3_free(errMsg); } // 4. 查询数据 sqlite3_stmt* stmt nullptr; const char* querySQL SELECT id, name, age FROM users;; rc sqlite3_prepare_v2(db, querySQL, -1, stmt, nullptr); if (rc SQLITE_OK) { while (sqlite3_step(stmt) SQLITE_ROW) { int id sqlite3_column_int(stmt, 0); const char* name reinterpret_castconst char*(sqlite3_column_text(stmt, 1)); int age sqlite3_column_int(stmt, 2); std::cout 用户: id id , 姓名 name , 年龄 age std::endl; } } sqlite3_finalize(stmt); // 5. 关闭数据库 sqlite3_close(db); std::cout 数据库操作完成 std::endl; return 0;}—## 五、总结通过本文的学习我们掌握了使用CMake构建SQLite库的完整流程1.基础构建从简单的add_library开始理解CMake构建静态库的基本模式2.选项定制利用option和target_compile_definitions灵活控制SQLite的编译特性如线程安全、全文搜索等3.跨项目集成通过IMPORTED目标或find_package机制将SQLite作为外部依赖引入其他项目CMake的价值在于它抽象了平台差异让我们可以专注于项目逻辑而非构建细节。对于SQLite这样的库使用CMake管理其构建过程可以更高效地适配不同项目需求同时保持构建系统的可维护性。建议读者在实际项目中尝试扩展更多编译选项如SQLITE_ENABLE_COLUMN_METADATA并探索使用FetchContent模块自动下载SQLite源码的现代化方式。