我正在尝试编写一个自定义 Makefile,在其中收集所有源文件以针对主文件进行编译。首先我收集他们的名字:
# other sources to compile against (without extensions, separated by spaces)
DEPENDENT_FILES = greet farewell
然后我想附加.o
到每个单词。在外壳中,我可以通过多种方式做到这一点,例如
echo '$DEPENDENT_FILES' | sed 's/\>/\.o/g' # but I know, it's UNIX dependant
# or ...
echo '$DEPENDENT_FILES' | sed 's/[^ ]*/&\.o/g'
greet.o farewell.o
两者都会在终端上产生结果,但在此make
过程中失败(导致空字符串)。我把它们写成
DEPENDENCIES := $(echo '$DEPENDENT_FILES' | sed 's/\>/\.o/g')
# or ...
DEPENDENCIES := $(echo '$DEPENDENT_FILES' | sed 's/[^ ]*/&\.o/g')
# but they result in
$(info DEPENDENCIES is $(DEPENDENCIES)) # "DEPENDENCIES is "
我不知道我在这里做错了什么,我怀疑这可能与 Makefile 中的 echo 或管道有关,但我无法弄清楚。
请注意,我更喜欢与工作 sed 和 echo 解决方案相关的答案,而不是提出不同的方法:这不是我第一次在 Makefile 中遇到 echo 和管道问题,而且我仍然不知道我的方法出了什么问题。
答案1
然后我想在每个单词后面附加 .o 。
无需通过 shell 进行往返。 Make 足够强大,可以提供帮助文件名的常见操作
像这样。在您的情况下,您需要具有不言自明的名称的函数
addsuffix
:
DEPENDENCIES = $(addsuffix .o, $(DEPENDENT_FILES))
这将为您a.o b.o c.o
提供输入列表a b c
。一个更完整的例子:
units = a b c
inc = $(addsuffix .h,$(units))
obj = $(addsuffix .o,$(units))
myprog: $(obj)
gcc -o $@ $(obj)
header-bundle.h: $(inc)
cat $< >$@
如果您需要更复杂的替换,还有多种通用字符串操作 但在它们足够的情况下,文件操作会更方便,而且在我看来,谦虚的人更容易理解。
答案2
您需要认识到,尽管它们的语法有很多相似之处,make
但shell
它们却截然不同,必须非常谨慎地使用。更糟糕的是,make 的警告非常吝啬。
您的make
代码中有两个地方出错了:
## bad code
DEPENDENCIES := $(echo '$DEPENDENT_FILES' | sed 's/\>/\.o/g')
- 没有
GNU make
名为 的内置函数echo l
,因为 make 就是这么理解它的意思的。 - 当您需要运行外部实用程序时,您需要做的是调用 gnu make 内置
$(shell ...)
函数。 - 现在,在编写 make 代码的方式中隐藏着一个潜在的问题,那就是变量
$DEPENDENT_FILES
。 make 会将其解析为 make 变量 $D ,后跟字符串文字 EPENDENT ! 这是因为当 make vars 没有用括号或大括号括起来时,它只有单个字母,其余的都被视为文字字符串。 - 注意 shell vars vegin 带有 $$ 除非 eval 正在运行。