提问人:Roland Tóbiás 提问时间:11/11/2023 最后编辑:Roland Tóbiás 更新时间:11/11/2023 访问量:79
如何将 Makefile 条件与 bash 命令一起使用作为 Makefile 规则的准备步骤?
How to use Makefile conditionals with bash commands as a preparation step for Makefile rules?
问:
出于一些实际原因,在工作目录中为 Makefile 规则准备位置对我来说会很有用。考虑一个假设的情况,如果值为 true,我需要在编译之前将文件移动到实际目录中。我尝试将条件与命令一起使用,但只有当我将其关闭为规则时,它才有效:$(VAR)
test.f
ifeq
mv
VAR=true
cond:
ifeq ($(VAR),true)
@mv dir/test.f .
endif
test.x: test.o
ifort -o test.x test.o
test.o: test.f
ifort -c -o test.o test.f
但是,在这种情况下,仅执行规则,但不执行。
有什么办法吗cond
test.x
test.o
ifeq ($(VAR),true)
@mv dir/test.f .
endif
是否应该始终在不阻止 Makefile 中(其他)规则执行的情况下执行?
为了完整起见,我附上了我想处理的真正条件块:
ifeq ($(VAR),"./")
@if [ -d mod ]; then \
mv mod/* .; \
rm -rf mod; \
fi
@if [ -d gen ]; then \
mv gen/* .; \
rm -rf gen; \
fi
@if [ -d extra ]; then \
mv extra/* .; \
rm -rf extra; \
fi
@if [ -d lnk ]; then \
mv lnk/* .; \
rm -rf lnk; \
fi
else
@if [ ! -d mod ]; then \
mkdir -p mod; \
mv mod_*.f* mod; \
fi
@if [ ! -d txt ]; then \
mkdir -p txt; \
mv *.txt txt; \
fi
@if [ ! -d gen ]; then \
mkdir -p gen; \
mv *.f* gen; \
fi
@if [ ! -d lnk ]; then \
mkdir -p lnk; \
mv *.o lnk; \
mv *.mod lnk; \
fi
endif
答:
VAR=true
ifeq ($(VAR),true)
DUMMY_PREREQUISITE = dummy_prerequisite
else
DUMMY_PREREQUISITE =
endif
$(DUMMY_PREREQUISITE):
@mv dir/test.f .
test.x: $(DUMMY_PREREQUISITE) test.o
ifort -o test.x test.o
test.o: $(DUMMY_PREREQUISITE) test.f
ifort -c -o test.o test.f
这样,目标将始终在任何其他规则之前执行,从而确保在不影响 Makefile 中的其他规则的情况下执行条件块。dummy_prerequisite
评论
Makefile:4: *** recipe commences before first target. Stop.
dummy_prerequisite
dummy_prerequisite
test.x
dir/test.f
VAR
test.x
test.o
dummy_prerequisite
dummy_prerequisite
test.x
$(dummy_prerequisite)
$(dummy_prerequisite)
To be clear, is not a shell and makefiles are not shell scripts. So you can't plop some shell scripting down anywhere in the makefile you want (whether it's prefixed with TAB or not) and have it work. can invoke a shell to run some shell scripting, but it will only do that for shell operations that appear in specific places. Any text outside of those specific places, is considered makefile text (even if it's preceded by a TAB) and you'll get parser errors if it's not valid makefile syntax (which most shell scripting is not).make
make
One place a shell script can appear is in the recipe of a rule (this is where it's indented with TAB: the TAB tells make which lines are part of the recipe and which are not). The issue with this is that the recipe of a rule is only invoked if the target of the rule needs to be rebuilt. There are various answers here which give some thoughts about how to do this.
The other place a shell script can appear (if you are using GNU Make) is in the function. So one option to solve your problem would be this:$(shell ..)
VAR := true
ifeq ($(VAR),true)
__dummy := $(shell mv dir/test.f .)
endif
The assignment is there just in case the shell script generates some output to stdout.__dummy
Of course if the script to be invoked is very complex it will be annoying to put it into a single invocation of but it can be done: shell syntax is flexible enough for that. Or you can use multiple invocations. Or you can put all the commands into a separate shell script file and invoke that inside of .$(shell ...)
$(shell ...)
Ultimately I think that John's idea above where there's a separate operation that users need to invoke to "prep" the workspace is the best one. This operation can be a makefile target like then you have:make setup
.PHONY: setup
setup:
mv dir/file.f .
etc. Be sure that is not the first target in the makefile and it will only be run if the user runs .setup
make setup
评论
$(shell ...)
评论
test.f: dir/test.f
cp $< $@
gen
mod
txt