如何检查makefile中目标的存在性
我希望根据当前目录中的默认makefile是否包含特定目标,在shell中运行特定操作如何检查makefile中目标的存在性,makefile,gnu-make,Makefile,Gnu Make,我希望根据当前目录中的默认makefile是否包含特定目标,在shell中运行特定操作 #!/bin/sh make -q some_target if test $? -le 1 ; then true # do something else false # do something else fi 这是可行的,因为如果目标不存在,GNU make返回错误代码2,否则返回0或1。问题是没有以这种方式记录。这是一个男人的片段: -q, --question
#!/bin/sh
make -q some_target
if test $? -le 1 ; then
true # do something
else
false # do something else
fi
这是可行的,因为如果目标不存在,GNU make返回错误代码2,否则返回0或1。问题是没有以这种方式记录。这是一个男人的片段:
-q, --question
``Question mode''. Do not run any commands, or print anything;
just return an exit status that is zero if the specified targets
are already up to date, nonzero otherwise.
仅区分零/非零。正确的方法是什么?你应该阅读而不是手册页:手册页只是一个摘要,不是一个完整的定义。手册上说:
The exit status of make is always one of three values:
0 The exit status is zero if make is successful
2 The exit status is two if make encounters any errors. It will print messages
describing the particular errors.
1 The exit status is one if you use the ‘-q’ flag and make determines that
some target is not already up to date.
由于试图创建一个不存在的目标是一个错误,因此在这种情况下,您总是会得到一个2的退出代码。稍后回答,但它可能会帮助将来面临相同问题的人 我使用下面的方法,这确实需要您修改Makefile(您需要添加一个%-规则exists模式规则)。如果不想这样做,可以直接从脚本运行
make-n-your target来检查&>/dev/null
我使用它来生成autobuild和autoupload等命令,这些命令包含在代码段的上下文中
%-rule-exists:
@$(MAKE) -n $* &> /dev/null
auto%: %-rule-exists
$(info Press CTRL-C to stop $*ing)
@while inotifywait -qq -r -e move -e create -e modify -e delete --exclude "\.#.*" src; do make $* ||: ; date ; done
示例输出:
$ make build-rule-exists; echo Exit code: $?
Exit code: 0
$ make nonsense-rule-exists; echo Exit code: $?
Exit code: 2
请注意,由于
make
的-n
标志,它实际上并不构建目标来确定规则是否存在。即使构建失败,我也需要它工作。另一种可能性是在读取makefile后产生的数据库中进行grep:
some_target:
@ if $(MAKE) -C subdir -npq --no-print-directory .DEFAULT 2>/dev/null | grep -q "^$@:" ; \
then \
echo "do something" ; \
fi
在哪里
-n --just-print, --dry-run
Print the commands that would be executed, but do not execute them.
-p, --print-data-base
Print the data base (rules and variable values) that results from reading
the makefiles
-q, --question
Question mode. Do not run any commands, or print anything; just return and
exit status that is zero if the specified targets are already up to date,
nonzero otherwise.
我需要一个解决方案,该解决方案将适用于多个目标/目标,并且不会触发重新制作Makefile 以下是我最终使用的:
#!/usr/bin/env bash
set -euo pipefail
dir="$1"
targets="$2"
# If there is no Makefile then return.
[[ ! -f "${dir}/Makefile" ]] && exit 1
# First check if this build will remake itself.
# If it does then add Makefile as a target to stop it.
if eval ${MAKE} --dry-run "--directory=${dir}" Makefile &> /dev/null; then
db_target=Makefile
else
db_target=
fi
# Search the Make internal database for the targets.
eval ${MAKE} --dry-run --print-data-base "--directory=${dir}" "${db_target}" | \
awk -v targets="${targets}" '
BEGIN {
# Count the number of targets and put them in an array keyed by their own value.
numRemaining = split(targets, temp)
for (i in temp) remaining[temp[i]]
}
# If we found all the targets then consume all the input so the pipe does not fail.
numRemaining == 0 { next }
# Skip everything from the first line up to the start of the database comment inclusive.
NR == 1, /\# Make data base/ { next }
# Skip those that are not real targets.
/\# Not a target:/, /^[^#]/ { next }
{
# Check if this line starts with any of the targets.
for (target in remaining) {
if ($0 ~ "^"target":") {
delete remaining[target]
numRemaining--
next
}
}
}
END {
# If we get to the end then make sure that we found all the targets.
exit (numRemaining ? 1 : 0)
}'
警告是:
- Make文件必须被称为
(或者根本不存在)Makefile
- MAKE文件中有一个
语句(如果愿意,可以将export MAKE
硬编码到脚本中)MAKE
- 你不介意一个邪恶的
(恶心!)eval
top_targets := all setup build clean mostlyclean
sub_dirs := foo bar
.PHONY: $(top_targets)
$(top_targets): $(sub_dirs)
.PHONY: $(sub_dirs)
$(sub_dirs):
@if ./bin/make-target-exists.sh '$@' '$(MAKECMDGOALS)'; then $(MAKE) --directory='$@' $(MAKECMDGOALS); fi
简单解决方案:
output=$(make -n some_target 2>&1 | head -1)
if [[ "$output" != *"No rule to make target"* ]]; then
echo "target is present"
fi
其思想是在不运行make的情况下检查make的输出。不确定,但这是100%正确的方式
可以包装在函数中:
function check_make_target {
output=$(make -n "$1" 2>&1 | head -1)
[[ "$output" != *"No rule to make target"* ]]
}
if check_make_target some_target; then
echo "target is present"
fi
因此,除了解析stderr输出?Correct,无法将这种错误与其他错误区分开来;make不会对可能遇到错误的所有可能方式使用不同的错误代码。为什么同时使用
-n
和-q
?