您的位置:首页 > 房产 > 家装 > Makefile学习笔记

Makefile学习笔记

2025/1/3 11:43:15 来源:https://blog.csdn.net/qq_44667259/article/details/139991774  浏览:    关键词:Makefile学习笔记

1. Makefile学习笔记

1.1 makefile简介

1.1.1 概述

  • Makefile 是一种用于自动化构建软件的文件,它定义了一系列的规则和命令来编译和链接程序。

  • Makefile 通常与 make 工具一起使用,make 工具会读取 Makefile 文件中的指令,并按照其中的规则自动化地完成构建过程。

  • 其命名一般为makefileMakefile

1.1.2 基本概念

makefile中的规则

一个Makefile文件中会定义一个或者多个规则,一个规则的格式如下:

目标依赖…

< TAB > 命令(shell命令)

< TAB > …(后续的命令)

名词解释:

  • 目标:这是一个文件或操作的名字。一般将定义了一个操作(一组命令的集合)的目标称为伪目标
  • 依赖:目标文件所依赖的文件或者其他目标
  • 命令:用来生成目标文件的实际命令(命令行前必须 Tab 缩进)
关于伪目标

伪目标(Phony Targets)是在 Makefile 中不会生成实际文件的目标,通常用于执行某些管理任务,如清理、中间文件的删除、运行测试等。伪目标的名字不对应于文件,而是一些操作指令

常见的伪目标:

clean:删除编译生成的文件。

all:编译所有目标文件。

install:安装编译生成的文件到指定位置。

test:运行测试用例。

.PHONY 的作用:

确保命令被执行,避免因文件名冲突导致命令不执行。如果当前目录下有一个与伪目标同名的文件make 会优先认为这个文件是目标文件而不是伪目标,进而跳过命令而不执行。将目标声明为 .PHONY后,即使存在与伪目标同名的文件,也会执行伪目标的命令,而不是根据文件的时间戳判断是否需要执行。

# 例如,目录结构如下:
.
├── a.cpp
├── a.out
├── clean
└── makefile# make文件内容如下:
# a.out:a.cpp
# 	g++ a.cpp -o a.out
# clean:
# 	rm a.out# 如果不使用.PHONY,执行make clean的命令行输出如下:
make: 'clean' is up to date.# 在makefile文件中添加:
# .PHONY:clean
# 之后,执行make clean的命令行输出如下:
rm a.out
包含伪目标的makefile示例
# 定义伪目标
.PHONY: all clean install test# 定义目标 all,依赖于 my_program
all: my_program# 定义目标 my_program,依赖于 source.o
my_program: source.ogcc -o my_program source.o# 定义目标 source.o,依赖于 source.c
source.o: source.cgcc -c source.c# 定义伪目标 clean,用于清理生成文件
clean:rm -f my_program source.o# 定义伪目标 install,用于安装程序
install:cp my_program /usr/local/bin# 定义伪目标 test,用于运行测试
test:./my_program --test
makefile中的注释

Makefile 中只有单行注释,没有多行注释。

注释以 # 开头,从 # 开始直到该行末尾均为注释内容。

例如:

# 这是一个注释
CC = gcc  # 定义编译器

1.2 makefile中的变量

Makefile 中的变量用于简化和管理构建过程中的重复部分,提高可读性和可维护性。变量允许你在 Makefile 中定义值,并在多个地方引用这些值。

变量的使用,使得修改makefile变得更加容易,只需要修改变量定义,避免了在每个使用它的地方进行修改。

1.2.1 自定义变量

变量的定义格式
VariableName = value

详细来讲,makefile的赋值有四种形式:延迟展开、立即展开、条件赋值、追加赋值。

=:延迟展开,变量在被引用时才进行赋值。这意味着变量的值是在使用时确定的,而不是在定义时确定的。

:=:立即展开,变量在定义时立即展开并赋值。变量的值在定义时就被固定下来,不会受后续变量修改的影响。

?=:条件赋值,只有在变量未定义时才进行赋值。如果变量已经被定义,则保持其原有值。

+=:追加赋值,将新的值追加到已有值后面。如果变量之前没有定义,则相当于 =

示例如下:

# 延迟展开
DELAYED = $(IMMEDIATE)
IMMEDIATE = delayed_value# 立即展开
IMMEDIATE := $(IMMEDIATE)
# 此时使用了 IMMEDIATE 的值,其值为delayed_value
# 再次定义了 IMMEDIATE,将其值设为 immediate_value
IMMEDIATE := immediate_value# 条件赋值
CONDITIONAL ?= conditional_value
CONDITIONAL ?= new_conditional_value# 追加赋值
APPEND = initial
APPEND += appended_valueall:echo DELAYED: $(DELAYED)echo IMMEDIATE: $(IMMEDIATE)echo CONDITIONAL: $(CONDITIONAL)echo APPEND: $(APPEND)

上述makefile的输出为:

echo DELAYED: immediate_value
echo IMMEDIATE: immediate_value
echo CONDITIONAL: conditional_value
echo APPEND: initial appended_value

1.2.2 变量的使用

变量的引用格式
$(变量名)

使用$来表示用于引用变量或表示自动化(预定义)变量

1.2.3 常用的自动化变量

$@:目标文件名(target file)

$<:第一个依赖文件的名字(first dependency)

$^: 所有依赖文件的名字(会去重),使用空格分隔(all dependencies)。

MAKE:make 程序本身的名字。

CURDIR:当前目录的绝对路径。

MAKEFILE_LIST:make 正在读取的所有 makefile 的名字列表。

1.2.4 常用的变量定义

CC:指定编译器

CFLAGS:指定 C 编译器标志

CXX:指定 C++ 编译器

CXXFLAGS:指定 C++ 编译器标志

LDFLAGS: 指定链接器标志

LDLIBS:指定链接的库文件

SRCS:指定源文件列表

OBJS:指定目标文件列表

INCLUDES:指定包含目录

LIBS:指定库目录和库文件

# Makefile 示例
CC = gcc
CFLAGS = -Wall -g
LDFLAGS = -lm
CPPFLAGS = -I/usr/local/include
SRCS = main.c util.c
OBJS = $(SRCS:.c=.o)
TARGET = myappall: $(TARGET)$(TARGET): $(OBJS)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^%.o: %.c$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@clean:rm -f $(OBJS) $(TARGET)

1.2.5 变量的匹配规则

% 通配符

% Makefile 中最常用的通配符,用于匹配零个或多个字符,通常用于表示任意文件名部分。

# 所有 .o 文件依赖于对应的 .c 文件
%.o: %.c$(CC) $(CFLAGS) -c $< -o $@
* 通配符

* 通配符用来匹配零个或多个字符,在 Makefile 中不常用,在shell脚本中常用。

#  匹配零个或多个字符。
FILES = *.c
? 通配符

? 通配符用于匹配单个字符。

# 匹配名称为 file?.c 文件,
all:@echo file?.c
[ ... ] 通配符

[] 用于匹配方括号内的任意一个字符。

# 匹配 filea.txt、fileb.txt 和 filec.txt
file[abc].txt:@echo $@
[ ^ ... ] 通配符

[ ^ … ]用于匹配不在方括号内的任意一个字符。

# 匹配不以 a、b 或 c 结尾的 .txt 文件,例如 filed.txt、filee.txt
file[^abc].txt:@echo $@

1.3 makefile中的常用函数

patsubst 函数

patsubst 函数用于模式替换

语法(注意逗号):

$(patsubst pattern,replacement,text)

示例:

# 将 src/ 目录下的 .c 文件名替换为 build/ 目录下的 .o 文件名。
SRC := src/a.c src/b.c src/c.c
OBJS := $(patsubst src/%.c, build/%.o, $(SRC))
wildcard 函数

wildcard 函数用于获取符合模式的文件列表

语法:

$(wildcard pattern)

示例:

# 获取 src 目录下所有的 .c 文件
SRC := $(wildcard src/*.c)
shell

shell 函数用于运行 shell 命令并返回结果。

语法:

$(shell command)

示例:

FILES := $(shell ls *.c)

返回当前目录下的所有 .c 文件。

其他

dir 函数返回文件名的目录部分

notdir 函数返回文件名的非目录部分。

basename 函数去掉文件名的扩展名部分。

addsuffix 函数用于在每个文件名后添加后缀

addprefix 函数用于在每个文件名前添加前缀

join 函数用于连接两组文件名

filter 函数用于过滤符合模式的文件名

filter-out 函数用于过滤不符合模式的文件名。

sort 函数用于对文件名排序并去重

1.4 示例makefile文件

目录结构:

project/
├── src/
│   ├── main.c
│   ├── util.c
│   └── helper.c
├── include/
│   └── util.h
└── Makefile

makefile文件:

# 变量定义
CC = gcc 
CFLAGS = -Wall -g -Iinclude
LDFLAGS = -lm
SRC_DIR = src		# 源文件目录
BUILD_DIR = build	# 编译中间文件目录
BIN_DIR = bin		# 目标二进制文件目录
# 使用 wildcard 函数获取所有源文件
SRC = $(wildcard $(SRC_DIR)/*.c)
# 使用 patsubst 函数将源文件路径转换为目标文件路径
OBJS = $(patsubst $(SRC_DIR)/%.c, $(BUILD_DIR)/%.o, $(SRC)) 
TARGET = $(BIN_DIR)/myapp# 规则定义
all: $(TARGET)$(TARGET): $(OBJS)@mkdir -p $(BIN_DIR)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c@mkdir -p $(BUILD_DIR)$(CC) $(CFLAGS) -c $< -o $@clean:rm -rf $(BUILD_DIR) $(BIN_DIR)# 伪目标
.PHONY: all clean

关于@mkdir -p $(BIN_DIR)的解释:

@ :@符号放在命令前面,表示在执行这个命令时不要打印出命令本身,这可以让输出更加简洁。
mkdir -pmkdir 是创建目录的命令;-p 选项表示“父目录”,它的作用是:如果目录不存在,则创建目录。如果目录已经存在,不会报错。可以递归地创建必要的父目录。
$(BIN_DIR):这是一个 Makefile 变量# 这个命令的意思是在执行目标规则时,确保 bin 目录存在。如果目录不存在,它会创建目录。如果目录已经存在,不会有任何影响。由于前面加了 @,这个命令本身不会被打印到控制台输出中。

1.5 参考内容

本笔记参考了以下内容:

  1. https://www.nowcoder.com/courses/cover/live/504
  2. https://blog.csdn.net/qq_53099212/article/details/132452987

如有不当或错误之处,恳请您的指正,谢谢!!!

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com