Makefile是一个简单组织代码编译的方法。这个入门只是设计到了make的一些皮毛,它主要是作为一个初学者指南来帮助你,能够快速和简单地去为中小型项目去创建自己的makefile文件。
一个简单地例子
这里有3个文件,hellomake.c,hellofunc.c和hellomake.h,他们能够代表一些典型的项目。
hellomake.c
#include int main() { // call a function in another file myPrintHelloMake(); return(0); }
hellofunc.c
#include int main() { // call a function in another file myPrintHelloMake(); return(0); }
hellomake.h
/* example include file */ void myPrintHelloMake(void);
一般情况下,你可能会使用如下命令去编译这些代码:
gcc -o hellomake hellomake.c hellofunc.c -I.
它编译这两个C文件成可执行文件hellomake. 参数I是为了帮助gcc编译器查找当前目录下面的头文件hellomake.h.如果没有makefile文件,最典型的方法去做测试,修改和调试是在终端不断的使用上标回来上次执行难的命令重新执行。特别是一旦有增加一些C文件到工程里去。
不幸的是,这种方法去编译代码有两个缺点。第一,如果你丢失了编译命令或更换电脑,你不得不去重新输入命令,这样就不是很高效了。第二,如果你只是修改了其中的一个C文件,重新编译所有的文件也是一件很花时间的事情,这个时候就轮到makefile上台了。
下面有5个小例子来帮助我们去了解makefile:
makefile1:
hellomake: hellomake.c hellofunc.c gcc -o hellomake hellomake.c hellofunc.c -I.
将这个命令写到文件并保存,命名为Makefile或者makefile,打开终端,输入make就可以去执行里面的命令了。注意make是没有参数去执行文件中的第一个规则的。此外,将执行命令依赖的文件列表放在:之后,make知道这个规则hellomake需要被执行,如果这些文件被改变的话。这样就解决了第一个问题,而且可以避免重复使用上标去查找你执行的上一条命令。但是,系统编译最近修改的文件时还是没有提高效率。
注意:makefile中编辑执行的命令行是,缩进是一个tab而不是空格,否则执行makefile时会报错的。
Makefile2
CC=gcc CFLAGS=-I. hellomake: hellomake.o hellofunc.o $(CC) -o hellomake hellomake.o hellofunc.o -I.
我们在这个makefile中定义个一些常量,CC和CFLAGS. 他们是用来传递一些特殊的常量给make去编译文件hellomake.c和hellofunc.c.特别,宏CC是C语言来编译使用的.
这个makefile基本可以满足大多数的小项目。然而,还是有一部分没有覆盖到,include文件的依赖关系。如果你修改了hellomake.h文件,make将不会重新编译,即使你真的需要重新编译。为了解决这个问题,我们需要告诉make所有的C文件依赖哪些确切的头文件。
Makefile3
CC=gcc CFLAGS=-I. DEPS = hellomake.h %.o: %.c $(DEPS) $(CC) -c -o $@ $< $(CFLAGS) hellomake: hellomake.o hellofunc.o gcc -o hellomake hellomake.o hellofunc.o -I.
这个文件问新建了一个宏DEPS, 表示所有的C文件依赖的头文件。接着,我们定义了一个规则给所有以.o结尾的文件,就是说.o文件依赖.c文件和在DEPS中的头文件。参数-c表示产生目标文件,参数-o $@表示:符号左边的那些内容,参数$<是第一个依赖。
我们来看看$@和$^,他们分别代表:的左边和右边。
Makefile4
CC=gcc CFLAGS=-I. DEPS = hellomake.h OBJ = hellomake.o hellofunc.o %.o: %.c $(DEPS) $(CC) -c -o $@ $< $(CFLAGS) hellomake: $(OBJ) gcc -o $@ $^ $(CFLAGS)
所有的目标文件都要在OBJ中列出。
Makefile5
IDIR =../include CC=gcc CFLAGS=-I$(IDIR) ODIR=obj LDIR =../lib LIBS=-lm _DEPS = hellomake.h DEPS = $(patsubst %,$(IDIR)/%,$(_DEPS)) _OBJ = hellomake.o hellofunc.o OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ)) $(ODIR)/%.o: %.c $(DEPS) $(CC) -c -o $@ $< $(CFLAGS) hellomake: $(OBJ) gcc -o $@ $^ $(CFLAGS) $(LIBS) .PHONY: clean clean: rm -f $(ODIR)/*.o *~ core $(INCDIR)/*~
如果想把头文件放在一个include目录,源代码都在src目录,本地库文件在lib目录该怎么办?我们能隐藏哪些烦人的.o文件吗?答案是当然的。这个makefile定义了include和lib目录,而且把目标文件放在一个obj的子目录中.。它也包括你想要包含的宏定义,例如math库-lm. 这个makefile位于src目录中。注意,它还包括clean的规则去清除所有的的代码和目标文件目录(运行make clean).
.PHONY规则处理一些与文件名相关的清理工作。
现在应该对makefile有一个基本的了解了,可以去修改makefile来管理中小型软件项目的编译工作。也可以加入一切其他的规则到makefile文件中来。更多信息可以参考http://www.gnu.org/software/make/manual/make.html