Makefile 9——為依賴關系文件建立依賴關系


現在我們再對complicated項目做一些更改,增加程序文件間依賴關系的復雜度。

 1 /×    main.c   ×/
 2 #include"foo.h"
 3 int main(void)
 4 {
 5     foo();
 6     return 0;
 7 }
 8 
 9 /*    foo.c    */
10 #include<stdio.h>
11 #include"foo.h"
12 void foo(void)
13 {
14     printf("%s,This is foo()!\n",HELLO);
15 }
16 
17 
18 /*   foo.h     */
19 #ifndef __FOO_H
20 #define __FOO_H
21 #include "define.h"
22 void foo(void);
23 
24 #endif /*__FOO_H*/
25 
26 /*    define.h    */
27 #ifndef __DEFINE_H
28 #define __DEFINE_H
29 
30 #define HELLO "hello"
31 
32 #endif/*__DEFINE_H*/

在之前的Makefile不做更改的情況下,我們make一下:

 

 在這次成功編譯的基礎上,我們再做一些改動,注意在這之前不要執行make clean,否則不能發現新問題。

 

 1 /×    define.h    */
 2 #ifndef __DEFINE_H
 3 #define __DEFINE_H
 4 
 5 #include "other.h"
 6 
 7 #endif/*__DEFINE_H*/
 8 
 9 
10 /*   other.h    */
11 #ifndef __OTHER_H
12 #define __OTHER_H
13 
14 #define HELLO "hello"
15 
16 #endif /*__OTHER_H*/

 

 

從結果看,盡管foo.c和main.c都被重新編譯了,但依賴關系卻沒有重新構建。運行complicated結果,其打印結果是我們所希望的“hello”。

現在,我們對other.h文件進行修改把hello改成hi,從下面運行結果來看,項目並沒有因為更改了other文件而重新編譯。

1 #ifndef __OTHER_H
2 #define __OTHER_H
3 
4 #define HELLO "hi"
5 
6 #endif /*__OTHER_H*/

更改Makefile如下,更改部分紅色標出了,其實只增加了一個$@:

 1 .PHONY: all clean
 2 
 3 MKDIR = mkdir
 4 RM = rm
 5 RMFLAGS = -rf
 6 
 7 CC=gcc
 8 
 9 DIR_OBJS=objs
10 DIR_EXES=exes
11 DIR_DEPS=deps
12 
13 DIRS =$(DIR_OBJS) $(DIR_EXES) $(DIR_DEPS)
14 
15 EXE=complicated
16 EXE:=$(addprefix $(DIR_EXES)/,$(EXE))
17 SRCS=$(wildcard *.c)
18 OBJS=$(SRCS:.c=.o)
19 OBJS:=$(addprefix $(DIR_OBJS)/,$(OBJS))
20 DEPS=$(SRCS:.c=.dep)
21 DEPS:=$(addprefix $(DIR_DEPS)/,$(DEPS))
22 
23 ifeq ($(wildcard $(DIR_OBJS)),)
24 DEP_DIR_OBJS :=$(DIR_OBJS)
25 endif#dir_objs
26 ifeq ($(wildcard $(DIR_EXES)),)
27 DEP_DIR_EXES :=$(DIR_EXES)
28 endif#dir_exes
29 ifeq ($(wildcard $(DIR_DEPS)),)
30 DEP_DIR_DEPS :=$(DIR_DEPS)
31 endif#dir_deps
32 all: $(EXE)
33 
34 include $(DEPS)
35 
36 $(DIRS):
37     $(MKDIR) $@
38 $(EXE):$(DEP_DIR_EXES) $(OBJS)
39     $(CC) -o $@ $(filter %.o,$^)
40 $(DIR_OBJS)/%.o:$(DEP_DIR_OBJS) %.c 
41     $(CC) -o $@ -c $(filter %.c,$^)
42 $(DIR_DEPS)/%.dep:$(DEP_DIR_DEPS) %.c
43     @echo "Creating $@ ..."
44     @set -e;\
45     $(RM) $(RMFLAGS) $@.tmp;\
46     $(CC) -E -MM $(filter %.c,$^) > $@.tmp;\
47     sed 's,\(.*\)\.o[:]*,objs/\1.o $@:,g' <$@.tmp >$@;\
48     $(RM) $(RMFLAGS) $@.tmp
49 
50 clean:
51     $(RM) $(RMFLAGS) $(DIRS)

這樣之后,Makefile就可以知道other.h的更改了。因為$@表示的是依賴關系的文件名,這個問題(Makefile 6隨筆中要把foo.h加在依賴關系中的更改一樣)和之前的那個問題解決方案一樣,用sed命令可以做到,問題的根本在於,我們應該為依賴文件增加依賴關系,這樣才能將整個項目全局聯系在一起。

但是,這樣之后,連續執行兩次make clean:

第一次clean時,沒什么問題,也是我們期望的,第二次clean時,make會先構建依賴項,緊接着又把目錄刪除。為什么第二次clean時,make會重新構建依賴文件?因為我們有一個include指令,他會優先於目標執行!!!

為了解決這個問題,我們再運用條件語法,並且用到我們之前提到的MAKECMDGOALS變量。更改后的Makefile如下:

 1 .PHONY: all clean
 2 
 3 MKDIR = mkdir
 4 RM = rm
 5 RMFLAGS = -rf
 6 
 7 CC=gcc
 8 
 9 DIR_OBJS=objs
10 DIR_EXES=exes
11 DIR_DEPS=deps
12 
13 DIRS =$(DIR_OBJS) $(DIR_EXES) $(DIR_DEPS)
14 
15 EXE=complicated
16 EXE:=$(addprefix $(DIR_EXES)/,$(EXE))
17 SRCS=$(wildcard *.c)
18 OBJS=$(SRCS:.c=.o)
19 OBJS:=$(addprefix $(DIR_OBJS)/,$(OBJS))
20 DEPS=$(SRCS:.c=.dep)
21 DEPS:=$(addprefix $(DIR_DEPS)/,$(DEPS))
22 
23 ifeq ($(wildcard $(DIR_OBJS)),)
24 DEP_DIR_OBJS :=$(DIR_OBJS)
25 endif#dir_objs
26 ifeq ($(wildcard $(DIR_EXES)),)
27 DEP_DIR_EXES :=$(DIR_EXES)
28 endif#dir_exes
29 ifeq ($(wildcard $(DIR_DEPS)),)
30 DEP_DIR_DEPS :=$(DIR_DEPS)
31 endif#dir_deps
32 
33 all: $(EXE)
34 ifneq ($(MAKECMDGOALS),clean)
35 include $(DEPS)
36 endif#clean
37 
38 $(DIRS):
39     $(MKDIR) $@
40 $(EXE):$(DEP_DIR_EXES) $(OBJS)
41     $(CC) -o $@ $(filter %.o,$^)
42 $(DIR_OBJS)/%.o:$(DEP_DIR_OBJS) %.c 
43     $(CC) -o $@ -c $(filter %.c,$^)
44 $(DIR_DEPS)/%.dep:$(DEP_DIR_DEPS) %.c
45     @echo "Creating $@ ..."
46     @set -e;\
47     $(RM) $(RMFLAGS) $@.tmp;\
48     $(CC) -E -MM $(filter %.c,$^) > $@.tmp;\
49     sed 's,\(.*\)\.o[:]*,objs/\1.o $@:,g' <$@.tmp >$@;\
50     $(RM) $(RMFLAGS) $@.tmp
51 
52 clean:
53     $(RM) $(RMFLAGS) $(DIRS)

這樣就解決了。

再看一個例子:

1 all:
2     @echo "command of rule"
3 
4 all: dep
5 
6 dep:
7     @echo "prerequisite of rule"

這個make的特性說明了一個問題:在生成的依賴關系文件中,其中的規則只描述了依賴關系,而沒有任何的命令,make是怎么知道使用哪些命令進行目標構建的呢?

當一個Makefile中存在構建同一目標的不同規則時,make會將這些規則合在一起,合並的內容包括先決條件和命令。盡管在自動生成的依賴關系文件中只存在目標和先決條件,但是由於Makefile中已經定義了.o 和.dep文件的生成規則,因此make會將這兩部分結合在一起,從而形成最終針對一個(類)構建目標的規則。上面的那個例子可以很好地幫助我們理解這個make特性。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM