You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何编写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_NAME vs PROJECT_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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 07:46:55