【编译、链接与构建详解】Makefile 与 CMakeLists 的作用

【编译、链接与构建详解】Makefile 与 CMakeLists 的作用

  • 前言
  • 源代码(.c、.cpp)
  • 编译
    • 编译的本质
    • 编辑的结果
    • 编译器(GCC、G++、NVCC 等)
  • 目标文件(`.o`)
    • 什么是 `.o` 目标文件
    • 为什么单个 `.o` 目标文件不能直接执行?
  • 链接
    • 链接的本质
    • 如果需要链接的 `.o` 文件很多且杂乱怎么办?
  • 库文件(.a、.so)
    • 静态库(`.a`)
    • 动态库(`.so`)
  • 构建
    • 构建的步骤
    • 自动化构建
  • 构建工具与构建规则(Make、Makefile)
  • 构建配置工具与构建配置文件(CMake、CMakeLists)

前言

在大型项目中,通常会使用 C 或 C++ 语言进行开发,而编译、链接、构建等概念,以及相关工具如 GCC、G++、NVCC、CMake、Make、Makefile 等,是每个开发者都无法绕过的重要内容。这些概念虽然至关重要,但往往容易混淆。因此,本文将简明扼要地介绍这些概念,帮助读者更深入地理解编译、链接与构建过程。

源代码(.c、.cpp)

我们编写的代码通常以 .c.cpp 文件的形式存在,这些源代码文件是人类可读的,但计算机无法直接理解和执行。
计算机只能理解二进制的机器语言,因此,需要通过编译将源代码转换为机器可以识别的格式,这就涉及到编译的相关知识。

编译

编译的本质

程序员编写的 .c.cpp 源代码是人类可读的,但计算机无法直接理解。为了让计算机执行这些代码,需要将其转换为计算机能够识别的二进制语言,这个过程就是编译的本质。

编辑的结果

编译的结果是目标文件.o 文件),它包含了经过翻译但尚未完整链接的二进制代码(机器可以理解的语言)。理解目标文件的作用,有助于更深入地掌握编译过程。

编译器(GCC、G++、NVCC 等)

编译器是将源代码翻译为计算机能够理解的目标文件的“翻译官”。它负责将人类编写的 .c.cpp.cu 等源代码转化为机器可执行的二进制代码。常见的编译器包括:

  • GCC(GNU Compiler Collection):主要用于编译 C 语言的源代码(.c 文件)。
  • G++:是 GCC 的 C++ 编译器,用于编译 C++ 语言的源代码(.cpp 文件)。
  • NVCC:NVIDIA CUDA 编译器,用于编译并行计算的 CUDA 程序(.cu 文件)。

这些编译器各自对应不同类型的源代码文件,执行代码翻译的任务。

目标文件(.o

什么是 .o 目标文件

.c.cpp 源代码经过编译后,会生成 .o 目标文件。目标文件是计算机可以理解的二进制代码,意味着源代码已经被翻译成机器语言,程序的执行又向前迈进了一步。

为什么单个 .o 目标文件不能直接执行?

目标文件(.o)本身并不能直接运行,因为它只是编译后的中间产物,尚未构成完整的可执行程序。通常,一个程序由多个 .c.cpp 文件组成,而 main 函数往往位于其中的一个文件中,负责调用其他模块的函数。

可以将程序比作一辆汽车:main 函数相当于车架,而各个 .o 文件代表轮子、方向盘、控制台等组件。单独的 .o 文件只是一个零件,只有经过链接,将所有模块正确拼接在一起,才能形成最终可运行的程序。

要将这些独立的目标文件整合成一个可执行程序,就涉及到链接的过程。

链接

链接的本质

当所有 .c.cpp 代码经过编译后,都会生成 .o 目标文件。这些 .o 文件虽然已经被翻译成机器可以识别的语言,但它们彼此独立,尚无法直接运行。

链接就是组装:
可以将 .o 文件比作汽车的零部件:单独的目标文件就像轮子、方向盘、发动机等组件,只有经过链接,将这些部件正确组装起来,才能形成一个完整的可执行程序(拼成一个可以跑的汽车)。链接的本质,就是将多个 .o 目标文件整合在一起,最终拼接成可以运行的可执行文件。

通常,在所有被链接的 .o 目标文件中,只有一个包含 main 主函数,它相当于汽车的车架,而其他 .o 文件则封装了各种功能模块(如发动机、刹车系统、座椅等)。链接的过程,就是将这个带有 main 入口的*“车架”与其他“零部件”*拼接在一起,使其成为一个完整可运行的程序。

如果需要链接的 .o 文件很多且杂乱怎么办?

在大型项目中,编译过程中会生成大量 .o 目标文件。如果直接链接所有 .o 文件,不仅会导致项目结构混乱,还会增加管理和分发的难度。

为了解决这个问题,通常会将多个 .o 文件打包成库文件,即 .so(动态/共享库).a(静态库)。这些库文件可以帮助我们更高效地组织、管理和复用代码,使项目结构更加清晰,链接过程也更加简洁。

库文件(.a、.so)

为了更方便地管理大量的 .o 目标文件,引入了库文件的概念。库文件可以看作是多个 .o 文件的集合,用于提高代码的组织性和复用性。然而,库文件分为两种类型:

  • .a(静态库)
  • .so(动态库/共享库)

二者虽然都是 .o 文件的集合,但在使用方式上存在明显区别。

静态库(.a

静态库(.a)本质上是多个 .o 目标文件的打包集合,在编译时会被直接链接到可执行文件中。这种方式可以提高代码复用性,并减少每次编译时重复编写相同代码的工作量。

然而,静态库是固定的,如果库中的 .o 文件对应的源代码发生修改,就需要重新编译修改的部分并更新静态库文件,然后再重新链接生成新的可执行文件。这意味着每次库文件更新后,所有依赖该库的程序都必须重新编译和链接。

动态库(.so

动态库(.so,共享库)与静态库类似,也是多个 .o 目标文件的集合,但它不会在编译时直接嵌入可执行文件,而是在程序运行时被加载。这种方式减少了可执行文件的体积,并允许多个程序共享同一个库,从而提高资源利用率。

此外,动态库是灵活的,如果库中的 .o 文件对应的源代码发生修改,只需重新编译动态库文件,无需重新编译和链接所有依赖它的程序。程序在运行时会自动加载最新版本的动态库,因此更新更加便捷。

构建

构建是将源代码转化为可执行文件的完整过程,通常包括以下几个主要步骤:

构建的步骤

  1. 清理
    在进行新一轮构建之前,需要先清理掉之前构建的产物,比如删除旧的目标文件 .o、可执行文件和库文件等。这一步确保构建环境干净,避免旧文件影响新一轮构建。

  2. 管理依赖
    项目可能依赖外部库或资源,这时候需要下载、安装并管理这些依赖,确保它们的版本正确且可用。

  3. 编译
    这一阶段将源代码文件(.c.cpp)编译成目标文件(.o)。编译过程将人类可读的代码转化为机器可以理解的中间产物。

  4. 链接
    链接过程将多个目标文件(.o 文件)和库文件(.a.so 文件)整合、拼接成一个完整的可执行文件,最终生成可以运行的程序。

  5. 其他
    在某些构建过程中,还可能涉及其他步骤,如单元测试、部署、打包等,这些步骤根据项目需求可能会有所不同。

自动化构建

如上所述,构建过程包含多个环节,涉及到源代码的编译、目标文件的生成、依赖的管理等操作。为了实现高效且自动化的构建,通常会使用构建工具来控制这一过程。

最常见的构建工具是 Make,它通过 Makefile 文件定义的构建规则和依赖关系,从而自动化管理和执行构建步骤。接下来,我们将介绍 Make 工具及其 Makefile 构建规则的相关内容。

构建工具与构建规则(Make、Makefile)

Make 是一种常用的构建工具,它根据 Makefile 中定义的 构建规则 来自动化构建过程。Makefile 中指定了构建目标、依赖关系、编译器选项、可执行文件名等具体的构建命令。
然而,Make 的一些局限性也较为明显:它的语法较为底层,可读性较差,并且对多平台兼容性较弱(例如,它通常只适用于 UNIX 系统,而在其他平台的构建可能会遇到困难)。

为了克服这些问题,CMake 应运而生。CMake 是一个更高级的构建配置工具,它通过平台无关的配置文件生成适用于不同平台的构建文件(例如 Makefile 或 Visual Studio 工程文件),从而解决了多平台兼容性和可读性差的问题。

构建配置工具与构建配置文件(CMake、CMakeLists)

正如前文所述,CMake 是一个高级的构建配置工具,它通过读取 CMakeLists.txt 文件中定义的构建配置来生成适应不同平台的构建规则。CMake 会根据 CMakeLists.txt 中的内容,自动生成对应的构建文件(例如 Makefile 或 Visual Studio 工程文件),然后调用相应的构建工具(如 make)来执行构建过程。

相较于 Make,CMake 提供了更高层次的抽象,具有更强的实用性和更好的跨平台兼容性。因此,CMake 在大型项目中得到了更广泛的应用,尤其是在需要支持多平台构建时,CMake 和 CMakeLists.txt 文件成为了主流的选择。

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

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

相关文章

Ubuntu / Debian 创建快捷方式启动提权

简述 在 Linux 系统中,.desktop 文件是 桌面入口文件,用于在桌面环境(如 GNOME、KDE)中定义应用程序的启动方式、图标、名称等信息。当你执行 touch idea.desktop 时,实际上创建了一个空的 .desktop 文件(…

ISIS报文

IS-IS 报文 目录 IS-IS 报文 一、报文类型与功能 二、报文结构解析 三、核心功能特性 四、典型应用场景 五、抓包数据分析 六、总结 IS-IS(中间系统到中间系统)协议报文是用于链路状态路由协议中网络设备间交换路由信息的关键载体,其设…

beikeshop多商户跨境电商独立站最新版v1.6.0版本源码

一.介绍 beikeshop跨境电商独立站最新版V1.6.0源码 多商户 多商家 多语言 多币结算 本博主亲测搭建代码全开源质量相对来说很稳定的 二.服务器环境 系统:CentOS、 环境:PHP7.4 Nginx 1.21 MySQL 5.6 常见插件:fileinfo ; re…

Redis批量操作详解

一、原生批量命令(MSET) 适用场景:所有键的过期时间相同或无过期设置,且无需条件判断。 方法: 将多个SET命令合并为MSET命令,但需要注意MSET的局限性(无法设置过期时间,且所有键值对…

Spring Boot 集成实战:AI 工具如何自动生成完整微服务模块

在数字化转型的浪潮中,开发效率和质量是企业竞争力的关键要素。飞算 JavaAI 作为一款创新的 AI 工具,能在 Spring Boot 开发中,自动生成完整微服务模块,极大提升开发效率。下面,我们就详细介绍如何借助飞算 JavaAI&…

算法 | 2024最新算法:斑翠鸟优化算法原理,公式,应用,算法改进研究综述,matlab代码

基于斑翠鸟优化算法的原理、应用及改进研究综述 一、算法原理 斑翠鸟优化算法(Pied Kingfisher Optimizer, PKO)是2024年由Bouaouda等人提出的一种新型仿生智能优化算法,其灵感来源于斑翠鸟的捕食行为与共生关系。算法通过模拟斑翠鸟的栖息悬停、潜水捕鱼及与其他生物的共生…

RabbitMQ高级特性--重试特性

目录 1.重试配置 2.配置交换机&队列 3.发送消息 4.消费消息 5. 运行程序观察结果 6. 手动确认 注意: 在消息传递过程中, 可能会遇到各种问题, 如网络故障, 服务不可用, 资源不足等, 这些问题可能导致消息处理失败. 为了解决这些问题, RabbitMQ 提供了重试机制, …

Vue 组件通信 - 中央事件总线

Vue 渐进式JavaScript 框架 基于Vue2的学习笔记 - Vue组件通信 - 中央事件总线 目录 中央事件总线 图示 准备工作 设置页面元素 创建组件 总结 中央事件总线 使用vue的监听和触发来实现中央事件总线方式。 on监听 emit触发,组件按钮绑定点击事件&#xff0c…

5.0 WPF的基础介绍1-Grid,Stack,button

WPF: Window Presentation Foundation. WPF与WinForms的对比如下: 特性WinFormsWPF技术基础基于传统的GDI(图形设备接口)基于DirectX,支持硬件加速的矢量渲染UI设计方式拖拽控件事件驱动代码(简单但局限)…

QT软件设计可考虑回答

在Qt应用中是否引入抽象类需要根据具体场景权衡&#xff0c;以下是分层建议&#xff1a; 建议采用抽象类的3个典型场景&#xff1a; 传感器系统抽象&#xff08;强推荐&#xff09; class AbstractSensor { public:virtual ~AbstractSensor() default;virtual QVector<L…

pytorch学习(b站小土堆学习)

1 环境配置 参考链接 2. dir 和 help函数 dir()&#xff1a;用于查看某一模块函数的方法 help()&#xff1a; 用于查看某方法的使用方法 3. dataset类实战 利用Image对象打开图片&#xff0c;利用os模块的地址拼接组成图片路径 当我们用方括号访问元素对象时&#xff0c;…

Unity TextMeshPro 实现文本逐字淡出效果

Unity TextMeshPro 实现文本逐字淡出效果 前言项目思路场景布置代码编写 前言 在处理角色对话时经常会用到一些文本动画&#xff0c;正好记录一下。使用 TextMeshPro&#xff0c;我们可以直接操作文本的顶点数据&#xff0c;实现诸如渐变、动画等效果&#xff0c;为游戏界面和…

Mathtype无法插入到Word中

在word工具栏上有没有出现Mtahtype&#xff0c;会出现以下两种情况&#xff1a; 1. 没有出现Mtahtype 2. 出现Mtahtype&#xff0c;但是点击会出现弹窗 “ Couldnt find the MathPage.wll ” 解决方案 首先查看word版本是32位还是64位&#xff0c;这个位数是office安装位数…

责任链模式_行为型_GOF23

责任链模式 责任链模式&#xff08;Chain of Responsibility Pattern&#xff09;是一种行为型设计模式&#xff0c;核心思想是将多个处理请求的对象连成一条链&#xff0c;请求沿链传递直到被处理。它像现实中的“多级审批流程”——请假或报销时&#xff0c;申请会逐级提交给…

Qt图形化界面为何总被“冷落“?

在Qt开发者的IDE中&#xff0c;Qt Designer总像一个被遗忘的角落——即便它有着直观的拖拽式界面设计功能。通过分析GitHub上超过5000个Qt项目发现&#xff0c;仅有17%的项目使用.ui文件构建界面。这个数据背后&#xff0c;隐藏着开发者群体对GUI构建方式的集体选择。我们不禁要…

SQL Server从安装到入门一文掌握应用能力。

本篇文章主要讲解,SQL Server的安装教程及入门使用的基础知识,通过本篇文章你可以快速掌握SQL Server的建库、建表、增加、查询、删除、修改等基本数据库操作能力。 作者:任聪聪 日期:2025年3月31日 一、SQL Server 介绍: SQL Server 是微软旗下的一款主流且优质的数据库…

简单视图函数

视图函数 文章目录 视图函数[toc]一、什么是视图函数二、简单视图函数三、返回错误视图 一、什么是视图函数 所谓视图函数&#xff08;简称视图&#xff09;&#xff0c;本质上就是一个Python函数&#xff0c;用于接收Web请求并且返回Web响应。Web响应可以包含很多类型&#x…

QT文件操作(QT实操学习3)

1.项目架构 1.UI界面 1.新建文本文档 2.打开文件 3.另存为文件 2.mainwindow.h​ #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow> #include <QFileDialog> #include <QMessageBox> #include <QDebug> QT_BEGIN_NAMESPACE namespa…

HX324双运算放大器:赋能万物互联时代的信号处理基石

一、运算放大器行业的技术演进与市场需求 在全球半导体市场规模突破6000亿美元的背景下&#xff0c;模拟芯片作为电子系统的"感官神经"&#xff0c;正迎来智能化升级浪潮。据IC Insights数据显示&#xff0c;2023年全球运算放大器市场规模达32.7亿美元&#xff0c;其…

C++ 结构体与函数

一.结构体 1.概念&#xff1a; 结构体&#xff08;struct&#xff09;是一种用户自定义复合数据类型&#xff0c;其中可以包含不同类型的不同成员 2.结构体的应用场景&#xff1a; 我们在使用多个变量描述一个对象时&#xff0c;虽然也可以做到&#xff0c;但是难免显得杂乱…