GuguMelon's Blog

今天所做之事勿候明天,自己所做之事勿候他人。

0%

gcc编译命令与makefile总结

写在前面

今天学习了$gcc$的基本指令,之前总是望而却步,今天一口气。

前置知识

我们知道,$gcc$在编译$C$语言或者$C++$时,分为四个步骤。

  • 预处理 替换头文件和宏,移除注释(.i文件)
  • 编译,生成汇编代码 (.s文件)
  • 汇编 生成目标文件(机器码 .o文件)
  • 链接 生成可执行文件

    编译命令

1
2
3
4
5
6
7
8
9
10
11
12
13
//以下均以test.c为例
gcc test.c //此行代码会直接生成可执行文件,并默认保存为a.out
gcc test.c -o test.o //-0指令表示生成文件命名为-o后的名字,若无其他指令则与后缀无关,都是可执行文件
//关于-o,以下几种需要-o重定向输出文件
gcc -S test.c//只处理预处理和编译 生成汇编代码
gcc -E test.c //只预处理
gcc -c test.c //只有预处理、编译、汇编三步,生成obj(.o)文件
gcc -I 路径 test.c //所调用的头文件所涉及的路径
gcc -Dmarco test.c //宏定义
gcc -Dmarc=def test.c//宏定义
gcc -g test.c//编译时,生成调试信息,常常与gdb配合使用
gcc -std=c9//指定语言标准
gcc -On(0-3) //开启编译优化选项,一般使用-O2

大明星:$makelist$

怎么样?看了上面的编译命令,是不是觉得原来也不过如此?

但是想一下,如果我们需要编译链接许多文件呢?有没有什么简便的方式呢?

这个时候,$makefile$就要闪耀登场了!

什么是$makefile$?之前用$windows$我从来没见过,因为强大的/一般的$IDE$已经为我们做好了一切事情。

$makefile$其实可以简单理解为指令的集合,是对指定的一些文件进行编译的指令,如果我们一个个写出来会很耗费时间,但是$makelist$可以让我们通过简单的$make$,实现相同的功能。

格式

1
2
3
4
5
6
7
8
9
10
11
12
目标文件:[依赖文件集合]
指令 //注意:此处开头必须打tab!

//实例
main:test.o delete.o add.o
gcc $^ -o $@
test.o:test.c
gcc -c test.c -o test.o
add.o:add.c
gcc -c add.c -o add.o
delete.o:delete.c
gcc -c delete.c -o delete.o

上面只是3个文件,需要一行一行写出来,如果有1000个需要处理的文件呢?还要一行一行写出来未免效率也太低了。这个时候,$makefile$的扩展用法就要登场了。

变量定义

预定义变量
1
2
3
4
5
$< 代表第一个依赖文件的名称

$@ 代表目标文件的名称

$^ 代表所有依赖文件的名称

此外还可以自己定义一些变量。

自定义变量
1
2
3
CC = gcc
CFLAGS = -I ../include
//注意等号左右两边都需要有空格

举个例子,上面代码可改为

1
2
3
CC = gcc
main:test.o delete.o add.o
$(CC) $^ -o $@

隐含规则

模式规则

将一个带有某种后缀的文件转换为另一种后缀的文件

1
2
.c.o:
$(CC) $(CCFLAGS) -c -o $@ $<
后缀规则

冒号后为依赖文件,冒号前为目标文件

个人感受

1
2
%.o:%.c(若有多个依赖文件则多写几个%)
$(CC) $(CCFLAGS) -c -o $@ $<

综合以上规则,$makefile$文件可写为

1
2
3
4
5
CC = gcc
main:test.o delete.o add.o
$(CC) $^ -o $@
.c.o:
$(CC) -c $< -o $@