菜鸟科技网

Linux makefile命令怎么写?

Makefile 是一个用于管理软件构建过程的工具,它定义了一系列规则(Rules),说明了如何从源文件(.c, .cpp 等)生成目标文件(可执行文件、库文件等)。make 命令则读取 Makefile 并执行这些规则。

Linux makefile命令怎么写?-图1
(图片来源网络,侵删)

核心概念:规则

Makefile 的核心是规则,一个规则的基本结构如下:

target: prerequisites
    command
  • target (目标):通常是要生成的文件名,比如可执行文件 my_program 或目标文件 main.o,它也可以是一个动作的名称,clean
  • prerequisites (依赖):生成 target 所需的文件,如果依赖比目标文件“新”,command 就会被执行。
  • command (命令):用于从依赖文件生成目标文件的 shell 命令。注意:每个命令行前面必须按一个 Tab,而不是空格。

工作流程

  1. make 首先会检查 target 文件是否存在。
  2. 如果不存在,或者任何一个 prerequisites 文件的修改时间比 target 文件新,make 就会执行 command 来更新 target
  3. target 存在并且所有依赖都比它旧,make 什么也不做,并报告“'target' is up to date”。

make 命令的基本用法

make 命令本身非常简单,它会默认在当前目录下寻找名为 Makefilemakefile 的文件。

默认执行

make
  • 如果不指定任何目标,make 会查找 Makefile 中的第一个目标(也称为终极目标默认目标)并尝试构建它。

指定目标

make <target_name>
  • 你可以显式地告诉 make 去构建哪个目标,这是最常用的方式。
  • make my_program 会尝试构建名为 my_program 的目标。

查看所有可用目标

make -n
# 或者
make --dry-run
  • 这个选项会显示 make 将要执行的命令,但不会真正执行它们,这对于调试 Makefile 非常有用。

强制重新构建

make -B
# 或者
make --always-make
  • 这个选项会强制重新构建所有指定的目标,忽略文件的修改时间戳。

输出详细信息

make -p
# 或者
make --print-data-base
  • 这个选项会打印出 make 内部所有的数据库信息,包括所有变量、规则和模式规则,对于理解复杂的 Makefile 或调试非常有帮助。

忽略错误继续执行

make -i
# 或者
make --ignore-errors
  • 如果某个命令执行失败(返回非零状态码),make 默认会停止。-i 选项会忽略错误,继续执行后续命令。

忽行所有命令,只检查依赖

make -q
# 或者
make --question
  • 这个选项会检查目标是否需要更新,但不执行任何命令
  • 如果目标是最新的,它会返回 0;如果需要更新,它会返回 1,这对于脚本检查非常有用。

一个简单的 Makefile 示例

让我们来看一个经典的 C 语言项目示例。

Linux makefile命令怎么写?-图2
(图片来源网络,侵删)

项目结构:

my_project/
├── main.c
├── utils.c
├── utils.h
└── Makefile
  • main.c:

    #include <stdio.h>
    #include "utils.h"
    int main() {
        int result = add(5, 3);
        printf("The result is: %d\n", result);
        return 0;
    }
  • utils.h:

    #ifndef UTILS_H
    #define UTILS_H
    int add(int a, int b);
    #endif
  • utils.c:

    Linux makefile命令怎么写?-图3
    (图片来源网络,侵删)
    #include "utils.h"
    int add(int a, int b) {
        return a + b;
    }

Makefile

# 定义变量,方便维护
CC = gcc
CFLAGS = -Wall -g
TARGET = my_program
SRC = main.c utils.c
OBJ = $(SRC:.c=.o)
# 默认目标(终极目标)
# 当只输入 make 时,这个目标会被构建
all: $(TARGET)
# 链接规则:从 .o 文件生成最终的可执行文件
$(TARGET): $(OBJ)
    $(CC) $(OBJ) -o $(TARGET)
# 隐式规则:从 .c 文件生成 .o 文件
# $(OBJ): $(OBJ:.c=.c)  <- 这行是隐含的,不需要显式写出
# 但我们可以写一个更明确的规则来处理 .h 文件
%.o: %.c utils.h
    $(CC) $(CFLAGS) -c $< -o $@
# 清理规则:删除所有生成的文件
clean:
    rm -f $(OBJ) $(TARGET)
# .PHONY 声明
# 告诉 make,clean 不是一个文件,而是一个伪目标
# 这样即使目录下存在一个名为 clean 的文件,make 也能正确执行这个规则
.PHONY: all clean

如何使用 make 命令:

  1. 首次构建项目

    make

    输出:

    gcc -Wall -g -c main.c -o main.o
    gcc -Wall -g -c utils.c -o utils.o
    gcc main.o utils.o -o my_program
  2. 再次执行 make

    make

    输出:

    make: 'my_program' is up to date.

    因为所有源文件都没有被修改,make 知道 my_program 已经是最新的,无需重新编译。

  3. 修改一个源文件后执行 make 修改 utils.c 中的 add 函数,然后再次运行:

    make

    输出:

    gcc -Wall -g -c utils.c -o utils.o
    gcc main.o utils.o -o my_program

    make 很聪明地发现只有 utils.c 被修改了,所以它只重新编译了 utils.c,然后重新链接了 main.o 和新的 utils.omain.c 没有被重新编译,这节省了大量时间。

  4. 执行 clean 目标

    make clean

    输出:

    rm -f main.o utils.o my_program

    这会删除所有编译生成的中间文件和最终可执行文件。


常用 make 命令总结表

命令 简写 描述
make --help make -h 显示帮助信息
make 构建Makefile中的第一个目标(默认目标)
make <target> 构建指定的目标
make -n make --dry-run 显示将要执行的命令,但不执行
make -B make --always-make 强制重新构建所有目标
make -p make --print-data-base 打印 make 的所有内部数据(变量、规则等)
make -i make --ignore-errors 忽略命令执行错误,继续执行
make -q make --question 检查目标是否需要更新(不执行命令),返回状态码
make -f <file> make --file=<file> 指定一个非默认名称的 Makefile 文件
make -j <N> make --jobs=<N> 允许并行执行 N 个任务,加速编译

进阶技巧

  • 变量:如示例中的 CC, CFLAGS,用于存储命令和选项,提高可维护性。
  • 自动变量
    • 表示规则中的目标文件。
    • $<:表示规则中的第一个依赖文件。
    • $^:表示规则中的所有依赖文件。
    • 表示所有比目标文件“新”的依赖文件。
    • 表示匹配模式中的“%”部分。
  • 函数make 提供了丰富的函数,如 wildcard (查找匹配文件)、patsubst (模式替换)、shell (执行shell命令) 等。
  • 伪目标:使用 .PHONY 关键字声明的目标,如 .PHONY: clean all,它告诉 make 这个目标不代表一个实际文件,这样即使目录下有同名文件,make 也会执行其命令。

掌握这些 make 命令和 Makefile 的基本概念,你就能高效地管理和自动化你的软件开发项目了。

分享:
扫描分享到社交APP
上一篇
下一篇