Linux中的make

make 是Linux及其他UNIX系统中常用的构建工具,主要用于自动化编译、管理大型项目中的文件依赖关系。它通过读取“Makefile”,根据文件的修改时间自动决定哪些文件需要重新编译,从而大大提高开发效率。

基本概念

  • 作用:根据Makefile中的规则自动编译程序或执行其他任务
  • 优势
    • 自动检测哪些源文件发生变化,只重新编译变化的部分
    • 管理多个目标文件、库和依赖关系
    • 简化复杂的构建过程

Makefile的结构

在项目目录下面创建Makefile

cd /path/to/你的项目目录
vim Makefile

或者用你喜欢的文本编辑器
nano Makefile

在项目目录下运行:

make

Makefile中定义了目标(目标文件或操作)、依赖关系和命令,格式为:

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

例:

# 编译所有目标
all: main

# 目标文件
main: main.o utils.o
    gcc -o main main.o utils.o
    #将两个目标文件(内容已经编译好)合成为一个完整的程序,可以直接运行。

# 依赖文件
main.o: main.c
    gcc -c main.c

utils.o: utils.c
    gcc -c utils.c
    #编译utils.c生成utils.o

# 清理编译产生的文件
clean:
    rm -f main *.o

注意:命令行必须以Tab键缩进!

类型作用例子说明
目标(目标文件)要“生成”的最终文件或中间文件mainmain.outils.o经过make规则处理得到的产物
源文件(源码文件)实现具体逻辑的源码文件main.cutils.c编写程序的原始数据
依赖文件影响目标文件生成的文件main.cutils.h变化会引发目标重建
  • 目标文件:你用make最终想要的文件(通常是可执行文件或目标文件)
  • 源文件:你用来“编译”的代码文件(含实现代码)
  • 依赖文件:影响目标的文件(源文件和头文件),如果它们修改了,目标就要重建。

常用用法

命令作用
make构建默认目标(第一个目标,通常是all或第一个定义目标)
make <目标>构建指定目标(如make clean
make -jN并行编译(N为同时执行的任务数)
make -f <文件名>使用特定的Makefile文件
make clean执行clean目标,通常用于清理临时文件
make -n显示将要执行的命令,但不实际执行
make -B强制重新构建所有目标

工作流程

  • 检查:make会对比目标文件和依赖文件的时间戳
    • 文件的时间戳是make判断是否需要重新编译的唯一依据。
    • 这大大节省了重复编译的时间,只处理变化部分。
  • 决定:如果依赖的源文件比目标文件新,则重新执行相关命令
  • 执行:运行相应的命令完成构建

文件的时间戳

  • 每个文件(目标文件、源代码文件、依赖文件)在操作系统中都带有“最后修改时间”。

  • 这可以用命令ls -l或stat查看:

ls -l main.o
stat main.o
  • 目标文件(如main.o或main)的时间戳表示它们最新的修改时间。

  • 源文件(如main.c、utils.c)的时间戳表示它们最后被更改的时间。

当你运行make时,它会根据Makefile中的规则,逐个目标检测:

  • a. 目标文件是否存在?

    • 如果目标文件不存在,make会执行对应的命令(即重新构建目标)。
  • b. 目标文件存在,依赖文件是否比目标新?

    • 比如:main.o依赖main.c和utils.h。

    • 如果任何依赖文件的修改时间比目标文件的时间更新(更“新”),说明依赖内容发生了变化。

    • 这种情况:make会重新执行规则中的命令以更新目标。

  • c. 依赖未变化(目标比所有依赖都旧)

    • make会跳过该目标的重建步骤。

例:
假设有以下两个文件:

main.o: main.c utils.h
    gcc -c main.c

  • 执行make main.o
  • make会检查:
    • main.o是否存在?存在吗?
    • main.c和utils.h的修改时间,是否比main.o的时间新?

案例一:

  • main.c在main.o之后被修改(时间更“新”):
    • make检测到这一点,重新运行gcc -c main.c。

案例二:

  • main.c和utils.h都没有变化,main.o的时间比它们都早:
    • make跳过重新编译,用已存在的main.o。

自动化mini说明

假设你有以下规则:

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

main.o: main.c utils.h
    gcc -c main.c

utils.o: utils.c utils.h
    gcc -c utils.c
  • 只要main.o、utils.o的依赖源文件没有变化,make就不会重建它们。
  • 如果源文件有更新(修改时间更晚),make会自动重新执行对应的编译命令。

小结

过程说明
检查目标文件是否存在不存在则必须编译,否则进入下一步
比较“依赖文件”的时间戳如果依赖文件比目标文件“新”,目标文件需要更新
执行命令重新生成目标根据规则中的命令行,重新生成目标文件
依赖未变化时跳过重新构建以提高效率,避免不必要的编译

示例

假设你的项目目录如下:

project/
├── main.c     -- 主程序源文件
├── utils.c    -- 其他功能实现的源文件
├── utils.h    -- 头文件,声明utils.c中的函数或变量
└── Makefile   -- 构建规则文件,用于自动化编译

Makefile内容:

# 定义变量
CC = gcc
CFLAGS = -Wall -g

# 默认目标
all: main

# 目标及依赖
main: main.o utils.o
	$(CC) -o main main.o utils.o

main.o: main.c utils.h
	$(CC) -c main.c $(CFLAGS)

utils.o: utils.c utils.h
	$(CC) -c utils.c $(CFLAGS)

# 清理临时文件
clean:
	rm -f main *.o

使用:

  • 编译全部:
make
  • 只重建main:
make main
  • 清除所有生成的文件:
make clean
  • 并行编译(比如同时编译两个任务):
make -j2

注意事项

  • 变量定义:用VAR = value定义变量,方便维护

  • 伪目标:clean等不对应文件的目标前加入.PHONY以避免冲突

.PHONY: clean
clean:
    rm -f main *.o
  • 条件编译:可以写条件语句(较高级用法)

  • 自动变量:如@代表目标文件、@代表目标文件、@代表目标文件、^代表所有依赖文件等

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值