首页 > 代码库 > Makefile简明教程

Makefile简明教程

        Linux的项目管理器Make类似于Windows中VC里的“工程”,它是个"自动编译管理器",能根据文件的时间戳自动发现更新过的文件而减少编译量。通过读入Makefile文件的内容来执行大量的编译工作,用户只需编写一次简单的编译语句就可以了。它提高了实际项目的工作效率,几乎所有Linux下的项目编程都会用到它。

        在如何写Makefile之前,我们首先看下Make工作时的流程:

             1)读入所有的Makefile文件;

             2)如果该Makefile文件通过include包含其他Makefile文件,则读入被包含的Makefile文件;

             3)初始化文件中的变量;

             4)推到隐晦规则,并分析所有规则;

             5)为所有目标文件创建依赖关系链;

             6)根据依赖关系,决定哪些目标要重新生成;

             7)执行生成命令。

        如果定义的变量被使用了,Make采用拖延战术,若变量出现在依赖关系的额规则中,仅当这条依赖被决定要使用时,变量才会在内部展开。

                                                                                                                                                                                                                                                                                                                        

Makefile文件的编写

Makefile 中的第一个目标会被作为其默认目标。

目标、依赖、命令的书写格式为

targets:prerequisites
TAB command
#这种方式居多,command前用tab键对齐

targets:prerequisites ; command
command

       没有依赖文件的目标称为“伪目标”。它只是一个标签不是一个文件。make无法生成它的依赖关系和决定它是否要执行。所以我们只能显式的指明这个“目标”才能让其生效——即通过make+ 伪目标名显示的调用让它得到执行。

       为避免伪目标和文件重名的情况,可以用".PHONY"这个特殊的标记指明一个伪目标。不管有无这个文件,这个目标都是伪目标。

 .PHONY:clean
clean:
        rm -f *.o
 //无论clean文件是否存在,clean就是一个伪目标 

        当然"伪目标"也可以有依赖文件,伪目标同样可以作为“默认目标”,只要将其放在第一个。一个示例就是,如果你的 Makefile 需要一口气生成若干个可执行文件,但你只想简单地敲一个 make 完事,并且,所有的目标文件都写在一个 Makefile 中,那么你可以使用“伪目标”这个特性:

all : prog1 prog2 prog3
.PHONY : all
prog1 : prog1.o
        cc -o prog1 prog1.o
prog2 : prog2.o
        cc -o prog2 prog2.o
prog3 : prog3.o
        cc -o prog3 prog3.o 

       现在我以数据结构C语言实现——顺序线性表SqList这篇博文中的源文件为例,先给出它的Makefiel文件。四个源文件declaration.h、function.h、function.c、main.c

main:main.o function.o
	gcc -o main main.o function.o
main.o:main.c function.h declaration.h
	gcc -c main.c
function.o:function.c function.h declaration.h
	gcc -c function.c
.PHONY:clean
clean:
	rm *.o
	
        这是一个很常规的写法,我们再来将他进一步优化。

        使用变量

         Makefile中的变量分为用户自定义变量、预定义变量、自动变量及环境变量。预定义变量及自动变量部分都默认值但也可修改。Makefile中常见的预定义变量如下:

CC——C编译器的名称,默认为cc

CPP——C编译器的名称,默认为$(CC) -E

CXX——C++编译器的名称,默认为g++

RM——文件删除程序的名称,默认为rm -f
 CFLAGS——C编译器的选项无默认值
//变量在声明的时候要赋初值。使用时变量名前加"$",最后用"()"或"{}"将变量名括起来,"$$"表示真实的"$"符号。

//若规则命令中有SHELL变量,引用使用Shell的“$temp”格式

        使用自动引导

让Makefile自动推导,只要看到.o文件,它就会自动的把对应的.c文件加到依赖文件中,并且gcc -c *.c也会被推导出来。简化如下

CC=gcc
OBJ=main.o function.o
RM=rm -f
make:$(OBJ)
	$(CC) -o main $(OBJ)
main.o:declaration.h function.h
function.o:function.h declaration.h
.PHONY:clean
clean:
	$(RM) $(OBJ)

        使用自动变量
<span style="color:#333333;">$@:目标文件      $^:所有的依赖文件      $<:第一个依赖文件</span>
        使用默认缺省规则

..c.o:
        gcc -c $<
这个规则表示所有的.o文件都是依赖于相应的.c文件
        使用函数
CC=gcc
RM=rm -f
CFLAGS=-Wall -c
SRCS=$(wildcard *.c)
OBJS=$(patsubst %c,%o,$(SRCS))
TARGET=main
.PHONY:all clean
all:$(TARGET)
$(TARGET):$(OBJS)
	$(CC) -o $@ $^
%.o:%.c
	$(CC) $(CFLAGS) -o $@ $<
clean:
	$(RM) *.o $(TARGET)

wildcard和patsubst函数的作用分别是扩展通配符和替换通配符,SRCS=$(wildcrad *.c)等于指定编译当前目录下所有.c文件。$(patsubst %.c,%.o ,$(SRCS))把$(SRCS)中的变量后缀是.c全部其换成.o

                                                                                                                                                                                                                                                                                                                   

指定Makefile文件

GNU make 找寻默认的 Makefile 的规则是在当前目录下依次找三个文件——“GNUmakefile”、“makefile”和“Makefile”。其按顺序找这三个文件,一旦找到,就开始读取这个文件并执行。

我们也可以自己定义Makefile文件的名字,假如有Makefile文件名为mfile,可按一下方式执行

make -f mfile/make --file mfile




Makefile简明教程