Makefile GNU Make |如何在源代码层次结构和编译器输出h-hy之间创建依赖关系?

Makefile GNU Make |如何在源代码层次结构和编译器输出h-hy之间创建依赖关系?,makefile,gnu,Makefile,Gnu,Makefile中的一些代码: tempDir := ... javaSources := $(wildcard src/java/**/%.java) javaClasses := $(subst src/java, $(tempDir)/java/classes, $(subst .java,.class, $(javaSources))) $(javaClasses): $(javaSources) mkdir -p $(tempDir)/java/classes || true

Makefile
中的一些代码:

tempDir := ...
javaSources := $(wildcard src/java/**/%.java)
javaClasses := $(subst src/java, $(tempDir)/java/classes, $(subst .java,.class, $(javaSources)))

$(javaClasses): $(javaSources)
  mkdir -p $(tempDir)/java/classes || true
  javac \
    -d  $(tempDir)/java/classes \
    -cp $(tempDir)/java/classes \
  $?
如何创建模式规则(如)以保持输入/输出顺序


@MadScientist

首先,您的
通配符将不起作用。GNU make只使用基本的shell globbing,这意味着它无法理解高级globbing,比如
***
意思是“搜索所有子目录”。其次,
%
根本不是一个shell全局字符,所以您只需要查找字面上命名为
%.java
的文件

相反,你可能想要这样的东西:

javaSources := $(shell find src/java -name '*.java')
接下来,要创建
javaClasses
内容,您确实不想使用
subst
,因为它会替换任何可能给出错误匹配的地方(例如,
$(subst.x.y,foo.xbar)
将生成
foo.ybar
,这可能不是您想要的)

像这样的事情更容易理解:

javaClasses := $(patsubst src/java/%.java,$(tempdir)/java/classes/%.class,$(javaSources))
最后,您正在重复上一个问题中犯的错误,您试图在同一规则中列出所有目标和所有先决条件。正如我在那个问题上所说的,这是不对的

答案与前面的问题完全相同:您应该编写一个模式规则,描述如何从一个源文件构建一个目标

同样,您需要一个
all
目标或类似目标,这取决于所有输出。

作为回答的补充,您可能应该使用如下模式规则:

$(tempDir)/java/classes/%.class: src/java/%.java
    mkdir -p $(dir $@)
    javac -d $(dir $@) -cp $(dir $@) $<
这样您就可以调用
makeall
来编译所有需要修改的源文件。如果您希望将
all
作为默认目标(如果您只调用
make
,则目标生成会选择),请将其置于任何其他显式目标之前,或者使用
。default\u goal
特殊变量:

.DEFAULT_GOAL := all

非常感谢您的回复!我的主要问题是——在这种情况下如何编写正确的模式规则。在前面的示例中,内容是在2个一级层次结构中,在这种情况下更复杂。GNU make中的模式不关心目录。它们进行字符串匹配,而不考虑目录分隔符(大多数情况下)。因此,只要您希望在源代码和类区域中保持相同的层次结构,您就没有问题。无论如何,增加复杂性并不意味着您应该继续尝试使用与以前显示不正确的方法完全相同的方法:)。相反,你应该尝试将前一个问题中的正确方法应用到你的新环境中,并在你的问题中展示这一点(只有在你尝试过并且无法使其发挥作用之后)。干杯
javac
在目录级别重新创建源代码的包结构。我们得到依赖项的显式列表和类的显式列表,这些类还不存在,但必须复制源的目录结构。我们如何告诉
make
在运行时创建隐式规则“已更改的源文件”-“所需的类”@Renaud Pacalet@MadScientist
.DEFAULT_GOAL := all