私たちのプロジェクトでは、Makefileを使用してすべてをまとめる必要がありますが、教授は私たちにその方法を教えてくれませんでした。
私は1つのファイルa3driver.cpp
しか持っていません。ドライバは場所"/user/cse232/Examples/example32.sequence.cpp"
からクラスをインポートします。
それだけです、それ以外のものはすべて.cpp
に含まれています。
どのように私はa3a.exe
と呼ばれる実行可能ファイルを作成する簡単なMakefileを作ることに行くでしょうか?
私はいつもこれが詳細な例で学ぶのがより簡単であると思ったので、ここで私はメイクファイルについてどう思うかです。各セクションには、インデントされていない1行があり、セクションの名前とそれに続く依存関係が示されています。依存関係は、他のセクション(現在のセクションの前に実行される)またはファイル(更新された場合に次回make
を実行するときに現在のセクションが再度実行される)のいずれかです。
簡単な例を示します(タブを使用する必要がある場所に4つのスペースを使用していますが、Stack Overflowではタブを使用できません)。
a3driver: a3driver.o
g++ -o a3driver a3driver.o
a3driver.o: a3driver.cpp
g++ -c a3driver.cpp
make
と入力すると、最初のセクション(a3driver)が選択されます。 a3driverはa3driver.oに依存しているので、そのセクションに行きます。 a3driver.oはa3driver.cppに依存しているため、前回の実行以降にa3driver.cppが変更された場合にのみ実行されます。 a3driver.cppが.oファイルにコンパイルされた(または実行されたことがない)と仮定してから、a3driverに戻って最終的な実行可能ファイルをコンパイルします。
ファイルは1つしかないため、次のように縮小することもできます。
a3driver: a3driver.cpp
g++ -o a3driver a3driver.cpp
最初の例を示したのは、それがメイクファイルの力を示しているからです。別のファイルをコンパイルする必要がある場合は、別のセクションを追加するだけです。これはsecondFile.cpp(secondFile.hという名前のヘッダを読み込む)の例です。
a3driver: a3driver.o secondFile.o
g++ -o a3driver a3driver.o secondFile.o
a3driver.o: a3driver.cpp
g++ -c a3driver.cpp
secondFile.o: secondFile.cpp secondFile.h
g++ -c secondFile.cpp
こうすれば、secondFile.cppまたはsecondFile.hで何かを変更して再コンパイルしても、secondFile.cppのみが再コンパイルされます(a3driver.cppは不可)。あるいは、a3driver.cpp内で何かを変更しても、secondFile.cppは再コンパイルされません。
質問がありましたら教えてください。
"all"という名前のセクションと "clean"という名前のセクションを含めるのも伝統的です。 "all"は通常すべての実行ファイルをビルドし、 "clean"は.oファイルや実行ファイルのような "build artifacts"を削除します。
all: a3driver ;
clean:
# -f so this will succeed even if the files don't exist
rm -f a3driver a3driver.o
編集:私はあなたがWindows上にいることに気づかなかった。唯一の違いは-o a3driver
を-o a3driver.exe
に変更することです。
なぜ誰もがソースファイルをリストアップしたいのですか?単純なfindコマンドでそれを簡単に処理できます。
これは汚れた単純なC++ Makefileの例です。 .C
ファイルを含むディレクトリにそれをドロップしてからmake
...と入力してください。
appname := myapp
CXX := clang++
CXXFLAGS := -std=c++11
srcfiles := $(Shell find . -name "*.C")
objects := $(patsubst %.C, %.o, $(srcfiles))
all: $(appname)
$(appname): $(objects)
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o $(appname) $(objects) $(LDLIBS)
depend: .depend
.depend: $(srcfiles)
rm -f ./.depend
$(CXX) $(CXXFLAGS) -MM $^>>./.depend;
clean:
rm -f $(objects)
dist-clean: clean
rm -f *~ .depend
include .depend
昔の質問、私は知っていますが、後世のためです。 2つの選択肢がありました。
オプション1:最も単純なmakefile = NO MAKEFILE。
"a3driver.cpp"の名前を "a3a.cpp"に変更してから、コマンドラインで次のように入力します。
nmake a3a.exe
以上です。 gnu-makeを使っているなら、 "make"や "gmake"などを使ってください。
オプション2:2行のmakefile。
a3a.exe: a3driver.obj
link /out:a3a.exe a3driver.obj
Voilà。
Makeファイルには、コンパイルして1つのコマンドでリンクするか、1つのコマンドでコンパイルと1つのリンクでリンクするかによって、1つまたは2つの依存関係規則があります。
依存関係は、次のような規則の木です。
main_target : source1 source2 etc
command to build main_target from sources
source1 : dependents for source1
command to build source1
ターゲットのコマンドの後にmustが空白行で、コマンドの前にnotが空白行である必要があります。メークファイルの最初のターゲットは全体的な目標です。他のターゲットは最初のターゲットがそれらに依存している場合にのみ構築されます。
それであなたのmakefileはこのようなものになるでしょう。
a3a.exe : a3driver.obj
link /out:a3a.exe a3driver.obj
a3driver.obj : a3driver.cpp
cc a3driver.cpp
私は提案します:
tool: tool.o file1.o file2.o
$(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $@
または
LINK.o = $(CXX) $(LDFLAGS) $(TARGET_Arch)
tool: tool.o file1.o file2.o
後者の提案は、GNU make暗黙のルールを再利用するため、わずかに優れています。しかし、うまくいくためには、ソースファイルは最終的な実行ファイルと同じ名前でなければなりません(例:tool.c
とtool
)。
注意してください、ソースを宣言する必要はありません。中間オブジェクトファイルは暗黙の規則を使用して生成されます。したがって、このMakefile
はCおよびC++(およびFortranなど)でも機能します。
また、デフォルトでは、Makefileはリンカとして$(CC)
を使います。 $(CC)
はC++オブジェクトをリンクするためには働きません。そのためだけにLINK.o
を修正します。 Cコードをコンパイルしたい場合は、LINK.o
値を強制する必要はありません。
もちろん、変数CFLAGS
を使ってコンパイルフラグを追加したり、ライブラリをLDLIBS
に追加したりすることもできます。例えば:
CFLAGS = -Wall
LDLIBS = -lm
注意:外部ライブラリを使用する必要がある場合は、CFLAGS
とLDLIBS
を正しく設定するために pkg-config を使用することを推奨します。
CFLAGS += $(Shell pkg-config --cflags libssl)
LDLIBS += $(Shell pkg-config --libs libssl)
注意深い読者は、1つのヘッダが変更された場合、このMakefile
は正しく再構築されないことに気付くでしょう。これらの行を追加して問題を解決してください。
override CPPFLAGS += -MMD
include $(wildcard *.d)
-MMD
は、ヘッダの依存関係についてのMakefileフラグメントを含む.dファイルを構築することを可能にします。 2行目はそれらを使うだけです。
確かに、よく書かれたMakefileはまたclean
とdistclean
の規則を含むべきです:
clean:
$(RM) *.o *.d
distclean: clean
$(RM) tool
$(RM)
はrm -f
と同等ですが、rm
を直接呼び出さないことをお勧めします。
all
ルールも大歓迎です。うまくいくためには、それがあなたのファイルの最初のルールであるべきです。
all: tool
install
ルールを追加することもできます。
PREFIX = /usr/local
install:
install -m 755 tool $(DESTDIR)$(PREFIX)/bin
DESTDIR
はデフォルトでは空です。ユーザーはあなたのプログラムを別のシステムにインストールするように設定することができます(クロスコンパイルプロセスには必須です)。複数配布用のパッケージメンテナは、あなたのパッケージを/usr
にインストールするためにPREFIX
を変更するかもしれません。
最後のWord、ソースファイルをサブディレクトリに配置しないでください。本当にそうしたいのなら、このMakefile
をルートディレクトリに保存し、あなたのファイルを識別するためにフルパスを使ってください(すなわちsubdir/file.o
)。
要約すると、完全なMakefileは以下のようになるはずです。
LINK.o = $(CXX) $(LDFLAGS) $(TARGET_Arch)
PREFIX = /usr/local
override CPPFLAGS += -MMD
include $(wildcard *.d)
all: tool
tool: tool.o file1.o file2.o
clean:
$(RM) *.o *.d
distclean: clean
$(RM) tool
install:
install -m 755 tool $(DESTDIR)$(PREFIX)/bin
私はfriedmudの答えを使いました。私はしばらくこれを調べました、そして始めるのが良い方法のようです。このソリューションには、コンパイラフラグを追加するための明確に定義された方法もあります。私の環境であるUbuntuとg ++で動作するように変更を加えたので、私は再び答えました。もっと実用的な例が、時には最高の先生です。
appname := myapp
CXX := g++
CXXFLAGS := -Wall -g
srcfiles := $(Shell find . -maxdepth 1 -name "*.cpp")
objects := $(patsubst %.cpp, %.o, $(srcfiles))
all: $(appname)
$(appname): $(objects)
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o $(appname) $(objects) $(LDLIBS)
depend: .depend
.depend: $(srcfiles)
rm -f ./.depend
$(CXX) $(CXXFLAGS) -MM $^>>./.depend;
clean:
rm -f $(objects)
dist-clean: clean
rm -f *~ .depend
include .depend
makefileは非常に複雑なようです。使用していましたが、g ++ライブラリでリンクしていないことに関連するエラーが発生していました。この構成はその問題を解決しました。