c语言 - 为什么 $(< file.txt) 在 makefile 上不起作用?



使用命令行,我得到了所需的输出

$ ./program $(< file.txt)
./program 1 2 3 4 5

但是使用makefile

all: program file.txt
./program $(< file.txt)
@rm -f program

program: program.c
gcc program.c -o program
我得到了输出
gcc program.c -o program
./program

因为在makefile中,$(...)语法用于变量插值。因此,您的makefile尝试展开名为< file.txt的makefile变量/环境变量的值。如果未设置,则展开为空字符串。

证明:

all:
echo $(< file.txt)

和包含

的file.txt
now it works

然后执行

% env '< file.txt=Hello world' make
echo Hello world
Hello world

。通过将环境变量< file.txt设置为值Hello world,打印问候语。修复方法是通过将$字符加倍来转义:

all:
echo $$(< file.txt)

% make
echo $(< file.txt)
now it works

Q.E.D.

最后,当POSIXshell中的$()插值语法$(< file.txt)不是,但您可以用$(cat file.txt)替换它,因此它可以与最低限度的posix兼容shell一起工作。当然,在makefile中,您需要再次将美元翻倍,因此获得最大兼容的
$$(cat file.txt)

或者您可以使用类似的makefile工具,即$(shell ),即

$(shell cat file.txt)

也可以…(现在有一个$)。最后你也可以使用$(file )GNU makefile函数来读取文件,即

all:
echo $(file <file.txt)

的工作原理类似,但根本不会调用shell。

您尝试使用的替换是Bash特性,但是make开箱运行常规的Bourne shellsh,其中该语法不可用(即使sh是Bash的符号链接,这在某些Linux发行版中仍然很常见)。

无论如何,要求在命令行上指定文件的内容看起来像是一个设计缺陷;如果您的C程序只是读取和处理标准输入(或者可能接受一个文件名列表,如果没有指定,则返回到stdin,就像许多Unix文件处理实用程序一样),则可能要好得多。

如果这只是一个测试用例来运行带有文件参数的程序,请查看xargs

xargs ./program <file.txt

如果您坚持只使用bash语法,请添加

SHELL=/bin/bash

(或任何在您的系统上正确的完整路径);但要理解这限制了Makefile的可移植性。

但是,您仍然需要将任何应该传递并暴露给shell的美元符号的字面量加倍。

最新更新