[Linux工具] Makefile

简介: Makefile是Linux环境下用于自动化编译和链接程序的配置文件,常用于简化大型项目的编译流程。通过定义目标文件、依赖文件及生成命令,Makefile能高效管理编译任务。它不仅适用于C语言项目,还可扩展到其他编程语言和非编程任务中。


简介

Linux的make程序用来自动化编译大型源码,很多时候,我们在Linux下编译安装软件,只需要敲一个make就可以全自动完成,非常方便。

make能自动化完成这些工作,是因为项目提供了一个Makefile文件,它负责告诉make,应该如何编译和链接程序。

Makefile相当于Java项目的pom.xml,Node工程的package.json,Rust项目的Cargo.toml,不同之处在于,make虽然最初是针对C语言开发,但它实际上并不限定C语言,而是可以应用到任意项目,甚至不是编程语言。此外,make主要用于Unix/Linux环境的自动化开发,掌握Makefile的写法,可以更好地在Linux环境下做开发,也可以为后续开发Linux内核做好准备。

在本教程中,我们将由浅入深,一步一步学习如何编写Makefile,完全针对零基础小白,只需要提前掌握如何使用Linux命令。

安装make

在Linux(Ubuntu)系统中,我们可以使用包管理工具直接安装make以及GCC工具链。例如在Ubuntu下,使用以下命令:

$ sudo apt update
$ sudo apt install build-essential

安装完成后,可以输入以下命令验证安装是否成功:

$ make -v
GNU Make 4.3
$ gcc --version
gcc (Ubuntu ...) 11.4.0

这样,我们就成功地安装了make,以及GCC工具链。

Makefile基础

在Linux环境下,当我们输入make命令时,它就在当前目录查找一个名为Makefile的文件,然后,根据这个文件定义的规则,自动化地执行任意命令,包括编译命令。

Makefile由若干条规则(Rule)构成,每一条规则指出一个目标文件(Target),若干依赖文件(Prerequisites),以及生成目标文件的命令。规则的基本格式如下:

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

紧接着,以Tab开头的是命令,用来生成目标文件。命令可以是任何Shell命令,如gcccpmv等。以#开头的是注释,会被make命令忽略。

编译C语言程序

下面是一个典型的Makefile,用于编译C语言程序:

BIN=code          # 目标文件
CC=gcc            # 编译器
SRC=$(wildcard *.c) # 所有的.c文件
OBJ=$(SRC:.c=.o)  # 替换为.o文件
LFLAGS=-o
FLAGS=-c
RM=rm -f          # 删除方式
$(BIN): $(OBJ)
    @$(CC) $(LFLAGS) $@ $^
%.o: %.c
    @$(CC) $(FLAGS) $<
.PHONY: clean
clean:
    $(RM) $(OBJ) $(BIN)

在这个Makefile中:

  • BIN=code:变量 BIN 的值是 code,表示目标文件名。
  • CC=gcc:变量 CC 的值是 gcc,表示所使用的编译器。
  • SRC=$(wildcard *.c)SRC 表示当前目录下所有的 .c 文件,使用 wildcard 函数动态生成。
  • OBJ=$(SRC:.c=.o):将 SRC 中的 .c 文件名替换为 .o,表示目标文件对应的中间文件(对象文件)。
  • LFLAGS=-o:链接选项,指定输出文件名。
  • FLAGS=-c:编译选项,用于生成中间文件。
  • RM=rm -f:删除命令,用于清理目标文件和中间文件。
  • $(wildcard *.c) 用于匹配当前目录下的所有.c文件。
  • $(SRC:.c=.o) 将所有的.c文件替换为.o文件。
  • $@ 表示目标文件。
  • $< 表示第一个依赖文件。
  • $^ 表示所有依赖文件。
  • .PHONY 声明clean为伪目标,避免与同名文件冲突。

执行make即可编译,执行make clean可清理生成的文件。

注意:如果在修改文件内容,但是其他文件没有改变内容(Modify time)没有更新,则未改变的文件不会进行重新编译,可能会造成程序出现问题。所以当项目出现问题的时候可以对项目进行重新创建,以此解决问题。

使用隐式规则

Makefile支持许多内置的隐式规则,例如编译C语言程序的规则:

%.o: %.c
    $(CC) $(FLAGS) $<

含义:

  • 将每个 .c 文件编译为对应的 .o 文件(对象文件)。
  • $< 表示第一个依赖文件。

所以该规则会使*.c从第一个开始,逐个编译为对应的.o文件。

小结:隐式规则让Makefile更简洁,很多情况下不需要显式定义规则。

使用变量

赋值形式 =

这种赋值在解析时是延迟展开的。也就是说,右侧的值在被使用时才会被计算,左值变为变量来使用。这种赋值方式是 GNU Make 的标准形式。

例如:

SRC=$(wildcard *.c)

变量可以提高Makefile的可读性和可维护性。例如:

CC=gcc
CFLAGS=-Wall -g
SRC=main.c utils.c
OBJ=$(SRC:.c=.o)
program: $(OBJ)
    $(CC) $(CFLAGS) -o $@ $^
%.o: %.c
    $(CC) $(CFLAGS) -c $< -o $@
.PHONY: clean
clean:
    rm -f $(OBJ) program

符号说明:

  • $(变量名):表示引用变量,例如$(CC)引用了变量CC,其值为gcc

示例:

  1. $@ 示例
objects = foo.o bar.o
$(objects): %.o: %.c
    gcc -c $< -o $@

在这个例子中,$@ 将被替换为每个 .o 文件的目标名称,如 foo.obar.o

  • $@ 代表当前规则的目标文件名(即左侧的文件)。
  • 它用于在命令中引用规则左侧的目标。
  1. $^ 示例
target: dependency1 dependency2
    gcc -o $@ $^

在这个例子中,$^ 将被替换为 dependency1 dependency2

  • $^ 代表当前规则中所有依赖文件的列表。
  • 它用于在命令中引用规则右侧的所有依赖文件。
  1. $< 示例
%.o: %.c
    gcc -c $< -o $@

在这个例子中,$< 将被替换为规则中的第一个依赖文件,如 main.c

  • $< 专门用来引用规则中列出的第一个依赖文件。

通过这些示例,可以清楚地理解这些符号的用途及功能。

使用模式规则

模式规则支持使用通配符定义一组目标文件的规则,例如:

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

符号说明:

  • %:通配符,表示任意文件名。例如,%.o匹配所有.o文件,%.c匹配所有.c文件。
  • $<:表示当前规则中的第一个依赖文件。例如,main.c
  • $@:表示目标文件。例如,main.o

通过模式规则,可以避免重复定义规则,适用于大规模项目中的批量操作。

自动生成依赖

对于大型项目,手动维护依赖关系容易出错。我们可以使用gcc-M选项自动生成依赖关系:

gcc -MM main.c > deps.d

然后在Makefile中包含生成的依赖文件:

include deps.d

自动生成依赖的意义:

  • 动态更新依赖关系:当源码文件发生变动时,重新运行依赖生成命令即可更新deps.d
  • 减少人工维护的错误:避免手动书写依赖关系带来的遗漏问题。

注意:

  • 包含依赖文件时,如果依赖文件不存在,Makefile可能会报错。为此,可以使用如下方式:
-include deps.d

这表示如果deps.d不存在,Makefile将不会报错。

示例:

  1. 自动生成依赖文件
%.d: %.c
    @set -e; rm -f $@; \
    $(CC) -MM $(CFLAGS) $< > $@.$$$$; \
    mv $@.$$$$ $@

在这个规则中,依赖文件 .d 将自动根据对应的 .c 文件生成。

  1. 包含所有依赖
include $(SRC:.c=.d)

通过这条规则,可以动态包含所有的依赖文件。

完善Makefile

通过上述方法,我们可以逐步完善一个Makefile。以下是一个完整的示例:

BIN=program
CC=gcc
CFLAGS=-Wall -g
SRC=$(wildcard *.c)
OBJ=$(SRC:.c=.o)
$(BIN): $(OBJ)
    $(CC) $(CFLAGS) -o $@ $^
%.o: %.c
    $(CC) $(CFLAGS) -c $< -o $@
.PHONY: clean
clean:
    rm -f $(OBJ) $(BIN)
.PHONY: all
all: clean $(BIN)
-include deps.d
%.d: %.c
    @set -e; rm -f $@; \
    $(CC) -MM $(CFLAGS) $< > $@.$$$$; \
    mv $@.$$$$ $@

通过以上内容的学习,已经足够编写寄出的Makefile~

目录
相关文章
|
3月前
|
Linux 网络安全 数据安全/隐私保护
Linux 超级强大的十六进制 dump 工具:XXD 命令,我教你应该如何使用!
在 Linux 系统中,xxd 命令是一个强大的十六进制 dump 工具,可以将文件或数据以十六进制和 ASCII 字符形式显示,帮助用户深入了解和分析数据。本文详细介绍了 xxd 命令的基本用法、高级功能及实际应用案例,包括查看文件内容、指定输出格式、写入文件、数据比较、数据提取、数据转换和数据加密解密等。通过掌握这些技巧,用户可以更高效地处理各种数据问题。
353 8
|
14天前
|
监控 安全 Ubuntu
Linux下如何安装配置Fail2ban防护工具
通过以上步骤,可以在Linux系统中成功安装和配置Fail2ban,从而有效保护服务器免受暴力破解等攻击。Fail2ban通过实时监控日志文件,自动更新防火墙规则,为系统安全提供了一层重要的保护。
71 36
|
10天前
|
Unix Linux C语言
【Linux】 Linux makefile 教程
本文详细介绍了 Linux 环境下 Makefile 的基本结构、语法和使用方法,并通过一个简单的 C++ 项目示例演示了 Makefile 的实际应用。Makefile 是一个强大而灵活的工具,通过合理配置,可以极大地简化项目的编译和管理过程,提高开发效率。希望本文能帮助您更好地理解和应用 Makefile,在实际项目中高效管理代码的编译和构建。
40 20
|
9天前
|
Unix Linux C语言
【Linux】 Linux makefile 教程
本文详细介绍了 Linux 环境下 Makefile 的基本结构、语法和使用方法,并通过一个简单的 C++ 项目示例演示了 Makefile 的实际应用。Makefile 是一个强大而灵活的工具,通过合理配置,可以极大地简化项目的编译和管理过程,提高开发效率。希望本文能帮助您更好地理解和应用 Makefile,在实际项目中高效管理代码的编译和构建。
43 16
|
1天前
|
Linux API
Linux下载工具wget与curl
`wget` 是一个用于从网络下载文件的命令行工具,支持HTTP、HTTPS和FTP协议。它能自动处理下载中断,并支持递归下载网站内容。基本用法:`wget URL`,可指定文件名(`-O`)、保存目录(`-P`),还支持断点续传(`-c`)、限速(`--limit-rate`)和递归下载(`-r`)。相比之下,`curl` 更侧重于发送各种HTTP请求(如GET、POST),并支持文件上传、自定义请求头和cookie等功能。
23 10
|
26天前
|
Linux 网络性能优化 网络安全
Linux(openwrt)下iptables+tc工具实现网络流量限速控制(QoS)
通过以上步骤,您可以在Linux(OpenWrt)系统中使用iptables和tc工具实现网络流量限速控制(QoS)。这种方法灵活且功能强大,可以帮助管理员有效管理网络带宽,确保关键业务的网络性能。希望本文能够为您提供有价值的参考。
82 28
|
23天前
|
网络协议 Unix Linux
深入解析:Linux网络配置工具ifconfig与ip命令的全面对比
虽然 `ifconfig`作为一个经典的网络配置工具,简单易用,但其功能已经不能满足现代网络配置的需求。相比之下,`ip`命令不仅功能全面,而且提供了一致且简洁的语法,适用于各种网络配置场景。因此,在实际使用中,推荐逐步过渡到 `ip`命令,以更好地适应现代网络管理需求。
35 11
|
1月前
|
安全 网络协议 Linux
结合 `nc` 工具利用笑脸漏洞(Smile Bug)攻击 Metasploitable2 Linux
本文介绍如何使用 `nc`(Netcat)工具结合笑脸漏洞(Smiley Bug)攻击 Metasploitable2 Linux 靶机。首先概述了 `nc` 的基本功能和高级用法,包括建立连接、监听端口、文件传输等操作。接着详细描述了笑脸漏洞的原理及其在网络攻防中的应用,展示了通过 `nc` 发送恶意输入检测漏洞的方法。最后结合 Python 脚本实现更复杂的攻击场景,并强调了合法性和环境隔离的重要性。
52 13
|
2月前
|
运维 监控 Linux
推荐几个不错的 Linux 服务器管理工具
推荐几个不错的 Linux 服务器管理工具
177 6
|
3月前
|
缓存 监控 Linux
Linux性能分析利器:全面掌握perf工具
【10月更文挑战第18天】 在Linux系统中,性能分析是确保软件运行效率的关键步骤。`perf`工具,作为Linux内核自带的性能分析工具,为开发者提供了强大的性能监控和分析能力。本文将全面介绍`perf`工具的使用,帮助你成为性能优化的高手。
273 1