你能学到什么?

朋友们好久不见,我是alibli,好久没有更新博客了。今天本人将通过构造一个实际的虚拟小项目,来让你彻底掌握CMake跨平台工程构建,学会CMakeLists.txt语法。该项目实现了一个简单的平方、立方的计算程序,只为演示工程构建方法。

每一行代码都会有非常非常详细的解释!

你将掌握如下内容:

  1. 构建静态库
  2. 构建动态库
  3. 构建可执行程序
  4. 动态库如何调用静态库
  5. 可执行程序如何调用动态库

项目整体构建

项目目录:

calculator_project/
├── CMakeLists.txt                 # 外层主 CMake 文件
├── math_utils/                    # 静态库源码
│   ├── CMakeLists.txt
│   ├── MathUtils.h
│   └── MathUtils.cpp
├── calculator/                    # 动态库(依赖静态库)
│   ├── CMakeLists.txt
│   ├── Calculator.h
│   └── Calculator.cpp
└── app/                           # 主程序├── CMakeLists.txt└── main.cpp

外层CMakeLists.txt

# calculator_project/CMakeLists.txt# 1. 指定项目所需的最低 CMake 版本
#    如果用户系统中的 CMake 版本低于 3.10,会报错
cmake_minimum_required(VERSION 3.10)# 2. 定义项目名称为 "CalculatorProject"
#    LANGUAGES CXX 表示这是一个 C++ 项目
#    CMake 会自动查找 C++ 编译器(如 g++)
project(CalculatorProject LANGUAGES CXX)# 3. 设置 C++ 标准为 C++17
#    要求编译器必须支持 C++17
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)# 4. 禁用编译器特定的扩展(如 GNU 扩展)
#    强制使用标准 C++,提高可移植性
set(CMAKE_CXX_EXTENSIONS OFF)# 5. 启用测试支持(即使现在不用,也先打开)
#    后续可以用 ctest 命令运行测试
enable_testing()# 6. 添加子目录 math_utils
#    CMake 会进入 math_utils/ 目录并读取其 CMakeLists.txt
#    该目录将构建一个静态库
add_subdirectory(math_utils)# 7. 添加子目录 calculator
#    该目录将构建一个动态库,依赖上面的静态库
add_subdirectory(calculator)# 8. 添加子目录 app
#    构建主程序,链接动态库
add_subdirectory(app)

静态库构建

进入math_utils目录

CMakeLists.txt

# calculator_project/math_utils/CMakeLists.txt# 1. 定义一个静态库目标,名为 "math_utils"
#    STATIC 表示生成静态库(.a 文件)
#    源文件列表:MathUtils.cpp
add_library(math_utils STATICMathUtils.cpp
)# 2. 设置目标 math_utils 的头文件搜索路径
#    PUBLIC 表示:
#      - math_utils 自己需要这些头文件(PRIVATE 部分)
#      - 链接 math_utils 的目标也能看到这些头文件(INTERFACE 部分)
#    ${CMAKE_CURRENT_SOURCE_DIR} 是当前目录(即 math_utils/)
#    所以其他代码可以 #include "MathUtils.h"
target_include_directories(math_utilsPUBLIC ${CMAKE_CURRENT_SOURCE_DIR}
)# 3. 关键:启用 PIC,以便被动态库链接
set_target_properties(math_utils PROPERTIESPOSITION_INDEPENDENT_CODE ON
)# 4. 为 math_utils 添加编译定义(可选)
#    这里定义一个宏 MATH_UTILS_VERSION="1.0"
#    在 MathUtils.cpp 中可以用 #ifdef MATH_UTILS_VERSION 条件编译
target_compile_definitions(math_utilsPRIVATE MATH_UTILS_VERSION=\"1.0\"
)# 5. 输出一条状态信息,帮助调试
#    构建时会显示:-- Building static library: math_utils
message(STATUS "Building static library: math_utils")

MathUtils.h

// calculator_project/math_utils/MathUtils.h23 #ifndef MATH_UTILS_H4 #define MATH_UTILS_H56 // 简单的数学工具类(静态库提供)7 class MathUtils {8 public:9     // 计算平方10     static double square(double x);1112     // 计算立方13     static double cube(double x);14 };1516 #endif // MATH_UTILS_H

MathUtils.cpp

// calculator_project/math_utils/MathUtils.cpp#include "MathUtils.h"
#include <iostream>// 实现平方函数
double MathUtils::square(double x) {return x * x;
}// 实现立方函数
double MathUtils::cube(double x) {return x * x * x;
}// 如果定义了版本宏,打印版本(用于验证独立编译)
#ifdef MATH_UTILS_VERSION
#include <iostream>
void print_version() {std::cout << "MathUtils Version: " << MATH_UTILS_VERSION << std::endl;
}
#endif

动态库构建

进入calculator目录

CMakeLists.txt

# calculator_project/calculator/CMakeLists.txt# 1. 定义一个共享库(动态库),名为 "calculator"
#    SHARED 表示生成 .so 文件(Linux)或 .dll(Windows)
#    源文件:Calculator.cpp
add_library(calculator SHAREDCalculator.cpp
)# 2. 设置 calculator 的头文件路径
#    PUBLIC:自己用 + 暴露给使用者
target_include_directories(calculatorPUBLIC ${CMAKE_CURRENT_SOURCE_DIR}
)# 3. 链接依赖:calculator 依赖 math_utils 静态库
#    PRIVATE 表示 math_utils 仅 calculator 内部使用,不暴露给主程序
#    但主程序仍能通过 calculator 调用 MathUtils 的功能
target_link_libraries(calculatorPRIVATE math_utils
)# 4. 为动态库添加版本号
#    这会影响生成的文件名,如 libcalculator.so.1.0
set_target_properties(calculator PROPERTIESVERSION 1.0SOVERSION 1
)# 5. 输出状态信息
message(STATUS "Building shared library: calculator (depends on math_utils)")

Caculator.h

// calculator_project/calculator/Calculator.h#ifndef CALCULATOR_H
#define CALCULATOR_H// 计算器类,使用 MathUtils 提供的功能
class Calculator {
public:// 计算一个数的平方(调用静态库)double square(double x);// 计算一个数的立方(调用静态库)double cube(double x);
};#endif // CALCULATOR_H

Caculator.cpp

// calculator_project/calculator/Calculator.cpp#include "Calculator.h"
#include "MathUtils.h"  // 包含静态库头文件// 使用 MathUtils::square
double Calculator::square(double x) {return MathUtils::square(x);
}// 使用 MathUtils::cube
double Calculator::cube(double x) {return MathUtils::cube(x);
}

可执行程序构建

进入app

CMakeLists.txt

# calculator_project/app/CMakeLists.txt# 1. 创建可执行文件 "app",源文件 main.cpp
add_executable(appmain.cpp
)# 2. 链接 app 与动态库 calculator
#    PRIVATE:仅 app 使用
target_link_libraries(appPRIVATE calculator
)# 3. 确保 app 能找到 calculator 的头文件
#    因为 calculator 的 PUBLIC include 路径会被继承
target_include_directories(appPRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
)# 4. 添加一个测试(可选)
#    创建一个测试,运行 app
add_test(NAME test_app_runCOMMAND app
)

main.cpp

// calculator_project/app/main.cpp#include "Calculator.h"
#include <iostream>int main() {Calculator calc;std::cout << "Square of 5: " << calc.square(5) << std::endl;   // 25std::cout << "Cube of 3: " << calc.cube(3) << std::endl;       // 27return 0;
}

构建&测试

进入根目录,即calculator_project目录

构建,为了保持工作目录干净新建build目录。

mkdir build
cd build
cmake ..
make

运行

./app/app

运行结果显示为

Square of 5: 25
Cube of 3: 27

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/96626.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/96626.shtml
英文地址,请注明出处:http://en.pswp.cn/web/96626.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

高并发场景下限流算法实践与性能优化指南

高并发场景下限流算法实践与性能优化指南 在大规模并发访问环境中&#xff0c;合理的限流策略能保护后端服务稳定运行&#xff0c;避免系统因瞬时高并发导致资源耗尽或崩溃。本文将从原理出发&#xff0c;深入解析几种主流限流算法&#xff0c;并结合Java和Redis给出完整可运行…

Vue3应用执行流程详解

精确化的完整执行流程 (以 Vite Vue3 SPA 为例)整个过程可以分为两部分&#xff1a;首次访问的“冷启动”和后续的Vue应用接管。第一部分&#xff1a;首次访问与页面加载客户端&#xff1a;发送请求用户打开浏览器&#xff0c;输入 URL&#xff08;如 http://localhost:5173&a…

Redis 持久化与高可用实践(RDB / AOF / Sentinel / Cluster 全解析)

这篇是我把几套生产环境踩坑与复盘整理成的一份“从 0 到 1 长期可维护”的实践文。目标是&#xff1a;明确策略、给出默认可用的配置模板、把常见坑一次讲透。 适用场景&#xff1a;新项目选型、老项目稳定性加固、从单机迁移到 HA/Cluster、应对数据安全与故障切换要求。目录…

Linux内核的PER_CPU机制

参考书《Linux内核模块开发技术指南》 1.原理 在多核CPU的情况下&#xff0c;为了提高CPU并发执行的效率&#xff0c;对于某些不是必须要在核间进行同步访问的资源&#xff0c;可以为每一个CPU创建一个副本&#xff0c;让每个CPU都访问自身的数据副本&#xff0c;而不是通过加锁…

VSCode 的百度 AI编程插件

VSCode 的百度 AI编程插件主要是 Baidu Comate&#xff08;文心快码&#xff09;&#xff0c;这是一款基于文心大模型的新一代编码辅助工具&#xff0c;旨在提升开发者的编码效率&#xff0c;让写代码变得更简单。以下是关于 Baidu Comate 的详细介绍&#xff1a; 一、功能特点…

阿里云监控使用

阿里云的云监控服务&#xff08;CloudMonitor&#xff09;是一款简单易用、功能强大的监控工具&#xff0c;主要用来帮助用户实时监控阿里云上的各种资源&#xff08;比如服务器、数据库、网络等&#xff09;&#xff0c;并在出现问题时及时发出警报&#xff0c;确保业务稳定运…

嵌入式C语言-关键字typedef

定义和作用 typedef是C/C中的一个关键字&#xff0c;作用是为现有的数据类型&#xff08;int 、char 、flaot等&#xff09;创建新的别名&#xff0c;其目的是为了方便阅读和理解代码。 用法 typedef 原有类型名 新类型名;基本类型创建别名 typedef unsigned char uint8_t; typ…

【混合开发】【大前端++】Vue节点优化Dome之单节点轮播图片播放视频二

动图更精彩 背景 Vue作为大前端开发页面交互&#xff0c;在数字屏&#xff0c;智慧大屏等大屏幕开发过程中&#xff0c;轮播效果作为丰富的展示组件经常作为首选。但也因为这个组件的交互体验很好&#xff0c;于是各种单点组件增加到轮播效果里。经过业务的扩展&#xff0c;人…

前端开发核心技术与工具全解析:从构建工具到实时通信

觉得主包文章可以的,可以点个小爱心哟&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 主页:一位搞嵌入式的 genius-CSDN博客 系列文章专栏: https://blog.csdn.net/m0_73589512/category_13028539.html 前端开发核心技术与工具全解…

GPT 系列论文 gpt3-4 175B参数 + few-shot + 多模态输入 + RLHF + system

GPT&#xff0c;GPT-2&#xff0c;GPT-3 论文精读【论文精读】 GPT-4论文精读 从1750亿参数的文本预言家&#xff0c;到多模态的通用天才&#xff0c;OpenAI用两次震撼世界的发布&#xff0c;重新定义了人工智能的可能性边界。这份笔记将带你深入GPT-3和GPT-4的核心突破&#…

.gitignore文件的作用及用法

目录 ​​.gitignore 文件的作用​​ ​​.gitignore 的基本语法​​ ​​Python 项目的 .gitignore 示例​​ ​​如何使用 .gitignore​​ ​​1. 创建 .gitignore 文件​​ ​​2. 编辑 .gitignore​​ ​​3. 检查 Git 状态​​ ​​常见问题​​ ​​Q1&#xff…

QEMU环境准备

QEMU环境准备 下载 qemu # qemu sudo apt install qemu-system-arm # gdb sudo apt install gdb-multiarchsudo apt-get update sudo apt-get install build-essential zlib1g-dev pkg-config libglib2.0-dev \libpixman-1-dev libfdt-dev ninja-build下载并自行编译 qemu(可…

003 cargo使用

cargo是什么 cargo 是 Rust 的构建系统和包管理器。Rust 开发者常用 cargo 来管理 Rust 工程和获取工程所依赖的库。 在上一篇文章中我们已经使用cargo new命令创建了一个名叫hello_rust的项目。也使用cargo run来运行项目。 cargo常用命令 cargo 除了创建工程以外还具备构建&a…

跨省跨国监控难题破解:多层级运维的“中国解法”

在全球化的商业浪潮中&#xff0c;集团型客户的业务布局日益广泛&#xff0c;涉及跨省甚至跨国的多个分支机构和业务节点。这种跨域管理的模式给企业的运维监控带来了前所未有的挑战。多个分支机构和业务节点运维调整首先&#xff0c;不同地区的网络环境差异巨大。从国内不同省…

pandas读取复合列名列头及数据和处理

pandas读取复合列名列头及数据和处理1. 效果图2. 源代码1. 效果图 原始excel&#xff1a; 读取1&#xff0c;2行为复合表头&#xff1a; 读取序号为1003一整行的数据&#xff0c;以及获取序号为1002行及1003行的C列复合表头列的值&#xff1a; 2. 源代码 import pandas …

制作一个简单的vscode插件

当前环境情况 操作系统&#xff1a;Windows 项目类型&#xff1a;VS Code 插件&#xff08;TypeScript 编写&#xff09; Node.js 版本&#xff1a;20.18.1 yarn 版本&#xff1a;1.22.22 npm 版本&#xff1a;10.8.2 npm registry&#xff1a;huawei ------- https://repo.hua…

分布式专题——10.2 ShardingSphere-JDBC分库分表实战与讲解

1 分库分表案例 下面实现一个分库分表案例&#xff0c;将一批课程信息分别拆分到两个库&#xff0c;四个表中&#xff1a; 需提前准备一个 MySQL 数据库&#xff0c;并在其中创建 Course 表。Course 表的建表语句如下&#xff1a; CREATE TABLE course (cid bigint(0) NOT N…

Digital Clock 4,一款免费的个性化桌面数字时钟

Digital Clock 4&#xff0c;一款免费的个性化桌面数字时钟 ** 功能 ** &#xff1a;一款免费的桌面数字时钟工具&#xff0c;支持多种皮肤、透明度调节和字体样式自定义&#xff0c;时钟可自由拖动&#xff0c;支持设置闹钟、定时关机、显示自定义消息等功能&#xff0c;适合想…

学习Python是一个循序渐进的过程,结合系统学习、持续实践和项目驱动,

学习Python是一个循序渐进的过程&#xff0c;结合系统学习、持续实践和项目驱动&#xff0c;你会掌握得更好。下面我为你梳理了一个分阶段的学习路线和实用建议&#xff0c;希望能帮你高效入门并逐步提升。 &#x1f40d; Python学习指南&#xff1a;从入门到精通 &#x1f5…

vcpkg:面向C/C++的跨平台库管理工具软件配置笔记经验教程

1、什么是vcpkg 对于使用过Python进行程序设计的开发者们&#xff0c;大多都会对Python的各种库和依赖&#xff0c;仅仅通过几条简单命令行就完成配置的操作感到惊叹&#xff0c;非常的省事省力。反倒是C/C开发时&#xff0c;要是每个库都要自己下载源码编译或者对环境进行配置…