通常源文件需要通过①预处理、②编译、③汇编、④链接四个步骤才可以生成可执行的程序文件,通常可以使用gcc编译链实现目的。
一、gcc编译链
下面给出一个程序样例:
a.c 文件
#include <stdio.h>
int main()
{
func_b();
return 0;
}
b.c 文件
#include <stdio.h>
void func_b(void)
{
printf("This is B\r\n");
}
通过命令gcc -o test a.c b.c可以完成上述四个步骤生成可执行文件test,执行文件结果如下:
我们会发现,每次利用gcc编译链生成可执行文件的时候都会把所有源文件重新编译一遍,当程序量级大的时候时间会非常的长。
因此,通常使用gcc -c a.c b.c,将所有源文件编译成.o文件,最后再通过gcc -o test a.o b.o 将所有.o文件链接成可执行文件。通过这样做方便某一个.c文件修改的时候,只需要再单独编译那一个文件。
二、Makefile的引入及规则
当源文件的数量足够多的时候,我们如果只使用gcc编译链的话每次都得把需要把依赖的文件写出来,这样很麻烦,因此引入了Makefile。
Makefile最基本的规则:
目标文件:依赖文件..
TAB 命令 //当目标文件比依赖文件新的时候,就会执行命令
将上节gcc编译命令写成Makefile文件如下:
test:a.o b.o
gcc -o test a.o b.o
a.o:a.c
gcc -c -o a.o a.c
b.o:b.c
gcc -c -o b.o b.c
可以在当前目录下通过make命令执行:
Makefile会自动检测目标文件的依赖文件是否有改动,如果没有改动则不会产生任何动作,如果某一个单一文件发生了改变则会单独编译被改动的文件,并最后链接生成目标执行文件。
三、Makefile语法
1、通配符
在上一节我们生成a.o和b.o分别写了两条命令来生成,在Makefile里面可以用通配符进行替代。结果如下:
test:a.o b.o
gcc -o test $^
%.o:%.c
gcc -c -o $@ $<
clean:
rm *.o test
%表示通配符,例如要生成a.o的时候 %.o:%.c就会被替换成a.o:a.c。
$^表示所有依赖文件
$@表示此命令对应目标文件
$<表示此命令对应依赖文件
可以通过make clean命令清除所有.o文件和test执行文件
2、假想目标
如下图所示,当当前目录下存在clean文件的时候make clean就不会执行清除操作,因为Makefile只有当依赖文件更新的时候才会执行对应的命令。
所以我们要引入假想目标phony,修改Makefile文件如下:
test:a.o b.o
gcc -o test $^
%.o:%.c
gcc -c -o $@ $<
clean:
rm *.o test
.PHONY:clean
在终端输入make clean命令发现可以正常执行:
3、即时变量、延时变量
即时变量:A:=xxx,变量在定义时直接确定
延时变量:B=xxx,B的值使用使确定
编写Makefile文件如下:
A:=$(C)
B=$(C)
C=abc
all:
@echo $(A)
@echo $(B)
由于变量C是最后定义的,所以A打印为空,B打印出来是abc,执行make all命令如下:
延时变量:A?=xxx,只有第一次定义才会生效,如果在前面该变量已经定义则会忽略此句。