首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

手把手教你寫 Makefile:從入門到專案級最佳實踐

     編輯:關於C語言

Makefile 是自動化建構的核心,掌握它等於掌握了專案編譯的完整控制權。本文以 GNU Make 為標準,從基本規則語法、變數、模式規則、自動推導、偽目標、函式、條件判斷、模組化設計,逐步建構適用於中大型 C/C++ 專案的標準化 Makefile 模板。

為什麼需要 Makefile?

  • 原始檔分散多目錄,手動編譯指令極長且易錯。
  • 修改單一檔案應只重編受影響模組,而非全專案。
  • 支援多平台 (Linux/macOS/Windows WSL)、多工具鏈 (GCC/Clang/MSVC)。
  • 整合靜態分析、單元測試、打包部署等完整 CI/CD 流程。

第 1 步:最小可行 Makefile


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

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

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

clean :
    rm -f $(TARGET) $(OBJS)

執行 make → 自動編譯連結;make clean → 清理。

第 2 步:加入頭檔自動相依


DEPFLAGS = -MMD -MP
CFLAGS += $(DEPFLAGS)
-include $(OBJS:.o=.d)  # 包含 .d 檔,- 忽略不存在錯誤

編譯時自動產生 .d 檔記錄 #include 相依,修改 .h 精確觸發重編。

第 3 步:目錄結構與模組化


project/
├── Makefile
├── src/
│   ├── module1/
│   │   ├── mod1.c
│   │   ├── mod1.h
│   │   └── Makefile.module
│   └── module2/
│       ├── mod2.c
│       ├── mod2.h
│       └── Makefile.module
└── include/
    └── common.h

主 Makefile 包含子模組:


include src/module1/Makefile.module
include src/module2/Makefile.module

各 Makefile.module 定義區域變數 MOD1_SRCS、MOD1_OBJS,主檔彙總至 OBJS。

第 4 步:建置模式與交叉編譯


BUILD ?= release          # make BUILD=debug
ifeq ($(BUILD),debug)
    CFLAGS += -g -O0 -DDEBUG
else
    CFLAGS += -O2 -DNDEBUG
endif

CROSS_COMPILE ?=          # make CROSS_COMPILE=arm-linux-gnueabihf-
CC = $(CROSS_COMPILE)gcc

第 5 步:常用函式與進階技巧

函式用途範例
wildcard擴展檔案通配符SRCS = $(wildcard src/*.c)
patsubst模式替換OBJS = $(patsubst %.c,%.o,$(SRCS))
shell執行 Shell 命令VERSION = $(shell git describe --tags)
foreach迴圈展開$(foreach d,$(DIRS),$(wildcard $(d)/*.c))
if/filter條件過濾$(if $(filter debug,$(MAKECMDGOALS)),-g,)

第 6 步:標準化偽目標


.PHONY: all clean install uninstall test distclean
all: $(TARGET)

install: $(TARGET)
    install -m 755 $(TARGET) $(DESTDIR)/usr/bin/

test: $(TEST_TARGET)
    ./$(TEST_TARGET)

distclean: clean
    rm -f *.d *.log config.cache

完整專案級 Makefile 模板 (節錄)


# === 專案設定 ===
PROJECT = myproject
VERSION = 1.0.0
BUILD ?= release
CROSS_COMPILE ?=

# === 工具鏈 ===
CC = $(CROSS_COMPILE)gcc
CXX = $(CROSS_COMPILE)g++
AR = $(CROSS_COMPILE)ar
STRIP = $(CROSS_COMPILE)strip

# === 編譯選項 ===
CFLAGS = -Wall -Wextra -std=c11 -fPIC
CXXFLAGS = -Wall -Wextra -std=c++17 -fPIC
LDFLAGS = -shared
DEPFLAGS = -MMD -MP

ifeq ($(BUILD),debug)
    CFLAGS += -g -O0 -DDEBUG
    CXXFLAGS += -g -O0 -DDEBUG
else
    CFLAGS += -O2 -DNDEBUG
    CXXFLAGS += -O2 -DNDEBUG
endif

# === 目錄 ===
SRCDIR = src
OBJDIR = build/$(BUILD)
BINDIR = bin/$(BUILD)

# === 自動搜尋來源檔 ===
SRCS = $(shell find $(SRCDIR) -name '*.c' -o -name '*.cpp')
OBJS = $(patsubst $(SRCDIR)/%,$(OBJDIR)/%,$(SRCS:.c=.o))
OBJS := $(OBJS:.cpp=.o)
DEPS = $(OBJS:.o=.d)

# === 目標 ===
TARGET = $(BINDIR)/$(PROJECT)

# === 規則 ===
all: $(TARGET)

$(TARGET): $(OBJS) | $(BINDIR)
    $(CXX) -o $@ $^ $(LDFLAGS)

$(OBJDIR)/%.o: $(SRCDIR)/%.c | $(OBJDIR)
    $(CC) $(CFLAGS) $(DEPFLAGS) -c $< -o $@

$(OBJDIR)/%.o: $(SRCDIR)/%.cpp | $(OBJDIR)
    $(CXX) $(CXXFLAGS) $(DEPFLAGS) -c $< -o $@

$(OBJDIR) $(BINDIR):
    mkdir -p $@

-include $(DEPS)

.PHONY: all clean install test
clean:
    rm -rf build bin

install: all
    install -D -m 755 $(TARGET) $(DESTDIR)/usr/bin/$(PROJECT)

避坑檢查清單

  • ✅ 命令行**必須以 Tab 開頭** (非空白鍵)。
  • ✅ 變數引用用 $(VAR) 或 ${VAR},單字元可省略括號 $@ $<。
  • ✅ 偽目標宣告 .PHONY 避免與檔案同名衝突。
  • ✅ 使用 -include 載入相依檔,忽略首次建置不存在情況。
  • ✅ 目錄建立規則用 | $(DIR) (順序依賴),避免重複觸發。
  • ✅ 交叉編譯變數 CROSS_COMPILE 以連字號結尾 (如 arm-linux-)。

掌握此模板,新專案複製調整變數區即可投入生產,建構過程透明、可控、可擴展。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved