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://test.idctop.com/article/483362.html

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

相关推荐

  • 5t存储云服务器一般多少钱?,哪家便宜?

    5T存储云服务器的市场价格通常在每月800元至3000元之间,具体取决于CPU、内存、带宽和存储类型,对于中小企业而言,选择持证机房的服务商既能保证性能,也能规避合规风险,价格构成的核心变量5T存储云服务器不是一口价商品,费用由多个组件叠加而成,了解这些变量,才能判断报价是否合理,存储类型决定基础成本存储盘是价……

    2026年7月29日
    1000
  • 2核8G服务器支持多少人同时在线?,性能怎么样?

    对于绝大多数Web应用场景,2核8G服务器在合理优化下可以支撑500至1000人同时在线,但具体数值取决于业务类型、架构设计以及服务商的基础设施质量,影响因素:为什么2核8G的承载能力差异巨大应用类型是核心变量静态页面:几乎不消耗计算资源,仅依赖网络IO,单台2核8G服务器可轻松应对数千并发,动态页面:每次请求……

    2026年7月30日
    1700
  • 衡天云618云服务器12元是真的吗?香港美国日本服务器租用价格

    这是一份为您定制的【衡天云】618年中Hi购季推广文案,针对不同的发布渠道(如朋友圈/社群、公众号/官网、短视频脚本)提供了不同风格的版本,您可以根据实际需求选择使用,朋友圈/社群短文案(直击痛点,强调性价比)🔥618年中大促!衡天云海外服务器低至12元起,手慢无!**🚀 跨境业务加速?海外建站首选衡天云!年中……

    2026年7月12日
    6800
  • 网络案例怎么分析?网络推广成功案例分享

    网络架构的稳定性与安全性是企业数字化转型的基石,直接决定了业务连续性与数据资产的价值,在当前复杂的网络环境中,构建高效、安全的网络体系,必须遵循“架构先行、安全贯穿、智能运维”的核心原则,通过对典型案列 网络_网络架构的深度剖析,我们可以清晰地看到,成功的网络部署并非单纯的技术堆砌,而是基于业务需求的精细化设计……

    2026年3月28日
    10000
  • 资质提交支持API接口吗?api接口如何防止重复提交?

    防止API接口重复提交是保障数据一致性与系统稳定性的核心机制,而针对“资质提交支持API接口吗?”这一疑问,明确的结论是:资质提交完全支持且强烈建议通过API接口实现,但必须构建完善的防重复提交机制,否则将导致严重的业务数据错乱与合规风险,在现代数字化业务流转中,资质审核往往涉及多方系统对接,API接口因其高效……

    2026年3月24日
    8800
  • 香港多IP服务器一个月多少钱,哪个机房最便宜?

    香港多IP服务器月租价格通常在500元至3000元区间,具体取决于你所需的IP数量、带宽大小和硬件配置,入门级配置(4核CPU、4GB内存、5个独立IPv4)每月开销约600-800元;高配方案(16核、32GB内存、16个IP)则可能突破2500元,价格背后的决定因素硬件配置与性能香港多IP服务器的成本第一块……

    2026年7月28日
    400
  • 自搭服务器一年多少钱

    自搭服务器一年的真实成本通常在1万到15万元之间,具体取决于硬件配置、带宽和部署方式,但大多数情况下,把服务器托管给持牌IDC服务商,比完全自建机房更划算, 一台服务器加上带宽、电费、场地和运维,隐性支出远比你想象得多,只有把每一项拆开看,才能避免预算超支,自搭服务器的成本构成:别被主机价格骗了很多人以为自搭服……

    2026年8月18日
    800
  • 安卓开发时可以用mysql数据库吗,安卓app如何连接mysql数据库

    安卓开发时可以用mysql数据库吗_App备案FAQ这一问题的核心结论是:安卓应用开发在技术层面可以直接连接MySQL数据库,但在工程实践、安全合规及App备案规范中,这种做法是严令禁止的, 正确的架构设计必须采用“安卓端+中间层(API)+数据库”的三层架构模式,严禁在移动端直连数据库,这既是行业铁律,也是保……

    2026年3月24日
    10100
  • Android如何跳转短信界面?android跳转短信界面代码

    在Android系统中,跳转短信界面的核心方法是通过Intent调用系统短信应用,具体路径为设置Action为Intent.ACTION_SENDTO,Data为smsto: URI,并可选地填入短信内容和收件人号码,对于开发者而言,处理短信跳转不仅仅是调用一个API那么简单,它涉及到系统权限、兼容性处理以及用……

    2026年6月1日
    4000
  • 简米云服务器硬盘1t要多少钱,云服务器硬盘1t报价?

    阿里云服务器1T硬盘的月成本大致在100元至500元区间,具体取决于硬盘类型、地域节点和计费方式,包年购买通常能节省约15%至30%的费用,很多朋友在选购阿里云服务器时,最纠结的就是硬盘容量和价格,1T(即1024GB)硬盘是当前建站、数据备份和中小型应用的主流配置,但价格并非固定数字,我会把影响价格的因素、具……

    2026年8月14日
    300

发表回复

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