My code works, I don’t know why.

國王的耳朵是驢耳朵

Makefile 自動將產生的檔案指定到特定目錄

| Comments

Mar/13/2014已更正錯誤:原本錯誤分析請看這邊

之前分享了Makefile header file dependency問題解決方式之一,裏面提到把.o 和.d 指定產生到特定目錄,而不是散落各處的改進方向。過了幾天網路上看到別人的解法,手癢自己也來玩一下。

範例程式細節在這邊,不想看code只要知道每個檔案都有參考到某個自訂的header file就好了。

這次加碼一下,把檔案散落在不同目錄如下

tree view
1
2
3
4
5
6
7
8
9
10
$ tree
.
├── include
│   ├── liba.h
│   └── libb.h
├── libs
│   ├── liba.c
│   └── libb.c
├── Makefile
└── test.c

Makefile更改如下

Makefile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
CFLAGS=-g -MMD -I ./include

# binaries
LIB_SRC=$(shell ls libs/*.c)
SRCS= $(LIB_SRC) test.c

OBJS = $(patsubst %.c, %.o, $(SRCS))

# Output
OUT_DIR = build
OUT_OBJS=$(addprefix $(OUT_DIR)/, $(OBJS))
DEPS = $(patsubst %.o, %.d, $(OUT_OBJS))

# Build Rules
TARGET=test

$(OUT_DIR)/$(TARGET): $(OUT_OBJS)
  $(CC) -o $@ $^

$(OUT_DIR)/%.o:%.c
  mkdir -p $(dir $@)
  $(CC) $(CFLAGS) -c $< -o $@


clean:
  rm -rf $(OUT_DIR)

-include $(DEPS)

整個Makefile主要是

  1. 找出所有要編譯的c檔案並放在變數SRCS
  2. 把變數SRC中的.c換成.o並存到變數OBJS
  3. 再把變數OBJS裏面的字串每一個都加上build/的prefix並存到變數OUT_OBJS
  4. 再把OUT_OBJS中的.o換成.d並存到變數DEP
  5. 編譯.c到.o的時候,先產生對應於C code的目錄並將.o .d存到裏面

參數說明如下

  • -MMD請參考這邊
  • shell請參考這邊
  • patsubst請參考這邊
  • addprefix,照字面就是加上prefix
  • dir,取得檔案的dir
  • $@
    • Makefile的內建巨集,代表target
  • $<
    • Makefile的內建巨集,代表第一個prerequisite
  • - *告訴make 忽略失敗
  • %.o:%.c
    • Pattern Rules
    • %表示萬用字元,而prerequisite的%會和target的% match到的相同。所以就是說所有.o結尾的檔案depends on .c檔案時要做下面的事
    • 舉例來說$(OUT_DIR)/%.o:%.c,表示build/xxx/file1.o 會依賴對應到的xxx/file1.c
  • 其實重點是mkdir -p $(dir $@)會自動在build產生對應的目錄存放.d和.o

跑起來結果如下

result
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$ make
mkdir -p build/libs/
cc -g -MMD -I ./include -c libs/liba.c -o build/libs/liba.o
mkdir -p build/libs/
cc -g -MMD -I ./include -c libs/libb.c -o build/libs/libb.o
mkdir -p build/
cc -g -MMD -I ./include -c test.c -o build/test.o
cc -o build/test build/libs/liba.o build/libs/libb.o build/test.o

$ tree
.
├── build
│   ├── libs
│   │   ├── liba.d
│   │   ├── liba.o
│   │   ├── libb.d
│   │   └── libb.o
│   ├── test
│   ├── test.d
│   └── test.o
├── include
│   ├── liba.h
│   └── libb.h
├── libs
│   ├── liba.c
│   └── libb.c
├── Makefile
└── test.c

參考資料

Comments