从 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.

See Arguments to Specify the Goals.

我认为,最接近您在这里尝试做的事情是手动在 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

使用示例:

  1. 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
    
  2. 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
    
  3. 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