Makefile杂记

  • makefile文件三要素
  • 伪目标
  • 三类变量
  • makefile 当中 常用函数

编写Makefile并执行make

复制代码
# Makefile
main : main.c
        gcc main.c -o main

(makefile 三要素)

make file 文件中的:.PHONY( 伪目标**)**

Phony Targets

A phony target is one that is not really the name of a file; rather it is just a name for a recipe to be executed when you make an explicit request. There are two reasons to use a phony target: to avoid a conflict with a file of the same name, and to improve performance.

伪目标的使用:

在 Makefile 中,伪目标(phony target)或称为伪目标规则(phony target rule)是一种特殊的规则,它本身不对应任何实际的文件。伪目标通常用于执行一系列命令或作为其他目标的依赖,以确保特定的任务被执行。在 GNU Make 中,伪目标通常通过 .PHONY 声明来指定。

以下是一些关于伪目标的要点和示例:

声明伪目标

在 Makefile 中,你可以使用 .PHONY 声明一个或多个伪目标。例如:

bash 复制代码
.PHONY: clean all test

这表示 cleanalltest 是伪目标,它们不会与文件名冲突。

使用伪目标

伪目标通常用作默认目标或作为其他目标的依赖。以下是一些示例:

示例 1:默认目标
bash 复制代码
.PHONY: all

all: program

program: main.o utils.o
    gcc -o program main.o utils.o

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

utils.o: utils.c
    gcc -c utils.c

clean:
    rm -f *.o program

在这个示例中,all 是一个伪目标,它依赖于 program。当你运行 make 时,默认会执行 all 目标,进而构建 program

示例 2:执行命令
bash 复制代码
.PHONY: hello

hello:
    @echo "Hello, World!"

在这个示例中,hello 是一个伪目标,当你运行 make hello 时,它会输出 "Hello, World!"。

示例 3:组合多个目标
bash 复制代码
.PHONY: all clean test

all: program

program: main.o utils.o
    gcc -o program main.o utils.o

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

utils.o: utils.c
    gcc -c utils.c

test:
    ./program --test-option

clean:
    rm -f *.o program

在这个示例中,allcleantest 都是伪目标。你可以通过运行 make all 来构建程序,通过 make test 来运行测试,通过 make clean 来清理构建文件。

注意事项

  1. 避免与文件名冲突 :伪目标通常不会与文件名冲突,但使用 .PHONY 声明可以避免潜在的命名冲突。
  2. 默认目标 :如果你没有指定目标,make 会尝试构建第一个目标。如果你希望指定一个默认目标,可以将其命名为 all 或其他你喜欢的名字,并确保它是第一个目标或在 Makefile 中明确指定。
  3. 命令前缀 :在伪目标的命令中,通常使用 @ 前缀来抑制命令本身的输出(仅显示命令的输出结果)。

变量:分为系统内置变量、自定义变量、自动化变量

内置变量

Makefile中的内置变量(也称为系统变量)在构建过程中非常有用,它们提供了一些预定义的值,用于简化Makefile的编写。以下是一些常见的Makefile内置变量及其使用示例:

1. $@

表示当前规则中的目标文件名,包含扩展名。

示例

bash 复制代码
# 定义目标文件和依赖文件
TARGET = myprogram
OBJS = main.o utils.o

# 规则: 编译目标文件
$(TARGET): $(OBJS)
	$(CC) $(CFLAGS) -o $@ $^

在这个示例中,$@会被替换为myprogram

2. $^

表示当前规则中所有的依赖文件名,以空格隔开,不重复。

示例

继续上面的例子,$^会被替换为main.o utils.o

3. $<

表示当前规则中的第一个依赖文件名。

示例

bash 复制代码
# 规则: 编译单个.o文件
%.o: %.c
	$(CC) $(CFLAGS) -c $< -o $@

在这个示例中,$<会被替换为第一个依赖文件,例如main.c(如果正在编译main.o)。

4. $*

表示目标文件的名称,不包含扩展名。

示例

bash 复制代码
# 假设有一个目标文件名为 main.o
# 那么 $* 会被替换为 main

5. $?

表示所有比目标文件新的依赖文件。这个变量在决定是否需要重新编译目标文件时非常有用。

示例

由于$?的使用场景比较特殊,它通常与条件语句结合使用,以确定哪些依赖文件已经更新,从而决定是否需要重新编译。在简单的Makefile示例中可能不太容易直接展示其用法。

6. CC 和 CXX

分别表示C语言编译器和C++语言编译器的名称。

示例

bash 复制代码
# 定义编译器
CC = gcc
CXX = g++

# 使用编译器编译目标文件
$(TARGET): $(OBJS)
	$(CC) $(CFLAGS) -o $@ $^

在这个示例中,CC被设置为gcc,用于编译C语言源文件。

7. RM

表示删除文件程序的名称。

示例

bash 复制代码
# 定义删除文件的命令
RM = rm -f

# 清理规则
clean:
	$(RM) $(TARGET) $(OBJS)

在这个示例中,RM被设置为rm -f,用于删除目标文件和依赖文件。

8. CFLAGS 和 CXXFLAGS

分别表示C语言编译器和C++语言编译器的编译选项。

示例

bash 复制代码
# 定义删除文件的命令
RM = rm -f

# 清理规则
clean:
	$(RM) $(TARGET) $(OBJS)

在这个示例中,CFLAGSCXXFLAGS分别被设置为C语言和C++语言的编译选项。

自定义变量:

= 是延迟赋值

:= 是立即赋值

?= 是空赋值

+= 是追加赋值

自动化变量:

$< 第一个依赖文件

$^ 全部依赖文件

$@ 目标

模式匹配

% 匹配任意多个字符

* 通配符

默认规则

.o文件默认.使用.c文件进行编译

条件分支1

ifeq(var1, var2)

...

else

..

endif


ifeq(<arg1>, <arg2>)

语句1

else ifeq(<arg3>, <arg4>)

语句2

else

语句3

endif

条件分支2

ifneq(<arg1>, <arg2>)

语句1

else

语句2

endif

ps:【Scripts系列】之Makefile中条件分支ifeq/else/endif/else ifeq/ifneq/ifdef/ifndef用法详解 - SoaringLee_fighting - 博客园

cc 命令时通过 -I 选项指定头文件所在路径

复制代码
# Makefile
INCS := -I./func
SRCS := $(wildcard *.c)
​
main : $(SRCS)
        gcc $(INCS) $(SRCS) -o mainmal

例子解读:

复制代码
# Makefile
SRCS := $(wildcard *.c)
​
main : $(SRCS)
        gcc $(SRCS) -o main

SRCS := $(wildcard *.c) 这行代码出现在使用Makefile文件构建项目的上下文中,特别是在GNU Make工具中。Makefile是一个包含了一系列规则和指令的文件,用于自动化编译和构建过程。让我们分解并详细说明这行代码的含义和作用:

  1. SRCS :
    • SRCS是一个变量名,在这里被用作一个容器,用于存储源文件的列表。变量名在Makefile中是自定义的,SRCS通常代表"Source Files"(源文件)。
  2. := :
    • :=是Makefile中的赋值操作符,用于给变量赋值。这种赋值方式称为简单扩展赋值,它在赋值时立即对右侧的值进行扩展(即解析其中的变量和函数)。
  3. $(wildcard *.c) :
    • $(wildcard pattern)是GNU Make的一个函数,用于匹配并返回符合特定模式的文件名列表。
    • *.c是一个文件模式,表示当前目录下所有以.c结尾的文件。这意味着,这个函数会查找当前目录(Makefile所在的目录)下所有C语言源文件。

综合起来,SRCS := $(wildcard *.c)这行代码的作用是:查找当前目录下所有以.c结尾的文件,并将这些文件的列表赋值给变量SRCS。这样,SRCS变量就包含了所有C语言源文件的名称,可以在Makefile的其他部分使用这些文件名来进行编译和链接等操作。

例如,如果当前目录下有main.cutils.ctest.c三个C语言源文件,那么执行这行代码后,SRCS变量的值将是这三个文件名的列表。

$(wildcard pattern)

在Makefile的上下文中,$(wildcard pattern)是一个函数,而wildcard是这个函数的名称。这个函数的作用是根据给定的模式(pattern)匹配文件名,并返回匹配到的文件名列表。

具体来说,wildcard函数的工作原理如下:

  • 它接受一个参数,即文件模式(pattern),这个模式可以包含通配符,比如*?等。
  • 函数会搜索当前工作目录(或者通过指定路径搜索其他目录,但这里没有涉及到)中所有符合该模式的文件。
  • 对于每个匹配的文件,函数都会将其完整路径(或相对路径,取决于Makefile的位置和上下文)添加到返回列表中。
  • 最终,函数返回一个包含所有匹配文件名的列表。

makefile 当中 常用函数

在Makefile中,有许多常用的函数,这些函数可以帮助自动化构建过程,提高构建效率和灵活性。以下是一些常用的Makefile函数及其功能:

一、字符串操作函数

  1. subst :字符串替换函数。把字符串<text>中的<from>字符串替换成<to>
  2. patsubst :模式字符串替换函数。查找<text>中的单词(单词以空格、Tab或回车、换行分隔)是否符合模式<pattern>,如果匹配则用<replacement>替换。<pattern>可以包括通配符%,表示任意长度的字符串。
  3. strip :去空格函数。去掉<string>字符串开头和结尾的空字符,并将其中多个连续空字符合并为一个空字符。
  4. findstring :查找字符串函数。在字符串<in>中查找<find>字符串,如果找到则返回<find>,否则返回空字符串。
  5. filter :过滤函数。以<pattern>模式过滤<text>字符串中的单词,保留符合<pattern>模式的单词。可以有多个模式。
  6. filter-out :反过滤函数。与filter函数相反,过滤掉<text>字符串中所有符合<pattern>模式的单词,保留所有不符合此模式的单词。
  7. sort :排序函数。给字符串<list>中的单词排序(升序),并去掉重复的单词。
  8. word :取单词函数。取字符串<text>中第<n>个单词(从1开始),若<n><text>大则返回空字符串。
  9. wordlist :取单词串函数。取字符串<text>中从<s>开始到<e>的单词串。<s><e>表示单词在字符串中位置的数字。
  10. words :单词个数统计函数。统计<text>中字符串的单词个数。
  11. firstword :首单词函数。取字符串<text>中的第一个单词。

二、文件名操作函数

  1. dir :取目录函数。从文件名序列<names...>中取出目录部分,目录部分是指最后一个反斜杠(/)之前的部分。如果没有反斜杠,则返回./
  2. notdir :取文件函数。从文件名序列<names...>中取出非目录部分,非目录部分是指最后一个反斜杠(/)之后的部分。
  3. suffix:取后缀函数。从文件名中取出后缀部分。
  4. basename:取前缀函数。从文件名中取出除去后缀的信息。
  5. addsuffix:加后缀函数。往文件名序列中添加后缀信息。
  6. addprefix:加前缀函数。往文件名序列中添加前缀信息。
  7. join :连接函数。把<list2>中的单词对应地加到<list1>的单词后面,返回连接后的字符串。
  8. wildcard:通配符函数。展开为已经存在的、使用空格分开的、匹配此模式的所有文件列表。如果不存在任何符合此模式的文件,函数会忽略模式字符并返回空。

三、其他常用函数

  1. foreach:循环函数。用于循环遍历列表中的每个元素,并对每个元素执行指定的操作。
  2. if:条件函数。根据条件判断执行不同的代码块。
  3. call:调用函数。调用一个用户自定义的函数,并传递参数给它。
  4. origin:起源函数。返回变量的来源,即变量是在哪个Makefile中定义的,或者是通过哪个命令设置的。
  5. shell:执行shell命令函数。执行一个shell命令,并将命令的输出结果赋值给变量。
相关推荐
Xiezequan8 分钟前
c语言进程直接的管道
linux
BLEACH-heiqiyihu11 分钟前
docker仓库数据传输加密
运维·docker·容器
对许12 分钟前
Linux计算时间差
linux
北京华人开创公司18 分钟前
京准电钟国产信创:北斗授时服务器的应用及详细介绍
运维·服务器
半__夏19 分钟前
什么是docker,docker解决了什么问题
运维·docker·容器
晓纪同学1 小时前
图漾相机-ROS1_SDK_ubuntu版本编译(新版本)
linux·数码相机·ubuntu
Allen Bright1 小时前
Linux中的mv命令深入分析
linux·运维·服务器
ken22321 小时前
linux ibus rime 中文输入法,快速设置为:默认简体 (****)
linux
基哥的奋斗历程2 小时前
解决Linux 虚拟机网段与虚拟机配置网段不一致
linux·运维·服务器
Cachel wood2 小时前
Vue.js前端框架教程5:Vue数据拷贝和数组函数
linux·前端·vue.js·python·阿里云·前端框架·云计算