Makefileの実例集
[履歴] [最終更新] (2019/08/22 23:15:53)
最近の投稿
注目の記事

概要

makeコマンドを使えば、Makefileにあらかじめ記述しておいた手順にしたがって、C/C++などのソースファイルから実行ファイルを自動で生成できます。

具体例

実例1

Makefileの基本的な構造は、

処理名: 依存するファイルあるいは処理名
[タブひとつ]実行されるコマンド

となります。以下のサンプルを使用するとき、タブがうまくコピーできなくてエラーになるかもしれません。手元でタブに置換して使用してください。

Makefile

Sample: sample.cpp
    g++ -o sample sample.cpp

sample.cpp

#include <iostream>
using namespace std;

int main() {
    cout << "This is a sample." << endl;
    return 0;
}

実行例

$ make
g++ -o sample sample.cpp
$ ./sample
This is a sample.

実例2

処理は複数記述できます。makeコマンドの引数を指定しなければ一番上の処理が実行されます。

Makefile

Sample1: sample1.cpp
    g++ -o sample1 sample1.cpp

Sample2: sample2.cpp
    g++ -o sample2 sample2.cpp

sample1.cpp

#include <iostream>
using namespace std;

int main() {
    cout << "This is Sample1." << endl;
    return 0;
}

sample2.cpp

#include <iostream>
using namespace std;

int main() {
    cout << "This is Sample2." << endl;
    return 0;
}

Sample2の処理を実行したければ、

$ make Sample2

とします。

実例3

変数を利用できます。

Makefile

CC = g++
CFLAGS = -g -Wall

Sample1: sample1.cpp
    $(CC) $(CFLAGS) -o sample1 sample1.cpp

Sample2: sample2.cpp
    $(CC) $(CFLAGS) -o sample2 sample2.cpp

実例4

処理をネストさせることができます。一番上にALLという名称の処理を用意して、依存する処理名にSample1とSample2を半角スペースで区切って指定します。すると、ALLの処理を実行すると再帰的にSample1,Sample2の処理も実行されます。

Makefile

CC = g++
CFLAGS = -g -Wall

ALL: Sample1 Sample2

Sample1: sample1.cpp
    $(CC) $(CFLAGS) -o sample1 sample1.cpp

Sample2: sample2.cpp
    $(CC) $(CFLAGS) -o sample2 sample2.cpp

実例5

ヘッダファイルが更新された場合にも処理が実行されるようにするためには、依存ファイルを記述する箇所にヘッダファイルを追記します。

Makefile

CC = g++
CFLAGS = -g -Wall

ALL: Sample1 Sample2

Sample1: sample1.cpp sample1.h
    $(CC) $(CFLAGS) -o sample1 sample1.cpp

Sample2: sample2.cpp sample2.h
    $(CC) $(CFLAGS) -o sample2 sample2.cpp

実例6

処理のネスト関係を利用すると、分割コンパイル (オブジェクトファイルmain.oとsub.oを-cフラグで別々に生成してから、ALLの処理でリンク) もできます。

Makefile

CC = g++
CFLAGS = -g -Wall

ALL: main.o sub.o
    $(CC) $(CFLAGS) -o main main.o sub.o

main.o: main.cpp
    $(CC) $(CFLAGS) -o main.o -c main.cpp

sub.o: sub.cpp sub.h
    $(CC) $(CFLAGS) -o sub.o -c sub.cpp

main.cpp

#include <iostream>
#include "sub.h"
using namespace std;

int main() {
    cout << sub::str << endl;
    return 0;
}

sub.h

namespace sub {
    extern char str[32];
}

sub.cpp

#include "sub.h"
namespace sub {
    char str[32] = "Externally defined string.";
}

実行例

$ make
g++ -g -Wall -o main.o -c main.cpp
g++ -g -Wall -o sub.o -c sub.cpp
g++ -g -Wall -o main main.o sub.o
$ ./main 
Externally defined string.

実例7

$@$< という特殊変数を用いると Makefile 内の共通部分の記述を省略できます。

Makefile

CC = g++
CFLAGS = -g -Wall

ALL: main.o sub.o
    $(CC) $(CFLAGS) -o main main.o sub.o

main.o: main.cpp
    $(CC) $(CFLAGS) -o $@ -c $<

sub.o: sub.cpp
    $(CC) $(CFLAGS) -o $@ -c $<

sub.o: sub.h

$@ には処理名が入っており、$< には依存するファイルあるいは処理名のうち更新されたものが入っています。sub.hだけ更新される場合があやしいので、sub.oを二つに分けてみました。

実例8

どの処理名よりも先に.cpp.oという処理を記述すると、依存ファイルがcppで処理名がoの処理を共通化させることができます。

Makefile

CC = g++
CFLAGS = -g -Wall

.cpp.o:
    $(CC) $(CFLAGS) -o $@ -c $<

ALL: main.o sub.o
    $(CC) $(CFLAGS) -o main main.o sub.o

sub.o: sub.h

実例9 (GNU make限定)

.cpp.oを用いない別の記述も可能です。処理名がワイルドカード%.oで一致した場合、依存ファイル%.cppの%に%.oの.oを除いた部分が代入されます。

CC = g++
CFLAGS = -g -Wall

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

ALL: main.o sub.o
    $(CC) $(CFLAGS) -o main main.o sub.o

sub.o: sub.h

実例10 (GNU make限定)

拡張子を置換したリストを生成するためにもワイルドカードを使用できます。

Makefile

CC = g++
CFLAGS = -g -Wall
OBJS = main.o sub.o
DOCS = $(OBJS:%.o=%.txt)
TARGET = main

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

ALL: $(OBJS)
    $(CC) $(CFLAGS) -o $(TARGET) $(OBJS)

sub.o: sub.h

docs:
    touch $(DOCS)

clean:
    rm -rf $(OBJS) $(TARGET) $(DOCS)

実行例

$ make
g++ -g -Wall -o main.o -c main.cpp
g++ -g -Wall -o sub.o -c sub.cpp
g++ -g -Wall -o main main.o sub.o
$ make docs
touch main.txt sub.txt
$ make clean
rm -rf main.o sub.o main main.txt sub.txt

その他

コマンドの出力を抑制

@ を付けるとコマンドが出力されなくなります。

$ make 
ok
echo ok2
ok2

Makefile

hello:
    @echo ok
    echo ok2

タスク名と同名のファイルが存在する場合を考慮

.PHONY: hello
hello:
        @echo ok
        echo ok2

同名のファイルが存在しており .PHONY がない場合、タスクが実行できなくなります。

$ ls
hello  Makefile
$ make
make: 'hello' is up to date.

既定で実行されるタスクを指定

.DEFAULT_GOAL を指定すると、二つ目以降のタスクが既定で実行されるように設定できます。

$ make
help

Makefile

.DEFAULT_GOAL := help

hello:
    @echo ok

help:
    @echo help
関連ページ
    デストラクタのサンプルコード #include <iostream> #include <algorithm> using namespace std; class MyClass { public: MyClass(int size); ~MyClass(); public: int Get(int i); private: int m_size;
    サンプルコード #include <iostream> #include <string> // ← 関数テンプレートのため、という訳ではなく string を使用したいため。 using namespace std; // シンプルなテンプレート template <typename MY_TYPE> MY_TYPE MyFunc(MY_TYPE a) { return a *
    リンケージ (linkage) ソースコードが複数ある場合にはリンケージという概念が登場します。関数およびグローバル変数が有する属性で、ファイルを越えて利用できるかどうかを示す性質です。実体が定義されたファイルの外で利用できる関数やグローバル変数を「外部 (external) リンケージをもつ」と表現します。逆に、実体が定義されたファイルの中でのみ利用できる関数やグローバル変数を「内部 (int
    サンプルコード プログラムはメモリ上に読み出されてその上で動いています。そのプログラム内で関数が使用されている場合、メモリ内には関数のアドレスも存在しています。関数を実行すると、関数の内容が読み出されているメモリのアドレスに処理のポイントが移動されます。この作業には多少の時間がかかるため、関数を実行した部分に関数の内容を直接埋め込んで、処理のポイントを移動させる必要のない状況を実現したいことがあ
    サンプルコード クラスのメンバ関数のフレンド登録などを行うためにクラスの相互参照が発生することがあります。このような場合はクラスの不完全型を宣言することで解決します。 my_class.h #ifndef MY_CLASS_H_20141223_0137_ #define MY_CLASS_H_20141223_0137_ #include "my_friend_class.h" // 「1
    サンプルコード メルセンヌ・ツイスタなど、C言語で記述されたライブラリをC++から利用するためには extern "C" を利用します。その際、組み込みマクロ __cplusplus を利用するとC言語からもC++からも利用できるヘッダファイルを作成できます。 sub.h #ifndef SUB_H_ #define SUB_H_ #ifdef __cplusplus extern "C"
    概要 Maven, sbt, cmake, make 等と同様に、ビルドツールとして有名な Gradle の基本的な使い方を、特に Java をビルド対象としてまとめます。2017/05/08 現在、Android における標準のビルドツールです。 参考ドキュメント 環境構築 Installation Creating New Gradle Builds
    概要 JHBuild は複数のソースパッケージの依存関係等を定義して、何らかの成果物をビルドするためのツールです。各ソースパッケージはモジュールとよばれます。モジュールのソースコードは Git や Subversion、FTP/Web サーバ上の zip、tar 等様々なものが利用できます。モジュールのビルドシステムとしては