GCC编译与Makefile基本语法

2023-05-16

写在最前面:所有的博文都是为了若干年月以后当我再次翻看可以快速回想起之前的零星知识。学海无涯,在看这篇文章的未来的你,加油吧!

目录

一、Makefile简介

二、Linux环境下的C语言编译过程

2.1 gcc编译流程

2.2 gcc常用参数解释

三、makefile基本语法

3.1 makefile基本语法

3.2 实战栗子


一、Makefile简介

Makefile是一种用于编译的脚本语言,它可以很便捷地管理项目的代码编译。如果项目中某些源文件被修改则只编译这几个被修改的源文件。又或者某个头文件被修改,则重新编译所有包含该头文件的源文件。文件夹内的makefile文件可以写做makefile或者Makefile。

二、Linux环境下的C语言编译过程

为了更好地理解makefile的编译工作流程,首先要搞明白一次完整的c语言的编译过程是什么样子的。gcc是我们常用的编译器,我们以它为例进行说明。

2.1 gcc编译流程

一个c源文件最终只有生成可执行文件才能被机器正确执行。使用gcc编译程序时,该过程分为以下四个阶段:预处理、编译、汇编、链接。假设我们有一个c源文件:啊对对对.c,我们用这个程序的变化过程来详细解释gcc的各编译阶段。(文献[5]中详细地进行了解释,下面为了方便理解,我们将[5]中各概念再次给出)

(1)预处理

该阶段编译器主要做加载头文件、宏替换、条件编译等工作,一般用于处理带"#"的语句,如#define xxx xxx。可以使用gcc -E 选项进行查看。在这一步骤中.c文件被预处理输出为.i文件,即

啊对对对.c --> 啊对对对.i

(2)编译

编译阶段主要做语法检查和词法分析,在确认所有指令都符合语法规则之后,将.i文件翻译成等价的中间代码或汇编代码。可以使用gcc -S 选项进行查看。在这一步骤中.i文件被编译输出为.s文件,即

啊对对对.i --> 啊对对对.s

(3)汇编

汇编阶段将.s文件转成二进制目标代码.o文件(并非最终的可执行文件)。在这一步骤中.s文件被汇编输出为.o文件,即

啊对对对.s --> 啊对对对.o

(4)链接

最终的链接阶段,将目标文件、启动代码、库文件链接成可执行文件。在这一步骤中.o文件被链接成最终的可执行文件,即

啊对对对.o --> 啊对对对  //假设最终的可执行文件的名字叫做:啊对对对(当然也可以不叫这个名字)

综上所述,一个c源文件最终生成可执行文件要经过如下的过程:

表1  gcc各阶段以及文件类型
gcc阶段文件类型(源文件为.c)
预处理.c → .i
编译.i →.s 
汇编.s →.o
链接.o →可执行文件

2.2 gcc常用参数解释

在使用gcc对c代码进行编译的过程中,通常会有两个参数-E、-S、-c和-o,这四个个参数分别表示如下:

-E 预处理后即停止,不进行编译、汇编和链接动作,即生成.i文件即停止

-S 预处理和编译后即停止,不进行汇编和链接动作,即生成.s文件即停止

-c 预处理、编译并汇编生成中间同名二进制目标文件,即生成.o文件即停止

-o 自定义生成的可执行文件或者其他输出文件(.s文件,.o文件)的的名字,不加-o会默认生成a.out(说简单点,就是给文件换名字的)

举两个栗子。第一个栗子:假设只有一个源文件名为happy.c,使用gcc对其编译通常可以用以下三种方法:

/*  方法1  */
1 gcc -c happy.c       //由于有参数-c,该语句生成了同名的.o文件并没有进行链接,因此需要下一步生成可执行文件
2 gcc -o HAPPY happy.o //由happy.o生成名为HAPPY的可执行文件
3 ./HAPPY              //执行HAPPY

或

2 gcc happy.o  //若不加-o,则生成a.out可执行文件
3 ./a.out      //执行a.out




/*  方法2  */
1 gcc -c happy.c -o HAPPY.o //将二进制目标文件命名为HAPPY.o
2 gcc -o HAPPY HAPPY.o      //将.o文件链接成可执行文件HAPPY                  
3 ./HAPPY                   //执行HAPPY

或

2 gcc HAPPY.o  //若不加-o,则生成a.out可执行文件
3 ./a.out      //执行a.out




/*  方法3  */
1 gcc happy.c  //由于没有任何参数,gcc直接生成可执行文件a.out(默认文件名)
2 ./a.out      //执行a.out

或

1 gcc happy.c -o HAPPY  //由于加了参数-o,因此可执行文件名为HAPPY
2 ./HAPPY               //执行HAPPY

第二个栗子,假设有三个c源文件: happy.c、little_happy.c和very_happy.c,我们可以通过以下命令对这三个源文件进行编译:

1 gcc happy.c little_happy.c very_happy.c -o HAPPY  //将三个源文件编译生成名为HAPPY的可执行文件
2 ./HAPPY                                           //执行HAPPY

//当然也可以加-c等参数,和第一个栗子的过程类似

可以看到,当源文件增多时,命令行的语句也随之增多。对于大型项目,往往有成千上万个文件(并且不同源文件的路径还不相同),如果还是用上面的命令行进行编译的话,将会非常麻烦低效。比如当一万个源文件中有一个被修改时,命令行将会把全部一万个源文件都编译一遍,这显然是一种低效的方案。并且命令行的输入字符数有上限,因此很有可能会使得无法对整个项目进行编译。

而makefile文件就很好地解决了上面这个问题。makefile可以保存命令行来化简编译工作,并且可以识别出哪些文件是修改过的,哪些是没变化的。它只去编译被修改过的文件,从而节省了时间,提高了效率。下面我们介绍makefile的基本语法。

三、makefile基本语法

首先介绍makefile的基本语法,然后以一个栗子进行说明。

3.1 makefile基本语法

1. make命令

make xxx : 执行xxx

make会在当前目录下寻找Makefile或者makefile文件,若查找到则会查找文件中的第一个.o文件,若.o文件不存在则根据依赖关系查找.s文件,若.s文件不存在,则根据依赖关系查找.i文件,若还不存在,则根据依赖关系查找.c文件。由于.c文件一定存在,于是生成一个.o文件再去执行。(依赖关系:我的理解是文件a需要文件b和文件c产生,所以a与b和c之间的关系为依赖关系)

2. makefile文件格式

目标: 依赖
[tab]命令1
[tab]命令2
[tab]命令3
...

目标:make命令所要构建的对象,可以是文件名也可以是某个操作名。Makefile 文件默认只生成第一个目标文件即完成编译。

在实际中,可能会存在这样一种情况,就是makefile中的目标名和相同目录下的某个文件名一样,这样在进行make的时候,makefile便不会执行目标内相应的指令。为了避免这种情况,我们引入伪目标(PHONY,中文意思是假的东西)。这样make命令便不再管目录中拥有相同名称的文件而是会执行makefile中目标的指令。

依赖:查看目标文件由哪些文件生成,通常是一组用空格隔开的文件名。如果找不到所依赖的生成文件,则会在其他位置寻找是否可以产生依赖文件。举一个简单的栗子:

all: output.out

output.out: file1.o file2.o
    gcc file1.o file2.o -o output.out

file1.o: file1.c
    gcc -c file1.c -o file1.o

file2.o: file2.c
    gcc -c file2.c -o file2.o

这是一个由file1.c和file2.c两个源文件生成可执行文件output.out的简单makefile文件。当执行该文件的时候,首先会寻找output.out文件,然后发现该文件依赖file1.o和file2.o两个文件,而这两个文件此时还没有生成,所以继续向下寻找。随后发现这两个.o文件依赖于file1.c和file2.c这两个.c文件,于是通过gcc生成这俩.o文件,随后向上生成output.out文件。

命令:通过执行该命令,由依赖文件生成目标文件。需要注意的是每个命令前面需要有一个tab!

3. makefile语法

(1)注释:每行以#开头的为注释

(2)echo:显示输出的内容

echo: 会在shell中显示echo这条命令和后面要输出的内容

@echo:  不会显示echo这条命令,只会显示后面要输出的内容

例如:

echo “happy”  输出为:echo "happy"  happy

@echo "happy" 输出为:happy

(3)通配符(*、?和[...]):指定一组符合条件的文件。

*:任意0个或多个字符

?:任意一个字符

[...]:方括号内任意一个字符

(4)匹配符:%,可以将大量相同的文件用一条规则构建。

假设有两个源文件file1.c和file2.c,现在需要将它们编译成.o文件,以下两种目标的构建是等价的:

%.o: %.c

//等价于
file1.o: file1.c
file2.o: file2.c

(5)变量与赋值

自定义变量,使用x=赋值,其中x=表示=、:=、?=或+=。调用变量时,将变量名放在$()中。下面举一个栗子来说明这些符号之间的区别:

#赋值符号“=”
#递归赋值,也就是说会寻找赋值变量的值,也是默认的赋值方式
var0=$(var1)
var1="MAKEFILE"
all:
    echo $(var0)
输出:MAKEFILE


#赋值符号“:=”
#直接赋值,不会递归,也就是不会向下寻找
var0:=$(var1)
var1="MAKEFILE"
all: 
    echo $(var0)
输出:空字符串


#赋值符号“?=”
#若变量未初始化,则赋值
var0="makemake"
var0?="MAKEFILE"
var1?="MAKEFILE"
all:
    echo $(var0) and $(var1)
输出:makemake and MAKEFILE


#赋值符号“+=”
#将字串加到现有字符串的末尾
var0="MAKE"
var0+="FILE"
all:
    echo $(var0)
输出:MAKEFILE

(6)自动变量$@、$^、$<、$?、$(@D)和$(@F)

$@:目标的名字

$^:构造所需文件列表所有所有文件的名字

$<:构造所需文件列表的第一个文件的名字

$?:构造所需文件列表中更新过的文件

$(@D):表示$@的目标名

$(@F):表示$@的文件名

再举个栗子:

HAPPY: happy.c
    gcc -o $@ $<  

#$@表示HAPPY,$<表示happy.c


HAPPY: happy.c very_happy.c
    gcc -o $@ $^

#$^表示happy.c very_happy.c

(7)函数

函数调用的语法如下:

$(func args): 其中,args参数之间以","隔开,func和args之间以" "隔开

$(subst <from>,<to>,<text>):字符串替换,将字符串<text>中的<from>转换成<to>,返回替换后的字符串

举个栗子:

$(subst .c,.o, happy.c very_happy.c)

表示用“.o”替换字符串“happy.c very_happy.c”中的字符“.c”,得到“happy.o very_happy.o”

$(patsubst <pattern>,<replacement>,<text>):模式字符串替换,查找字符串<text>中符合模式<pattern>的单词,并替换成<replacement>

$(strip <string>):去空格,去掉<string>中开头和结尾的空白符,返回去掉空格的字符串

$(findstring <find>,<in>):查找字符串,在字符串<in>中查找<find>字符串,若找到则返回<find>,否则返回空字符串

$(filter <pattern...>,<text>):过滤,以<pattern>模式过滤<text>字符串中的单词,保留符合模式的单词,返回符合模式的字符串;可有多个模式,模式之间以" "隔开

$(wildcard 寻找的文件):在系统中寻找文件。例如:$(wildcard *.c) 就等于找到系统中所有后缀为.c的文件(“*”表示任意个字符),返回以空格隔开的一整行字符

$(basename <names>):取去掉后缀的文件名,也就是前缀,比如$(basename happy.c),就可以获得happy(basename: 中文意思是基本的名称)

$(suffix <names...>):取后缀,从文件名序列<names>中获取并返回各文件的后缀序列,例如$(suffix happy.o),就可以获得后缀“.o”(suffix: 中文意思是后缀,所以带这个单词的函数都和后缀有关)

其他未列出的函数可以自行百度。

3.2 实战栗子

该makefile文件为侧信道形式化验证工具SILVER中的makefile,网址为:GitHub - Chair-for-Security-Engineering/SILVER: SILVER - Statistical Independence and Leakage Verification

本栗子的目的是为了理解该makefile文件是如何运行的。

 可以看到在1-26行,均为变量的赋值,各赋值符号以及通配符的含义在3.1小节中详细地给出

 

 27-52行可以看到,构建了all、build、debug、release和clean五个目标,并在第38行将它们五个都设置为伪目标。

按照Build Instructions步骤,最后一步为make release。当我们输入该指令并按下回车后,它会首先在当前目录下寻找makefile文件。找到后,寻找release目标。找到后发现其有两部分构成。在给CXXFLAGS拼接上相应字符串后,开始寻找目标all。

在第28行找到了all,发现其有两个依赖:build和$(BIN_DIR)/$(TARGET)。对于第一个依赖build,在第40行找到目标build,并按照命令创建两个目录。对于第二个依赖$(BIN_DIR)/$(TARGET),在第34行找到目标,发现其依赖$(OBJECTS),在第25行找到对应的赋值,发现其中缺少$(OBJ_DIR)/%.o。在第30行找到对应的目标$(OBJ_DIR)/%.o,按照第31和第32行的命令创建目录并编译(不链接,因为是-c),生成目标.o文件。

此时目标$(BIN_DIR)/$(TARGET)中的依赖$(OBJECTS)构建完成,开始执行35和36行的命令,创建目录并完成最终的编译。此时目标all构建完毕,make release命令结束。

参考文献:

[1]Makefile 语法入门_阿飞__的博客-CSDN博客_makefile语法

[2]makefile中=、:=和+=的区别 - _小百 - 博客园

[3]Makefile中的匹配符%_忘尘~的博客-CSDN博客_makefile中%

[4]一文详解CMake编译工具与项目构建

[5]gcc -c -o编译过程_奔跑的码农的博客-CSDN博客

[6]makefile脚本基本语法_月亮+六便士的博客-CSDN博客_简述makefile基本语法格式

写在最后面:疫情赶紧结束吧。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

GCC编译与Makefile基本语法 的相关文章

  • 《嵌入式系统》 |(四) STM32软件架构 知识梳理

    系列索引 嵌入式系统 嵌入式系统 重点知识梳理 目录 CMSIS软件架构库文件说明 CMSIS软件架构 CMSIS概述 CMSIS软件架构由四层 xff1a 用户应用层 操作系统及中间件接口层 CMSIS层和硬件层 由三部分构成 核内外设访
  • Cmake链接第三方库的三种方法

    Cmake链接第三方库的三种方法 本文介绍链接第三方库的3种方法 以OpenBLAS举例 使用的工程名称为Test lib xff08 可执行文件名字 xff09 xff0c 主程序为library c 代码中的各路径请自行替代 xff1a
  • SADP功能使用

    SADP主要使用的是链路层多播及UDP多播的原理进行实现的 1 链路层多播 span class token function socket span span class token punctuation span PF PACKET
  • MatlabR2022b + Visual Studio环境配置

    在Matlab中输入 mex setup c 43 43 命令确认MEX使用VS2022编译环境 VC 43 43 目录 包含目录 添加 D Matlab2022b extern include VC 43 43 目录 库目录 添加 D M
  • ROS小车自主导航

    在进行ROS小车自主导航时 xff0c 需要用到三维可视化软件rviz xff0c 然而出现了问题 问题 xff1a 在运行rosrun rviz rviz xff0c 导入自己导航的程序后 xff0c 需要通过2D Pose Estima
  • SIYI AK28 遥控器接收机的SBUS口与STM32通讯

    SBUS介绍 SBUS是Futaba公司定义的一种串口通信协议 xff0c Futaba的产品应用越来越广泛 xff0c 不论是航模 xff0c 无人机 xff0c 还是机器人 xff0c 遥控车 xff0c 总能有它的身影 SBUS是一个
  • 基于STM32F407四旋翼无人机---AK8975磁力计(四)

    基于STM32F407四旋翼无人机 AK8975磁力计 xff08 四 xff09 磁力计基本介绍1 2 磁力计原理图 2 磁力计数据获取3 磁力计椭球拟合校准3 1 简单介绍椭球拟合 磁力计基本介绍 该模块采用高灵敏度霍尔传感器技术 xf
  • 硬链接与软链接

    硬链接 hard link 与软链接 xff08 又称符号链接 xff0c 即 soft link 或 symbolic link xff09 链接为 Linux 系统解决了文件的共享使用 xff0c 还带来了隐藏文件路径 增加权限安全及节
  • 基于STM32F407四旋翼无人机 --- 姿态解算讲解(四元数)(叉积法融合陀螺仪数据和加速度数据)(五)

    基于STM32F407四旋翼无人机 姿态解算讲解 xff08 五 xff09 姿态解算姿态解算定义欧拉角四元数四元数性质 方向余弦矩阵四元数方向余弦矩阵 叉积法融合陀螺仪数据和加速度数据叉积运算 一阶龙格库塔法四元数更新获得欧拉角 姿态解算
  • 基于STM32F407四旋翼无人机---PID算法控制(六)

    基于STM32F407四旋翼无人机 PID算法控制 xff08 六 xff09 PID介绍PID仿真分析 PID介绍 PID介绍 此算法是由P xff08 比例 xff09 I xff08 积分 xff09 和D xff08 微分 xff0
  • 四足机器人(一)----MATLAB simulink对四足机器人物理建模

    四足机器人 xff08 一 xff09 MATLAB simulink对四足机器人物理建模 一 本设计中用的是网上下载的别人已经画好的四足机器狗的3D模型 那么我们就需要将这些3D模型导入到MATLAB的建模中 xff0c 打开MATLAB
  • 四足机器人(二)---运动学逆解和步态规划

    四足机器人 xff08 二 xff09 运动学逆解和步态规划 运动学逆解步态规划MATLAB仿真 运动学逆解 其实运动学分为运动学正解和运动学逆解 xff0c 二者有什么区别呢 xff1f 因为在四足机器人中用的是12个舵机 xff0c 所
  • 四足机器人(三)--- 姿态控制

    四足机器人 xff08 三 xff09 姿态控制 概述姿态表示使用MATLAB实现姿态控制算法效果 概述 四足机器人运动过程中 xff0c 身体部分的姿态会不断地发生变化 假如机器人的足端一直保持与地面接触且相对位置不发生变化 xff0c
  • VSCode+python+opencv搭建过程

    VSCode 43 python 43 opencv搭建过程 python安装VSCode安装安装opencv python安装 首先打开python的官网 www python org xff0c 进入python官网下载页面 xff0c
  • 智能家居之主机---计划筹备

    智能家居之主机 计划筹备 前言绪言前期构思 硬件平台结构平台 前言 绪言 感觉有一年多没发过文章了 xff0c 这一年多太忙了 xff0c 来到新的公司后要学的太多了 xff0c 代码风格 xff0c 架构 xff0c 操作系统 xff0c
  • 智能家居之主机--环境搭建

    智能家居之主机 环境搭建 硬件环境软件环境结构 硬件环境 上节说到硬件平台的搭建 xff0c 之前是在altium designer上面画好的 xff0c 现在要支持国产 xff0c 没办法只能在立创EDA上面重新画了 xff0c 有的人说
  • 智能家居之主机--驱动层搭建

    智能家居之主机 驱动层搭建 bsp 底层驱动bsp gpiobsp adcbsp uartbsp timer 伪调度 bsp 底层驱动 bsp gpio 利用一个config h的配置文件 xff0c 把所有要使用的gpio的属性配置好 x
  • STM32串口自定义数据接收协议

    文章目录 写在前面0 需求1 问题产生1 1 模块 43 上位机实验1 2 电路板串口数据接收实验1 3 问题来了 xff01 2 开始分析2 1 串口数据格式2 2 测一波波形 3 代码分析4 新的问题 xff1a 串口数据累加总结 写在
  • 科普:电池的保护电路

    科普 xff1a 电池的保护电路 http www cnbeta com articles 204504 htm
  • 汇编语言基础知识-寄存器

    汇编语言基础知识 寄存器 寄存器是距离CPU中最近的存储单元 xff0c 对于现代CPU其获取数据的顺序往往是 CPU 61 61 gt 寄存器 61 61 gt 一级缓存 61 61 gt 二级缓存 61 61 gt 三级缓存 61 61

随机推荐

  • ERROR:未定义标识符“cout“、“endl“

    ERROR情况 xff1a 未定义标识符 span class token string 34 cout 34 span 未定义标识符 span class token string 34 endl 34 span 问题原因 xff1a c
  • VSCode格式化快捷键

    Shift 43 Ctrl 43 F
  • Linux内核源代码分析一(Linux0.12)

    Linux内核源代码分析一 xff08 Linux0 12 xff09 Linux 内核主要由 5 个模块构成 xff0c 它们分别是 xff1a 进程调度模块 内存管理模块 文件系统模块 进程间通信模块和网络接口模块 1 引导启动程序 x
  • Qt类继承关系以及所属模块关系一览表

    Qt类关系一览表 高清版下载 xff1a Qt类继承关系以及所属模块关系一览表 更多内容请关注个人博客 xff1a https blog csdn net qq 43148810
  • cartographer主从机rviz订阅地图出错

    参考 xff1a https answers ros org question 261071 rviz client md5sum error ERROR 1563347805 272316618 Client rviz wants top
  • Gooseeker软件使用教程

    因为课程需要使用到Gooseeker软件 xff0c 写个使用教程防止以后忘记 安装好gooseeker软件 xff0c 下图为安装好的界面 xff1a 点击右上方的 MS谋数台 xff0c 弹出如下界面 xff1a 在左上方的网址栏输入想
  • HTTP Auth认证请求(附代理)-代码篇

    2种方式 方式一 xff1a Http请求头上添加Basic Authentication认证 httpPost httpPost addHeader Authorization 34 Basic 34 43 Base64 encodeBa
  • Makefile以及CMakelists的编辑

    1 概念 在linux中不像windows和mac有图形界面 xff0c 怎么快速的用命令行运行大型项目成为一个问题 xff0c 并且像c c 43 43 需要自己添加include文件的位置 xff0c 当文件数目变多的时候 xff0c
  • python爬虫练习1:计算评分平均值

    练习要求 xff1a 抽取某本书的前50条短评内容并计算评分的平均值 提示 xff1a 有的评论中并不包含评分 代码 xff1a span class token comment coding utf 8 span span class t
  • python爬虫练习2:取道指成分股数据

    练习要求 xff1a 在 http money cnn com data dow30 上抓取道指成分股数据并将30家公司的代码 公司名称和最近一次成交价放到一个列表中输出 代码 xff1a span class token comment
  • python中sort函数的使用

    转自https blog csdn net lyy14011305 article details 76148512 我们需要对List进行排序 xff0c Python提供了两个方法 对给定的List L进行排序 xff0c 方法1 用L
  • Python序列与文件编程练习

    练习一 xff1a 使用以下语句存储一个字符串 xff1a string 61 My moral standing is 0 98765 将其中的数字字符串转换成浮点数并输出 代码 xff1a span class token commen
  • 简单平台用户信息管理系统

    要求 xff1a 用字典创建一个平台的用户信息 xff08 包含用户名和密码 xff09 管理系统 xff0c 新用户可以用与现有系统帐号不冲突的用户名创建帐号 xff0c 已存在的老用户则可以用用户名和密码登陆重返系统 实现代码 xff1
  • DataFrame小练习

    练习要求 xff1a 已知有一个列表中存放了一组音乐数据 xff1a music data 61 the rolling stones Satisfaction Beatles Let It Be Guns N Roses Don t Cr
  • nenuacm 2019 新生训练#10 字符串处理 题解

    题目链接 Ultra Fast Mathematician 解题思路 xff1a 题目说辣么多 xff0c 其实就是将两个二进制进行异或运算 xff1a 相同位上的数字相同 xff0c 异或结果为0 xff0c 否则为1 AC代码 span
  • 比较两个字符串大小(C语言)

    比较两个字符串的大小 比较两个字符串的大小 xff0c 不许使用strcmp函数 输入格式 在两行分别输入两个长度小于20的字符串 在字符串中不要出现换行符 xff0c 空格 xff0c 制表符 输出格式 直接输出 gt 或 lt 或 61
  • 海康web3.0使用记录

    项目中集成海康web3 0控制摄像头 近期项目中的业务需求涉及播放控制实时监控 xff0c 采用了海康web3 0的开发包 xff0c 开发包规范是32位IE11浏览器 xff0c 业务前期本来只是播放rtsp流的监控 xff0c 所以采取
  • 字符串与数字范围

    当字符串由数字组成时 xff0c 告诉你字符串的长度是length xff0c 意味着变成数字时最大会达到10length 1 比如告诉字符串长度最长为105 xff0c 那要注意数字可以达到10的105 1次方 xff0c 大约是1010
  • 如何在VS2019上配置OpenCV

    目录 前言正文1 安装Visual Studio2017 20192 配置 OpenCV https so csdn net so search q 61 OpenCV amp spm 61 1001 2101 3001 7020 2 1
  • GCC编译与Makefile基本语法

    写在最前面 xff1a 所有的博文都是为了若干年月以后当我再次翻看可以快速回想起之前的零星知识 学海无涯 xff0c 在看这篇文章的未来的你 xff0c 加油吧 xff01 目录 一 Makefile简介 二 Linux环境下的C语言编译过