Makefile は C++ プロジェクト専用だと思っていましたが、このファイルを見ると頭が痛くなります。なぜなら、コンパイルとリンクを待つために一連の make コマンドを実行する必要があるからです。
しかし最近、make コマンドはそれほど神秘的ではなく、逆に開発プロジェクトで使用されるさまざまなコマンド、環境変数、シェルコマンドなどを効果的に整理できることを理解しました。
さらに、Makefile の大きな利点は、python プロジェクトの pip install や node プロジェクトの npm install など、自動化された前提ステップを設定できることです。
最後に、Makefile はローカルファイルに依存することができ、ファイルが更新されていない場合、対応するタスクは実行されません。これはローカルの CI に似ています。
次に、Makefile の簡単な書き方と例を見てみましょう。
Makefile の基本構文#
.PHONY#
Makefile の設計の目的は、ローカルファイルの更新を監視し、一連のアクションをトリガーすることです。そのため、単純なシェルコマンドの実行には.PHONY(仮想)を使用します。例えば:
dev:
@echo "Hello, world!"
.PHONY: dev
依存関係#
Makefile は段階的に進行し、各ステップには前提タスクがあります。一般的な書き方は次のとおりです:
target1 [target2 ...]: [pre-req1 pre-req2 pre-req3 ...]
[recipes
...]
最も簡単な例として、next.js プロジェクトのローカルプレビューを実行したい場合、前提条件として対応する依存関係がインストールされている必要があります。次のように書くことができます:
dev: node_modules ## ローカルサービスを開始
@./node_modules/.bin/next dev
.PHONY: dev
node_modules: package.json
@yarn install
ここで依存関係の実行順序が構成されます:
- make dev を実行すると、前提条件 node_modules(これはステップの名前です)をチェックします。
- node_modules ステップは package.json に依存しており、最初に yarn install を一度実行し、その後 package.json が更新された場合にのみ実行されます。
上記の簡単な例から、Makefile は一般的な開発ステップを明確かつ秩序正しく管理できることがわかります。package.json を変更したが yarn install を実行するのを忘れるといった「悲劇」を避けることができます。
ヘルプドキュメント#
上記の例では、##
を使用してコメントを作成しています。
このとき、Makefile に次のコードを追加すると:
help: ## このヘルプを表示
@echo "\nコマンドを指定してください。選択肢は次のとおりです:\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 と入力するとヘルプドキュメントが自動的に印刷されます。これは非常に素晴らしいですね。
簡単な例:Makefile を使用して hugo ブログを管理する#
hugo でブログを管理するための最も簡単なコマンドはいくつかあります。サーバーを起動したり、サイトの静的ファイルを生成したりすることです。これらをすべて Makefile にまとめることができます。
all: help ## デフォルトでヘルプドキュメントを表示
serve: ## サーバーを起動
@echo "Hugoサーバーを起動中..."
hugo server
build: ## サイトを構築
@echo "サイトを構築中..."
hugo
clean: ## 生成されたファイルをクリーンアップ
@echo "公開ディレクトリをクリーンアップ中..."
rm -rf public/
help: ## このヘルプを表示
@echo "\nコマンドを指定してください。選択肢は次のとおりです:\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
コマンドを指定してください。選択肢は次のとおりです:
all デフォルトでヘルプドキュメントを表示
serve サーバーを起動
build サイトを構築
clean 生成されたファイルをクリーンアップ
help このヘルプを表示
もちろん、これは最も簡単な表示に過ぎません。必要に応じて、対応する依存ファイルや新しい投稿の操作も統合できます。
一歩ずつ 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 ファイルとしても使用できます。