Model: GPT-4
Date: 2023-03-16
これから「コマンドラインでこういう入力をしたときにはこういう処理をしてほしい」という仕様をいくつかお伝えしていきますので、それに対応したmakefileを作ってほしいと思います。一度に仕様のすべては書けないので、対話しながら仕様をお伝えします。あなたはmakefileを作ることもできますよね。
もちろん、Makefileを作成することができます。どのような仕様をお考えでしょうか?教えていただけると、それに応じたMakefileを作成していきます。
通常makefileはソースとオブジェクトの依存関係を記述して、最低限のコンパイルで全体をビルドするみたいな使い方をしますけれど、そういうのを作りたいわけではありません。いまから作りたいシステムは、ある種のコマンドインタプリタみたいなものです。まず最初に、make eとコマンドラインで入力したときには、current という変数に入っているファイルをテキストファイルだと思って、vim で編集開始するという仕様があります。どうでしょう、伝わってます?
はい、理解しました。make e を実行したときに、current という変数に格納されたファイル名を使って、そのテキストファイルをvimで開くMakefileを作成します。
以下のようなMakefileを作成しました。
current := example.txt
e:
@vim $(current)このMakefileでは、current という変数に example.txt を設定しています。make e コマンドを実行すると、vimで example.txt が開かれます。current 変数に別のファイル名を設定すれば、そのファイルが開かれるようになります。
そうです。やりたいのはそういうことです。次の仕様をお伝えする前にお聞きしたいんですが、makefile に:= という記述方法があるんですか。それは知りませんでした。私が使ったことがあるのは=を使って変数に値を代入するものだけでした。
はい、Makefileでは:=という記述方法があります。:=と=の違いを説明します。
= : 再帰的変数代入 (recursive variable assignment)
この方法で代入された変数は、参照されるたびに評価されます。そのため、変数の値が他の変数を含んでいる場合、参照時点での他の変数の値が使用されます。
:= : 単純変数代入 (simple variable assignment)
この方法で代入された変数は、代入時点で評価されます。そのため、変数の値が他の変数を含んでいても、代入時点での他の変数の値が使用されます。 再帰的変数代入を使用する場合、変数の評価が遅延されるため、より柔軟な動作が期待できます。しかし、その分処理が遅くなる可能性があります。一方、単純変数代入を使用すると、変数の評価が即座に行われるため、処理速度が向上しますが、動的な値の変更には対応できません。
今回の例では、単純変数代入:=を使用しても問題ありませんが、再帰的変数代入=を使用しても動作に大きな違いはありません。必要に応じてどちらの記法を使用しても構いません。
よくわかりました。ありがとうございます。次の仕様です。コマンドラインからmake showと入力すると、変数outputにファイル名が入ったファイルを、変数viewerにコマンド名が入ったプログラムによって、表示するようにmakefileを書いてください。先ほどのmake eのmakefileに付け加える形でお願いします。
了解しました。指定された仕様に従って、make show コマンドが output 変数に格納されたファイル名のファイルを、viewer 変数に格納されたコマンド名のプログラムで表示するように、先ほどのMakefileに追加します。
以下のようにMakefileを更新しました。
current := example.txt
output := output.txt
viewer := cat
e:
@vim $(current)
show:
@$(viewer) $(output)このMakefileでは、output 変数に output.txt を設定し、viewer 変数に cat コマンドを設定しています。make show コマンドを実行すると、cat コマンドで output.txt が表示されます。output と viewer の変数に別の値を設定すれば、それに応じた挙動が得られます。
特に説明しませんでしたが、変数viewerのデフォルト値としてcatを入れてくださったのはわかりやすいですね。私の意図が伝わっているのを感じます。ところで次の仕様に行く前に質問があるのですが、makefileではこういうふうにコマンド的な使い方をする際にターゲットに対して.PHONYの指定をした記憶があるんですが、.PHONYの指定はいらないんでしたっけ。
.PHONY についてのご質問、承知しました。.PHONY は、Makefile内で指定されたターゲットがファイルではなく、あくまでコマンドやアクションを示すものであることを明示するために使用されます。
.PHONY を指定しない場合、ターゲット名と同じファイルが存在すると、Makeはそのファイルのタイムスタンプを元にして、ターゲットが実行されるかどうかを判断します。そのため、ターゲットが実行されない場合があります。
今回のようなコマンド的な使い方をする場合、.PHONY を指定することで、ファイルの存在やタイムスタンプに関係なく、ターゲットが必ず実行されることが保証されます。したがって、今回のMakefileに .PHONY を追加することをお勧めします。
以下のようにMakefileを更新しました。
current := example.txt
output := output.txt
viewer := cat
.PHONY: e show
e:
@vim $(current)
show:
@$(viewer) $(output)これで、make e と make show コマンドは、ファイルの存在やタイムスタンプに関係なく、必ず実行されるようになりました。
.PHONYの説明もありがとうございました。では最後の仕様として、デフォルトの動作を指定します。単にmakeと入力したときには、単に「default action is not defined.」とだけ表示するようにしてください。これも、これまでのmakefileに追加してください。
了解しました。make コマンドを実行したときに、デフォルトで「default action is not defined.」と表示するようにMakefileを更新します。
以下のようにMakefileを更新しました。
current := example.txt
output := output.txt
viewer := cat
.PHONY: e show default
default:
@echo "default action is not defined."
e:
@vim $(current)
show:
@$(viewer) $(output)ただし、この状態ではまだデフォルトターゲットが default になっていません。デフォルトターゲットを default に設定するために、Makefileの先頭に default ターゲットを追加します。
default: ## Set the default target
.PHONY: default
default:
@echo "default action is not defined."
current := example.txt
output := output.txt
viewer := cat
.PHONY: e show
e:
@vim $(current)
show:
@$(viewer) $(output)これで、単に make と入力したときに、「default action is not defined.」と表示されるようになりました。
ありがとうございます。今回作ってみたかったものはおおむねこれでできあがりました。感謝します。いろいろ教えてくださったのも助かります。また次回何かを作るときにも助けてくださいね。それでは、また!
どういたしまして!お手伝いできてうれしいです。また何かお手伝いできることがあれば、いつでもお気軽にお声がけください。次回もお手伝いできることを楽しみにしています。それでは、またお会いできる日を楽しみにしています!