linux makefile教程怎么用?makefile教程视频

Linux Makefile 完整教程

目录

  1. 什么是 Make 和 Makefile
  2. 基本语法
  3. 变量
  4. 模式规则
  5. 自动变量
  6. 函数
  7. 条件判断
  8. 实战示例
  9. 最佳实践

什么是 Make 和 Makefile

Make 是一个自动化构建工具,Makefile 是它的配置文件。

  • 核心思想:只重新编译发生变化的源文件,提高构建效率
  • 应用场景:C/C++ 项目编译、大型工程构建、自动化部署等

基本工作流程

Makefile → make 命令 → 检查依赖关系 → 只编译有变化的文件

基本语法

1 基本结构

# 目标: 依赖
# <Tab> 命令(注意:必须用 Tab,不能用空格!)
target: dependency1 dependency2
    <command1>
    <command2>

2 第一个 Makefile 示例

# 编译 main.c 生成 main 可执行文件
main: main.o utils.o
    gcc -o main main.o utils.o
main.o: main.c
    gcc -c main.c
utils.o: utils.c
    gcc -c utils.c
# 清理生成的文件
clean:
    rm -f .o main

运行:

20分钟Makefile光速入门教程
加载中
20分钟Makefile光速入门教程
make          # 构建
make clean    # 清理

3 伪目标

.PHONY: clean all install
clean:
    rm -f .o main
all: main

.PHONY 声明伪目标,避免与同名文件冲突。


变量

1 变量定义

# 简单赋值(立即求值)
CC = gcc
CFLAGS = -Wall -g
# 递归赋值(延迟求值)
CC ?= gcc        # 如果未定义则赋值
CC := gcc        # 简单赋值,立即展开
CC += -std=c11   # 追加赋值
# 条件赋值
override CC = clang   # 覆盖命令行传入的值

2 常用内置变量

CC       # C 编译器
CXX      # C++ 编译器
CFLAGS   # C 编译选项
CXXFLAGS # C++ 编译选项
LDFLAGS  # 链接选项
LDLIBS   # 链接库
AR       # 归档工具
RM       # 删除命令

3 使用变量

CC = gcc
CFLAGS = -Wall -O2
TARGET = myapp
SRCS = main.c utils.c helper.c
OBJS = $(SRCS:.c=.o)
$(TARGET): $(OBJS)
    $(CC) $(LDFLAGS) -o $@ $^
%.o: %.c
    $(CC) $(CFLAGS) -c $< -o $@
clean:
    rm -f $(OBJS) $(TARGET)

linux makefile教程怎么用?makefile教程视频

= 目标名,$^ = 所有依赖,$< = 第一个依赖


模式规则

1 通配符规则

# %.o: %.c 表示所有 .o 文件依赖于同名的 .c 文件
%.o: %.c
    $(CC) $(CFLAGS) -c $< -o $@

2 多模式规则

# 同时匹配 .c 和 .cpp
%.o: %.c %.cpp
    $(CC) $(CFLAGS) -c $< -o $@

3 静态模式规则

OBJS = main.o utils.o helper.o
$(OBJS): %.o: %.c
    $(CC) $(CFLAGS) -c $< -o $@

自动变量

变量 含义
目标文件名
$< 第一个依赖文件名
$^ 所有依赖文件名(去重)
所有依赖文件名(不去重)
目标中 匹配的部分
比目标更新的依赖文件列表
所有先决条件(包括 order-only)

示例

main.o: main.c main.h
    gcc -c $< -o $@    # 等价于 gcc -c main.c -o main.o
# 使用 $? 只编译更新的依赖
main: main.o utils.o
    gcc -o $@ $?       # 只链接更新的依赖

函数

1 常用函数

# wildcard: 获取匹配文件
SRCS = $(wildcard .c)
# patsubst: 模式替换
OBJS = $(patsubst %.c,%.o,$(SRCS))
# notdir: 去除路径
DIRS = $(notdir $(SRCS))
# addprefix: 添加前缀
PATHS = $(addprefix src/,$(SRCS))
# realpath: 获取绝对路径
REAL_PATHS = $(realpath $(DIRS))
# foreach: 循环
# $(foreach var,list,text)
OBJS = $(foreach src,$(SRCS),$(src:.c=.o))
# if: 条件判断
# $(if condition,true-part[,false-part])
RESULT = $(if $(CC),using gcc,using clang)
# warning/error: 输出警告/错误
$(warning This is a warning)
$(error This is an error)
# shell: 执行 shell 命令
DATE = $(shell date +%Y%m%d)

2 函数示例

# 获取所有 C 源文件
SRCS = $(wildcard src/.c)
# 转换为对象文件
OBJS = $(patsubst src/%.c,build/%.o,$(SRCS))
# 创建目录
build/%.o: src/%.c | build
    @mkdir -p $(@D)
    $(CC) $(CFLAGS) -c $< -o $@
build:
    mkdir -p build
clean:
    rm -rf build

条件判断

1 ifeq / ifneq

ifeq ($(CC),gcc)
    CFLAGS += -O3
else ifeq ($(CC),clang)
    CFLAGS += -O3 -Qunused-arguments
else
    CFLAGS += -O2
endif

2 ifdef / ifndef

linux makefile教程怎么用?makefile教程视频

ifdef DEBUG CFLAGS += -g -DDEBUG else CFLAGS += -O2 endif ifndef VERBOSE QUIET := @ endif

3 结合变量使用

ifeq ($(OS),Linux)
    LDFLAGS += -lpthread
else ifeq ($(OS),Darwin)
    LDFLAGS += -lpthread
endif

实战示例

1 简单 C 项目

# ==================== 配置区 ====================
CC = gcc
CFLAGS = -Wall -Wextra -std=c11 -g
LDFLAGS =
LDLIBS = -lm
TARGET = myapp
SRCDIR = src
OBJDIR = build
BINDIR = bin
SRCS = $(wildcard $(SRCDIR)/.c)
OBJS = $(patsubst $(SRCDIR)/%.c,$(OBJDIR)/%.o,$(SRCS))
# ==================== 规则区 ====================
.PHONY: all clean install uninstall
all: $(TARGET)
$(TARGET): $(OBJS) | $(BINDIR)
    $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
$(OBJDIR)/%.o: $(SRCDIR)/%.c | $(OBJDIR)
    $(CC) $(CFLAGS) -c $< -o $@
$(OBJDIR):
    mkdir -p $(OBJDIR)
$(BINDIR):
    mkdir -p $(BINDIR)
clean:
    rm -rf $(OBJDIR) $(BINDIR) $(TARGET)
install: $(TARGET)
    cp $(TARGET) $(BINDIR)/
uninstall:
    rm -f $(BINDIR)/$(TARGET)

2 C++ 项目

# ==================== 配置区 ====================
CXX = g++
CXXFLAGS = -Wall -Wextra -std=c++17 -O2
LDFLAGS =
LDLIBS = -lpthread -lstdc++fs
TARGET = mycppapp
SRCDIR = src
OBJDIR = build
# 自动收集所有 .cpp 文件
SRCS = $(wildcard $(SRCDIR)/.cpp)
OBJS = $(patsubst $(SRCDIR)/%.cpp,$(OBJDIR)/%.o,$(SRCS))
# 自动收集头文件依赖
DEPS = $(OBJS:.o=.d)
# ==================== 规则区 ====================
.PHONY: all clean
all: $(TARGET)
$(TARGET): $(OBJS)
    $(CXX) $(LDFLAGS) -o $@ $^ $(LDLIBS)
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp
    @mkdir -p $(@D)
    $(CXX) $(CXXFLAGS) -MMD -MP -c $< -o $@
# 包含自动生成的依赖文件
-include $(DEPS)
clean:
    rm -rf $(OBJDIR) $(TARGET)

-MMD -MP 自动生成 .d 依赖文件,当修改头文件时会自动重新编译相关源文件。

3 多目标项目

# 构建多个可执行文件
TARGETS = app1 app2 app3
.PHONY: all clean
all: $(TARGETS)
app1: app1.o lib.o
    $(CC) -o $@ $^
app2: app2.o lib.o
    $(CC) -o $@ $^
app3: app3.o lib.o
    $(CC) -o $@ $^
%.o: %.c
    $(CC) $(CFLAGS) -c $< -o $@
clean:
    rm -f $(TARGETS) .o

4 带测试的项目

CC = gcc
CFLAGS = -Wall -g
LDFLAGS =
LDLIBS = -lcheck -lm -lpthread
TARGET = mylib
TEST_TARGET = test_mylib
.PHONY: all clean test
all: $(TARGET) $(TEST_TARGET)
# 编译库
$(TARGET): main.o utils.o
    $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
# 编译测试
$(TEST_TARGET): test_main.o main.o utils.o
    $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
%.o: %.c
    $(CC) $(CFLAGS) -c $< -o $@
test: $(TEST_TARGET)
    ./$(TEST_TARGET)
clean:
    rm -f $(TARGET) $(TEST_TARGET) .o

linux makefile教程怎么用?makefile教程视频


最佳实践

1 通用模板

# 1. 始终使用 .PHONY 声明伪目标
.PHONY: all clean install uninstall test
# 2. 使用变量而非硬编码
CC ?= gcc
CFLAGS ?= -Wall -Wextra
CXX ?= g++
CXXFLAGS ?= -Wall -Wextra
# 3. 使用自动变量
# 4. 使用模式规则减少重复
# 5. 提供 clean 目标
# 6. 使用 -include 包含依赖文件
# 7. 使用 @ 前缀抑制命令回显(可选)
# 8. 使用 - 前缀忽略错误(可选)
# 示例:安静模式
quiet_cmd = @echo "  CC      $<"
quiet_cmd = @$(CC) $(CFLAGS) -c $< -o $@

2 常见陷阱

# ❌ 错误:使用空格而不是 Tab
target: dep
    command    # 空格!会报错
# ✅ 正确:使用 Tab
target: dep
    command    # Tab
# ❌ 错误:变量名大小写敏感
CC = gcc
$(cc) ...    # cc 未定义!
# ✅ 正确
$(CC) ...
# ❌ 错误:忘记 .PHONY
clean:
    rm -f .o
# 如果当前目录有名为 clean 的文件,make 不会执行
# ✅ 正确
.PHONY: clean
clean:
    rm -f .o

3 调试技巧

# 显示执行的命令
make -n          # 预览命令(dry run)
make -d          # 详细调试信息
make VERBOSE=1   # 自定义 verbose 模式
# 在 Makefile 中调试
$(info CC is $(CC))
$(warning CFLAGS is $(CFLAGS))
$(error Stop here)

快速参考卡片

基本结构:  target: dependencies
                <tab> command
变量:       VAR = value
            $(VAR) 或 ${VAR}
自动变量:   $@ 目标  $< 第一个依赖  $^ 所有依赖
函数:       $(wildcard .c)
            $(patsubst %.c,%.o,$(SRCS))
条件:       ifeq / ifneq / ifdef / ifndef
伪目标:     .PHONY: clean all

概念 要点
核心 依赖关系 + 增量编译
语法 目标: 依赖 → Tab 命令
变量 用 $(VAR) 引用,善用自动变量
模式规则 %.o: %.c 减少重复
函数 wildcard, patsubst, foreach 等
最佳实践 使用 .PHONY、变量抽象、自动依赖

Makefile 是 Linux 开发中不可或缺的工具,掌握它能极大提升构建效率,建议从简单项目开始,逐步掌握高级特性。

首发原创文章,作者:王坚‌,如若转载,请注明出处:https://idctop.com/linux-makefile%e6%95%99%e7%a8%8b%e6%80%8e%e4%b9%88%e7%94%a8%ef%bc%9fmakefile%e6%95%99%e7%a8%8b%e8%a7%86%e9%a2%91/

赞 (0)
费用中心合并是什么意思?企业财务软件费用中心合并怎么操作
上一篇 2026年7月11日 21:19
Linux课程论文怎么写?Linux系统安装配置教程
下一篇 2026年7月11日 21:22

相关推荐

  • ice服务器被炸小学生要赔多少,赔偿标准是什么?

    如果一个小学生炸了Ice服务器,根据服务器配置、数据损失规模以及业务中断时长,赔偿金额通常在数万元到数十万元不等,甚至更高;选择正规IDC服务商如简米科技和酷番云,能通过完善的备份和防护机制大幅降低此类风险,赔偿金额怎么算?四大因素决定最终数额Ice服务器被炸,无论是因为小学生恶意操作还是误删数据,赔多少都要看……

    2026年8月25日
    700
  • 刀片服务器回收能卖多少钱?二手刀片服务器回收价格多少?

    刀片服务器回收没有统一一口价,通常按“刀片配置+刀箱配件+成色+数据合规”综合评估,常见单台从几百元到上万元,完整刀箱或高配刀片可能到数万元;没有配置清单和检测记录前,报价只能算初估, 想卖得接近真实成交价,先把型号、CPU、内存、硬盘、刀箱配件和序列号盘清楚,再找有资质、能合规交付的回收方比价,刀片服务器回收……

    相关资讯 2026年11月5日
    000
  • 金盾服务器PDU一个到底多少钱,PDU电源插座怎么选

    金盾服务器PDU的主流成交价多数集中在几百元到上千元区间,基础型单相产品通常几百元可拿下,带智能监控、大功率或特殊插口规格的型号会到千元级,实际价格受采购渠道、插口数量、功能配置影响较大,影响金盾服务器PDU价格的核心因素很多用户看到“金盾服务器PDU多少钱一个”时,第一反应是要一个固定数字,但PDU属于基础设……

    2026年9月14日
    100
  • linux程序堆栈如何查看?linux程序堆栈崩溃怎么分析

    Linux程序堆栈是内存中函数调用的有序记录,通过回溯栈帧可精准定位代码崩溃或死锁根源,是系统调试的核心手段,在Linux开发环境中,内存管理如同精密的钟表机械,而堆栈(Stack)则是其中负责追踪“当前动作”的关键齿轮,当程序发生段错误(Segmentation Fault)或需要分析性能瓶颈时,堆栈信息就是……

    2026年7月5日
    19110
  • 做APP租服务器一年要花多少钱,服务器租赁费用有哪些?

    CPU:核心数越多,并行处理能力越强,价格成倍增加,内存:8G起步是常见选择,16G以上适合中型应用,硬盘:SSD比机械硬盘贵2-3倍,但随机读写速度优势明显,带宽是长期开销大头带宽费用通常按“峰值”或“月流量”计费,大部分服务商提供1Mbps-10Mbps的共享带宽,年费在1000-5000元,如果APP涉及……

    2026年8月9日
    1600
  • 超小服务器显卡到底多少钱,服务器显卡价格一般多少钱?

    入门低功耗半高卡常见几百到一千多元,主流单槽或半高专业卡多在数千到上万元,紧凑型高算力GPU往往到数万元;真正决定预算的是尺寸、功耗、接口、算力和机房配套,而不是一张卡单独报价,先拆价格:超小服务器显卡多少钱由哪些因素决定尺寸与插槽决定“能不能装”超小服务器显卡通常指半高半长、单槽或薄双槽、低功耗、涡轮散热的卡……

    2026年10月20日
    200
  • 我的世界服务器最多能进多少人?,人数上限怎么设置?

    Minecraft服务器没有绝对的硬性人数上限,原版单服默认20人,优化后单机可承载几十到几百人,代理分布式架构能扩展到数千甚至数万人,实际瓶颈在CPU单核性能、带宽、网络质量和架构设计,先搞清:mc服务器最多多少人由什么决定原版服务端的软限制Mojang官方文档里,Java版服务端server.propert……

    2026年10月11日
    100
  • 各地DNS服务器地址是多少?,国内DNS服务器地址有哪些?

    各地DNS服务器地址并没有一份全国统一的“标准答案”,真正靠谱的做法是优先用本地运营商下发的DNS,再备份一到两个公共DNS(如223.5.5.5、119.29.29.29、114.114.114.114),需要跨省访问或企业组网时再按机房线路做针对性配置,DNS这件事,说小很小,填两行数字就完事;说大也大,填……

    相关资讯 2026年10月25日
    000
  • 3m服务器到底能支持多少人访问?,多少钱一台

    3M服务器多少人,没有统一数字:在轻量网页、小程序API场景,3M独享带宽大约能撑几十到一两百人同时在线;到了图片站、视频、下载场景,可能只有几人到十几人同时使用,真正决定承载量的,是并发峰值、单请求流量和线路质量,先弄清:3M服务器到底指什么很多人问“3M服务器多少人”,其实把两个概念混在一起了,3M通常指公……

    2026年10月8日
    200
  • CVR存储服务器到底能存多少天,监控录像保存多长时间?

    CVR存储服务器能存多少天,没有统一答案,常见项目里,30天、60天、90天是三个主流档位;32路1080P、2Mbps码率、4块4TB硬盘做RAID5,通常只能存半个月左右;同样路数降到1Mbps或换成8块8TB,才能摸到60天到90天,真正决定天数的,是码率、路数、可用容量和RAID策略,CVR存储服务器能……

    2026年10月7日
    000

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注