首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【CMake】CMake 项目打包与 find_package 使用流程:从 A 到 B 的完整范例

【CMake】CMake 项目打包与 find_package 使用流程:从 A 到 B 的完整范例

作者头像
LuckiBit
发布2025-07-19 10:23:24
发布2025-07-19 10:23:24
18700
代码可运行
举报
文章被收录于专栏:C语言C语言
运行总次数:0
代码可运行

1. 项目概述

本示例展示了如何使用 CMake 创建一个 C 语言静态库项目(A),并在 另一个完全独立的项目(B) 中通过 find_package() 使用该库。

特性:

  1. 项目 A
    • 提供 a_lib
    • 自带 main.c 测试程序
    • 控制是否生成库(通过 BUILD_LIB_A 开关)
    • 安装时导出头文件、库文件和 CMake 配置文件
  2. 项目 B
    • 无需 A 的源码
    • 通过 find_package(A) 自动找到 A 的头文件和库
    • 直接调用 A 提供的接口函数

2. 构建前目录结构

代码语言:javascript
代码运行次数:0
运行
复制
project_root/
├── A/                      # 项目 A:开发者 A 创建的库
│   ├── include/
│   │   └── a_lib.h         # 库的头文件
│   ├── src/
│   │   ├── a_lib.c         # 库的实现
│   │   └── main.c          # A 的测试用程序
│   ├── CMakeLists.txt
│   └── AConfig.cmake.in
├── B/                      # 项目 B:开发者 B 使用库
│   ├── main.c
│   └── CMakeLists.txt

3. 项目 A:源代码与构建文件

3.1 头文件 A/include/a_lib.h

代码语言:javascript
代码运行次数:0
运行
复制
#ifndef A_LIB_H
#define A_LIB_H

// 输出一个测试消息
void a_print(void);

#endif

3.2 库实现文件 A/src/a_lib.c

代码语言:javascript
代码运行次数:0
运行
复制
#include <stdio.h>
#include "a_lib.h"

void a_print(void) {
    printf("Hello from A library!\n");
}

3.3 测试程序 A/src/main.c

代码语言:javascript
代码运行次数:0
运行
复制
#include "a_lib.h"

int main() {
    a_print();  // 测试 A 库函数
    return 0;
}

3.4 CMake 配置文件 A/CMakeLists.txt

代码语言:javascript
代码运行次数:0
运行
复制
cmake_minimum_required(VERSION 3.14)
project(A LANGUAGES C)

# === 变量管理 ===
set(A_PROJECT_NAME       A)
set(A_TARGET_NAME        a_lib)
set(A_TEST_TARGET        a_test)
set(A_VERSION            1.0.0)
set(A_HEADER_DIR         ${CMAKE_CURRENT_SOURCE_DIR}/include)
set(A_SRC_DIR            ${CMAKE_CURRENT_SOURCE_DIR}/src)
set(A_HEADERS            ${A_HEADER_DIR}/a_lib.h)
set(A_SOURCES            ${A_SRC_DIR}/a_lib.c)
set(A_TEST_SOURCE        ${A_SRC_DIR}/main.c)

# 控制是否生成库
option(BUILD_LIB_A "Build A as library" OFF)

# 测试可执行文件
add_executable(${A_TEST_TARGET} ${A_TEST_SOURCE} ${A_SOURCES})
target_include_directories(${A_TEST_TARGET} PRIVATE ${A_HEADER_DIR})

# 库构建与安装
if(BUILD_LIB_A)
    add_library(${A_TARGET_NAME} STATIC ${A_SOURCES})
    target_include_directories(${A_TARGET_NAME}
        PUBLIC
            $<BUILD_INTERFACE:${A_HEADER_DIR}>
            $<INSTALL_INTERFACE:include>
    )

    include(GNUInstallDirs)

    install(TARGETS ${A_TARGET_NAME}
        EXPORT ${A_PROJECT_NAME}Targets
        ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
        LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
        RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
    )

    install(DIRECTORY ${A_HEADER_DIR}/
        DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
    )

    install(EXPORT ${A_PROJECT_NAME}Targets
        FILE ${A_PROJECT_NAME}Targets.cmake
        NAMESPACE ${A_PROJECT_NAME}::
        DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${A_PROJECT_NAME}
    )

    include(CMakePackageConfigHelpers)
    write_basic_package_version_file(
        "${CMAKE_CURRENT_BINARY_DIR}/${A_PROJECT_NAME}ConfigVersion.cmake"
        VERSION ${A_VERSION}
        COMPATIBILITY AnyNewerVersion
    )

    configure_package_config_file(
        ${CMAKE_CURRENT_SOURCE_DIR}/${A_PROJECT_NAME}Config.cmake.in
        "${CMAKE_CURRENT_BINARY_DIR}/${A_PROJECT_NAME}Config.cmake"
        INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${A_PROJECT_NAME}
    )

    install(FILES
        "${CMAKE_CURRENT_BINARY_DIR}/${A_PROJECT_NAME}Config.cmake"
        "${CMAKE_CURRENT_BINARY_DIR}/${A_PROJECT_NAME}ConfigVersion.cmake"
        DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${A_PROJECT_NAME}
    )
endif()

3.5 AConfig 模板 A/AConfig.cmake.in

代码语言:javascript
代码运行次数:0
运行
复制
@PACKAGE_INIT@

include("${CMAKE_CURRENT_LIST_DIR}/@A_PROJECT_NAME@Targets.cmake")

4. 项目 B:源代码与构建文件

4.1 主程序 B/main.c

代码语言:javascript
代码运行次数:0
运行
复制
#include "a_lib.h"

int main() {
    a_print();  // 调用 A 库的函数
    return 0;
}

4.2 CMake 配置文件 B/CMakeLists.txt

代码语言:javascript
代码运行次数:0
运行
复制
cmake_minimum_required(VERSION 3.14)
project(B LANGUAGES C)

# === 变量定义 ===
set(B_EXECUTABLE_NAME     B_exec)
set(B_SOURCE_FILE         ${CMAKE_CURRENT_SOURCE_DIR}/main.c)
set(A_PROJECT_NAME        A)
set(A_TARGET_NAME         a_lib)
set(A_INSTALL_DIR         ${CMAKE_CURRENT_SOURCE_DIR}/../A_export)

# 告诉 CMake 去哪里找 A
set(CMAKE_PREFIX_PATH "${A_INSTALL_DIR}")

find_package(${A_PROJECT_NAME} REQUIRED)

add_executable(${B_EXECUTABLE_NAME} ${B_SOURCE_FILE})
target_link_libraries(${B_EXECUTABLE_NAME} PRIVATE ${A_PROJECT_NAME}::${A_TARGET_NAME})

5. 构建步骤

5.1 A 项目测试构建

代码语言:javascript
代码运行次数:0
运行
复制
cd A
mkdir build_test && cd build_test
cmake .. -DBUILD_LIB_A=OFF
cmake --build .
./a_test           # 输出: Hello from A library!

5.2 A 项目生成库并安装

代码语言:javascript
代码运行次数:0
运行
复制
cd ..
mkdir build_install && cd build_install
cmake .. -DBUILD_LIB_A=ON -DCMAKE_INSTALL_PREFIX=../../A_export
cmake --build .
cmake --install .

5.3 B 项目构建(使用 A)

代码语言:javascript
代码运行次数:0
运行
复制
cd ../../B
mkdir build && cd build
cmake ..
cmake --build .
./B_exec           # 输出: Hello from A library!

6. 构建后目录结构

6.1 项目 A

测试构建 (A/build_test/)
代码语言:javascript
代码运行次数:0
运行
复制
build_test/
├── a_test
├── CMakeFiles/...
└── Makefile / ninja.build
安装导出 (A_export/)
代码语言:javascript
代码运行次数:0
运行
复制
A_export/
├── include/
│   └── a_lib.h
├── lib/
│   ├── liba_lib.a (或 a_lib.lib/.so/.dll,视平台而定)
│   └── cmake/
│       └── A/
│           ├── AConfig.cmake
│           ├── AConfigVersion.cmake
│           └── ATargets.cmake

6.2 项目 B

代码语言:javascript
代码运行次数:0
运行
复制
B/build/
├── B_exec
├── CMakeFiles/...
└── Makefile / ninja.build

7. 使用总结

  1. 开发者 A
    • 开发和测试 A
    • 在测试通过后,用 cmake --install 导出 A_export/
    • A_export/ 提供给 B(打包 zip 或共享)
  2. 开发者 B
    • 不需要 A 源码
    • 只要设置 CMAKE_PREFIX_PATH 指向 A_export/
    • 使用 find_package(A) 即可自动引入头文件和库
  3. 本节内容已经全部介绍完毕,希望通过这篇文章,大家对 CMake 有了更深入的理解和认识。
  4. 感谢各位的阅读和支持,如果觉得这篇文章对你有帮助,请不要吝惜你的点赞和评论,这对我们非常重要。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-07-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 项目概述
  • 2. 构建前目录结构
  • 3. 项目 A:源代码与构建文件
    • 3.1 头文件 A/include/a_lib.h
    • 3.2 库实现文件 A/src/a_lib.c
    • 3.3 测试程序 A/src/main.c
    • 3.4 CMake 配置文件 A/CMakeLists.txt
    • 3.5 AConfig 模板 A/AConfig.cmake.in
  • 4. 项目 B:源代码与构建文件
    • 4.1 主程序 B/main.c
    • 4.2 CMake 配置文件 B/CMakeLists.txt
  • 5. 构建步骤
    • 5.1 A 项目测试构建
    • 5.2 A 项目生成库并安装
    • 5.3 B 项目构建(使用 A)
  • 6. 构建后目录结构
    • 6.1 项目 A
      • 测试构建 (A/build_test/)
      • 安装导出 (A_export/)
    • 6.2 项目 B
  • 7. 使用总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档