使用CMake发布模块化库包的三类技术问题求助
问题描述
我要搭建一个类似Boost的模块化库lib-ezpz,用来收纳后续编写的实用代码,新项目里可以按需使用,每个功能类别对应独立库文件(比如文件操作类的libEzPzFileIO.lib、数学类的LibEzPzMath.lib)。当前文件夹结构如下:
EzPz/ ├── fileio/ │ ├── parser.h │ └── parser.cpp ├── math/ │ └── basicops.h └── CMakeLists.txt
遇到三个技术问题:
- 项目构建后,build目录只生成编译后的库文件,需要实现类似Linux
make install或Windows的功能,把头文件和库文件一起发布到指定目录(比如/usr/lib等); - 希望输出有合理的目录结构,每个库文件存放在独立子目录,但当前CMake把所有文件直接放在build根目录;
- 仅头文件的数学模板库编译正常,但build目录没生成对应的库文件。
原文件内容:
fileio/parser.h
#pragma once #include <iostream> #include <vector> namespace EzPz::FileIO::Parser { std::vector<std::vector<std::string>> parseCsvFile(); }
fileio/parser.cpp
#include "parser.h" namespace EzPz::FileIO::Parser { std::vector<std::vector<std::string>> parseCsvFile() { return { {"line one", "haha", "hoho"}, {"line two", "hihi", "weewee"} }; } }
math/basicops.h
#pragma once namespace EzPz::Math::BasicOperations { template<typename T> T addValues(const T& lhs, const T& rhs) { return (lhs + rhs); } }
原CMake文件
cmake_minimum_required(VERSION 3.0) project(EzPz) set(CMAKE_CXX_STANDARD 17) # Library for FILE IO Oeprations add_library(EzPzFileIo fileio/parser.cpp) # Library for MATH stuff (header only) add_library(EzPzMath STATIC math/basicops.h) set_target_properties(EzPzMath PROPERTIES LINKER_LANGUAGE CXX) target_compile_definitions(EzPzMath PRIVATE "haha")
解决方案
下面是修改后的CMakeLists.txt,一次性解决三个问题:
cmake_minimum_required(VERSION 3.14) # 升级到更现代的版本,支持更多实用特性 project(EzPz LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 设置默认安装目录,可通过cmake -DCMAKE_INSTALL_PREFIX=/your/path自定义 if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX "/usr/local" CACHE PATH "Install prefix" FORCE) endif() # -------------------------- # 文件操作库 EzPzFileIo # -------------------------- add_library(EzPzFileIo STATIC fileio/parser.cpp) # 指定build目录下的输出子目录 set_target_properties(EzPzFileIo PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib/EzPzFileIo" LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib/EzPzFileIo" RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/EzPzFileIo" ) # 安装库文件到系统目录的对应子文件夹 install(TARGETS EzPzFileIo ARCHIVE DESTINATION lib/EzPzFileIo LIBRARY DESTINATION lib/EzPzFileIo RUNTIME DESTINATION bin/EzPzFileIo ) # 安装头文件到系统include目录的EzPz/fileio子目录 install(FILES fileio/parser.h DESTINATION include/EzPz/fileio ) # -------------------------- # 仅头文件数学库 EzPzMath # -------------------------- # 仅头文件库用INTERFACE类型,无需编译生成二进制文件 add_library(EzPzMath INTERFACE) # 配置头文件搜索路径,让依赖项目能找到模板头文件 target_include_directories(EzPzMath INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/math> $<INSTALL_INTERFACE:include/EzPz/math> ) # 安装头文件到系统目录,同时导出目标方便其他项目引用 install(TARGETS EzPzMath EXPORT EzPzMathTargets INCLUDES DESTINATION include/EzPz/math ) install(FILES math/basicops.h DESTINATION include/EzPz/math ) install(EXPORT EzPzMathTargets FILE EzPzMathTargets.cmake DESTINATION lib/cmake/EzPzMath )
针对三个问题的具体说明
问题1:实现头文件+库文件的安装发布
- 用
install(TARGETS ...)处理库文件安装,install(FILES ...)处理头文件安装; - 默认安装到
/usr/local,可以通过cmake .. -DCMAKE_INSTALL_PREFIX=/your/custom/path指定自定义目录; - 执行
make install(Linux)或在VS中运行INSTALL目标(Windows)即可完成发布。
问题2:每个库文件存放在独立子目录
- 通过
set_target_properties的ARCHIVE/LIBRARY/RUNTIME_OUTPUT_DIRECTORY参数,指定build目录下的子文件夹; - 安装时通过
DESTINATION参数,让系统目录下的库也按模块分类存放。
问题3:仅头文件模板库无输出文件的问题
- 模板库不需要编译二进制文件,改用
INTERFACE类型库替代STATIC; INTERFACE库专门用来管理头文件路径、编译选项等依赖,符合仅头文件库的特性;- 通过
target_include_directories配置头文件搜索路径,确保依赖项目能正确引用模板代码。
内容的提问来源于stack exchange,提问作者DEKKER
相关产品推荐
相关产品推荐

