Makefile的简化
一般常用的方法:
一.变量
二.隐含规则
三.Makefile的引用
四.Makefile的函数
一.变量
例子:
CC = gcc
引用变量前需要添加$: 如$(CC)
Makefile 变量定义
(1).Makefile变量定义跟Shell变量定义刚好相反!
Shell 变量定义时, = 两边不能有空格.
Makefile 变量定义, = 两边一定要有空格
Shell 变量用{}来保护变量, 而Makefile变量用()来保护变量
(2) Makefile变量定义要独立于规则之外,
在Makefile当中,所有Shell环境变量都是缺省当做Makefile变量,并且在Makefile中,可以用export把自己变量变成环境变量
export语句可以独立在规则之外
境变量也是多个Makefile之 通讯方法之一
(3) = 与:= 区别
两者都用于变量赋值,:=是简单赋值,=带递归引用
如= 后面是变量, 则变量本身值可能还要进行运算
:= 只是简单赋值, 后面变量只简单取值, 没有定义变量取为空, 一般比较安全
假设CFLAGS 预先定义有值, 则CFLAGS = $(CFLAGS)-g 变成无限递归调用, 最后变成最终堆栈溢出,正确写法是CFLAGS :=
$(CFLAGS) -g
#这里foo最终值为Huh,因为foo后面bar还要做递归调用,而ugh也会做递归调用
foo = $(bar)
bar = $(ugh)
ugh = Huh?
#这里foo最终值为空,定义foo时,bar并未定义,这里取空.
foo := $(bar)
bar := $(ugh)
ugh := Huh?
GNU make 的主要预定义变量(1)
(l) GNU make有许多预定义变量,这些变量具有特殊的含义,可在规则中使用。
(2) 除这些变量外,GNU make 还将所有的环境变量作为自己的预定义变量。
预定义变量 含义
$< 第一个依赖文件的名称。
$@ 目标的完整名称。
$^ 所有的依赖文件,以空格分开,不包含重复的依赖文件。
$* 不包含扩展的目标文件名称。
$+ 所有的依赖文件,以空格分开,并以出现的先后为序,可能包含重复的依赖文件。
$? 所有的依赖文件,以空格分开,这些依赖文件的修改日期比目标的创建日期晚。
$% 如果目标是归档成员,则该变量表示目标 归档成员名称。例如,
如果目标 称为mytarget.so(image.o),则$@为 mytarget.so,而$% 为image.o。
GNU make 的主要预定义变量(2)
AR 归档维护程序名称,默认值为ar
ARFLAGS 归档维护程序的选项
AS 汇编程序名称,默认值为as
ASFLAGS 汇编程序的选项。
CC C 编译器名称,默认值为cc
CCFLAGS C 编译器的选项。
CPP C 预编译器名称,默认值为$(CC) -E
CPPFLAGS C 预编译的选项。
CXX C++ 编译器名称,默认值为g++
CXXFLAGS C++ 编译器的选项。
FC FORTRAN 编译器名称,默认值为f77
FFLAGS FORTRAN 编译器的选项。
变量的替换(待补充)
VPATH变量
vpath 关键字
二.隐含规则
GNU make 支持两种类型的隐含规则:1.后缀规则 2.模式规则
1.后缀规则(Suffix Rule):
后缀规则定义了将一个具有某个 后缀的文件(例如,.c 文件)转换为具有另外一种后缀的文件(例如,.o 文件)的方法。每
个后缀规 则以两个成对出现的后缀名定义,例如,将 .c 文件转换为 .o 文件的后缀规则可定义为:
.c.o:
$(CC) $(CCFLAGS) $(CPPFLAGS) -c -o $@ $<
2.模式规则(pattern rules)
这种规则更加通用,因为可以利用模式规则定义更加复杂的依赖性规则。 模式规则看起来非常类似于正则规则,但在目标名称
的前面多了一个 % 号,同时可用来定义目标和依赖 文件之间的关系,例如下面的模式规则定义了如何将任意一个 X.c 文件转换为 X.o
文件:
%.o:%.c
$(CC) $(CCFLAGS) $(CPPFLAGS) -c -o $@ $<
缺省规则,所有规则执行前调用
%::
touch $@
或
.DEFAULT :
touch $@
常见的隐含规则
编译C程序
执行命令为“$(CC) -c $(CPPFLAGS) $(CFLAGS)”。
编译C++程序
执行命令为“$(CXX) -c $(CPPFLAGS) $(CFLAGS)”。建议使用“.cc”作为C++源文件的后缀,而不是“.C”
汇编和需要预处理的汇编程序
“$(AS) $(ASFLAGS)”
链接单一的object文件
“$(CC) $(LDFLAGS) N.o $(LOADLIBES) $(LDLIBS)”
但一般建议每个Makefile都用自己隐含规则来代替缺省规则,这样比较容易读懂,并且容易调整
例子:
以动态库作为参考
例子1
all:main
main:hello_main.o libhello.so
gcc hello_main.o -L. -lhello -o main
hello_main.o:hello_main.c
gcc -c hello_main.c -o hello_main.o -I.
libhello.so:hello.o
gcc -shared hello.o -o libhello.so
hello.o:hello.c
gcc -c -fpic hello.c -o hello.o
clean:
-rm -f *.o main libhello.so
run:main
export LD_LIBRARY_PATH=.;./main
例子2:
CC = gcc
EXECUTE = main
LIBHELLO = libhello.so
OBJS = hello_main.o
CCFLAGS = -fpic
LDFLAGS = -L. -lhello
LIBOBJS = hello.o
all:$(EXECUTE)
$(EXECUTE):$(LIBHELLO) $(OBJS)
$(CC) $^ $(LDFLAGS) -o $@
$(LIBHELLO):$(LIBOBJS)
$(CC) -shared $^ -o $@
%.o:%.c
$(CC) -c $< -o $@ $(CCFLAGS)
clean:
rm -f *.o $(OBJS) $(LIBHELLO) $(EXECUTE)
run:$(EXECUTE)
export LD_LIBRARY_PATH=.;./$(EXECUTE)
输入:make
输入:/main (最后一句可能手动导入,export LD_LIBRARY_PATH=.;./$main)
(待补充)
阅读(1647) | 评论(0) | 转发(0) |