从MAKECMDGOALS中删除目标?

时间:2015-07-16 01:24:24

标签: makefile gnu-make

我的makefile中有以下内容。它是GNUmakefile,因此支持其他制作功能:

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

我知道正在执行代码路径(通过在块中引入错误)。如何从命令目标中删除目标?

3 个答案:

答案 0 :(得分:5)

据我所知,你不能在这里做你想做的事。

您可以修改变量值,如果您自己检查值,则会看到更改,但修改MAKECMDGOALS的值不会以任何方式影响make。

如果你看一下GNU Make Manual中的Appendix A Quick Reference,你会看到它说:

  

MAKECMDGOALS

     

在命令行上指定的目标。设置此变量对make的操作没有影响。

     

请参阅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

答案 1 :(得分:1)

我使用以下模式传递参数,它有其局限性(只有[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

答案 2 :(得分:1)

是的,可以。根据我最近对另一个问题Force Makefile to execute script after building any target (just before exiting)的回答,很容易做到自己想要的事情。

这只是一个缺点,您将丢失直接传递为make all --silent的所有命令行参数。但是,您可以调查以下问题:How to detect if the makefile `--silent/--quiet` command line option was set?,然后重新捕获要传递给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