GNU Makeは思っている以上のことができます

プロジェクトのソースコードを配布する必要があるとすぐに、お気に入りのIDEを生成する代わりに、ビルドシステムを使用する必要が生じます。 Autotoolsは(gnuフィードを使用して)UNIXの世界で伝統的に使用されており、cmakeまたはsconsの形式の優れた代替手段があります。 しかし、何らかの理由で、LinuxカーネルはGNU Makeを使用してビルドされ、ポートを含むすべてのFreeBSDはBSD Makeを使用してビルドされます。 WTF?



オートツールで苦労した後、私は実験を行うことにしました-多かれ少なかれ便利なアセンブリを自分自身に提供するために、Makefileをどれだけシャベルできますか。







なぜなら 現代のmakeは非常に異なるため、GNU Makeを使用しました。 私のメインシステム(GNU / Linux)にネイティブです。

それで、私が最初に気づいたのは、各ファイルにルールを書く必要がないことです。 つまり 次のようにファイルブロックごとに繰り返す代わりに:

 foo.o:foo.c
	 $(CC)-c foo.c


特定のbinarikの依存オブジェクトのリストを指定するだけで、それらを収集できます。

 main_executable:foo.o bar.o test.o main.o
     $(CC)$ ^ -o $ @ $(LDFLAGS)


$ ^および$ @とは何ですか? これらは自動変数で、ここでは$ @はターゲットの名前(つまりmain_executable)で展開され、$ ^はすべての依存関係のリストで展開されます。 すべての自動変数の詳細な説明はこちらです。



解決したい2番目の問題は、依存関係の生成です。 あるファイルは別のファイルに依存する場合がありますが、システムヘッダーなどに依存します。 あなたが手でそれらを処方する場合、以前の発見には意味がありません。

判明したように、gccは-Mスイッチを使用して、ソースを解析し、依存するヘッダーを一覧表示できます:gcc -Mfoo.c。 コマンドの出力はMakefile形式であるため、ファイルに保存してMakefileに接続できます。 ほとんどのビルドシステムもgcc -Mを使用します。 古典的に、依存関係の生成はターゲットのどこかに詰め込まれていました:依存関係ですが、 マニュアルではすべての依存関係を自動的に更新する方法がありました。

ボードはオブジェクトの単一リストを使用しますが、複数の目標がある場合はどうなりますか? 私はみんなのために手を書くのが面倒です! したがって、このスキームに従ってMakefileを整理することにしました。

*すべてのターゲット(バイナリ)を含むターゲットリストがあります。 アセンブリのルールは手動で登録されます。

*各ターゲットには、そのオブジェクトのリストがあります:target_obj = foo.o bar.oなど。

*すべての目標を通過するすべての目標があります。

これに基づいて、すべての目標を取得し、それらの名前をtarget_obj型に変換し、それらからオブジェクトを引き出し、それらの接尾辞を.dep(または.d)に変更してから、接続するだけです。 複雑に聞こえますか? これをさらに混乱させる行: deps = $(foreach o、$(targets:= _ obj)、$($(o):%。O = .deps /%。Dep)) 。 ニュアンスを説明することすらしません。.deps/ foo.depの形式で、各オブジェクトの依存関係のリストを生成するだけです。 .depsディレクトリにのみ、並べ替えでディレクトリ内を破壊しないようにします。



結論として、メイクファイルの例:

 CFLAGS = -Wall -pipe -ggdb

 compiler_obj = compiler.o string_util.o tokenizer.o btree.o memory.o ast.o
 vm_obj = vm.o

ターゲット=コンパイラvm

 all:$(ターゲット)

 .deps /%。dep:%.c
	 @mkdir -p .deps
	 @set -e;  rm -f $ @;  \
		 $(CC)-M $(CFLAGS)$ <> $ @;  \
		 sed -i 's、\($ * \)\。o [:] *、\ 1.o $ @ :, g' $ @;

 deps = $(foreach o、$(targets:= _ obj)、$($(o):%。o = .deps /%。dep))
 -include $(deps)

エコーデプス:
	 @echo $(deps)

コンパイラー:$(compiler_obj)
	 @ $(CC)$ ^ -o $ @ $(LDFLAGS)

 vm:$(vm_obj)
	 @ $(CC)$ ^ -o $ @ $(LDFLAGS)

きれいな:
	 rm -f * .o .deps / *。dep $(ターゲット)

 ctags:
	 @ctags * .c * .h




PSこの場合、まだ多くの欠点がありますが、GNU Makeの経験から、必要に応じて完全なビルドシステムを作成できることがわかりました。 おそらく将来的には、メイクファイルのより一般的なライブラリを作成して投稿する予定です。



All Articles