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/article/483362.html

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

相关推荐

  • linux编译debug报错怎么办?linux编译debug详细教程

    在Linux环境下编译Debug版本,核心在于使用GCC或Clang编译器时添加-g参数,并配合-O0关闭优化,从而生成包含完整调试符号的可执行文件,以便GDB等工具进行断点调试和变量查看,很多开发者在初次接触Linux编译时,往往只关注程序能否跑通,却忽略了调试信息的生成,这就像买了一辆车却忘了装导航,虽然能……

    2026年7月7日
    19400
  • ThinkPad安装Linux失败怎么办?ThinkPad安装Linux教程

    ThinkPad安装Linux的核心结论是:选择Ubuntu LTS或Fedora Workstation版本,并在BIOS中关闭Secure Boot(安全启动)及开启Legacy/UEFI兼容模式,即可实现最稳定的双系统或单系统体验,ThinkPad作为商务笔记本的标杆,其硬件兼容性在Linux社区中一直享……

    2026年7月9日
    4800
  • linux strings命令怎么用?linux strings命令详解

    Linux strings命令的核心作用是直接从二进制文件、图像文件或任意非文本文件中提取并显示可打印的字符串序列,它是逆向工程、日志分析和故障排查中不可或缺的高效工具,在日常的Linux运维和开发工作中,我们习惯了处理纯文本文件,比如用cat或grep去查看配置或日志,但当你面对一个编译好的.so动态链接库……

    2026年7月4日
    11900
  • linux常用配置有哪些?linux服务器基础配置教程

    Linux系统配置的核心在于通过命令行精准管理用户权限、优化网络参数及自动化服务部署,熟练掌握这些基础操作能显著提升服务器稳定性与安全性,很多刚接触Linux的朋友,面对黑底白字的终端界面往往感到无从下手,Linux的配置逻辑非常直观,它不像Windows那样依赖图形界面的层层点击,而是通过文件编辑和指令执行来……

    2026年7月8日
    8300
  • Linux中cd命令怎么用?cd命令切换目录详解

    在 Linux 系统中,cd 命令(Change Directory)是最基础且最常用的命令之一,用于切换当前工作目录,以下是 cd 命令的详细用法、常用场景及技巧:基本语法cd [目录路径]常用用法示例✅ 切换到指定目录cd /home/user/Documents这会切换到 /home/user/Docum……

    2026年7月10日
    17700
  • Linux IP欺骗是什么原理?如何检测与防范IP欺骗

    在 Linux 系统中,”IP 欺骗”(IP Spoofing)通常指的是伪造数据包的源 IP 地址,这种行为在网络安全中常被用于攻击(如 DDoS、会话劫持等),因此在合法和道德的前提下,我们不应进行非法的 IP 欺骗活动,从安全研究、渗透测试(需获得授权)或网络防御的角度,了解 IP 欺骗的原理和检测方法是……

    2026年7月11日
    11400
  • linux退出帮助怎么操作?linux退出帮助命令

    在Linux终端中,直接输入exit或按Ctrl+D组合键即可安全退出当前会话或Shell环境,若需强制终止进程则使用kill命令配合进程ID,很多刚接触Linux的用户在面对黑底白字的终端界面时,往往会产生一种“被困住”的焦虑感,这种焦虑通常源于对退出机制的不熟悉,或者误以为需要像图形界面那样寻找一个显眼的……

    2026年7月7日
    14000
  • java swftools linux怎么用?swftools在linux下安装教程

    在Linux环境下利用Java结合SWFTools实现PDF转SWF,核心在于部署libswf库并调用命令行接口,虽然SWF格式已逐渐退出主流,但在特定遗留系统维护中,通过SwfTools的pdf2swf工具配合Java的Runtime.exec或ProcessBuilder仍是稳定且低成本的解决方案,Linu……

    2026年7月6日
    14500
  • Linux如何加载光驱?linux挂载光驱详细教程

    在Linux系统中加载光驱的核心方法是使用mount命令将光盘设备文件挂载到指定的空目录,通常设备路径为/dev/cdrom或/dev/sr0,挂载点建议设为/mnt/cdrom,许多刚接触Linux的用户在面对光驱时,往往会感到困惑,因为现代Linux发行版大多已不再默认自动挂载光盘,这与Windows系统的……

    2026年7月5日
    7700
  • linux ipsec内核配置出错怎么办?linux ipsec内核模块加载失败

    Linux IPSec内核通过XFRM子系统实现零拷贝加解密,相比用户态方案性能提升显著,是构建企业级虚拟专用网的首选底层架构,Linux IPSec内核架构深度解析Linux内核中的IPSec实现并非简单的协议叠加,而是基于XFRM(Transform)框架的精密设计,这一框架将安全策略、安全关联和转换操作解……

    2026年7月6日
    8010

发表回复

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