初识Linux下的gcc与makefile

最近在学linux相关的操作,接触到makefile文件,在此做个笔记

文章目录

    • gcc
        • 1.预处理
        • 2. 编译
        • 3.汇编
        • 4.链接
    • makefile
        • 不使用makefile
        • makefile格式
        • 第一个makefile
        • 看第二个makefile

gcc

初识Linux下的gcc与makefile_第1张图片
gcc常用命令选项:
初识Linux下的gcc与makefile_第2张图片

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

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

1.预处理

使用命令:gcc -E hello.c –o hello.i,得到预处理后的文件,这里的-o是重命名的意思。如下
初识Linux下的gcc与makefile_第3张图片
可以用vim打开hello.i文件,可看到源代码本只有几行,经过预处理后得到几百行。
初识Linux下的gcc与makefile_第4张图片

2. 编译

使用命令:gcc -S hello.i -o hello.s,生成汇编文件。
在这里插入图片描述
用vim打开可见:
初识Linux下的gcc与makefile_第5张图片

3.汇编

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

4.链接

使用命令:gcc hello.o。尽管3中得到了二进制文件,但还是不能直接执行,需要通过链接,得到a.out文件,才能运行。
初识Linux下的gcc与makefile_第7张图片

makefile

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

#include 
extern void fun1();
extern void fun2();
int main()
{
        printf("main\n");
        fun1();
        fun2();
        return 0;
}

fun1.c:

#include 
void fun1()
{
        printf("fun1()\n");
}

fun2.c:

#include 
void fun1()
{
        printf("fun2()\n");
}

不使用makefile

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

makefile格式

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

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

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

第一个makefile

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

看第二个makefile

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

初识Linux下的gcc与makefile_第12张图片
这时修改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工作原理
初识Linux下的gcc与makefile_第13张图片
上述makefile代码冗余还很严重,可以通过变量简化该代码,具体的可见视频。

你可能感兴趣的:(Linux)