web-dev-qa-db-ja.com

SIMPLE C ++ Makeファイルを作る方法

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

私は1つのファイルa3driver.cppしか持っていません。ドライバは場所"/user/cse232/Examples/example32.sequence.cpp"からクラスをインポートします。

それだけです、それ以外のものはすべて.cppに含まれています。

どのように私はa3a.exeと呼ばれる実行可能ファイルを作成する簡単なMakefileを作ることに行くでしょうか?

259
Befall

私はいつもこれが詳細な例で学ぶのがより簡単であると思ったので、ここで私はメイクファイルについてどう思うかです。各セクションには、インデントされていない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に変更することです。

50
Brendan Long

なぜ誰もがソースファイルをリストアップしたいのですか?単純な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
32
friedmud

昔の質問、私は知っていますが、後世のためです。 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à。

12
No one

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
6
John Knoeller

私は提案します:

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.ctool)。

注意してください、ソースを宣言する必要はありません。中間オブジェクトファイルは暗黙の規則を使用して生成されます。したがって、このMakefileはCおよびC++(およびFortranなど)でも機能します。

また、デフォルトでは、Makefileはリンカとして$(CC)を使います。 $(CC)はC++オブジェクトをリンクするためには働きません。そのためだけにLINK.oを修正します。 Cコードをコンパイルしたい場合は、LINK.o値を強制する必要はありません。

もちろん、変数CFLAGSを使ってコンパイルフラグを追加したり、ライブラリをLDLIBSに追加したりすることもできます。例えば:

CFLAGS = -Wall
LDLIBS = -lm

注意:外部ライブラリを使用する必要がある場合は、CFLAGSLDLIBSを正しく設定するために 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はまたcleandistcleanの規則を含むべきです:

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
5
Jezz

私は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 ++ライブラリでリンクしていないことに関連するエラーが発生していました。この構成はその問題を解決しました。

5
VectorVortec