modified: _posts/2015-11-17-my-oaths.md
[GalaxyBlog.git] / _posts / 2012-07-29-gmake-magic.md
blob1b3971b1bd33393745d26672c486d3251b71e88c
1 ---
2 layout: post
3 title: "Make的黑魔术咒文"
4 tagline: "见习魔法师的Spellbook"
5 description: ""
6 category: Coding
7 tags: [Make, ZT]
8 ---
9 {% include JB/setup %}
11 作为Spellbook,也就是小抄,我才不会介绍[make](http://en.wikipedia.org/wiki/Make_%28software%29)到底是什么呢!
13 ## 咒文三要素
15 ……也就是规则(rule)啦。每条规则都包括以下三部分:
17 * Targets
18 * Prerequisites
19 * Commands
21 实际写出来是这个样子的:
23     target1 target2 ... : preq1 preq2
24         cmd1
25         cmd2
27 规则的触发条件很简单: 当prerequisites中某项的修改时间新于targets中的某项,则执行commands部分。
29 ## 咒文好长我不想重复读怎么办
31 ……请使用变量(variables)
33     CC = g++
34     OBJECTS = hello.o bye.o
35     greeting : $(OBJECTS)
36         $(CC) -o $@ $(OBJECTS)
38 * `$@`是规则中的目标名;
39 * 使用`+=`添加新条目进入列表 `OBJECTS += hey.o`;
40 * 使用`=`时,若等号左边没被用到,等号右边就不会展开;当需要等号右边在定义时马上被展开的话,改用`:=`;
41 * `?=`仅在该变量从未被设置过时生效
43 ## 写依赖项好麻烦啊怎么办
45 ……请使用隐含规则(Implicit Rule)以及`-M`选项
47     # 定义隐含规则
48     %.d : %.cpp
49         $(CC) $(CFLAGS) $(CPPFLAGS) -M $< > $@
50     # 当参数不为clean时
51     ifeq($(findstring $(MAKECMDGOALS), clean),)
52     -include $(OBJECTS:.o=.d)
53     endif
55 呜啊这个例子好复杂,能不解释么……(逃)
57 * `-M`选项可以从源文件中产生规则;如果是GNU C编译器的话,可以换成`-MM`, 该选项不会生成系统头文件的prerequisites
58 * `$<`是规则中的第一个prerequisite的名称
59 * `$(CC)`使用的编译器的名称
60 * `$(CFLAGS)`传入编译器的选项
61 * `$(CPPFLAGS)`传入预处理器的选项
62 * `$(OBJECTS:.o=.d)`将OBJECTS里每项的后缀从.o改成.d
64 ## 呜啊.d/.o文件都生成在.c文件的目录里了好讨厌
66 ……请把它们扔到单独的文件夹中
68     BUILDDIR = build
69     SOURCES = hello.cpp bye.cpp
70     OBJECTS = $( addprefix $(BUILDDIR)/,$(SOURCES :.cpp=.o) )
71     DEPS = $( OBJECTS :.o=.d)
72     # ...
73     $( BUILDDIR )/%.o : %.cpp
74         $(CC) $( CFLAGS ) $( CPPFLAGS ) -o $@ -c $<
75     $( BUILDDIR )/%.d : %.cpp
76         $(CC) $( CFLAGS ) $( CPPFLAGS ) -MT $(@:.d=.o) -M $< > $@
78 还、还要解释么……
80 * `-MT`选项强制指定target为`$(@:.d=.o)`
82 ## 好复杂的赶脚有没有实例呢
84 …………
85 [source link](https://gist.github.com/ZephyrSL/3194416/)
87 {% highlight Makefile %}
88 CC = g++
89 EXECUTABLE = Datastructure_test
90 SOURCES = Datastructure_test.cpp SPList.cpp
91 # Put generated files into seperate directory
92 BUILDDIR = build
93 OBJECTS = $(addprefix $(BUILDDIR)/,$(SOURCES:.cpp=.o))
94 DEPS = $(OBJECTS:.o=.d)
96 # Switch of full output
97 Q ?= @
99 # user configuration
100 # include config.mak
102 # Adapt C flags for debug/optimized build
103 ifdef NDEBUG
104 CFLAGS += -O3 -DNDEBUG
105 else
106 CFLAGS += -O0 -g
107 endif
109 CFLAGS          += $(MY_CFLAGS)
110 CPPFLAGS        += $(MY_CPPFLAGS)
112 .PHONY: clean
114 $(BUILDDIR)/$(EXECUTABLE) : $(OBJECTS)
115         $(CC) -o $@ $(OBJECTS)
117 ifeq ($(findstring $(MAKECMDGOALS), clean),)
118 -include $(DEPS)
119 endif
121 # %.d : %.c
122 #       $(CC) -M $< > $@
124 $(BUILDDIR)/%.o : %.cpp
125         @echo "===> DEPEND $@"
126         $(Q)$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ -c $<
128 $(BUILDDIR)/%.d : %.cpp
129         @echo "===> COMPILE $@"
130         $(Q)$(CC) $(CFLAGS) $(CPPFLAGS) -MT $(@:.d=.o) -M $< > $@
132 clean :
133         rm -f $(OBJECTS) $(EXECUTABLE)
134 {% endhighlight %}
136 * 引入了`config.mak`文件,用来分离放置用户自定义的选项
137 * 因为`clean`不是文件,所以将其声明为`.PHONY`
138 * 加入了`$(Q)`这样的黑魔术,使用`make Q=`能输出详细内容
140 ## 这份小抄弱爆了请给我更好的spellbook
142 ……请猛击[GNU Make Manual Quick Reference](http://www.gnu.org/software/make/manual/make.html#Quick-Reference)