码迷,mamicode.com
首页 > 其他好文 > 详细

make总结(三):高级

时间:2015-12-31 19:11:14      阅读:257      评论:0      收藏:0      [点我收藏+]

标签:

一、几点细节帮助理解Makefile

  1. makefile中的变量引用方法为$(VAR), 若为$VAR,则make只对$V进行替换。(我的系统上是这样。)

  2. 若要在makefile中写shell指令,引用shell中的变量时的格式是$$VAR。make将$$VAR做一次转椅,扔给shell时,shell看到的是$VAR,符合shell中引用变量的格式。

  3. make的规则中的命令若没有;结尾,则每条指令都是在一个新的shell中,若想多条命令在一个shell中执行,可以用;将他们连起来。(涉及到shell执行的方式)

  4. make中存在大量隐式规则,简化makefile的编写。隐式规则可以被覆盖。

  5. make按照从上到下从左到右读入makefile中的内容,但是在处理makefile中的语句是并不是这样的顺序。

  6. make处理makefile分为两个阶段,第一个阶段读入makefile,以及包含的其他makefile,分析变量名及变量值,隐式规则和显式规则

    构建所有目标关系树,以及他们的先决条件。

    第二阶段根据第一阶段建立的关系树分析哪些目标需要重新构建,执行哪些命令来构建。

  7. make处理makefile时存在立即展开(第一阶段就展开)和延迟展开(第二阶段展开)。

      变量赋值时,赋值号左边总是立即展开,但是右边的变量却不一定。

    所有条件语句都是立即展开,自动变量都是延迟展开(他们都是在规则的命令块中被设置),所以自动变量在条件语句中不能使用。如果一定要使用,则只能使用shell条件语法。

  8. 规则的展开策略:目标和依赖都是立即展开,命令只能延迟展开(自动变量在命令中)。

二、举例 

  项目huge的目录结构如图所示:

技术分享

  1. build目录下的Makefile的作用:分别进入./code/huge/src和./code/foo/src并执行子目录里面的makefile。

  2. 将两个子目录的Makefile的公用部分抽离到build下的make.rule。并在子目录中包含make.rule简化子目录的Makefile编写,增加复用性。

技术分享
 1 .PHONY: all clean
 2 
 3 # get the root of the project, you can use func: abspath
 4 ROOT=$(realpath ..)
 5 
 6 # list all directory we need to go to.
 7 DIRS = $(ROOT)/code/foo/src  8     $(ROOT)/code/bar/src  9     $(ROOT)/code/huge/src
10 
11 RM=rm
12 RMFLAFGS=-rf
13 RMS=$(ROOT)/build/bins $(ROOT)/build/libs
14 
15 all clean:
16     #tell shell that if any error occur, exit immediately. then make will stop.
17     @set -e; 18     for dir in $(DIRS); 19     do 20         cd $$dir && $(MAKE) ROOT=$(ROOT) -r $@; 21     done
22     @set -e; 23     if [ "$(MAKECMDGOALS)" == "clean" ]; then $(RM) $(RMFLAFGS) $(RMS); fi 
24     @echo ""
25     @echo ":-) Completed"
26     @echo ""
./build/Makefile
技术分享
 1 .PHONY: all clean
 2 
 3 MKDIR=mkdir
 4 RM=rm
 5 RMFLAGS=-rf
 6 
 7 CC=gcc
 8 AR=ar
 9 ARFLAGS=crs
10 
11 DIR_OBJS=objs
12 DIR_BINS=$(ROOT)/build/bins
13 DIR_DEPS=deps
14 DIR_LIBS=$(ROOT)/build/libs
15 DIRS=$(DIR_OBJS) $(DIR_BINS) $(DIR_DEPS) $(DIR_LIBS)
16 RMS=$(DIR_OBJS) $(DIR_DEPS)
17 
18 ifneq ("$(BIN)", "")
19 BIN:=$(addprefix $(DIR_BINS)/, $(BIN))
20 RMS+=$(BIN)
21 endif
22 
23 ifneq ("$(LIB)", "")
24 LIB:=$(addprefix $(DIR_LIBS)/, $(LIB))
25 RMS+=$(LIB)
26 endif
27 
28 SRC=$(wildcard *.c)
29 OBJ=$(SRC:.c=.o)
30 OBJ:=$(addprefix $(DIR_OBJS)/, $(OBJ))
31 DEP=$(SRC:.c=.dep)
32 DEP:=$(addprefix $(DIR_DEPS)/, $(DEP))
33 
34 ifeq ("$(wildcard $(DIR_OBJS))", "")
35 DEP_DIR_OBJS := $(DIR_OBJS)
36 endif
37 
38 ifeq ("$(wildcard $(DIR_BINS))", "")
39 DEP_DIR_BINS := $(DIR_BINS)
40 endif
41 
42 ifeq ("$(wildcard $(DIR_DEPS))", "")
43 DEP_DIR_DEPS := $(DIR_DEPS)
44 endif
45 
46 ifeq ("$(wildcard $(DIR_LIBS))", "")
47 DEP_DIR_LIBS := $(DIR_LIBS)
48 endif
49 
50 ifneq ($(INCLUDE_DIRS), "")
51 INCLUDE_DIRS:=$(strip $(INCLUDE_DIRS))
52 INCLUDE_DIRS:=$(addprefix -I, $(INCLUDE_DIRS))
53 endif
54 
55 ifneq ($(LINK_LIBS), "")
56 LINK_LIBS:=$(strip $(LINK_LIBS))
57 LIB_ALL:=$(notdir $(wildcard $(DIR_LIBS)/*))    #find out all the filename in "$(DIR_LIBS)/"
58                                                 #TEST_LIB:=$(addprefix $(DIR_LIBS)/, $(LIB_ALL))
59 LIB_FILTERED:=$(addsuffix .%, $(addprefix lib, $(LINK_LIBS))) # result is libxxx.%
60 $(eval DEP_LIBS=$(filter $(LIB_FILTERED), $(LIB_ALL)))
61 DEP_LIBS:=$(addprefix $(DIR_LIBS)/, $(DEP_LIBS))
62 LINK_LIBS:=$(addprefix -l, $(LINK_LIBS))
63 endif
64 
65 #first goal must allocate this position
66 all: $(BIN) $(LIB)
67 
68 #this include directive will import rule, if "all: $(BIN) $(LIB)" after this include directive
69 #the default target will not be "all: $(BIN) $(LIB)"
70 ifneq ("$(MAKECMDGOALS)", "clean")
71 include $(DEP)
72 endif
73 
74 $(DIRS):
75     $(MKDIR) $@
76 
77 $(BIN): $(DEP_DIR_BINS) $(OBJ) $(DEP_LIBS)
78     $(CC) -o $@ -L$(DIR_LIBS) $(filter %.o, $^) $(LINK_LIBS)
79     
80 $(LIB): $(DEP_DIR_LIBS) $(OBJ)
81     $(AR) $(ARFLAGS) $@ $(filter %.o, $^)
82 
83 $(DIR_OBJS)/%.o: $(DEP_DIR_OBJS) %.c
84     $(CC) -c -o $@ $(INCLUDE_DIRS) $(filter %.c, $^)
85     
86 $(DIR_DEPS)/%.dep: $(DEP_DIR_DEPS) %.c
87     @echo "Creating $@ ..."
88     @set -e; 89     $(RM) $(RMFLAGS) $@.tmp; 90     $(CC) -E -MM $(INCLUDE_DIRS) $(filter %.c, $^) > $@.tmp; 91     sed ‘s,\(.*\)\.o[ :]*,objs/\1.o $@: ,g‘ < $@.tmp > $@; 92     $(RM) $(RMFLAGS) $@.tmp
93     
94 clean:
95     $(RM) $(RMFLAGS) $(RMS) 
96     
./build/make.rule
技术分享
1 BIN=
2 
3 LIB=libfoo.a
4 
5 INCLUDE_DIRS=$(ROOT)/code/foo/inc
6 
7 LINK_LIBS=
8 
9 include $(ROOT)/build/make.rule
./code/foo/src/Makefile
技术分享
1 BIN=huge
2 
3 LIB=
4 
5 INCLUDE_DIRS=$(ROOT)/code/foo/inc $(ROOT)/code/bar/inc
6 LINK_LIBS=foo bar
7 
8 include $(ROOT)/build/make.rule
./code/huge/src/Makefile

 三、其他

  1. make提供很多命令选项,其中--debug用来打印调试信息,对于理解make的具体执行过程很有帮助。

  2. 调试makefile时除了--debug外,还可以通过echo打印。

  3. make默认是会从隐式规则中开始查找,如果我们不想要使用隐式规则,使用-r,提高编译效率。

  4. 活用make:

     经常遇到项目在不同计算机间拷贝或通过ftp传输时,不同计算机的时间设置不同造成项目文件的时间戳是将来的时间。

     解决:在makefile添加touch目标,命令是:find $(ROOT) -exec touch {} \;

     -exec  参数后面跟的是command命令,它的终止是以;为结束标志的,所以这句命令后面的分号是不可缺少的,考虑到各个系统中分号会有不同的意义,所以前面加反斜杠。

   

  

make总结(三):高级

标签:

原文地址:http://www.cnblogs.com/pdsrazor/p/5086987.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!