英文:
Makefile assertions with if-else statements (How to run only when needed?)
问题
我在我的Makefile中定义了一些变量,当需要构建软件时,我将这些变量传递给编译器。然而,我需要确保这些变量在Makefile级别满足某些布尔恒等式。我目前正在执行类似以下的操作。
SHELL := /bin/bash
NUMBER := 1
all: test.x
%.x: %.c ASSERT
@echo "Compiling $< -> $@ with NUMBER=$(NUMBER)."
@gcc $< -D NUMBER=$(NUMBER) -o $@
ASSERT: Makefile
@if (( $(NUMBER) < 0 || $(NUMBER) > 4 )); then \
echo "ERROR: NUMBER must be positive and less than 4."; \
exit 1; \
fi
@echo "Ran ASSERT. No errors found."
上述设置的问题在于,即使目标已经存在且没有发生更改,它也总是运行编译配方。
如何正确运行Makefile断言,以便仅在Makefile变量发生更改时创建目标?
英文:
I have some variables defined in my Makefile which I pass to a compiler when I need to build my software. However, I need to make sure that these variables satisfy certain boolean identities at the level of the Makefile. I am currently doing something like the following.
SHELL := /bin/bash
NUMBER := 1
all: test.x
%.x: %.c ASSERT
@echo "Compiling $< -> $@ with NUMBER=$(NUMBER)."
@gcc $< -D NUMBER=$(NUMBER) -o $@
ASSERT: Makefile
@if (( $(NUMBER) < 0 || $(NUMBER) > 4 )); then \
echo "ERROR: NUMBER must be positive and less than 4."; \
exit 1; \
fi
@echo "Ran ASSERT. No errors found."
The problem with the above setup is that it always runs the compilation recipe even if the target already exists and nothing has changed.
How can I run Makefile assertions properly so that targets are made only when there are changes in the Makefile variables?
答案1
得分: 1
你提到所有的目标文件都依赖于先决条件ASSERT
。但是这个先决条件并不存在,所以make
会尝试创建它。一旦make
尝试创建它,它就会被视为"非常新",因此任何依赖于它的目标都会被视为过时并重新构建。
然后,下次运行make
时,它会发现先决条件ASSERT
不存在,所以它会尝试创建它,并将其视为"非常新"。等等,依此类推。
如果你不希望重新构建一切,那么你的ASSERT
的配方必须在成功时创建文件ASSERT
:
ASSERT: Makefile
@...
@touch $@
@echo "运行 ASSERT。未发现错误。"
只要记住,如果你运行make NUMBER=10
而不是编辑makefile
,这不会产生任何影响。由于makefile
没有更改,ASSERT
不会过时,因此不会调用其配方。
补充说明
如果你只想验证没有人能够使用非法的NUMBER
值,你可以直接使用make
进行测试,而不是使用一个配方来执行它:
SHELL := /bin/bash
NUMBER := 1
$(if $(filter $(NUMBER), 0 1 2 3 4),\
$(info NUMBER is good),\
$(error ERROR: NUMBER must be positive and less than 4.))
all: test.x
%.x: %.c ASSERT
@echo "Compiling $< -> $@ with NUMBER=$(NUMBER)."
@gcc $< -D NUMBER=$(NUMBER) -o $@
英文:
You have said that all your object files depend on the prerequisite ASSERT
. That prerequisite does not exist, so make will try to create it. Once make tries to create it, it will be considered "very new" and so any target that depends on it will be considered out of date and rebuilt.
Then the next time make runs, it sees that the prerequisite ASSERT
does not exist, so it will try to create it and it will be considered "very new". Etc. etc.
If you don't want everything to be rebuilt, then your recipe for ASSERT
must create the file ASSERT
when it succeeds:
ASSERT: Makefile
@...
@touch $@
@echo "Ran ASSERT. No errors found."
Just remember that this won't have any impact if you run make NUMBER=10
rather than editing the makefile. Since the makefile isn't changed, ASSERT
won't be out of date and so its recipe won't be invoked.
ETA
If all you want to do is verify that no one can use a NUMBER
value that's illegal, ever, you can just test that directly with make rather than using a recipe to do it:
SHELL := /bin/bash
NUMBER := 1
$(if $(filter $(NUMBER), 0 1 2 3 4),\
$(info NUMBER is good),\
$(error ERROR: NUMBER must be positive and less than 4.))
all: test.x
%.x: %.c ASSERT
@echo "Compiling $< -> $@ with NUMBER=$(NUMBER)."
@gcc $< -D NUMBER=$(NUMBER) -o $@
答案2
得分: 1
由于您的断言与 *.c
无关,您可以使 all
依赖于 ASSERT:
SHELL := /bin/bash
NUMBER := 1
all: ASSERT test.x
%.x: %.c
@echo "Compiling $< -> $@ with NUMBER=$(NUMBER)."
@gcc $< -D NUMBER=$(NUMBER) -o $@
ASSERT: Makefile
@if (( $(NUMBER) < 0 || $(NUMBER) > 4 )); then \
echo "ERROR: NUMBER must be positive and less than 4."; \
exit 1; \
fi
@echo "Ran ASSERT. No errors found."
英文:
As your assertion is not related to *.c
, can you make all
depend on ASSERT:
SHELL := /bin/bash
NUMBER := 1
all: ASSERT test.x
%.x: %.c
@echo "Compiling $< -> $@ with NUMBER=$(NUMBER)."
@gcc $< -D NUMBER=$(NUMBER) -o $@
ASSERT: Makefile
@if (( $(NUMBER) < 0 || $(NUMBER) > 4 )); then \
echo "ERROR: NUMBER must be positive and less than 4."; \
exit 1; \
fi
@echo "Ran ASSERT. No errors found."
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论