シンプルなC++ Makefileの作り方 質問する

シンプルなC++ Makefileの作り方 質問する

私たちのプロジェクトでは、すべてをまとめるために Makefile を使用する必要がありますが、教授はその方法を教えてくれませんでした。

ファイルは1 つだけですa3driver.cpp。ドライバーは という場所からクラスをインポートします"/user/cse232/Examples/example32.sequence.cpp"

以上です。その他すべては に含まれています.cpp

という実行可能ファイルを作成する簡単な Makefile を作成するにはどうすればよいですかa3a.exe?

ベストアンサー1

これは Unix 用なので、実行ファイルには拡張子がありません。

注目すべき点の 1 つは、root-config適切なコンパイル フラグとリンク フラグ、およびルートに対してアプリケーションを構築するための適切なライブラリを提供するユーティリティであるということです。これは、このドキュメントの本来の読者に関連する詳細です。

メイク・ミー・ベイビー

あるいは、初めて犯された時のことを決して忘れない

make の入門的な説明と、簡単な makefile の書き方

Make とは何ですか? なぜ気にする必要があるのですか?

このツールは作るはビルド依存関係マネージャです。つまり、ソース ファイル、オブジェクト ファイル、ライブラリ、ヘッダーなどのコレクション (最近変更されたものもあります) からソフトウェア プロジェクトを取得し、それらをプログラムの正しい最新バージョンに変換するために、どのコマンドをどのような順序で実行する必要があるかを把握します。

実際、Make は他の用途にも使用できますが、それについてはここでは説明しません。

簡単な Makefile

、および を含むディレクトリがありtool tool.cc tool.o support.cc support.hhsupport.oこれらは および に依存しておりroot、 というプログラムにコンパイルされることになっているtoolとします。また、ソース ファイルをハッキングしていて (つまり、既存の はtool古くなっています)、プログラムをコンパイルするとします。

これを自分で行うには

  1. support.ccまたはがsupport.hhより新しいかどうかを確認しsupport.o、新しい場合は次のようなコマンドを実行します。

    g++ -g -c -pthread -I/sw/include/root support.cc
    
  2. support.hhまたはがtool.ccより新しいかどうかを確認しtool.o、新しい場合は次のようなコマンドを実行します。

    g++ -g  -c -pthread -I/sw/include/root tool.cc
    
  3. tool.oが より新しいかどうかを確認しtool、新しい場合は次のようなコマンドを実行します。

    g++ -g tool.o support.o -L/sw/lib/root -lCore -lCint -lRIO -lNet -lHist -lGraf -lGraf3d -lGpad -lTree -lRint \
    -lPostscript -lMatrix -lPhysics -lMathCore -lThread -lz -L/sw/lib -lfreetype -lz -Wl,-framework,CoreServices \
    -Wl,-framework,ApplicationServices -pthread -Wl,-rpath,/sw/lib/root -lm -ldl
    

うわー!面倒だ!覚えることがたくさんあり、間違いを犯す可能性もかなりあります。(ちなみに、ここで紹介するコマンド ラインの詳細は、ソフトウェア環境によって異なります。これらは私のコンピューターでは動作します。)

もちろん、毎回 3 つのコマンドをすべて実行することもできます。その方法は機能しますが、実質的なソフトウェア (MacBook でゼロからコンパイルするのに 15 分以上かかる DOGS など) には適していません。

代わりに、次のようなファイルを作成することもできますmakefile

tool: tool.o support.o
    g++ -g -o tool tool.o support.o -L/sw/lib/root -lCore -lCint -lRIO -lNet -lHist -lGraf -lGraf3d -lGpad -lTree -lRint \
        -lPostscript -lMatrix -lPhysics -lMathCore -lThread -lz -L/sw/lib -lfreetype -lz -Wl,-framework,CoreServices \
        -Wl,-framework,ApplicationServices -pthread -Wl,-rpath,/sw/lib/root -lm -ldl

tool.o: tool.cc support.hh
    g++ -g  -c -pthread -I/sw/include/root tool.cc

support.o: support.hh support.cc
    g++ -g -c -pthread -I/sw/include/root support.cc

makeコマンドラインに入力するだけです。これにより、上記の 3 つの手順が自動的に実行されます。

ここでインデントされていない行は、 「ターゲット: 依存関係」という形式になっており、依存関係のいずれかがターゲットよりも新しい場合、関連するコマンド (インデントされた行) を実行するように Make に指示します。つまり、依存関係の行は、さまざまなファイルの変更に対応するために何を再構築する必要があるかというロジックを記述します。support.cc変更があった場合は再構築する必要があることを意味しますsupport.oが、そのtool.oままにしておくこともできます。support.o変更があった場合はtool再構築する必要があります。

各依存関係行に関連付けられたコマンドはタブで区切られており (下記参照)、ターゲットを変更する (または少なくともターゲットをタッチして変更時間を更新する) 必要があります。

変数、組み込みルール、その他の便利な機能

この時点で、makefile は実行する必要がある作業を単に記憶しているだけですが、必要なコマンドをすべて完全に理解して入力する必要がありました。しかし、そうする必要はありません。Make は、変数、テキスト操作関数、およびこの作業をはるかに簡単にする多数の組み込みルールを備えた強力な言語です。

変数を作成する

make 変数にアクセスするための構文は次のとおりです$(VAR)

Make 変数に割り当てる構文は次のとおりです: VAR = A text value of some kind(またはVAR := A different text value but ignore this for the moment)。

次のような makefile の改良版のように、ルール内で変数を使用できます。

CPPFLAGS=-g -pthread -I/sw/include/root
LDFLAGS=-g
LDLIBS=-L/sw/lib/root -lCore -lCint -lRIO -lNet -lHist -lGraf -lGraf3d -lGpad -lTree -lRint \
       -lPostscript -lMatrix -lPhysics -lMathCore -lThread -lz -L/sw/lib -lfreetype -lz \
       -Wl,-framework,CoreServices -Wl,-framework,ApplicationServices -pthread -Wl,-rpath,/sw/lib/root \
       -lm -ldl

tool: tool.o support.o
    g++ $(LDFLAGS) -o tool tool.o support.o $(LDLIBS)

tool.o: tool.cc support.hh
    g++ $(CPPFLAGS) -c tool.cc

support.o: support.hh support.cc
    g++ $(CPPFLAGS) -c support.cc

読みやすくなりましたが、それでも多くの入力が必要です

関数を作成する

GNU make は、ファイルシステムやシステム上の他のコマンドからの情報にアクセスするためのさまざまな関数をサポートしています。この場合、$(shell ...)引数の出力に展開される which と、テキスト内の$(subst opat,npat,text)すべての のインスタンスを に置き換える whichに注目します。opatnpat

これを利用すると次のことが可能になります。

CPPFLAGS=-g $(shell root-config --cflags)
LDFLAGS=-g $(shell root-config --ldflags)
LDLIBS=$(shell root-config --libs)

SRCS=tool.cc support.cc
OBJS=$(subst .cc,.o,$(SRCS))

tool: $(OBJS)
    g++ $(LDFLAGS) -o tool $(OBJS) $(LDLIBS)

tool.o: tool.cc support.hh
    g++ $(CPPFLAGS) -c tool.cc

support.o: support.hh support.cc
    g++ $(CPPFLAGS) -c support.cc

入力が簡単になり、読みやすくなります。

注意してください

  1. 各オブジェクトファイルと最終的な実行可能ファイルの依存関係を明示的に指定しています。
  2. 両方のソースファイルに対してコンパイルルールを明示的に入力する必要がありました

暗黙のルールとパターンルール

一般的に、すべての C++ ソース ファイルは同じように扱われるはずですが、Make ではこれを示す 3 つの方法が用意されています。

  1. サフィックスルール (GNU make では廃止されていると考えられていますが、下位互換性のために残されています)
  2. 暗黙のルール
  3. パターンルール

暗黙のルールが組み込まれており、いくつかは以下で説明します。パターンルールは次のような形式で指定されます。

%.o: %.c
    $(CC) $(CFLAGS) $(CPPFLAGS) -c $<

つまり、示されているコマンドを実行することによって C ソース ファイルからオブジェクト ファイルが生成されるということです。ここで、「automatic」変数は$<最初の依存関係の名前に展開されます。

組み込みルール

Make には、非常に単純な makefile でプロジェクトをコンパイルできることが多いことを意味している組み込みルールが多数あります。

C ソース ファイル用の GNU make 組み込みルールは、上記に示したものです。同様に、次のようなルールを使用して C++ ソース ファイルからオブジェクト ファイルを作成します$(CXX) -c $(CPPFLAGS) $(CFLAGS)

単一のオブジェクト ファイルは を使用してリンクされます$(LD) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS)が、複数のオブジェクト ファイルをリンクしたいため、この場合は機能しません。

組み込みルールで使用される変数

組み込みルールでは、一連の標準変数を使用して、すべてのルールを書き直すことなく、ローカル環境情報 (ROOT インクルード ファイルの場所など) を指定できます。最も興味深いと思われるものは次のとおりです。

  • CC-- 使用するCコンパイラ
  • CXX-- 使用する C++ コンパイラ
  • LD-- 使用するリンカー
  • CFLAGS-- C ソースファイルのコンパイルフラグ
  • CXXFLAGS-- C++ ソースファイルのコンパイルフラグ
  • CPPFLAGS-- C および C++ で使用される C プリプロセッサのフラグ (通常は、コマンドラインで定義されたファイル パスとシンボルが含まれます)
  • LDFLAGS-- リンカーフラグ
  • LDLIBS-- リンクするライブラリ

基本的なMakefile

組み込みルールを利用することで、makefile を次のように簡素化できます。

CC=gcc
CXX=g++
RM=rm -f
CPPFLAGS=-g $(shell root-config --cflags)
LDFLAGS=-g $(shell root-config --ldflags)
LDLIBS=$(shell root-config --libs)

SRCS=tool.cc support.cc
OBJS=$(subst .cc,.o,$(SRCS))

all: tool

tool: $(OBJS)
    $(CXX) $(LDFLAGS) -o tool $(OBJS) $(LDLIBS)

tool.o: tool.cc support.hh

support.o: support.hh support.cc

clean:
    $(RM) $(OBJS)

distclean: clean
    $(RM) tool

また、特別なアクション (ソース ディレクトリのクリーンアップなど) を実行するいくつかの標準ターゲットも追加しました。

引数なしで make が呼び出されると、ファイル内で見つかった最初のターゲット (この場合は all) が使用されることに注意してください。ただし、make cleanこの場合 make がオブジェクト ファイルを削除するターゲットに名前を付けることもできます。

すべての依存関係はまだハードコードされています。

謎の改良点

CC=gcc
CXX=g++
RM=rm -f
CPPFLAGS=-g $(shell root-config --cflags)
LDFLAGS=-g $(shell root-config --ldflags)
LDLIBS=$(shell root-config --libs)

SRCS=tool.cc support.cc
OBJS=$(subst .cc,.o,$(SRCS))

all: tool

tool: $(OBJS)
    $(CXX) $(LDFLAGS) -o tool $(OBJS) $(LDLIBS)

depend: .depend

.depend: $(SRCS)
    $(RM) ./.depend
    $(CXX) $(CPPFLAGS) -MM $^>>./.depend;

clean:
    $(RM) $(OBJS)

distclean: clean
    $(RM) *~ .depend

include .depend

注意してください

  1. ソース ファイルの依存関係行がなくなりました!?!
  2. .dependとdependに関連する奇妙な魔法がある
  3. そうするとmake、makeの依存関係の行のようなものを含む、というls -A名前のファイルが表示されます。.depend

その他の読み物

バグと履歴情報を知る

Make の入力言語は空白文字を区別します。特に、依存関係に続くアクション行はタブで始まる必要があります。しかし、一連のスペースは同じに見えることがあります (実際、タブをスペースに、またはその逆に変換するエディターがあります)。その結果、Make ファイルは正しく見えるものの、動作しません。これは早い段階でバグとして認識されましたが、(物語は)すでに 10 人のユーザーがいたため、修正されませんでした。

(これは私が物理学の大学院生向けに書いたウィキペディアの投稿からコピーしたものです。)

おすすめ記事