news 2026/3/13 4:10:10

Linux操作系统使用及C高级编程日报Day17(Makefile基础规则、条件判断与 make 命令选项)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux操作系统使用及C高级编程日报Day17(Makefile基础规则、条件判断与 make 命令选项)

📚 目录(TOC)

  • 第 1 节:Make 与 Makefile 基本概念

  • 第 2 节:变量、自动变量与模式规则

  • 第 3 节:条件判断(ifeq / ifdef 等)

  • 第 4 节:Makefile 常用函数(wildcard / patsubst 等)

  • 第 5 阶段:make 命令行选项与变量覆盖

  • 今日学习总结


第 1 节:Make 与 Makefile 基本概念

核心总结

  • make是一个“自动化构建工具”,会根据Makefile里的目标 + 依赖 + 命令自动决定编译哪些文件。

  • 相比直接写gcc main.c -o main,Makefile 的优势在于:增量编译统一管理规则一条命令完成多步操作

  • 基本语法三要素:

    目标: 依赖1 依赖2 ... 命令1 命令2

讲解内容

  1. 目标(target)

    • 可以是最终生成的可执行文件,如app

    • 可以是中间文件,如main.o

    • 也可以是“伪目标”,例如clean,只表示一系列操作,不对应真实文件。

  2. 依赖(prerequisites)

    • 当前目标生成所依赖的文件列表。

    • 当依赖文件比目标“新”时,make 会重新执行命令更新目标。

  3. 命令(command)

    • 真正执行的 shell 命令,一定要以Tab开头。

    • 支持任意 shell 命令:gccrmcp、脚本等。

  4. make 的工作方式(简化理解)

    • 找到指定的目标(缺省为 Makefile 中的第一个目标);

    • 检查依赖是否存在、是否比目标新;

    • 如需要,则执行规则中的命令;

    • 对每个依赖递归重复上述过程。

示例代码

简单单文件工程:

# 文件:Makefile app: main.o gcc main.o -o app main.o: main.c gcc -c main.c -o main.o clean: rm -f app main.o

使用方式:

make # 默认目标是 app make clean # 只执行 clean 目标

输出说明

第一次执行make

gcc -c main.c -o main.o gcc main.o -o app

再次执行make(没有修改main.c):

make: 'app' is up to date.

说明 make 检查到app不比main.c旧,无需重新编译,这就是增量构建

错误示例

app: main.o gcc main.o -o app # 这里没有 Tab main.o: main.c gcc -c main.c -o main.o # 这里是空格,不是 Tab

执行:

make

错误原因

  • Makefile 中命令行必须以Tab开头,而不是空格。

  • 上面的写法会出现类似错误:missing separator

正确写法

app: main.o gcc main.o -o app main.o: main.c gcc -c main.c -o main.o

一条命令一行,前面保证是 Tab。


第 2 节:变量、自动变量与模式规则

核心总结

  • 用变量统一管理编译器、编译选项和对象文件列表,可以极大减少重复。

  • 自动变量$@$^$<在规则内部代表“目标”、“所有依赖”、“第一个依赖”。

  • 模式规则%.o : %.c可以一条规则生成所有.o文件,用于多文件工程。

讲解内容

  1. 普通变量

CC := gcc CFLAGS := -Wall -O2 OBJS := main.o utils.o TARGET := app

在后续规则中直接使用$(变量名)即可。

  1. 自动变量

  • $@:当前规则的目标名

  • $^:当前规则的所有依赖

  • $<:当前规则的第一个依赖

  1. 模式规则

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

表示:所有.c文件都可以通过这个规则生成对应的.o文件。

示例代码

# 文件:Makefile CC := gcc CFLAGS := -Wall -O2 OBJS := main.o utils.o TARGET := app $(TARGET): $(OBJS) $(CC) $(CFLAGS) $^ -o $@ %.o: %.c $(CC) $(CFLAGS) -c $< -o $@ clean: rm -f $(TARGET) $(OBJS)

使用:

make # 构建 app make clean # 清理

输出说明

第一次执行make

gcc -Wall -O2 -c main.c -o main.o gcc -Wall -O2 -c utils.c -o utils.o gcc -Wall -O2 main.o utils.o -o app

根据依赖关系,先生成所有.o文件,再链接成app

错误示例

OBJS = main.o, utils.o # 使用了逗号 $(TARGET): $(OBJS) $(CC) $(CFLAGS) $^ -o $@

执行make时会发现只找到一个main.o,utils.o被当成第二个目标或无效内容。

错误原因

  • OBJS列表中不需要逗号,文件名用空格分隔即可。

  • 错误写法导致OBJS实际只有一个名字为main.o,的文件,构建规则会失败。

正确写法

OBJS = main.o utils.o

第 3 节:条件判断(ifeq / ifdef 等)

核心总结

  • Makefile 支持简单的条件编译,用于根据变量值是否定义来切换编译选项、启用/禁用特性。

  • 常用指令:ifeqifneqifdefifndefelseendif

  • 典型场景:DEBUG开关、根据操作系统选择不同的命令或库。

讲解内容

  1. 基于值的判断

DEBUG ?= 0 ifeq ($(DEBUG),1) CFLAGS += -g -O0 else CFLAGS += -O2 endif
  • DEBUG=1时,开启调试信息、关闭优化;

  • 否则使用优化选项。

  1. 基于是否定义的判断

ifdef USE_MATH LIBS += -lm endif

如果USE_MATH被定义了,就链接数学库。

  1. ifneq / ifndef

  • ifneq ($(OS),Windows):非某个值

  • ifndef VAR:VAR 未定义时执行代码块

示例代码

CC := gcc CFLAGS := -Wall DEBUG ?= 0 ifeq ($(DEBUG),1) CFLAGS += -g -O0 else CFLAGS += -O2 endif SRC := main.c OBJS := main.o TARGET := app $(TARGET): $(OBJS) $(CC) $(CFLAGS) $^ -o $@ %.o: %.c $(CC) $(CFLAGS) -c $< -o $@ clean: rm -f $(TARGET) $(OBJS)

命令行:

make # 使用 -O2 优化 make DEBUG=1 # 使用 -g -O0 调试选项

输出说明

  • make:编译命令中会出现-Wall -O2

  • make DEBUG=1:编译命令变为-Wall -g -O0

错误示例

ifeq (DEBUG,1) # 少了 $(),并且逗号两边空格不一致 CFLAGS += -g endif

错误原因

  • ifeq结构正确写法是:ifeq (A,B)ifeq ($(VAR),value),比较的是文本展开后的字符串

  • 上例中写成ifeq (DEBUG,1),实际上比较的是字符串DEBUG1,永远不相等。

正确写法

ifeq ($(DEBUG),1) CFLAGS += -g endif

或者保证两边都用变量/常量的一致写法:

DEBUG ?= 0 ifeq ($(DEBUG),1) ... endif

第 4 节:Makefile 常用函数(wildcard / patsubst 等)

核心总结

  • Makefile 提供一批“文本处理函数”,常用来批量生成文件列表和做路径替换。

  • 重点函数:

    • $(wildcard pattern):按模式匹配文件

    • $(patsubst pattern,replacement,text):模式替换

    • $(subst from,to,text):简单字符串替换

    • $(addprefix prefix,names...)/$(addsuffix suffix,names...)

    • $(dir files...)/$(notdir files...)

讲解内容

  1. wildcard:自动收集源文件

SRC := $(wildcard src/*.c)

会把src/目录下所有.c文件列出来。

  1. patsubst:从源文件生成目标文件列表

OBJ := $(patsubst src/%.c, build/%.o, $(SRC))

src/foo.c转成build/foo.o

  1. addprefix / addsuffix

HDR := a.h b.h c.h INC := $(addprefix include/, $(HDR)) # 结果:include/a.h include/b.h include/c.h
  1. dir / notdir

FILES := src/main.c src/utils/io.c DIRS := $(dir $(FILES)) # 结果:src/ src/utils/ BASENAM := $(notdir $(FILES)) # 结果:main.c io.c

示例代码

CC := gcc CFLAGS := -Wall -O2 SRC_DIR := src OBJ_DIR := build SRC := $(wildcard $(SRC_DIR)/*.c) OBJ := $(patsubst $(SRC_DIR)/%.c, $(OBJ_DIR)/%.o, $(SRC)) TARGET := app $(TARGET): $(OBJ) $(CC) $(CFLAGS) $^ -o $@ $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c @mkdir -p $(OBJ_DIR) $(CC) $(CFLAGS) -c $< -o $@ clean: rm -rf $(OBJ_DIR) $(TARGET)

输出说明

  • SRC自动包含src/下所有.c

  • OBJ自动生成对应的build/*.o

  • make时会自动创建build/目录并进行编译。

错误示例

SRC := wildcard src/*.c # 少了 $() OBJ := patsubst src/%.c, build/%.o, $(SRC)

错误原因

  • Makefile 函数必须写成$(函数名 参数...)

  • 少了$()wildcardpatsubst只是普通字符串,不会被执行。

正确写法

SRC := $(wildcard src/*.c) OBJ := $(patsubst src/%.c, build/%.o, $(SRC))

第 5 阶段:make 命令行选项与变量覆盖

核心总结

  • make命令本身有许多选项用来控制构建行为:

    • -f file:指定 Makefile

    • -C dir:先切换到指定目录再执行 make

    • -n:只打印命令,不真正执行

    • -i:忽略命令执行错误

    • -s:静默模式,不打印命令本身

    • -w:打印当前所在目录(进入/离开子目录时提示)

    • -k:遇到错误时尽量继续构建其它不依赖该目标的任务

  • 命令行可以对 Makefile 中的变量进行覆盖:make VAR=value优先级最高。

讲解内容

  1. 指定 Makefile:-f

make -f Makefile.debug make -f Makefile.release

当目录下有多个 Makefile 时,使用-f明确选择一个。

  1. 切换目录:-C

make -C src make -C build all

等价于:

cd src && make cd build && make all
  1. 预演构建:-n

make -n make -n clean

只打印即将执行的命令行,不真正执行操作,常用于检查clean或危险命令。

  1. 忽略错误:-i-k

  • -i:忽略所有命令错误,继续执行后续规则。

  • -k:当某个目标失败时,尽量构建其它不依赖它的目标。

示例:

make -k all

构建过程中某些目标失败,make 会记录错误,但不会立即停止。

一般情况下建议谨慎使用-i,以免掩盖真正的构建问题。

  1. 静默模式:-s

make -s make -s all

只显示程序运行产生的输出,不打印gcc ...等命令本身,相当于在每个命令前加@

  1. 显示目录信息:-w

make -w make -C src -w

会额外打印:

make: Entering directory '/path/to/src' ... make: Leaving directory '/path/to/src'

以便在多层子目录构建时跟踪执行位置。

  1. 变量覆盖:命令行优先

# Makefile CC ?= gcc CFLAGS ?= -O2

在命令行:

make CC=arm-linux-gnueabihf-gcc CFLAGS="-O0 -g"

此时:

  • CC会被覆盖为交叉编译器;

  • CFLAGS会使用命令行指定的调试参数。

示例代码

结合前面的 Makefile,只演示选项使用方式:

# 使用自定义 Makefile make -f Makefile.debug # 在 src 子目录中构建,但在项目根目录执行命令 make -C src all # 预演 clean,不真正删除 make -n clean # 遇到错误时尽量继续其它目标 make -k all # 静默模式,只看程序输出 make -s # 在命令行上覆盖变量 make CC=clang CFLAGS="-Wall -O0 -g"

错误示例

make -D DEBUG=1 make --assign CC=clang

错误原因

  • -D/--assign不是 GNU make 用来覆盖变量的选项;

  • 覆盖变量的正确方式是直接在命令行写VAR=value

  • -e的含义是“让环境变量优先于 Makefile 中的设置”,并不是覆盖 Makefile 变量的首选方式。

正确写法

make DEBUG=1 make CC=clang CFLAGS="-Wall -O0 -g"

今日学习总结

  • 理解了makeMakefile的基本关系与工作流程,掌握了“目标–依赖–命令”的核心结构。

  • 使用变量、自动变量和模式规则,提高了多文件工程中规则编写的复用性与可维护性。

  • 通过ifeq/ifneq/ifdef等条件判断,可以根据环境、开关变量灵活切换编译选项。

  • 利用wildcardpatsubst等文本函数,可以自动收集源文件并生成对应的目标文件列表。

  • 掌握了make -f/-C/-n/-i/-s/-w/-k等常用命令行选项,并能通过make VAR=value在命令行覆盖 Makefile 中的变量设置。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/12 18:16:36

LMMS开源音乐制作软件:二十年技术演进与创新突破

LMMS开源音乐制作软件&#xff1a;二十年技术演进与创新突破 【免费下载链接】lmms Cross-platform music production software 项目地址: https://gitcode.com/gh_mirrors/lm/lmms 在数字音乐创作的世界里&#xff0c;LMMS&#xff08;Linux MultiMedia Studio&#xf…

作者头像 李华
网站建设 2026/3/12 1:01:54

前端高频面试题之手写Promise

1、什么是 promise&#xff1f; Promise 译为 “承诺”&#xff0c;是 JavaScript 中用于处理异步操作的解决方案。它代表一个异步操作的最终完成&#xff08;或失败&#xff09;及其结果值。 2、Promise 的特点 特点一&#xff1a;Promise 有三种状态。 pending&#xff1…

作者头像 李华
网站建设 2026/3/11 22:58:57

AI原生应用工具链全解析:从数据收集到模型部署

AI原生应用工具链全解析&#xff1a;从数据收集到模型部署 1. 引入与连接&#xff1a;AI开发的"建造工具箱" 想象你是一位数字世界的建筑师&#xff0c;想要建造一座智能大厦——AI原生应用。你不会只拿着一把锤子就开始动工&#xff0c;对吧&#xff1f;你需要测量工…

作者头像 李华
网站建设 2026/3/11 16:57:29

面试经验,自动化测试面试题汇总(附回答)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、你有没有做过自…

作者头像 李华
网站建设 2026/3/12 1:04:28

主流编程考级对比:全科目覆盖vs窄科目,哪个更科学?

主流编程考级对比:全科目覆盖vs窄科目,哪个更科学? 内容概要 青少年编程考级有助于将抽象的学习目标具体化,为学习过程提供清晰的路径参考。 在选择编程等级考试时,可优先考虑主办单位权威、标准清晰、科目体系完整的项目。 不同考级体系在科目覆盖上存在差异,例如有的体…

作者头像 李华