$(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:一些附加信息
我系统上的软件 运行:
- GNU 制作 4.2.1
- Bash 5.0.007 在 POSIX 模式下(通过 /bin/sh 调用)
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 ...)
函数中食谱,因此在食谱扩展期间也是 运行。
我写了这个 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:一些附加信息
我系统上的软件 运行:
- GNU 制作 4.2.1
- Bash 5.0.007 在 POSIX 模式下(通过 /bin/sh 调用)
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 ...)
函数中食谱,因此在食谱扩展期间也是 运行。