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命令,并将命令的输出结果赋值给变量。
相关推荐
matlab的学徒14 分钟前
Web与Nginx网站服务(改)
linux·运维·前端·nginx·tomcat
Insist75319 分钟前
prometheus安装部署与alertmanager邮箱告警
linux·运维·grafana·prometheus
BAGAE1 小时前
MODBUS 通信协议详细介绍
linux·嵌入式硬件·物联网·硬件架构·iot·嵌入式实时数据库·rtdbs
灿烂阳光g1 小时前
SELinux 策略文件编写
android·linux
xqlily1 小时前
Linux操作系统之Ubuntu
linux·运维·ubuntu
阿部多瑞 ABU1 小时前
《基于国产Linux的机房终端安全重构方案》
linux·安全
倔强的石头1062 小时前
【Linux指南】Makefile入门:从概念到基础语法
linux·运维·服务器
ajassi20002 小时前
linux C 语言开发 (七) 文件 IO 和标准 IO
linux·运维·服务器
程序猿编码2 小时前
基于 Linux 内核模块的字符设备 FIFO 驱动设计与实现解析(C/C++代码实现)
linux·c语言·c++·内核模块·fifo·字符设备
一只游鱼2 小时前
Zookeeper介绍与部署(Linux)
linux·运维·服务器·zookeeper