从 MAKECMDGOALS 中删除目标?
Remove target from MAKECMDGOALS?
我的 makefile 中有以下内容。它是 GNUmakefile
,因此支持额外的 make 功能:
# Undefined Behavior Sanitzier (Clang and G++)
ifeq ($(findstring ubsan,$(MAKECMDGOALS)),ubsan)
CXXFLAGS += -fsanitize=undefined
MAKECMDGOALS := $(subst ubsan,,$(MAKECMDGOALS))
endif # UBsan
运行 结果是:
make ubsan
make: *** No rule to make target 'ubsan'. Stop.
我知道正在执行代码路径(通过在块中引入错误)。如何从命令目标中删除目标?
据我所知,你不能在这里为所欲为。
您可以修改变量值,如果您自己检查该值,您会看到更改,但修改 MAKECMDGOALS
的值不会以任何方式影响 make。
如果您查看 GNU Make 手册中的 Appendix A Quick Reference,您会看到它说:
MAKECMDGOALS
The targets given to make on the command line. Setting this variable has no effect on the operation of make.
我认为,最接近您在这里尝试做的事情是手动在 Makefile
(或其他)上重新执行 make。
话虽如此,这种事情最好作为变量而不是目标来完成。
$ cat Makefile
$(info $(origin UBSAN))
$ make
undefined
$ make UBSAN=
command line
所以像这样。
# Undefined Behavior Sanitzier (Clang and G++)
ifneq (undefined,$(origin UBSAN))
CXXFLAGS += -fsanitize=undefined
endif # UBsan
我使用以下模式来传递参数,它有其局限性(仅 [a-z,0-9] 个字符)但可以变得非常方便:
ifeq (console,$(firstword $(MAKECMDGOALS)))
CONSOLE_ARGS := $(wordlist 2,$(words $(MAKECMDGOALS))
$(eval $(CONSOLE_ARGS):;@:)
endif
console::
run-some-command $(CONSOLE_ARGS)
对于您的情况,以下工作:
# Undefined Behavior Sanitzier (Clang and G++)
ifeq (ubsan,$(firstword $(MAKECMDGOALS)))
CXXFLAGS += -fsanitize=undefined
$(eval $(CONSOLE_ARGS):;@:)
endif # UBsan
是的,你可以。根据我最近对另一个问题 Force Makefile to execute script after building any target (just before exiting) 的回答,很容易做你想做的事。
这只有一个缺点,您将丢失任何直接传递给 make 的命令行参数 make all --silent
。但是,您可以查看问题:,并重新获取您希望重新传递给 make -f ${MAKEFILE_JUSTNAME} ${MAKECMDGOALS}
.
上的第二个 make call 命令的命令行参数
ECHOCMD:=/bin/echo -e
SHELL := /bin/bash
ifeq (${IS_MAKEFILE_RUNNING_TARGETS},)
MAKEFILE_JUSTNAME := $(firstword ${MAKEFILE_LIST})
# UBsan
ifeq ($(findstring ubsan,${MAKECMDGOALS}),ubsan)
MAKECMDGOALS := $(subst ubsan,,${MAKECMDGOALS})
USELESS := $(eval export IS_UBSAN_CXXFLAGS_SET=1)
endif
define DEFAULTTARGET :=
printf 'Calling "%s" "%s"\n\n' "${MAKEFILE_JUSTNAME}" "${MAKECMDGOALS}"
make -f ${MAKEFILE_JUSTNAME} ${MAKECMDGOALS}
printf '\n'
printf 'Running something after all rules finished\n'
endef
%:
@:
# printf 'IS_MAKEFILE_RUNNING_TARGETS="%s"\n' "${IS_MAKEFILE_RUNNING_TARGETS}"
$(if ${IS_MAKEFILE_RUNNING_TARGETS},,${DEFAULTTARGET})
$(eval export IS_MAKEFILE_RUNNING_TARGETS=1)
all:
@:
# printf 'IS_MAKEFILE_RUNNING_TARGETS="%s"\n' "${IS_MAKEFILE_RUNNING_TARGETS}"
$(if ${IS_MAKEFILE_RUNNING_TARGETS},,${DEFAULTTARGET})
$(eval export IS_MAKEFILE_RUNNING_TARGETS=1)
else
# UBsan
ifneq (${IS_UBSAN_CXXFLAGS_SET},)
CXXFLAGS += -fsanitize=undefined
endif
all:
printf 'Calling my all rule, CXXFLAGS="%s"\n' "${CXXFLAGS}"
foo:
printf 'Calling my foo rule, CXXFLAGS="%s"\n' "${CXXFLAGS}"
bar:
printf 'Calling my bar rule, CXXFLAGS="%s"\n' "${CXXFLAGS}"
xyzzy:
printf 'Calling my xyzzy rule, CXXFLAGS="%s"\n' "${CXXFLAGS}"
endif
使用示例:
make
printf 'Calling "%s" "%s"\n\n' "Makefile" ""
Calling "Makefile" ""
make -f Makefile
make[1]: Entering directory '/cygdrive/d/User/Downloads'
printf 'Calling my all rule, CXXFLAGS="%s"\n' ""
Calling my all rule, CXXFLAGS=""
make[1]: Leaving directory '/cygdrive/d/User/Downloads'
printf '\n'
printf 'Running something after all rules finished\n'
Running something after all rules finished
make foo bar
printf 'Calling "%s" "%s"\n\n' "Makefile" "foo bar"
Calling "Makefile" "foo bar"
make -f Makefile foo bar
make[1]: Entering directory '/cygdrive/d/User/Downloads'
printf 'Calling my foo rule, CXXFLAGS="%s"\n' ""
Calling my foo rule, CXXFLAGS=""
printf 'Calling my bar rule, CXXFLAGS="%s"\n' ""
Calling my bar rule, CXXFLAGS=""
make[1]: Leaving directory '/cygdrive/d/User/Downloads'
printf '\n'
printf 'Running something after all rules finished\n'
Running something after all rules finished
make foo bar ubsan
printf 'Calling "%s" "%s"\n\n' "Makefile" "foo bar "
Calling "Makefile" "foo bar "
make -f Makefile foo bar
make[1]: Entering directory '/cygdrive/d/User/Downloads'
printf 'Calling my foo rule, CXXFLAGS="%s"\n' "-fsanitize=undefined"
Calling my foo rule, CXXFLAGS="-fsanitize=undefined"
printf 'Calling my bar rule, CXXFLAGS="%s"\n' "-fsanitize=undefined"
Calling my bar rule, CXXFLAGS="-fsanitize=undefined"
make[1]: Leaving directory '/cygdrive/d/User/Downloads'
printf '\n'
printf 'Running something after all rules finished\n'
Running something after all rules finished
我的 makefile 中有以下内容。它是 GNUmakefile
,因此支持额外的 make 功能:
# Undefined Behavior Sanitzier (Clang and G++)
ifeq ($(findstring ubsan,$(MAKECMDGOALS)),ubsan)
CXXFLAGS += -fsanitize=undefined
MAKECMDGOALS := $(subst ubsan,,$(MAKECMDGOALS))
endif # UBsan
运行 结果是:
make ubsan
make: *** No rule to make target 'ubsan'. Stop.
我知道正在执行代码路径(通过在块中引入错误)。如何从命令目标中删除目标?
据我所知,你不能在这里为所欲为。
您可以修改变量值,如果您自己检查该值,您会看到更改,但修改 MAKECMDGOALS
的值不会以任何方式影响 make。
如果您查看 GNU Make 手册中的 Appendix A Quick Reference,您会看到它说:
MAKECMDGOALS
The targets given to make on the command line. Setting this variable has no effect on the operation of make.
我认为,最接近您在这里尝试做的事情是手动在 Makefile
(或其他)上重新执行 make。
话虽如此,这种事情最好作为变量而不是目标来完成。
$ cat Makefile
$(info $(origin UBSAN))
$ make
undefined
$ make UBSAN=
command line
所以像这样。
# Undefined Behavior Sanitzier (Clang and G++)
ifneq (undefined,$(origin UBSAN))
CXXFLAGS += -fsanitize=undefined
endif # UBsan
我使用以下模式来传递参数,它有其局限性(仅 [a-z,0-9] 个字符)但可以变得非常方便:
ifeq (console,$(firstword $(MAKECMDGOALS)))
CONSOLE_ARGS := $(wordlist 2,$(words $(MAKECMDGOALS))
$(eval $(CONSOLE_ARGS):;@:)
endif
console::
run-some-command $(CONSOLE_ARGS)
对于您的情况,以下工作:
# Undefined Behavior Sanitzier (Clang and G++)
ifeq (ubsan,$(firstword $(MAKECMDGOALS)))
CXXFLAGS += -fsanitize=undefined
$(eval $(CONSOLE_ARGS):;@:)
endif # UBsan
是的,你可以。根据我最近对另一个问题 Force Makefile to execute script after building any target (just before exiting) 的回答,很容易做你想做的事。
这只有一个缺点,您将丢失任何直接传递给 make 的命令行参数 make all --silent
。但是,您可以查看问题:make -f ${MAKEFILE_JUSTNAME} ${MAKECMDGOALS}
.
ECHOCMD:=/bin/echo -e
SHELL := /bin/bash
ifeq (${IS_MAKEFILE_RUNNING_TARGETS},)
MAKEFILE_JUSTNAME := $(firstword ${MAKEFILE_LIST})
# UBsan
ifeq ($(findstring ubsan,${MAKECMDGOALS}),ubsan)
MAKECMDGOALS := $(subst ubsan,,${MAKECMDGOALS})
USELESS := $(eval export IS_UBSAN_CXXFLAGS_SET=1)
endif
define DEFAULTTARGET :=
printf 'Calling "%s" "%s"\n\n' "${MAKEFILE_JUSTNAME}" "${MAKECMDGOALS}"
make -f ${MAKEFILE_JUSTNAME} ${MAKECMDGOALS}
printf '\n'
printf 'Running something after all rules finished\n'
endef
%:
@:
# printf 'IS_MAKEFILE_RUNNING_TARGETS="%s"\n' "${IS_MAKEFILE_RUNNING_TARGETS}"
$(if ${IS_MAKEFILE_RUNNING_TARGETS},,${DEFAULTTARGET})
$(eval export IS_MAKEFILE_RUNNING_TARGETS=1)
all:
@:
# printf 'IS_MAKEFILE_RUNNING_TARGETS="%s"\n' "${IS_MAKEFILE_RUNNING_TARGETS}"
$(if ${IS_MAKEFILE_RUNNING_TARGETS},,${DEFAULTTARGET})
$(eval export IS_MAKEFILE_RUNNING_TARGETS=1)
else
# UBsan
ifneq (${IS_UBSAN_CXXFLAGS_SET},)
CXXFLAGS += -fsanitize=undefined
endif
all:
printf 'Calling my all rule, CXXFLAGS="%s"\n' "${CXXFLAGS}"
foo:
printf 'Calling my foo rule, CXXFLAGS="%s"\n' "${CXXFLAGS}"
bar:
printf 'Calling my bar rule, CXXFLAGS="%s"\n' "${CXXFLAGS}"
xyzzy:
printf 'Calling my xyzzy rule, CXXFLAGS="%s"\n' "${CXXFLAGS}"
endif
使用示例:
make
printf 'Calling "%s" "%s"\n\n' "Makefile" "" Calling "Makefile" "" make -f Makefile make[1]: Entering directory '/cygdrive/d/User/Downloads' printf 'Calling my all rule, CXXFLAGS="%s"\n' "" Calling my all rule, CXXFLAGS="" make[1]: Leaving directory '/cygdrive/d/User/Downloads' printf '\n' printf 'Running something after all rules finished\n' Running something after all rules finished
make foo bar
printf 'Calling "%s" "%s"\n\n' "Makefile" "foo bar" Calling "Makefile" "foo bar" make -f Makefile foo bar make[1]: Entering directory '/cygdrive/d/User/Downloads' printf 'Calling my foo rule, CXXFLAGS="%s"\n' "" Calling my foo rule, CXXFLAGS="" printf 'Calling my bar rule, CXXFLAGS="%s"\n' "" Calling my bar rule, CXXFLAGS="" make[1]: Leaving directory '/cygdrive/d/User/Downloads' printf '\n' printf 'Running something after all rules finished\n' Running something after all rules finished
make foo bar ubsan
printf 'Calling "%s" "%s"\n\n' "Makefile" "foo bar " Calling "Makefile" "foo bar " make -f Makefile foo bar make[1]: Entering directory '/cygdrive/d/User/Downloads' printf 'Calling my foo rule, CXXFLAGS="%s"\n' "-fsanitize=undefined" Calling my foo rule, CXXFLAGS="-fsanitize=undefined" printf 'Calling my bar rule, CXXFLAGS="%s"\n' "-fsanitize=undefined" Calling my bar rule, CXXFLAGS="-fsanitize=undefined" make[1]: Leaving directory '/cygdrive/d/User/Downloads' printf '\n' printf 'Running something after all rules finished\n' Running something after all rules finished