$(file < $@) 扩展为空,但它不应该

$(file < $@) expands to nothing but it should not

我写了这个 make 规则

$(COMPDIR)/%.d: $(COMPDIR)/%.cpp
# other code...
    $(file > $@,$(foreach path,$(file < $@),$(shell echo "$(path)" | sed 's!$(SRCDIR)/!$(COMPDIR)/!')))
# other code...

这应该读取目标文件 $@,以通常的 make 方式对其内容进行标记(空格分隔的单词),将标记传递给 sed,然后将结果保存回同一文件。

如果我用文字文件路径代替 $@,代码将按预期工作,但如果我保持原样,它什么也不做。

我追踪到根本问题是我在标题中写的,因为我已经验证了

    echo '$(file < $@)'

不打印任何内容。

该文件肯定会被填充,因为在我显示的命令之前的唯一命令是创建和填充它的命令。

有什么想法吗?

编辑 1:一些附加信息

我系统上的软件 运行:

makefile中定义的相关变量:

SHELL   ?= /bin/sh
SRCDIR  := src
COMPDIR := build/files

为了回应评论,这里是添加了测试代码的完整规则:

$(COMPDIR)/%.d: $(COMPDIR)/%.cpp
    @ mkdir -p $(dir $@)
    @ echo "Generating make rule for $(subst .d,.o,$@)"

# Generate recipe dependencies
    $(CXX) -o $@ $(subst $(COMPDIR),$(SRCDIR),$<) -MM -MT $(subst .d,.o,$@) $(ALL_CPPFLAGS) $(ALL_CXXFLAGS)

# Patch the generated recipe to request source files from $(COMPDIR)
    $(file > $(@),$(foreach path,$(file < $(@)),$(shell echo "$(path)" | sed 's!$(SRCDIR)/!$(COMPDIR)/!')))

# Inject compilation instructions
    @ echo -e "\t$(CXX) -c -o $(subst .d,.o,$@) $^ $(ALL_CPPFLAGS) $(ALL_CXXFLAGS)" >> $@

# Tests
    @ echo -e "\n\n"
    @ echo -------------

    @ echo TARGET: $@

    @ echo -e "\n\n"

    ls -R $(COMPDIR)

    @ echo -e "\n\n"

    cat $@

    @ echo -------------
    @ echo -e "\n\n"

以及调用 make 时产生的输出

ln -sf /home/qub1750ul/work/studentIngegneria/AssociateManager.BACKEND/src/auth/auth.cpp build/files/auth/auth.cpp
Generating make rule for build/files/auth/auth.o
g++ -o build/files/auth/auth.d src/auth/auth.cpp -MM -MT build/files/auth/auth.o -DDEBUG -I/usr/local/include -Ilib/json/single_include -Ilib/pistache/include -g -std=c++17



-------------
TARGET: build/files/auth/auth.d



ls -R build/files
build/files:
auth

build/files/auth:
auth.cpp  auth.d



cat build/files/auth/auth.d
build/files/auth/auth.o: src/auth/auth.cpp src/auth/auth.hpp \
 lib/json/single_include/nlohmann/json.hpp \
 src/auth/../database/interface.hpp
-------------



ln -sf /home/qub1750ul/work/studentIngegneria/AssociateManager.BACKEND/src/server/server.cpp build/files/server/server.cpp
Generating make rule for build/files/server/server.o
g++ -o build/files/server/server.d src/server/server.cpp -MM -MT build/files/server/server.o -DDEBUG -I/usr/local/include -Ilib/json/single_include -Ilib/pistache/include -g -std=c++17



-------------
TARGET: build/files/server/server.d



ls -R build/files
build/files:
auth  server

build/files/auth:
auth.cpp  auth.d

build/files/server:
server.cpp  server.d



cat build/files/server/server.d
build/files/server/server.o: src/server/server.cpp src/server/server.hpp \
 lib/pistache/include/pistache/endpoint.h \
 lib/pistache/include/pistache/listener.h \
 lib/pistache/include/pistache/tcp.h \
 lib/pistache/include/pistache/flags.h \
 lib/pistache/include/pistache/prototype.h \
 lib/pistache/include/pistache/common.h \
 lib/pistache/include/pistache/net.h lib/pistache/include/pistache/os.h \
 lib/pistache/include/pistache/config.h \
 lib/pistache/include/pistache/async.h \
 lib/pistache/include/pistache/typeid.h \
 lib/pistache/include/pistache/reactor.h \
 lib/pistache/include/pistache/http.h \
 lib/pistache/include/pistache/http_headers.h \
 lib/pistache/include/pistache/http_header.h \
 lib/pistache/include/pistache/mime.h \
 lib/pistache/include/pistache/optional.h \
 lib/pistache/include/pistache/http_defs.h \
 lib/pistache/include/pistache/type_checkers.h \
 lib/pistache/include/pistache/cookie.h \
 lib/pistache/include/pistache/stream.h \
 lib/pistache/include/pistache/peer.h \
 lib/pistache/include/pistache/transport.h \
 lib/pistache/include/pistache/mailbox.h \
 lib/pistache/include/pistache/view.h \
 lib/json/single_include/nlohmann/json.hpp src/server/../auth/auth.hpp \
 src/server/../auth/../database/interface.hpp
-------------



ln -sf /home/qub1750ul/work/studentIngegneria/AssociateManager.BACKEND/src/main.cpp build/files/main.cpp
Generating make rule for build/files/main.o
g++ -o build/files/main.d src/main.cpp -MM -MT build/files/main.o -DDEBUG -I/usr/local/include -Ilib/json/single_include -Ilib/pistache/include -g -std=c++17



-------------
TARGET: build/files/main.d



ls -R build/files
build/files:
auth  main.cpp  main.d  server

build/files/auth:
auth.cpp  auth.d

build/files/server:
server.cpp  server.d



cat build/files/main.d
build/files/main.o: src/main.cpp src/auth/auth.hpp \
 lib/json/single_include/nlohmann/json.hpp \
 src/auth/../database/interface.hpp
-------------



rm build/files/server/server.cpp build/files/main.cpp build/files/auth/auth.cpp
g++ -c -o build/files/auth/auth.o build/files/auth/auth.cpp -DDEBUG -I/usr/local/include -Ilib/json/single_include -Ilib/pistache/include -g -std=c++17
g++: error: build/files/auth/auth.cpp: No such file or directory
g++: fatal error: no input files
compilation terminated.
make: *** [build/files/auth/auth.d:4: build/files/auth/auth.o] Error 1

我明白了。您的原始示例没有说明您实际要做什么:

$(COMPDIR)/%.d: $(COMPDIR)/%.cpp
        $(CXX) -o $@ ...
        $(file > $(@),$(foreach path,$(file < $(@)),...)))

那是你的 makefile 中的第一行创建目标,然后你使用 make 函数来尝试操作目标。

这行不通,因为 make 会在尝试之前为配方中的 all 行扩展 all 宏(变量和函数) 运行 第一个命令。因此,当 $(CXX) 命令启动时,make 已经扩展了 file 命令(如果 $@ 不存在,则导致读取一个空文件,或者更令人困惑的是, 文件的前一个 版本(如果存在)。

我经常想知道为什么 make 会这样,因为我看不出有什么好的理由,而且它会引起很多混乱,但这就是它工作 30 多年的方式。

您将需要 (a) 使用 shell 命令而不是 make 函数来操作生成的文件,或者 (b) 将编译器的调用放在 $(shell ...) 函数中食谱,因此在食谱扩展期间也是 运行。