Makefile 可以執行終端機的指令,所以也可以搭配重新導向 (redirection) 用來做簡單測試

例如:

test:
    ./a.out < input.txt > output.txt

這樣只需要用 $ make test 就可以測試輸入 input.txt,並把結果存到 output.txt

舊方法

不過若是有很多種輸入測資的話會有點麻煩,當然還是可以寫成這樣

test1:
    ./a.out < input1.txt > output1.txt

test2:
    ./a.out < input2.txt > output2.txt

test3:
    ./a.out < input3.txt > output3.txt

或是

test:
    ./a.out < input1.txt > output1.txt
    ./a.out < input2.txt > output2.txt
    ./a.out < input3.txt > output3.txt

這樣寫的缺點就是每次測資增加的時候舊需要修改 Makefile

Makefile 內建函式

不過其實有更好的寫法,利用 makefile 內建的函式

INPUT_DIR = input/linux/
INPUTS = $(wildcard $(INPUT_DIR)*.txt)
OUTPUT_DIR = output/linux/
OUTPUTS = $(addprefix $(OUTPUT_DIR),$(notdir $(INPUTS)))
  • wildcard: 獲取輸入檔案列表
  • notdir: 獲得檔案名稱 (去掉前面路徑)
  • addprefix: 加上前綴 (修改輸出路徑)

這樣的優點就是只要 input/linux/ 中有多的 .txt 檔就會自動加入測試,不需要修改 Makefile

完整範例

檔案們

t.c:

#include <stdio.h>

int main() {
    int a, b;
    scanf("%d%d", &a, &b);
    printf("%d\n", a + b);
    return 0;
}

Makefile:

CC = gcc
EXEC = a.out

INPUT_DIR = input/linux/
INPUTS = $(wildcard $(INPUT_DIR)*.txt)
OUTPUT_DIR = output/linux/
OUTPUTS = $(addprefix $(OUTPUT_DIR),$(notdir $(INPUTS)))
.PHONY: all, test, mk_parent_dir

all: $(EXEC)

mk_parent_dir:
    @mkdir -p $(OUTPUT_DIR)

test: mk_parent_dir $(OUTPUTS)

$(OUTPUT_DIR)%.txt: $(INPUT_DIR)%.txt $(EXEC)
    ./a.out < $< > $@
    @cat $< $@ # cat the content of file

$(EXEC): t.c
    $(CC) t.c

clean:
    rm -rf $(OUTPUT_DIR) a.out

檔案架構

$ tree .
.
├── input
│   └── linux
│       ├── test1.txt
│       ├── test2.txt
│       └── test3.txt
├── Makefile
├── output
└── t.c

使用

指令同為 $ make test

$ make test
gcc t.c
./a.out < input/linux/test2.txt > output/linux/test2.txt
1 6
7
./a.out < input/linux/test3.txt > output/linux/test3.txt
78 99
177
./a.out < input/linux/test1.txt > output/linux/test1.txt
3 4
7

結果檔案架構

$ tree .
.
├── a.out
├── input
│   └── linux
│       ├── test1.txt
│       ├── test2.txt
│       └── test3.txt
├── Makefile
├── output
│   └── linux
│       ├── test1.txt
│       ├── test2.txt
│       └── test3.txt
└── t.c

後記

上面的簡單例子中可能看不出 $(INPUTS)$(OUTPUTS) 的用途,不過在相依多的話可以直接代表全部的檔案,但若是需要做名稱配對的話還是需要 % 出馬,就像 $(OUTPUT_DIR)%.txt: $(INPUT_DIR)%.txt 來表示輸入輸出的檔名要一致。

  • ⊛ Back to top
  • ⊛ Go to bottom