红联Linux门户
Linux帮助

linux编程初步之跟我学makefile学习笔记

发布时间:2009-04-13 17:12:46来源:红联作者:kevin_2009
objects = main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
edit : $(objects)
cc -o edit $(objects)


.PHONY : clean
clean :
rm edit $(objects)


Makefile里有
1、显式规则
2、隐晦规则
3、变量的定义
4、文件指示
5、注释 #

include
当前目录下:a.mk、b.mk、c.mk、foo.make、e.mk、f.mk
bar=e.mk f.mk

include foo.make *.mk $(bar)
等价于:
include foo.make a.mk b.mk c.mk e.mk f.mk

make会在当前目录下首先寻找,如果当前目录下没有找到,那么,make还会在下面的几个目录下找:
1、如果make执行时,有“-I”或“--include-dir”参数,那么make就会在这个参数所指定的目录下去寻找。
2、如果目录;/include(一般是:/usr/local/bin或/usr/include)存在的话,make也会去找。

-include

1、读入所有的Makefile。
2、读入被include的其它Makefile。
3、初始化文件中的变量。
4、推导隐晦规则,并分析所有规则。
5、为所有的目标文件创建依赖关系链。
6、根据依赖关系,决定哪些目标要重新生成。
7、执行生成命令。

targets : prerequisites ; command
或者
targets : prerequisites
command

objects := $(wildcard *.o)

VPATH
我的目录结构如下:
ctest
|
|--hello.c
|--Makefile
|--printf2.h
|--sub
|--printf2.c

//*****printf2.h****
void printf2(void);

//*****printf2.c***
#include
void printf2(void)
{
printf("I am printed by printf2\n");
}

//*****hello.c****
#include
#include "printf2.h"
int main(void)
{
printf2();
return 1;
}

//makefile
VPATH=./sub

hello : hello.o printf2.o
gcc -o hello hello.o printf2.o

hello.o : hello.c printf2.h

用下面的Makefile结构会好一些:
PROG = hello
OBJS = hello.o printf2.o
RM = rm -f

VPATH=./sub
all:$(PROG)

hello:$(OBJS)
$(CC) $(CFLAGS) $(CPPFLAGS) $^ $(LDFLAGS) -o $@

hello.o:hello.c printf2.h

clean:
$(RM) $(PROG) $(OBJS)

或者
VPATH=./sub
hello : hello.o printf2.o
gcc -o hello hello.o printf2.o
printf2.o : printf2.c
gcc -c $ <
hello.o : hello.c printf2.h
gcc -c hello.c


用: 分隔 VPATH = src:../headers

vpath
1、vpath vpath %.h ../headers
为符合模式;的文件指定搜索目录;。

2、vpath
清除符合模式的文件的搜索目录。

3、vpath
清除所有已被设置好了的文件搜索目录。

vpath %.c foo
vpath % blish
vpath %.c bar
其表示“.c”结尾的文件,先在“foo”目录,然后是“blish”,最后是“bar”目录

vpath %.c foo:bar
vpath % blish
而上面的语句则表示“.c”结尾的文件,先在“foo”目录,然后是“bar”目录,最后才是“blish”目录。


静态模式
: : ;
;


objects = foo.o bar.o

all: $(objects)

$(objects): %.o: %.c
$(CC) -c $(CFLAGS) $< -o $@
等价:
foo.o : foo.c
$(CC) -c $(CFLAGS) foo.c -o foo.o

bar.o : bar.c
$(CC) -c $(CFLAGS) bar.c -o bar.o

*********************************************
files = foo.elc bar.o lose.o

$(filter %.o,$(files)): %.o: %.c
$(CC) -c $(CFLAGS) $< -o $@

$(filter %.elc,$(files)): %.elc: %.el
emacs -f batch-byte-compile $<

自动生成依赖性
cc -M main.c

其输出是:
main.o : main.c defs.h

如果你使用GNU的C/C++编译器,你得用“-MM”参数,不然,“-M”参数会把一些标准库的头文件也包含进来。

我们可以写出[.c]文件和[.d]文件的依赖关系,并让make自动更新或自成[.d]文件,并把其包含在我们的主Makefile中,这样,我们就可以自动化地生成每个文件的依赖关系了。
%.d: %.c
@set -e; rm -f $@; \
$(CC) -M $(CPPFLAGS) $< >; $@.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ >; $@; \
rm -f $@.$$$$

如果make执行时,带入make参数“-n”或“--just-print”或“--dry-run” 或“--recon”,那么其只是显示命令,但不会执行命令
“-t” 或“--touch” 这个参数的意思就是把目标文件的时间更新,但不更改目标文件。
make参数“-s”或“--slient”则是全面禁止命令的显示。
make的参数的是“-k”或是“--keep-going”,这个参数的意思是,如果某规则中的命令出错了,那么就终目该规则的执行,但继续执行其它规则。
“-w”或是“--print-directory”会在make的过程中输出一些信息,让你看到目前的工作目录。
当你使用“-C”参数来指定make下层Makefile时,“-w”会被自动打开的。如果参数中有“-s”(“--slient”)或是“--no-print-directory”,那么,“-w”总是失效的。
“-f”或是“--file”参数 指定Makefile make -f hchen.mk 如果在make的命令行是,不只一次地使用了“-f”参数,那么,所有指定的makefile将会被连在一起传递给make执行。
“-q” 或“--question” 这个参数的行为是找目标的意思,也就是说,如果目标存在,那么其什么也不会输出,当然也不会执行编译,如果目标不存在,其会打印出一条出错信息。



subsystem:
cd subdir && $(MAKE)
其等价于:

subsystem:
$(MAKE) -C subdir


如果你要传递变量到下级Makefile中,那么你可以使用这样的声明:
export ;

如果你不想让某些变量传递到下级Makefile中,那么你可以这样声明:
unexport ;

定义命令包
define run-yacc
yacc $(firstword $^)
mv y.tab.c $@
endef

foo.c : foo.y
$(run-yacc)

“=”号 右侧中的变量不一定非要是已定义好的值,其也可以使用后面定义的值。
foo = $(bar)
bar = $(ugh)
ugh = Huh?
all:
echo $(foo)

:=前面的变量不能使用后面的变量,只能使用前面已定义好了的变量。如果是这样:

y := $(x) bar

x := foo

那么,y的值是“bar”,而不是“foo bar”。

ifeq (0,${MAKELEVEL})
cur-dir := $(shell pwd)
whoami := $(shell whoami)
host-type := $(shell arch)
MAKE := ${MAKE} host-type=${host-type} whoami=${whoami}
endif

高级使用

foo := a.o b.o c.o
bar := $(foo:.o=.c)

$(bar)”的值是“a.c b.c c.c
//*****************
objects = main.o foo.o bar.o utils.o
objects += another.o

//****************
override如果有变量是通过make的命令行参数设置的,那么Makefile中对这个变量的赋值会被忽略
override =

目标变量
prog : CFLAGS = -g

prog : prog.o foo.o bar.o

$(CC) $(CFLAGS) prog.o foo.o bar.o

prog.o : prog.c

$(CC) $(CFLAGS) prog.c

foo.o : foo.c

$(CC) $(CFLAGS) foo.c

bar.o : bar.c

$(CC) $(CFLAGS) bar.c
不管全局的$(CFLAGS)的值是什么,在prog目标,以及其所引发的所有规则中(prog.o foo.o bar.o的规则),$(CFLAGS)的值都是“-g”


模式变量
%.o : CFLAGS = -O



libs_for_gcc = -lgnu
normal_libs =

foo: $(objects)
ifeq ($(CC),gcc)
$(CC) -o foo $(objects) $(libs_for_gcc)
else
$(CC) -o foo $(objects) $(normal_libs)
endif

ifdef ;

如果变量;的值非空,那到表达式为真
文章评论

共有 3 条评论

  1. time00 于 2010-11-26 11:08:10发表:

    收藏备用

  2. gllw915 于 2010-10-29 16:40:59发表:

    先收藏之,慢慢研究

  3. xidianwxm 于 2010-01-02 20:16:07发表:

    谢谢