make scripts
如何使用 make 來達到像是 「npm scripts」或是「composer scripts」的功能
基本概念
撰寫「Makefile」
撰寫「Makefile」內容如下
.PHONY: help status deploy
help:
    echo make [command]
    echo ====================
    echo make help
    echo make status
    echo make deploy
status:
    echo show status
deploy:
    echo deploying...「完整範例」
關於「.PHONY」的用法,請參考「GNU make / 4.6 Phony Targets」
執行指令
執行
$ make顯示
echo make [command]
make [command]
echo ====================
====================
echo make help
make help
echo make status
make status
echo make deploy
make deploy執行
$ make help顯示
echo make [command]
make [command]
echo ====================
====================
echo make help
make help
echo make status
make status
echo make deploy
make deploy這個結果跟上面直接下「
make」是一樣的,因為若沒給第一個參數,就會找第一個Rule,「help」在這個範例是放在第一個,所以「make」和「make help」結果一樣。
執行
$ make status顯示
echo show status
show status執行
$ make deploy顯示
echo deploying...
deploying...執行
$ make deploy -s顯示
deploying...這裡加上「-s」,就不會把指令也印出來,請參考「GNU make / 5.2 Recipe Echoing」。
或是改寫「Makefile」,在指令前面加上「@」。
.PHONY: help status deploy
help:
    @echo make [command]
    @echo ====================
    @echo make help
    @echo make status
    @echo make deploy
status:
    @echo show status
deploy:
    @echo deploying...「完整範例」
執行
$ make顯示
make [command]
====================
make help
make status
make deploy執行
$ make deploy顯示
deploying...設定預設「Rule」
或是改寫「Makefile」, 最前面加上一個「Rule」名稱是「default」,然後相依「help」這個「Rule」, 這樣就可以指定預設的「Rule」。
注意:「default」可以任意命名,只要放在第一個「Rule」就行了。
.PHONY: default help status deploy
default: help
status:
    @echo show status
deploy:
    @echo deploying...
help:
    @echo make [command]
    @echo ====================
    @echo make help
    @echo make status
    @echo make deploy「完整範例」
分散「.PHONY」
或是改寫「Makefile」, 將「.PHONY」分散,寫到各個「Rule」底下, 這樣的寫法除了可以防止「.PHONY」後面不會接了一長串之外,然後漏寫, 分散到各個「Rule」底下,除了容易增加,也容易刪除。
default: help
.PHONY: default
status:
    @echo show status
.PHONY: status
deploy:
    @echo deploying...
.PHONY: deploy
help:
    @echo make [command]
    @echo ====================
    @echo make help
    @echo make status
    @echo make deploy
.PHONY: help「完整範例」
把指令分散到「Shell Script」
上面的寫法,只需要一個「Makefile」搞定。
而我個人慣用把這些指令,拆解到個別的「Shell Script」去,就會如同下面的結構。
./
├── bin
│   ├── deploy.sh
│   ├── status.sh
│   └── help.sh
└── Makefile
1 directory, 4 files撰寫「Makefile」,內容如下
THE_MAKEFILE_FILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
THE_BASE_DIR_PATH := $(abspath $(dir $(THE_MAKEFILE_FILE_PATH)))
THE_BIN_DIR_PATH := $(THE_BASE_DIR_PATH)/bin
default: help
.PHONY: default
help:
    @$(THE_BIN_DIR_PATH)/help.sh
.PHONY: help
status:
    @$(THE_BIN_DIR_PATH)/status.sh
.PHONY: status
deploy:
    @$(THE_BIN_DIR_PATH)/deploy.sh
.PHONY: deploy「完整範例」
撰寫「bin/help.sh」,內容如下
#!/usr/bin/env bash
THE_BASE_DIR_PATH=$(cd -P -- "$(dirname -- "$0")" && pwd -P)
usage()
{
    echo ""
    echo "Usage: make [command]"
    echo
    cat <<EOF
Ex:
$ make
$ make help
$ make status
$ make deploy
EOF
}
usage撰寫「bin/status.sh」,內容如下
#!/usr/bin/env bash
echo show status撰寫「bin/deploy.sh」,內容如下
#!/usr/bin/env bash
echo deploying...執行指令
執行
$ make或是執行
$ make help顯示
Usage: make [command]
Ex:
$ make
$ make help
$ make status
$ make deploy執行
$ make status顯示
show status執行
$ make deploy顯示
deploying...設定「PATH」
撰寫「Makefile」,內容如下
THE_MAKEFILE_FILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
THE_BASE_DIR_PATH := $(abspath $(dir $(THE_MAKEFILE_FILE_PATH)))
THE_BIN_DIR_PATH := $(THE_BASE_DIR_PATH)/bin
PATH := $(THE_BIN_DIR_PATH):$(PATH)
default: help
.PHONY: default
help:
    @help.sh
.PHONY: help
status:
    @status.sh
.PHONY: status
deploy:
    @deploy.sh
.PHONY: deploy
test:
    @firefox
.PHONY: test
dump-path:
    @echo $(PATH)「完整範例」
上面加上下面這一行,來設定「PATH」這個「環境變數」。
PATH := $(THE_BIN_DIR_PATH):$(PATH)原本的
    @$(THE_BIN_DIR_PATH)/help.sh就可以改寫成
    @help.sh注意「$(THE_BIN_DIR_PATH)」要寫在「$(PATH)」前面,這樣就會先尋找「$(THE_BIN_DIR_PATH)」這個資料夾裡面的資料。
執行
make test顯示
firefox starting...並不會真的啟動「firefox」,請看「bin/firefox」裡面的內容。
若是改寫成下面這一行
PATH := $(PATH):$(THE_BIN_DIR_PATH)若執行「make test」, 會執行「firefox」這個指令, 不過不是「bin/firefox」裡面這個檔, 而是系統的「firefox」,通常路徑是「/usr/bin/firefox」,所以會啟動「Firfox」。
另外有一個「Rule」是「dump-path」
可以執行
$ make dump-path就可以看到「PATH」的內容了。
include
然後將剛剛的某部份寫到「mak/debug.mk」這個檔裡。
test:
    @firefox
.PHONY: test
dump-path:
    @echo $(PATH)使用「include $(THE_MAK_DIR_PATH)/debug.mk」來「include」, 撰寫「Makefile」,內容如下
THE_MAKEFILE_FILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
THE_BASE_DIR_PATH := $(abspath $(dir $(THE_MAKEFILE_FILE_PATH)))
THE_BIN_DIR_PATH := $(THE_BASE_DIR_PATH)/bin
THE_MAK_DIR_PATH := $(THE_BASE_DIR_PATH)/mak
PATH := $(THE_BIN_DIR_PATH):$(PATH)
default: help
.PHONY: default
help:
    @help.sh
.PHONY: help
status:
    @status.sh
.PHONY: status
deploy:
    @deploy.sh
.PHONY: deploy
include $(THE_MAK_DIR_PATH)/debug.mk「完整範例」
一樣可以執行
$ make test顯示
firefox starting...執行
$ make dump-path關於「include」的用法,請參考「GNU make / 3.3 Including Other Makefiles」。
傳參數
尚未研究傳參數的方式,因為在工作流程上,就是要把一些常用的動作包在一起,所以就直接把參數寫死在「script」上了。
只需要下「make [command]」就行了。
更多參考
- GNU make / 4.6 Phony Targets
- GNU make / 5.2 Recipe Echoing
- GNU make / 2.4 Variables Make Makefiles Simpler
- GNU make / 6 How to Use Variables
- GNU make / 6.5 Setting Variables
- GNU make / 3.3 Including Other Makefiles
- 用Open Source工具開發軟體: 新軟體開發關念 / Chapter 5. Makefile撰寫