0

我正在尝试从编程书中实现各种项目。我的意图是让每个项目在其自己的文件夹中进行练习,然后有一个 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文件夹中。

4

2 回答 2

1

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

遵循该方案将为顶级 makefile 留下一个明确定义的角色:执行 per-exercise 构建(通过递归运行make),并将生成的二进制文件复制到bin/. 这不是建立协作生成文件系统的唯一方法,但它相当容易,这将使您能够专注于练习而不是构建系统。

那么,让我们假设每个单独的练习都可以通过更改到其目录并运行来构建,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],但无论如何,这是一个方便的功能,而不是必需的。

于 2020-06-21T14:38:58.257 回答
0

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

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/降到目标的 plus 文件名部分以在那里运行 make。我们创建目标的目录以确保它在那里,并main从我们下降的目录复制到目标的路径。

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

于 2020-06-21T12:24:23.810 回答