banner
raye~

Raye's Journey

且趁闲身未老,尽放我、些子疏狂。
medium
tg_channel
twitter
github
email
nintendo switch
playstation
steam_profiles

學習使用Makefile來管理專案

Group 4

一直以為 Makefile 是獨屬於 C++ 專案的,看到這個文件就比較頭大,因為少不了需要執行一堆 make 命令來等待編譯鏈接。

不過最近才了解到,make 命令其實並沒有那麼神秘,相反,它可以有效地組織開發專案中會使用到的各種命令、環境變數、shell 命令等。

除此之外,Makefile 的一大好處就是可以配置一些自動化的前置步驟,比如 python 專案的 pip install, node 專案的 npm install 等。

最後,Makefile 還可以依賴本地的文件,如果文件沒有更新,則與之相應的任務並不會執行,有點類似於本地的 CI 了。

接下來就認識一下 Makefile 的簡單編寫以及實例吧。

Makefile 的基礎語法#

.PHONY#

因為 Makefile 的設計初衷其實是監控本地的文件是否有更新,再去觸發一系列動作,所以單純的 shell 命令執行得使用.PHONY(虛假)來實現,比如

dev:
	@echo "Hello, world!"
.PHONY: dev

依賴#

Makefile 是分步驟進行的,每一個步驟都會有其前置任務,其寫法一般是:

target1 [target2 ...]: [pre-req1 pre-req2 pre-req3 ...]
    [recipes
    ...]

最簡單的舉例,比如我們想執行一個 next.js 專案的本地預覽,其前置條件必須是已經安裝了對應的 dependences,那麼就可以這樣寫:

dev: node_modules ## 開啟本地服務
	@./node_modules/.bin/next dev
.PHONY: dev

node_modules: package.json
	@yarn install

這裡就構成了一個依賴的執行順序:

  1. 執行 make dev,會檢查前置條件 node_modules(注意這是一個步驟的命名)
  2. node_modules 步驟依賴於 package.json,即首先會執行一次 yarn install,後續如果 package.json 如果更新了才會執行。

根據上述簡單的示例就可以看到,Makefile 可以讓我們清晰有序地管理一些常見的開發步驟,免去諸如修改 package.json 但是忘記執行 yarn install 的 “悲劇”。

幫助文檔#

可以看到在上面的示例中,有通過 ## 來編寫註釋。

此時如果在 Makefile 中加入下面這段:

help: ## Show this help
	@echo "\nSpecify a command. The choices are:\n"
	@grep -E '^[0-9a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "  \033[0;36m%-12s\033[m %s\n", $$1, $$2}'
	@echo ""
.PHONY: help

就可以自動生成註釋了,即輸入 make help 自動打印幫助文檔,是不是非常神奇呢 hh。

簡單示例:使用 Makefile 來管理你的 hugo 博客#

hugo 管理博客有幾個最簡單的命令,如開啟伺服器,生成站點靜態文件等,我們可以將其都放在一個 Makefile 中。

all: help ## 默認打開幫助文檔

serve: ## 啟動伺服器
	@echo "Starting Hugo server..."
	hugo server

build: ## 構建站點
	@echo "Building the site..."
	hugo 

clean: ## 清理生成的文件
	@echo "Cleaning up the public directory..."
	rm -rf public/

help: ## Show this help
	@echo "\nSpecify a command. The choices are:\n"
	@grep -E '^[0-9a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "  \033[0;36m%-12s\033[m %s\n", $$1, $$2}'
	@echo ""

.PHONY: all serve build clean help

默認的命令 all 就是顯示幫助文檔,而幫助文檔的生成只需要寫清楚註釋即可自動完成,現在輸入 make 命令的效果如下:

$:~/develop$ make

Specify a command. The choices are:

  all          默認打開幫助文檔
  serve        啟動伺服器
  build        構建站點
  clean        清理生成的文件
  help         Show this help

當然這裡只是最簡單的展示,你還可以根據需要添加對應的依賴文件,以及 new post 的操作也都是可以集成進來的。

一步步使用 Makefile 來管理 python 專案#

簡單版本#

首先,假設我們的 python 專案入口為 app.py,那麼我們最終執行的目標就是

run: ## 記得加註釋,可以自動生成幫助文檔
  python app.py
.PHONY run ## 因為並沒有依賴文件,所以需要使用.PHONY

其次,python 肯定有前置依賴需要安裝,一般依賴都會寫在 requirements.txt,於是我們有

setup: requirements.txt
    pip install -r requirements.txt

當然,一般還會補充一個 clean 的命令,於是有

clean:
    rm -rf __pycache__

進階版本#

由於每個人電腦上本地的 python 環境變數都不同,當然這個也可以用 docker 來解決,不過 python 本身提供了 venv 這種更輕量級的解決方案,於是可以

python3 -m venv venv

-m venv 代表使用 venv 命令,創建一個虛擬環境,位於 venv 目錄。

此時安裝依賴就可以使用

./venv/bin/pip install -r requirements.txt

因為此時 pip 是位於 ./venv/bin/ 目錄下的。

所以得到 Makefile

venv/bin/activate: requirements.txt
 python3 -m venv venv
 ./venv/bin/pip install -r requirements.txt

但是每次都要寫 ./venv/bin/ 比較麻煩,可以使用變數做一下簡化。

即聲明一個變數 VENV 它的值默認為 venv 目錄,但是你也可以通過命令行傳遞的方式來修改。

引用變數的方式則是 $(VENV),可以理解為簡單的字串替換,於是 Makefile 就可以修改為:

VENV = venv
PYTHON = $(VENV)/bin/python3
PIP = $(VENV)/bin/pip

run: $(VENV)/bin/activate
 $(PYTHON) app.py
.PHONY run

$(VENV)/bin/activate: requirements.txt
 python3 -m venv $(VENV)
 $(PIP) install -r requirements.txt

clean:
 rm -rf __pycache__
 rm -rf $(VENV)
.PHONY clean

簡單總結#

有了 GPT 之後,其實 Makefile 完全可以讓 GPT 來代勞,對於其語法完全可以做一個簡單了解,能看懂就行了,所以我也只列舉出了最簡單的語法以及對應的示例。

不得不說有了 AI 之後,諸如此類的工作已經完全不用開發者操心了。從另一個方面來說,以前覺得一些麻煩的,不太想了解的技術細節,其實往往有很多意想不到的作用。

具體到 Makefile,完全可以將其當做一系列命令的封裝,以及一些繁瑣依賴人工記錄的步驟,甚至可以將其當做 README 文件來使用了。

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。