所以我正在编译java代码,它通常会创建文件名中有美元符号的.class文件。 GNU make似乎讨厌这个并且不断干扰文件名。
作为一个简单的(人为的)示例,假设我想创建一个GNU Makefile任务,它将对MyFolder目录中的所有.class文件(以及它的子文件夹)执行hexdump。
现在假设MyFolder有以下文件:
MyFolder/makefile MyFolder/sample.java MyFolder/subdir/abc$1.class MyFolder/subdir/test.java MyFolder/xyz.class
目标是编写一个运行hexdump的配方,将其传递给MyFolder(及其子文件夹)中的所有.class文件。因此,对于上面的文件列表,GNU make应该执行的最终命令是:
hexdump subdir/abc$1.class xyz.class
这应该像从日志中掉落一样容易,但GNU make似乎已经付出了极大的痛苦,使其尽可能地难以实现。使用以下Makefile的天真尝试不起作用:
default: hexdump $(shell find -name '*.class')
如果运行此Makefile,则会出现以下错误:
hexdump ./subdir/abc$1.class ./xyz.class hexdump: ./subdir/abc.class: No such file or directory make: *** [makefile:3: default] Error 1
请注意,在上面输出的第一行中,命令是否正确(文件名包含美元符号字符)。但是后来执行的实际命令“$ 1”已经被评估了。
事实上,即使是下面的Makefile也会失败,当用双美元符号正确地转出美元符号时。当然我想编写一个不会对文件名进行硬编码的配方,但是应该使用$(shell find ...)命令找到文件
default: hexdump subdir/abc$$1.class xyz.class
即使上面的Makefile失败也会出现与第一个Makefile相同的错误。
如何阻止GNU make干扰包含美元符号的文件名? java编译器一直在创建这些东西,所以肯定有人之前必须遇到这个问题吗?
答案 0 :(得分:4)
在配方中以这种方式使用时,Make不会再次解释$(shell …)
输出。问题是 shell 解释$1
并将其扩展为第一个(不存在的)参数,即空字符串。
如何解决这个问题取决于遇到此问题时您正在做什么。 GNU make不提供任意的shell引用函数,并且无论如何都会出现包含空格的文件名的问题。您可以尝试通过使用'
包围文件名来避免Java类文件的参数替换:
hexdump $(patsubst %,'%',$(shell find -name '*.class'))
另一种方法是在shell中创建文件列表,使用类似:
find -name -print0 | xargs -0 hexdump
这完全避免了shell对字符串的解释。即使有了
hexdump $$(find -name '*.class')
shell不会解释文件名中的$
符号,因为命令替换输出仅受分词和路径名扩展(globbing)的影响,但不是参数替换。
答案 1 :(得分:1)
首先,为输出文件选择这样一个愚蠢的命名约定确实是Java的错误。
其次,尝试用make构建Java代码几乎肯定是一种令人沮丧的练习。 Make的构建是为了使用主文件作为输入并生成一个文件作为输出的工具,其中输出文件名与输入文件名相关。 Java不是那样的。
但是,要直接回答您的问题,问题是$
是一个特殊字符,因为它引入了make变量。您必须使用$$
转义它,如上例所示。
但是,这还不够,因为$
也对shell来说是特殊的,所以如果你在食谱中使用$
,你也必须从shell使用单引号或反斜杠。所以,你的最终命令将是:
default:
hexdump 'subdir/abc$$1.class' xyz.class
或:
default:
hexdump subdir/abc\$$1.class xyz.class