メイクファイルの例

メイクファイルの作成は頭痛の種になることがあります。 ただし、見てみると、すべてが適切に配置されており、任意の大規模プロジェクト用の強力な40行のメイクファイルを作成するのは迅速かつエレガントです。



注意! GNU makeユーティリティの基本的な知識を前提としています。





次のディレクトリ構造を持つ典型的な抽象プロジェクトがあります。







ソースにヘッダーファイルをインクルードするために#include <dir1 / file1.h>のようなものが使用されると仮定します。つまり、プロジェクト/インクルードディレクトリはコンパイル中に標準化されます。



組み立て後、次のようになることが必要です。







つまり、binディレクトリには作業(アプリケーション)およびデバッグ(application_debug)バージョンがあり、project / objディレクトリのReleaseおよびDebugサブディレクトリでは、project / srcディレクトリ構造が、binディレクトリの内容を構成するオブジェクトファイルの対応するソースファイルで繰り返されます。



この効果を実現するには、プロジェクトディレクトリに次の内容のMakefileを作成します。

  1. root_include_dir:=含める
  2. root_source_dir:= src
  3. source_subdirs:=。 dir1 dir2
  4. compile_flags:= -Wall -MD -pipe
  5. link_flags:= -s -pipe
  6. ライブラリ:= -ldl
  7. relative_include_dirs:= $ addprefix .. / .. / 、$ root_include_dir
  8. relative_source_dirs:= $ addprefix .. / .. / $ root_source_dir / 、$ source_subdirs
  9. objects_dirs:= $ addprefix $ root_source_dir / 、$ source_subdirs
  10. オブジェクト:= $ patsubst .. / .. /% 、$ wildcard $ addsuffix / * .c * 、$ relative_source_dirs ))
  11. オブジェクト:= $ オブジェクト:.cpp = .o
  12. オブジェクト:= $ オブジェクト:.c = .o
  13. all:$ program_name
  14. $ program_name :obj_dirs $ objects
  15. g ++ -o $ @ $ オブジェクト $ link_flags $ ライブラリ
  16. obj_dirs:
  17. mkdir -p $ objects_dirs
  18. VPATH:= .. / .. /
  19. .o: %. cpp
  20. g ++ -o $ @ -c $ < $ compile_flags $ build_flags $ addprefix -I、$ relative_include_dirs
  21. .o: %. c
  22. g ++ -o $ @ -c $ < $ compile_flags $ build_flags $ addprefix -I、$ relative_include_dirs
  23. .PHONY:クリーン
  24. きれいな:
  25. rm -rf bin obj
  26. include $ ワイルドカード$ addsuffix / * .d、$ objects_dirs ))


純粋な形式では、このようなmakefileはbinおよびobjディレクトリを削除するクリーンな目標を達成するためにのみ役立ちます。

Releaseという別のスクリプトを追加して、作業バージョンをビルドします。



mkdir -p bin mkdir -p obj mkdir -p obj/Release make --directory=./obj/Release --makefile=../../Makefile build_flags="-O2 -fomit-frame-pointer" program_name=../../bin/application
      
      







デバッグバージョンをビルドする別のデバッグスクリプト:



 mkdir -p bin mkdir -p obj mkdir -p obj/Debug make --directory=./obj/Debug --makefile=../../Makefile build_flags="-O0 -g3 -D_DEBUG" program_name=../../bin/application_debug
      
      







私たちのプロジェクトが作業バージョンまたはデバッグバージョンで収集するのは、そのうちの1人の挑戦です。 そして今、まず最初に。



デバッグバージョンをビルドする必要があるとしましょう。 プロジェクトディレクトリに移動し、。/ Debugを呼び出します。 最初の3行はディレクトリを作成します。 makeユーティリティの4行目は、起動時にproject / obj / Debugを現在のディレクトリにする必要があることを報告します。これに関連して、makefileへのパスが渡され、2つの定数が設定されます:build_flags(これはデバッグバージョンの重要なコンパイルフラグをリストします)およびprogram_name(デバッグバージョンの場合-これはapplication_debugです)。



次に、GNU makeが作用します。 メイクファイルの各行にコメントします。



1:変数は、ヘッダーファイルのルートディレクトリの名前で宣言されます。



2:変数は、ソースルートディレクトリの名前で宣言されます。



3:ソースルートディレクトリのサブディレクトリの名前で変数が宣言されます。



4:共通のコンパイルフラグを持つ変数が宣言されます。 -MDを指定すると、コンパイラは各ソースに対して拡張子.dの同じ名前の依存関係ファイルを生成します。 そのような各ファイルはルールのように見えます。ターゲットはソースの名前であり、依存関係はすべて、#includeディレクティブに含まれるソースおよびヘッダーファイルです。 -pipeフラグは、コンパイラにファイルシステムの代わりにIPCを使用するように強制します。これにより、コンパイルが多少速くなります。



5:変数は、一般的なレイアウトフラグで宣言されます。 -sは、結果のELFファイルからリンカーに.symtab、.strtab、および.debug *などの名前のセクションを強制的に削除させ、サイズを大幅に縮小します。 デバッグを改善するために、このキーを削除できます。



6:変数は、レイアウトキーとして使用されるライブラリの名前で宣言されます。



8:標準ヘッダーファイルを持つ相対ディレクトリ名を含む変数が宣言されます。 次に、そのような名前はコンパイラに直接渡され、-Iスイッチが前に付きます。 この場合、そのようなディレクトリが1つあるため、.. / .. / includeになります。 addprefix関数は、2番目の引数が設定するすべての目標に最初の引数を追加します。



9:ソースルートディレクトリのすべてのサブディレクトリの相対名を含む変数が宣言されます。 結果として、.. / .. / src /が得られます。 ../../src/dir1 ../../src/dir1。



10:現在のプロジェクト/ obj / Debugに関連するプロジェクト/ obj / Debug / srcディレクトリのサブディレクトリ名を含む変数が宣言されます。 つまり、これにより、project / srcディレクトリ構造のコピーを列挙します。 その結果、次のようになります:/ src / dir1 src / dir2。



11:現在のディレクトリに関係なく、同じ名前の* .c *(.cpp \ .c)ファイルに基づいて見つかったソースの名前を含む変数が宣言されます。 段階的に調べます。addsuffixの結果は../../src/./*.*../../src/dir1/*.*../../src/dir2/*.*になります。 ワイルドカード機能は、アスタリスクを使用してパターンを実際のファイル名に展開します:../../src/./main.pp../../src/dir1/file1.../../src/dir1/file2.pp ../../src/dir2/file3.c ../../src/dir2/file4.c patsubsb関数は、ファイル名から../../プレフィックスを削除します(最初の引数で指定されたパターンを2番目の引数のパターンに置き換え、%は任意の数の文字を示します)。 その結果、次のようになります:src /./main.ppsrc / dir1 /file1.src / dir1 /file2.ppsrc / dir2 /file3.src / dir2 /file4.



12:拡張子のソース名を持つ変数では、.cppが.oに置き換えられます。



13:拡張子のソース名を持つ変数では、.cが.oに置き換えられます。



15:最初に発表されたルール-その目標はプロジェクト全体の目標になります。 依存関係は、プログラムの名前(../../bin/application_debugをスクリプトから作成したときに渡した)を含む定数です。



17:主な目的の説明。 依存関係も明らかです。project/ srcディレクトリの構造と、その中の多くのオブジェクトファイルを繰り返すproject / obj / Debugで作成されたサブディレクトリの存在。



18:オブジェクトファイルをターゲットにリンクするためのアクションを説明します。



20:ターゲットがプロジェクト/ obj / Debug / srcディレクトリとそのサブディレクトリであるルール。



21:目標を達成するためのアクションは、対応するディレクトリsrc /.、Src / dir1およびsrc / dir2を作成することです。 mkdirユーティリティの-pスイッチは、ディレクトリの作成時にディレクトリが既に存在する場合、エラーを無視します。



23:VPATH変数は値../../を取ります。 これは、次のルールテンプレートに必要です。



25:目標が%.oパターンに一致する目標(つまり、.oで終わる名前)であり、これらの目的の依存関係が%.cppパターンに一致する同じ名前(つまり、 .cpp)。 この場合、同じ名前は完全に一致するだけでなく、依存関係の名前の前にVPATH変数の内容がある場合も意味します。 例えば、VPATHには../../が含まれているため、名前src / dir1 / file2および../../src/dir1/file2は一致します。



26:C ++ソースをオブジェクトファイルに変換するコンパイラー呼び出し。



28:目標が%.oパターン(つまり、.oで終わる名前)に一致する目標であり、これらの目的の依存関係が%.cパターン(つまり、名前で終わる名前)に一致する目標である一連のルールが記述されています.c)。 23行目と同じです。



29:コンパイラを呼び出して、Cソースをオブジェクトファイルに変換します。



31:一部のクリーンターゲットが抽象として宣言されています。 抽象目標の達成は常に発生し、同じ名前のファイルの存在に依存しません。



32:抽象ターゲットのクリーンを宣言します。



33:それを達成するためのアクションは、project / binおよびproject / objディレクトリをすべてのコンテンツとともに破棄することです。



36:現在のディレクトリのサブディレクトリにあるすべての依存ファイル(拡張子.d)の内容を含めます。 makeユーティリティは、メイクファイルの解析の開始時にこのアクションを実行します。 ただし、依存ファイルはコンパイル後にのみ作成されます。 したがって、最初のビルドでは、そのようなファイルは含まれません。 しかし、これは怖くない。 これらのファイルを含める目的は、変更されたヘッダーファイルに応じてソースを再コンパイルすることです。 2回目以降のビルドでは、makeユーティリティにすべての依存ファイルに記述されているルールが含まれ、必要に応じて、変更されたヘッダーファイルに依存するすべての目標を達成します。



頑張って



All Articles