如何编写C++库顶层CMakeLists.txt:兼顾外部引用与Demo构建
兼顾库引用与单独构建Demo的CMake配置方案
我经常帮人处理这类库开发的CMake配置需求,刚好可以给你一套成熟的方案,完美适配两种场景:
核心思路
我们需要让CMake能区分「当前库是作为子项目被其他工程引用」和「当前库是单独构建」这两种情况,只在单独构建时自动编译Demo,同时保证库本身在两种场景下都能正常被使用。
顶层CMakeLists.txt 完整示例
# 最低CMake版本要求,根据你的实际需求调整 cmake_minimum_required(VERSION 3.14) # 定义库项目名称 project(MyAwesomeLib LANGUAGES CXX) # 设置C++标准,按需调整 set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) # -------------------------- # 1. 定义库本身的核心配置 # -------------------------- # 收集库的源文件(这里假设你的源文件都在src目录下) file(GLOB_RECURSE LIB_SOURCES src/*.cpp) file(GLOB_RECURSE LIB_HEADERS include/*.hpp) # 创建库目标(静态库或动态库,按需改STATIC为SHARED) add_library(${PROJECT_NAME} STATIC ${LIB_SOURCES} ${LIB_HEADERS}) # 设置库的头文件目录,PUBLIC意味着引用这个库的项目也能访问这些头文件 target_include_directories(${PROJECT_NAME} PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> $<INSTALL_INTERFACE:include> ) # 如果有编译选项,也可以在这里设置,比如警告等级 target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Wpedantic ) # -------------------------- # 2. 条件编译Demo项目 # -------------------------- # 定义一个选项,控制是否构建Demo,默认关闭 option(BUILD_DEMO "Build the demo application for MyAwesomeLib" OFF) # 关键判断:只有当当前项目是顶层构建项目时,才自动开启Demo编译 if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) set(BUILD_DEMO ON CACHE BOOL "Build the demo application for MyAwesomeLib" FORCE) endif() # 如果开启了BUILD_DEMO,就添加Demo子项目 if(BUILD_DEMO) # 假设Demo代码在demo目录下,这里也可以直接用add_executable写Demo的配置 add_subdirectory(demo) message(STATUS "Demo project enabled: will build alongside the library") endif()
Demo目录的CMakeLists.txt 示例(demo/CMakeLists.txt)
# 创建Demo可执行文件 add_executable(MyAwesomeLibDemo main.cpp) # 链接我们的库 target_link_libraries(MyAwesomeLibDemo PRIVATE MyAwesomeLib) # 如果Demo有自己的头文件或编译选项,也可以在这里添加 target_include_directories(MyAwesomeLibDemo PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
关键细节解释
CMAKE_PROJECT_NAMEvsPROJECT_NAME:
当你的库被其他项目通过add_subdirectory(MyAwesomeLib)引入时,CMAKE_PROJECT_NAME是上层项目的名称,而PROJECT_NAME是你的库的名称(MyAwesomeLib),两者不相等,所以BUILD_DEMO保持OFF,不会编译Demo;当你单独在库的根目录执行cmake ..时,两者名称一致,自动把BUILD_DEMO设为ON,编译Demo。option的灵活性:
即使是单独构建,你也可以通过cmake -DBUILD_DEMO=OFF ..手动关闭Demo编译,适配不同的开发需求。BUILD_INTERFACE和INSTALL_INTERFACE:
这两个是为了支持库的安装和导出(如果后续需要用find_package引用的话),如果暂时不需要安装,也可以简化成target_include_directories(${PROJECT_NAME} PUBLIC include)。
额外建议
- 如果你的库是纯头文件库(只有.h/.hpp),可以把
add_library改成add_library(${PROJECT_NAME} INTERFACE),然后用target_sources添加头文件,逻辑完全通用。 - 建议把库的源文件收集方式改成手动列出(比如
src/a.cpp src/b.cpp),比GLOB更可靠,避免CMake遗漏新增的文件。
内容的提问来源于stack exchange,提问作者Kryx
相关产品推荐
相关产品推荐

