9.

Linux make コマンド完全ガイド — Makefile 文法と運用

編集
この記事の要点
  • makeMakefile を読み、依存関係に応じてターゲットをビルドするツール
  • 基本構文: target: dependencies 改行 recipe必ず TAB、スペース不可)
  • make all / make clean / make install が慣習的ターゲット名
  • 並列ビルド: make -j8。別 Makefile: make -f path/to/Makefile
  • 自動変数: $@(ターゲット)$<(最初の依存)$^(全依存)
  • .PHONY 宣言で「ファイルではない」ターゲットを定義(clean 等)
  • GNU Make が事実上標準。代替に CMake(メタビルド)Bazel(大規模)Ninja(高速)

make とは

makeファイルの依存関係に基づいてビルドを自動化するツール。1976 年に Stuart Feldman が作成した古典的ツールで、現在も C/C++ プロジェクトを中心に広く使われています。更新されたソースだけを再コンパイルすることで開発効率を上げます。

最小の Makefile

# Makefile(プロジェクト直下に配置)
hello: hello.c
	gcc -o hello hello.c

clean:
	rm -f hello

実行:

$ make           # 最初のターゲット(hello)が対象
gcc -o hello hello.c

$ make hello     # 明示
make: 'hello' is up to date.

$ make clean     # クリーンアップ
rm -f hello

# 並列実行(4 コア使用)
$ make -j4

# 別 Makefile
$ make -f Makefile.debug

Makefile の基本文法

target: dependency1 dependency2
recipe-line-1
recipe-line-2

# target: 生成したいファイル名 or 名前付きアクション
# dependency: ターゲット生成に必要なファイル
# recipe: 実行するシェルコマンド(先頭は必ずタブ文字)

重要: recipe の先頭はタブ文字(\tでなければなりません。スペース 4 個や 8 個ではエラーになります。エディタの設定に注意。

変数

# 単純代入
CC      = gcc
CFLAGS  = -Wall -O2 -std=c11
LDFLAGS = -lm
TARGET  = myapp

# 参照は $(変数名) または ${変数名}
$(TARGET): main.o util.o
	$(CC) $(CFLAGS) -o $(TARGET) main.o util.o $(LDFLAGS)

# 環境変数も使える
INSTALL_DIR ?= /usr/local/bin     # ?= は未定義時のみ代入
INSTALL_DIR := $(HOME)/bin        # := は単純代入(その場で展開)

自動変数

変数意味
$@ターゲット名
$<最初の依存ファイル名
$^全依存ファイル名(空白区切り)
$?更新された依存ファイル名のみ
$*パターンルールの % 部分
# パターンルール: %.o を %.c から作る
%.o: %.c
	$(CC) $(CFLAGS) -c $< -o $@
# $< → main.c
# $@ → main.o

.PHONY ターゲット

cleaninstall のように、実ファイルを生成しないターゲットには .PHONY を宣言します。同名ファイルが存在しても無視して実行されるようになります。

.PHONY: all clean install test run

all: $(TARGET)

clean:
	rm -f *.o $(TARGET)

install: $(TARGET)
	install -m 755 $(TARGET) $(INSTALL_DIR)/

test: $(TARGET)
	./run-tests.sh

run: $(TARGET)
	./$(TARGET)

実践的な C プロジェクト Makefile

CC      := gcc
CFLAGS  := -Wall -Wextra -O2 -std=c17 -Iinclude
LDFLAGS := -lpthread -lm

SRC_DIR := src
OBJ_DIR := build
BIN     := bin/myapp

# src/*.c をすべて拾う
SRCS := $(wildcard $(SRC_DIR)/*.c)
# src/main.c → build/main.o に変換
OBJS := $(patsubst $(SRC_DIR)/%.c, $(OBJ_DIR)/%.o, $(SRCS))

.PHONY: all clean

all: $(BIN)

$(BIN): $(OBJS)
	@mkdir -p $(dir $@)
	$(CC) $(OBJS) -o $@ $(LDFLAGS)

$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
	@mkdir -p $(OBJ_DIR)
	$(CC) $(CFLAGS) -c $< -o $@

clean:
	rm -rf $(OBJ_DIR) $(BIN)

暗黙ルール

GNU Make は暗黙的なビルドルールを多数持ちます。main.c があれば、明示的なルールなしで:

$ make main
cc     main.c   -o main

# Makefile が無くてもこれだけで動く。
# 内部的に %.c → % のルールが効いている

条件分岐とインクルード

# OS で分岐
UNAME := $(shell uname)
ifeq ($(UNAME), Darwin)
    CFLAGS += -DMACOS
endif
ifeq ($(UNAME), Linux)
    CFLAGS += -DLINUX
endif

# デバッグビルド切替
ifdef DEBUG
    CFLAGS += -g -O0
else
    CFLAGS += -O2
endif

# 別 Makefile を取り込む
include common.mk
-include $(OBJS:.o=.d)   # 依存関係ファイル(-include は無くてもエラーにしない)

主要なコマンドラインオプション

オプション用途
-j N / --jobs=NN 並列でビルド
-f FILE別ファイルを Makefile として使用
-n / --dry-run実行せず手順だけ表示
-B / --always-make強制全リビルド
-C DIRDIR に移動してから make
-kエラーがあっても可能な限り続行
-sサイレント(コマンドを表示しない)
--debugデバッグ情報を出す

他のビルドツールとの比較

ツール立ち位置特徴
GNU Make標準枯れている。中小規模に十分
BSD MakeBSD 系標準GNU 拡張は使えない。pkgsrc / ports で利用
CMakeメタビルドCMakeLists.txt から Makefile / Ninja / VS プロジェクトを生成。クロスプラットフォーム標準
Ninja低レベル高速CMake / Meson から生成して使う。Make より高速
MesonメタビルドPython 風 DSL。Ninja を出力
Bazel大規模モノレポGoogle 製。多言語・分散ビルド・キャッシュ
Autotools古典./configure && make && make install の生成元

FAQ

Q: *** missing separator. Stop. エラー
A: recipe の先頭がスペースになっている。エディタを確認し、TAB に置き換える。cat -A Makefile^I(TAB)か空白かを確認可能。

Q: make: Nothing to be done for 'all'
A: 依存ファイルが最新で再ビルド不要。make -B で強制リビルドできる。

Q: 並列ビルドで時々失敗する
A: ターゲット間の依存記述が不足している。-j1 なら通るのに -j8 で落ちるのが典型サイン。依存関係を見直す。

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. ls ファイル/ディレクトリ一覧表示
  2. sudo ユーザー指定
  3. cron/crontab ジョブの自動実行と登録方法
  4. wget http通信によるファイルダウンロード
  5. rm ファイル/ディレクトリ削除
  6. pwd カレントディレクトリの表示
  7. cd ディレクトリの移動
  8. ./configure
  9. make
  10. make install
  11. unzip ファイルの解凍
  12. mv ファイル/ディレクトリの移動および名称変更
  13. mkdir ディレクトリの作成
  14. touch 空ファイルの新規作成
  15. vi テキストディタの使用
  16. find ファイル/ディレクトリ検索
  17. grep 文字列の検索
  18. tail ファイルの末尾表示
  19. curl HTTP通信によるリクエスト
  20. nslookup ドメインのIP解決
  21. apt update パッケージリストの情報を更新
  22. apt upgrade パッケージの更新
  23. ln リンク/ショートカットの作成と削除
  24. rsync ファイル/ディレクトリの同期
  25. ssh リモートとの暗号化通信
  26. scp sshを利用したファイルのコピー
  27. unzip zip ファイルを解凍する
  28. cp ファイル/ディレクトリのコピー
  29. diffファイルの差分抽出
  30. fdisk ハードディスクに対する操作
  31. lsblk デバイスをツリー状で表示する
  32. kill プロセスを終了させる
  33. zip ファイルやディレクトリをzip形式に圧縮する
  34. host ドメインからIPアドレスを確認
  35. chmod 権限の変更
  36. ip IPアドレスの確認
  37. chown ファイル/ディレクトリ所有者の変更
  38. chgrp ファイル/ディレクトリのグループ情報の変更
  39. nohupと'&' プログラムのバックグラウンド実行(ssh接続時)
  40. lsof 開いているポート番号の確認
  41. tar ファイルの圧縮と解凍
  42. file ファイルの種類を表示
  43. cat ファイルの中身を表示
  44. head ファイルの先頭部分を表示
  45. wc 行数/単語数/文字数を確認
  46. shutdown システムのシャットダウンと再起動
  47. ps プロセスの確認
  48. which コマンドの絶対パスを調べる
  49. yum RedHat系ディストリビューションの管理
  50. mount ファイルシステムのマウント
  51. 特定フォルダ以下の特定拡張子のファイルを再帰的に削除する方法
  52. 特定のフォルダとそのサブフォルダ内にある特定のファイル名のファイルを再帰的に削除