如何使用 GNU make 编译多个简单项目

How to compile multiple simple projects with GNU make

我正在尝试实现编程书籍中的各种项目。我的意图是让每个项目练习都放在它自己的文件夹中,然后有一个 makefile 用类似 make all 的东西编译所有这些项目。文件夹结构是这样的:

.
├── Makefile
├── bin
│   ├── prog1
│   ├── prog2
│   └── prog3
└── src
    ├── prog1
    │   ├── Makefile
    │   └── main.c
    ├── prog2
    │   ├── Makefile
    │   └── main.c
    └── prog3
        ├── Makefile
        └── main.c

我想学习如何设置这样的结构。特别是顶部 makefile 访问 src 中所有文件夹的部分调用 make,然后将可执行文件复制并重命名到 bin 文件夹中。

有不同的方法来解决这个问题,但像这样的方法应该适用于您的示例:

PROGS := bin/prog1 bin/prog2 bin/prog3

all: $(PROGS)

$(PROGS):
    $(MAKE) -C src/$(@F)
    mkdir -p $(@D)
    cp src/$(@F)/main $@

.PHONY: clean

clean:
    rm -f $(PROGS)
    for t in $(PROGS); do make -C src/`basename $$t` clean; done

我们定义了我们要构建的目标列表 (PROGS)。我们说这些目标是 all 的先决条件,然后我们继续定义它们应该如何构建,即:我们递归下降到 src/ 加上目标的文件名部分到 运行 make那里。我们创建目标目录以确保它在那里,并从我们下降到目标路径的目录中复制 main

作为一个很好的衡量标准,还有一个 clean 目标可以在 src/ 中递归地删除所有 PROGS 和 运行s make clean

您的布局示意图显示了每个练习的 makefile,以及您似乎实际上要询问的顶级 makefile。顶层 makefile 最好避免重复每个练习 makefile 的行为,因为这样的重复会给您带来额外的维护负担。此外,您很可能最终会进行涉及多个源文件的练习,并且可能会进行一些需要构建多个工件的练习。这就是每个练习 makefile 包含构建与之关联的练习所需的一切(进入练习特定目录)以及顶级 makefile 依赖于这些的更多原因。

遵循该方案将为顶级 makefile 留下明确定义的角色:执行每次练习构建(通过递归 运行 make),并复制生成的二进制文件至 bin/。这不是 唯一 设置协作 makefile 系统的方法,但它相当简单,并且可以让您专注于练习而不是构建系统。

然后,让我们假设,每个单独的练习都可以通过切换到其目录和 运行 make 来构建,结果是在同一目录中具有相同名称的可执行文件作为目录。也就是说,从顶级目录执行 cd src/prog2; make 会生成所需的可执行文件 src/prog2/prog2。在那种情况下,顶层 makefile 只需要所有练习的名称和一些规则:

EXERCISES = prog1 prog2 prog3
BINARIES =  $(EXERCISES:%=bin/%)

all: $(BINARIES)

$(BINARIES):
        make -C src/$$(basename $@)
        cp src/$$(basename $@)/$$(basename $@) $@

注意:它使用特定于 GNU 的 make 实现的功能来根据练习名称计算所需二进制文件的名称。我认为这是可以接受的,因为你标记了 [gnu-make],但无论如何,这是一个方便的功能,而不是必需的。