初识Linux下的gcc与makefile

推荐文章:https://blog.csdn.net/chenlong_cxy/article/details/119183448
最近在学linux相关的操作,接触到makefile文件,在此做个笔记

gcc

在这里插入图片描述
gcc常用命令选项:
在这里插入图片描述

刚接触linux时,关于gcc编译器只会用形如 gcc hello.c 的命令来对代码进行编译(实际上这个命令是一键完成上面四个编译过程的),对整个编译过程还不了解,以至于后面在接触makefile的编写时出问题。现在先来看一看gcc的基础知识:
如上图所示,c程序的编译过程分为以上四个步骤,这四个步骤在c基础中也学过,但过于理论导致一知半解:

  1. 预处理:包括(宏替换,头文件展开,去掉注释),生成.i文件,(看内容实际上也是.c文件)
  2. 编译 :检查代码规范,语法错误等,生成汇编文件
  3. 汇编:转成二进制目标代码
  4. 链接:生成最终可执行文件
1.预处理

使用命令:gcc -E hello.c –o hello.i,得到预处理后的文件,这里的-o是重命名的意思。如下
在这里插入图片描述
可以用vim打开hello.i文件,可看到源代码本只有几行,经过预处理后得到几百行。
在这里插入图片描述

2. 编译

使用命令:gcc -S hello.i -o hello.s,生成汇编文件。
在这里插入图片描述
用vim打开可见:
在这里插入图片描述

3.汇编

使用命令:gcc -c hello.s -o hello.o,生成二进制文件,但还不能直接运行,这里-c命令是将代码转换为二进制语言,不进行链接。
在这里插入图片描述
关于-c这个命令,参考gcc 和 gcc -c有什么区别呢
在这里插入图片描述

4.链接

使用命令:gcc hello.o。尽管3中得到了二进制文件,但还是不能直接执行,需要通过链接,得到a.out文件,才能运行。
在这里插入图片描述

makefile

了解了上述gcc编译过程之后,接下来就可学习makefile了。
先给出测试例子–三个.c文件:
main.c :

#include <stdio.h>
extern void fun1();
extern void fun2();
int main()
{
        printf("main\n");
        fun1();
        fun2();
        return 0;
}

fun1.c:

#include <stdio.h>
void fun1()
{
        printf("fun1()\n");
}

fun2.c:

#include <stdio.h>
void fun1()
{
        printf("fun2()\n");
}
不使用makefile

单纯的在shell界面用gcc,可以做到对以上三个文件的一起编译,如下图:
在这里插入图片描述
但是,假如我只对其中的某一个文件进行修改,再次编译时仍然需要对以上三个文件都重新编译,当文件数特别多的时候,这将做很多重复工作,花很大时间。

makefile格式
1 target: prerequisites
2         commands    //注意这里为Tab缩进

翻译一下就是
目标文件 :依赖项
      命令

**即是用依赖项生成对应的目标文件,而依赖项是通过下面的命令生成的。

在这里插入图片描述

第一个makefile

先看最简单的一种情形**,新建一个名为makefile文件,输入以下内容:
在这里插入图片描述
再在终端输入make后得到以下结果:
在这里插入图片描述
可看出,这种makefile文件同只有gcc的一样,是对所有的文件进行编译,特别耗时。

常用规则

注意到,上述第一个makefile文件是直接使用 gcc 指令对多个.c源文件直接生成源文件,这在实际中用的很少。一般是先用源文件汇编生成对应的.o二进制文件(前面有介绍),再将多个二进制文件链接生成可执行文件。

看第二个makefile

通过拆分,现在想,修改哪个文件,就只编译哪个文件,未修改的不参加编译。如下图,第一个目标cpp为终极目标,下面的为子目标。当我们想利用依赖项生成目标cpp时,会先查找后面的依赖项main.o ,没有就会向下查找对应的规则生成main.o依赖项。后面同理。即makefile向下检索,子目标是用来生成终极目标的依赖项,然后依次往上执行命令。
在这里插入图片描述
终端执行后可看到其执行顺序为:

在这里插入图片描述
这时修改fun2.c文件中一点点内容,重新make,可看到只是编译了fun2.c文件。原因在于
makefile更新目标文件是比较时间的,即比较依赖项和目标文件的修改时间,依赖文件修改时间新于目标文件,则更新目标文件
在这里插入图片描述
以fun2.c为例,如上图,fun2.c变化前,fun2.o生成时间是晚于fun2.c; fun2.c变化后,通过比较修改时间,发现fun2.o的时间是早于fun2.c,这时说明fun2.c已修改,就需要执行上图所示命令生成新的子目标文件fun2.o,即重新编译fun2.c文件。而其他的文件对应的.c和.o时间无变化,故不需要重新编译。参考视频:C++ linux 服务器开发基础—makefile工作原理
在这里插入图片描述
上述makefile代码冗余还很严重,可以通过变量简化该代码,具体的可见视频。

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

通信仿真爱好者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值