当前位置: 首页 > news >正文

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

LuckiBit

目录

  • 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. 使用总结
    • 相关文章:

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. 构建前目录结构

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

#ifndef A_LIB_H
#define A_LIB_H// 输出一个测试消息
void a_print(void);#endif

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

#include <stdio.h>
#include "a_lib.h"void a_print(void) {printf("Hello from A library!\n");
}

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

#include "a_lib.h"int main() {a_print();  // 测试 A 库函数return 0;
}

3.4 CMake 配置文件 A/CMakeLists.txt

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}TargetsARCHIVE 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}TargetsFILE ${A_PROJECT_NAME}Targets.cmakeNAMESPACE ${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

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

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

4.1 主程序 B/main.c

#include "a_lib.h"int main() {a_print();  // 调用 A 库的函数return 0;
}

4.2 CMake 配置文件 B/CMakeLists.txt

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 项目测试构建

cd A
mkdir build_test && cd build_test
cmake .. -DBUILD_LIB_A=OFF
cmake --build .
./a_test           # 输出: Hello from A library!

5.2 A 项目生成库并安装

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)

cd ../../B
mkdir build && cd build
cmake ..
cmake --build .
./B_exec           # 输出: Hello from A library!

6. 构建后目录结构

6.1 项目 A

测试构建 (A/build_test/)

build_test/
├── a_test
├── CMakeFiles/...
└── Makefile / ninja.build

安装导出 (A_export/)

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

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) 即可自动引入头文件和库

  1. 本节内容已经全部介绍完毕,希望通过这篇文章,大家对 CMake 有了更深入的理解和认识。
  2. 感谢各位的阅读和支持,如果觉得这篇文章对你有帮助,请不要吝惜你的点赞和评论,这对我们非常重要。再次感谢大家的关注和支持!点我关注❤️

相关文章:

  • 指针的神秘探险:从入门到精通的奇幻之旅 !
http://www.dtcms.com/a/286331.html

相关文章:

  • 基于MATLAB的朴素贝叶斯NB的数据分类预测方法应用
  • 一种新颖的可解释人工智能框架,用于整合统计、视觉和基于规则的方法进行医学图像分类|文献速递-医学影像算法文献分享
  • Flutter ScaffoldMessenger 详细介绍
  • P1205 [USACO1.2] 方块转换 Transformations
  • 《通信原理》学习笔记——第四章
  • 【论文阅读】BEVFusion: A Simple and Robust LiDAR-Camera Fusion Framework
  • Redis——BigKey
  • Radix-4 Booth乘法器计算步骤
  • 【AI论文】CLiFT:面向计算高效与自适应神经渲染的压缩光场标记
  • vue2 面试题及详细答案150道(41 - 60)
  • Node.js链接MySql
  • Vue常见指令
  • Java大厂面试实录:从Spring Boot到AI微服务架构的深度解析
  • 深度学习零基础入门(3)-图像与神经网络
  • UE5 一些关于过场动画sequencer,轨道track的一些Python操作
  • 力扣347:前K个高频元素
  • 科技照亮童心|激光院与跳伞塔社区开展公益活动
  • Day24| 93.复原IP地址、78.子集、90.子集II
  • NIO简单介绍和运用
  • MySQL计数函数count原理分析
  • 深入理解Linux文件I/O:系统调用与标志位应用
  • 区块链加密技术全景解析
  • 高效VLP蛋白表达|病毒样颗粒生产|疫苗研发平台
  • 【无标题】标准模型粒子行为与11维拓扑量子色动力学模型严格对应的全面论述
  • 文献分享0719
  • MyBatis:配置文件完成增删改查_添加
  • 智慧后厨检测算法构建智能厨房防护网
  • 零基础入门:用按键精灵实现视频自动操作(附完整脚本)
  • C语言:数组
  • MySQL的关键日志