最近刚换工作,项目需要用Makefile,而我只会一点点,看Makefile文件,完全看不懂,所以在网上找了一些资料学习,总结,方便后期复习。
首先了解GCC编译
一、gcc常用选项:-c、-o
1、c表示只编译源文件但不链接,会把.c或.cc的c源程序编译成目标文件,一般是.o文件。
2、-o用于指定输出(out)文件名。不用-o的话,一般会在当前文件夹下生成默认的a.out文件作为可执行程序。
gcc -c test.c //将生成test.o的目标文件
gcc -o app test.c //将生成可执行程序app
gcc test.c //将生成可执行程序a.out
gcc -c test.c -o test.o //表示把源文件test.c编译成指定文件名a.o的中间目标文件(其实在这里,把-o test.o省掉,效果是一样的,因为中间文件默认与源文件同名,只是后缀变化)。
一、首先来一个最简单的Makefile,同时编译多个文件:
object:main.c test.c
gcc -o object main.c test.c
注意:在第二行的“gcc”命令之前必须要有一个tab缩进;
object:冒号之前,为目标目标文件;
main.c test.c:冒号之后,为依赖关系表,也就是编译object所需要的文件;
gcc -o object main.c test.c:编译命令;
二、再看下面的例子
cc = gcc
prom = mytest
source = main.c test.c
$(prom):$(source)
$(cc) -o $(prom) $(source)
cc:为所使用的编译器为gcc;
prom:要编译的目标;
source:为源文件(自己所需要的文件);
三、上面两种方法,如果修改了一个文件,都会全部重新编译,而且如果我们修改的是test.h文件,make就无法察觉到变化了,所以也得为头文件专门设置一个常量,并将其加入到依赖关系表中,就有下列方法。
cc = gcc
prom = myobject
deps = test.h
obj = main.o test.o
$(prom):$(obj)
$(cc) -o $(prom) $(obj)
main.o:main.c $(deps)
$(cc) -c main.c
test.o:test.c $(deps)
$(cc) -c test.c
deps:为头文件依赖表;
四、虽然解决了上面问题,但代码显得繁琐,就有下面方法:
cc = gcc
prom = myobject
deps = test.h
obj = main.o test.o
$(prom):$(obj)
$(cc) -o $(prom) $(obj)
%.o:%.c $(deps)
$(cc) -c $< -o $@
在这里,我们用到了几个特殊的宏。首先是%.o:%.c,这是一个模式规则,表示所有的.o目标都依赖于与它同名的.c文件(当然还有deps中列出的头文件)。再来就是命令部分的$<和$@,其中$<代表的是依赖关系表中的第一项(如果我们想引用的是整个关系表,那么就应该使用$^),具体到我们这里就是%.c。而$@代表的是当前语句的目标,即%.o。这样一来,make命令就会自动将所有的.c源文件编译成同名的.o文件。不用我们一项一项去指定了。整个代码自然简洁了许多。
五、如果我们需要往工程中添加一个.c或.h,可能同时就要再手动为obj常量再添加第一个.o文件,如果这列表很长,代码会非常难看,为此,我们需要用到Makefile中的函数,这里我们演示两个:
cc = gcc
prom = myobject
deps = $(shell find ./ -name "*.h")
src = $(shell find ./ -name "*.c")
obj = $(src:%.c=%.o)
$(prom):$(obj)
$(cc) -o $(prom) $(obj)
%.o:%.c $(deps)
$(cc) -c $< -o $@
六、用make clean命令,删除.o文件、执行文件等。
cc = gcc
prom = myobject
deps = $(shell find ./ -name "*.h")
src = $(shell find ./ -name "*.c")
obj = $(src:%.c=%.o)
$(prom):$(obj)
$(cc) -o $(prom) $(obj)
%.o:%.c $(deps)
$(cc) -c $< -o $@
clean:
rm -rf $(obj) $(prom)