Windows XP Windows 7 Windows 2003 Windows Vista Windows 綜合教學 Linux 系統教學
Windows 10 Windows 8 Windows 2008 Windows NT Windows Server 電腦軟體教學
您现在的位置: Windows教程網 >> Windows教程 >  >> Linux 系統教學 >> 關於 Linux

Linux make 指令與 Makefile 完整教學:從入門到大型專案建置自動化

編輯:關於 Linux

make 是 Unix 世界最經典的建置自動化工具,配合 Makefile 實現「只重建變更過的目標」,是 C/C++、核心模組、嵌入式專案的標準建置系統。本文涵蓋語法核心、依賴圖邏輯、變數/函數、模式規則、遞歸建置、自動化工具鏈與最佳實踐。

一、核心運作原理

  1. 目標 : 依賴 關係圖 (DAG)。
  2. 時間戳比較:目標檔案修改時間 < 任何依賴檔案修改時間 → 目標過時 → 執行配方。
  3. 遞歸由葉至根:先建構最底層依賴,再向上建構最終目標。

二、Makefile 基礎語法

# 註解
變數 = 值              # 遞歸展開 (延遲)
變數 := 值             # 立即展開 (推薦)
變數 ?= 值             # 僅當未定義時賦值
變數 += 值             # 追加

目標: 依賴1 依賴2 ...
	配方行1 (必須以 Tab 開頭)
	配方行2
	...

# 內建變數
CC = gcc
CFLAGS = -Wall -O2
LDFLAGS = -lm
RM = rm -f

三、最小可行範例

# Makefile
CC = gcc
CFLAGS = -Wall -O2 -I.
TARGET = myapp
SRCS = main.c utils.c
OBJS = $(SRCS:.c=.o)

all: $(TARGET)

$(TARGET): $(OBJS)
	$(CC) -o $@ $^ $(LDFLAGS)

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

clean:
	$(RM) $(OBJS) $(TARGET)

.PHONY: all clean

關鍵自動變數:

變數含義範例
$@目標完整名稱myapp
$<第一個依賴main.c
$^所有依賴 (去重)main.o utils.o
$?比目標新的依賴修改過的 .c 檔
$%歸檔成員名 (靜態庫用)

四、進階技巧

1. 模式規則與靜態模式

# 模式規則 (隱含規則)
%.o: %.c
	$(CC) $(CFLAGS) -c $< -o $@

# 靜態模式 (限定特定目標集合)
$(OBJS): %.o: %.c
	$(CC) $(CFLAGS) -c $< -o $@

2. 變數與函數

# 搜尋所有 .c 檔
SRCS := $(wildcard *.c)
# 取檔名不含副檔名
BASES := $(basename $(SRCS))
# 字串替換
OBJS := $(SRCS:.c=.o)
# 條件判斷
ifeq ($(DEBUG),1)
CFLAGS += -g -DDEBUG
endif
# Shell 命令結果
GIT_VER := $(shell git describe --tags --always)

3. 遞歸 Make (子目錄建置)

SUBDIRS = lib app test

all: $(SUBDIRS)

$(SUBDIRS):
	$(MAKE) -C $@

clean:
	for d in $(SUBDIRS); do $(MAKE) -C $$d clean; done

現代建議:避免遞歸 Make (Recursive Make Considered Harmful),改用非遞歸 Make:單一頂層 Makefile,以目錄前綴區分目標 (如 lib/foo.o),利用 VPATH 或 out-of-tree build。

4. 自動相依產生 (GCC -MMD)

CFLAGS += -MMD -MP
DEPS := $(OBJS:.o=.d)

-include $(DEPS)

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

clean:
	$(RM) $(OBJS) $(DEPS) $(TARGET)

-MMD 編譯時產生 .d 檔記錄標頭檔相依,-MP 為缺失標頭產生空目標避免錯誤,-include 靜默包含。

5. Out-of-tree Build (分離建置產物)

BUILD_DIR := build
OBJS := $(addprefix $(BUILD_DIR)/, $(SRCS:.c=.o))

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

$(TARGET): $(OBJS)
	$(CC) -o $@ $^ $(LDFLAGS)

五、大型專案標準化架構

project/
├── Makefile           # 頂層總覽,包含 config.mk、core.mk
├── config.mk          # 工具鏈、旗標、安裝前綴 (可被使用者覆蓋)
├── core.mk            # 核心規則、函數、自動相依邏輯
├── src/
│   ├── module1/
│   │   ├── Makefile   # 僅定義 MODULE_SRCS、MODULE_DEPS
│   │   └── *.c/*.h
│   └── module2/
└── tests/
    └── Makefile

config.mk 範例:

PREFIX ?= /usr/local
CC ?= gcc
CFLAGS ?= -Wall -Wextra -O2
CFLAGS += -I$(CURDIR)/include
LDFLAGS ?=
DESTDIR ?=

六、自動化工具鏈 (Autotools / CMake / Meson)

工具定位學習曲線適用場景
手寫 Makefile完全控制中中小專案、核心模組、嵌入式、教學
Autotools (autoconf/automake)GNU 標準、極致可移植高開源庫、需支援古老 Unix、系統級軟體
CMake跨平台、IDE 整合、現代標準中C++ 大型專案、Qt、LLVM、ROS、交叉編譯
Meson快速、Python 腳本、強類型低新專案、GNOME、Flatpak、追求建置速度

選型建議:新專案首選 Meson 或 CMake;維護舊專案/核心模組繼承 Makefile;需極致可移植 (含非 GNU 系統) 用 Autotools。

七、常見錯誤與除錯

現象原因修正
「missing separator」配方行未用 Tab (用空白)編輯器設定「Tab 插入 Tab 字元」
目標重複定義同一目標出現多條規則合併規則或使用雙冒號 ::
循環相依A 依賴 B,B 依賴 A重構模組拆分
並行建置失敗 (-j)缺少相依宣告補全依賴、使用 .NOTPARALLEL (臨時)
變數未展開使用 = 導致遞歸展開順序錯誤改用 := 立即展開

八、實用指令速查

make                    # 建置預設目標 (第一個目標,通常是 all)
make clean              # 執行 clean 目標
make -j8                # 8 核心並行建置
make -n                 # 乾跑 (只印指令不執行)
make -p                 # 印出完整內建規則與變數資料庫
make VAR=value          # 命令列覆蓋變數
make -C subdir          # 切換目錄執行
make --trace            # 追蹤規則觸發 (GNU Make 4.0+)

核心心法:「Makefile 是宣告式依賴圖,而非腳本。寫規則描述『什麼依賴什麼』,讓 make 決定『何時怎麼建』。善用自動變數、模式規則、自動相依,讓 Makefile 精簡、健壯、可擴展。」

Copyright © Windows教程網 All Rights Reserved