GNU Make 全局变量在子 make 中更新

4

我需要帮助解决一个项目中的Makefile问题。源代码目录看起来像这样。

|-- Makefile
|-- drivers
|   |-- Makefile
|   |-- tty
|       |-- Makefile
|       |-- console.c
|       |-- keyboard.c
|-- kernel
|   |-- Makefile
|   |-- kmain.c

在顶层 Makefile 中,我已经导出了一个变量 OBJECTS,我希望将其填充为目标文件,以便在顶层 Makefile 中一起构建和链接它们。
例如,我想通过以下方式更新 drivers/tty/Makefile 中的 OBJECTS 变量:
OBJECTS += $(CURDIR)console.o
OBJECTS += $(CURDIR)keyboard.o

但是对OBJECTS的更改不会传递到顶层Makefile。我一直在查看Linux源代码树中的Makefile,它们似乎在做类似的事情。然而,我无法使其正常工作。我是否漏掉了什么?

2个回答

2

您似乎正在递归使用Make,类似于

# Makefile:

export OBJECTS :=
all:
    $(MAKE) -C drivers/tty
    @echo OBJECTS is $(OBJECTS)

# drivers/tty/Makefile:

OBJECTS += $(CURDIR)console.o
all:
    whatever

这种方法行不通,因为每个Make都有自己的OBJECTS;子Make不能修改父Make中的变量。正确的做法是使用export,而不是import/exportshare(没有import/exportshare这样的东西,我只是在举例说明)。
您可以通过包含其他makefile来达到想要的效果,而不是调用它们:
# Makefile:

OBJECTS :=
all: DRIVERS_TTY
    @echo OBJECTS is $(OBJECTS)

include drivers/tty/Makefile

# drivers/tty/Makefile:

OBJECTS += drivers/tty/console.o

DRIVERS_TTY:
    whatever

你会注意到这里存在一些不愉快的地理位置依赖性; drivers/tty/Makefile 内部完整地拼写了 "drivers/tty",这使得维护变得痛苦。一旦你掌握了这个基本的 include 技巧,就有方法来解决这个问题。


这可能是我想要的。我猜我可以让顶层Makefile包含driver/Makefile、kernel/Makefile等,而drives/Makefile则包含drivers/tty/Makefile等。Linux内核的Makefile可能会这样做,但它们有点hacky和难以阅读 :) - tobier
是的,你可以用那种方式做。我不知道Linux内核的Makefile是如何做到的。 - Beta

1
当您递归运行make时,每个后续调用都会打开一个新的子shell,因此您无法通过导出回到链上。一种方法是对于每个对submake的调用,将其附加到对象列表文件中,然后可能包含该文件。更好的解决方案可能是让您的主要makefile直接include每个这些submake文件,而不是在它们上调用make。此方法允许使用每个submake文件使用您的OBJECTS +=语句构建OBJECTS变量。另一个附加的好处是,您只运行一个make实例,而不是多个submake,这使得make能够进行更好的依赖关系生成。请参阅“递归make被认为是有害的”http://aegis.sourceforge.net/auug97.pdf

这里之前由用户Dan Moulding https://stackoverflow.com/users/95706/dan-moulding 发布的一个很酷的Makefile构建系统,真正展示了使用子Makefile文件可以做很多很酷的事情,同时只需要一个主Makefile。Dan的boilermake项目在这里:https://github.com/dmoulding/boilermake


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接