Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Remove target from MAKECMDGOALS?

I have the following in my makefile. Its a GNUmakefile, so the additional make features are supported:

# Undefined Behavior Sanitzier (Clang and G++)
ifeq ($(findstring ubsan,$(MAKECMDGOALS)),ubsan)
CXXFLAGS += -fsanitize=undefined
MAKECMDGOALS := $(subst ubsan,,$(MAKECMDGOALS))
endif # UBsan    

Running it results in:

make ubsan
make: *** No rule to make target 'ubsan'. Stop.

I know the code path is being executed (by introducing an error in the block). How do I remove the target from the command goals?

like image 347
jww Avatar asked Jul 16 '15 01:07

jww


People also ask

What is the default make target?

By default, the goal is the first target in the makefile (not counting targets that start with a period). Therefore, makefiles are usually written so that the first target is for compiling the entire program or programs they describe.

What is $@ in makefile?

$@ is the name of the target being generated, and $< the first prerequisite (usually a source file). You can find a list of all these special variables in the GNU Make manual.

What is Makecmdgoals?

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.

What are targets in makefile?

A simple makefile consists of "rules" with the following shape: target ... : dependencies ... command ... ... A target is usually the name of a file that is generated by a program; examples of targets are executable or object files.


2 Answers

You cannot do what you want here as far as I know.

You can modify the variable value and you will see the changes if you check the value yourself but modifying the value of MAKECMDGOALS will not affect make in any way.

If you look at Appendix A Quick Reference in the GNU Make Manual you will see that it says:

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.

The closest you could get to what you are trying to do here, I think, would be to re-execute make on the Makefile (or whatever) manually.

That being said this sort of thing is probably better done as variables instead of targets.

$ cat Makefile
$(info $(origin UBSAN))
$ make
undefined
$ make UBSAN=
command line

So something like this.

# Undefined Behavior Sanitzier (Clang and G++)
ifneq (undefined,$(origin UBSAN))
CXXFLAGS += -fsanitize=undefined
endif # UBsan
like image 65
Etan Reisner Avatar answered Oct 18 '22 03:10

Etan Reisner


Yes, you can. Based on my recent answer to this other question Force Makefile to execute script after building any target (just before exiting), it was very easy to do what you would like.

This has only a drawback, you will lose any command-line arguments you pass directly to make as make all --silent. However, you can look into the question: How to detect if the makefile `--silent/--quiet` command line option was set?, and recapture the command-line arguments you would like to repass to the second make call command on 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

Usage examples:

  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
    
like image 21
user Avatar answered Oct 18 '22 02:10

user