[解決済み】SIMPLE C++のMakefileの作り方
質問
私たちのプロジェクトでは、Makefile を使ってすべてをまとめることが要求されていますが、教授はその方法を教えてくれません。
しか持っていません。
一
ファイルを作成します。
a3driver.cpp
. ドライバは、ある場所からクラスをインポートします。
"/user/cse232/Examples/example32.sequence.cpp"
.
これだけです。それ以外のものはすべて
.cpp
.
という実行ファイルを作成する簡単なMakefileを作るにはどうしたらいいでしょうか?
a3a.exe
?
解決方法は?
Unix用なので、実行ファイルには拡張子がありません。
一つ注意すべきは
root-config
は、正しいコンパイルとリンクのフラグ、および root に対してアプリケーションをビルドするための正しいライブラリを提供するユーティリティです。これは、このドキュメントの本来の読者に関連する詳細です。
メイクミーベイビー
or You Never Forget The First Time You Got Made(初めて作られた時を決して忘れない
makeの入門的な議論と簡単なmakefileの書き方
Makeとは?そしてなぜ私は気にする必要がありますか?
というツールは 作る は、ビルドの依存関係を管理するものです。つまり、ソースファイル、オブジェクトファイル、ライブラリ、ヘッダなどの集合体からソフトウェアプロジェクトを取り出し、最近変更されたかもしれないものを正しい最新版のプログラムにするために、どのコマンドをどの順番で実行する必要があるかを知ることを引き受けてくれるのです。
実は、Makeは他のことにも使えるのですが、その話は割愛します。
簡単なMakefile
を含むディレクトリがあるとします。
tool
tool.cc
tool.o
support.cc
support.hh
および
support.o
に依存している
root
というプログラムにコンパイルされることになっています。
tool
で、ソースファイルをハックしていたとします(つまり、既存の
tool
が古くなったので、プログラムをコンパイルしたい。
自分でこれを行うには、次のようにします。
-
以下のいずれかを確認します。
support.cc
またはsupport.hh
よりも新しいです。support.o
のようなコマンドを実行します。g++ -g -c -pthread -I/sw/include/root support.cc
-
のどちらかをチェックします。
support.hh
またはtool.cc
よりも新しいです。tool.o
のようなコマンドを実行します。g++ -g -c -pthread -I/sw/include/root tool.cc
-
をチェックします。
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つのコマンドを毎回実行すればいいのです。しかし、この方法では、かなりのソフトウェア(DOGSのように、私のMacBookで一からコンパイルするのに15分以上かかるもの)に対してうまく機能しません。
その代わりに
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つのステップが自動的に実行されます。
ここでインデントされていない行は、次のような形式になっています。
target: dependencies"
で、依存関係のどれかがターゲットより新しい場合、関連するコマンド(インデントされた行)を実行するよう 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 ...)
は、引数の出力に展開されます。
$(subst opat,npat,text)
のインスタンスをすべて置き換えます。
opat
を
npat
をテキストで表示します。
これを利用することで、私たちは
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
の方が入力しやすく、読みやすいと思います。
に注目してください。
- 各オブジェクトファイルと最終的な実行ファイルの依存関係を明示的に記述しています。
- 両方のソースファイルについて、コンパイルルールを明示的に入力する必要がありました
暗黙のルールとパターンのルール
一般に、すべての C++ ソースファイルは同じように扱われるべきだと思われますが、Make はこれを表明するための方法を 3 つ提供しています。
- サフィックスルール (GNU make では時代遅れとされていますが、後方互換性のために残されています)
- 暗黙のルール
- パターンルール
暗黙のルールが組み込まれており、そのうちのいくつかを以下に説明する。パターンルールは、次のような形式で指定します。
%.o: %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -c $<
これは、C言語のソースファイルからオブジェクトファイルを生成するコマンドを実行することを意味します。
$<
は、最初の依存関係の名前に展開されます。
組み込みルール
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
また、特殊なアクション(ソースディレクトリのクリーンアップなど)を実行する標準ターゲットもいくつか追加しました。
引数なしで起動された場合、ファイル内で最初に見つかったターゲット(この場合はall)を使用しますが、ターゲットに名前を付けて取得することも可能です。
make clean
は、この場合、オブジェクト・ファイルを削除します。
まだ、すべての依存関係がハードコーディングされています。
謎の改良
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
注目すべきは
- ソースファイルの依存行がなくなった!!!?
- .dependとdependに関連した奇妙なマジックがあります。
-
もし、あなたが
make
ではls -A
という名前のファイルが表示されます。.depend
には、make の依存行のようなものが含まれています。
その他の読み物
- GNU makeマニュアル
- 有害と思われる再帰的Make 最適とは言い難い一般的な makefile の書き方と、それを避ける方法について。
バグを知る・歴史的なメモ
Make の入力言語は空白を気にします。特に 依存関係に続くアクションラインは、タブで始まる必要があります。 . しかし、スペースが連続しても同じに見えることがあり(実際、タブをスペースに無言で変換するエディターもあります)、その結果、Make ファイルは正しく見えても動作しないことがあるのです。これは早い段階でバグとして認識されましたが、( 話はそれから すでに10人のユーザーがいたため、修正されませんでした。
<サブ (これは、私が物理学の大学院生向けに書いたwikiの記事からコピーしたものです)。
関連
-
[解決済み】makefile:4。*** missing separator. 停止する
-
[解決済み】Makefileの中の.PHONYの目的は何ですか?
-
[解決済み】コマンドラインからmakeに追加の変数を渡す場合
-
[解決済み] 文字列の単語を反復処理するにはどうすればよいですか?
-
[解決済み] 1ビットのセット、クリア、トグルはどのように行うのですか?
-
[解決済み] Linux上で動作するC++コードのプロファイリングを行うにはどうすればよいですか?
-
[解決済み] GNU Makefile の変数割り当て =, ?=, :=, += の違いは何ですか?
-
[解決済み] makefile の記号 $@ と $< はどういう意味ですか?
-
[解決済み】makefileに'cd'コマンドを記述するには?
-
[解決済み】gcc makefileのエラー。"No rule to make target ..." (ターゲットにするルールがありません)
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】 unsigned int vs. size_t
-
[解決済み] テスト
-
[解決済み] エラーが発生する。ISO C++は型を持たない宣言を禁じています。
-
[解決済み】「corrupted size vs. prev_size」glibc エラーを理解する。
-
[解決済み】エラー:strcpyがこのスコープで宣言されていない
-
[解決済み】ファイルから整数を読み込んで配列に格納する C++ 【クローズド
-
[解決済み] 非静的データメンバの無効な使用
-
[解決済み】1つ以上の多重定義されたシンボルが見つかる
-
[解決済み】クラスのコンストラクタへの未定義参照、.cppファイルの修正も含む
-
[解決済み】c++で.txtファイルから2次元の配列に読み込む