jww
jww

Reputation: 102205

Suppress "make: Nothing to be done for 'target'"

According to the GNUmake manual, 5.9 Using Empty Recipes, I can do the following to create an empty recipe:

target: ;

I have an empty recipe that prints system information to help in troubleshooting:

.PHONY: system
system: ;
    $(info CXX: $(CXX))
    $(info CXXFLAGS: $(CXXFLAGS))
    $(info GCC_COMPILER: $(GCC_COMPILER))
    $(info CLANG_COMPILER: $(CLANG_COMPILER))
    $(info INTEL_COMPILER: $(INTEL_COMPILER))
    $(info SUN_COMPILER: $(SUN_COMPILER))
    ...

However, it ends with:

...
IS_MINGW: 0
IS_CYGWIN: 1
IS_OPENBSD: 0
IS_SUN: 0
make: Nothing to be done for 'system'.

For some reason, I made the leap an empty rule would be silent (obviously wrong). Is there a way to suppress the message "Nothing to be done for 'target'"? If so, how?

Upvotes: 4

Views: 1701

Answers (2)

Kevin E
Kevin E

Reputation: 3186

I was in the same situation, and achieved what I wanted by just adding a "no-op" recipe to the rule.

The : command is exactly that for the Bash/Bourne shell: a null operation.

.PHONY: vars
vars:  # print Makefile variables and values
⇥   @:
⇥   @$(foreach V, \
⇥   ⇥   $(sort $(.VARIABLES)), \
⇥   ⇥   $(if $(filter-out environment% default automatic,$(origin $V)), \
⇥   ⇥   ⇥   $(info $V=$($V) ($(value $V))) \
⇥   ⇥   ␣) \
⇥   ␣␣)

Because $(info ...) produces an side effect to standard out but doesn't actually create any work for the rule itself to do, make sees it as an empty target, hence the warning message.

Upvotes: 0

Etan Reisner
Etan Reisner

Reputation: 80921

You've given the system target a recipe by putting the $(info) lines under it. Make doesn't care that they are all make context and not shell context recipe lines though. That's why adding ; isn't doing anything. Your recipe is already not empty.

That all said you can either not use $(info) there and use @echo (or whatever) instead and you'll avoid that message.

Or you can go with just system: ; and then a make-level conditional on system being in MAKECMDGOALS to then use $(info) to display the information.

ifneq ($(filter system,$(MAKECMDGOALS)),)
    $(info CXX: $(CXX))
    $(info CXXFLAGS: $(CXXFLAGS))
    $(info GCC_COMPILER: $(GCC_COMPILER))
    $(info CLANG_COMPILER: $(CLANG_COMPILER))
    $(info INTEL_COMPILER: $(INTEL_COMPILER))
    $(info SUN_COMPILER: $(SUN_COMPILER))
endif

system: ;

Which would then let you use make target1 target2 system and get the system output printed before the targets are run.

The above does output

make: `system' is up to date.

at the end though. To avoid that you need to actually give the rule a recipe.

system: ;@:

but that will actually run a shell (the empty recipe does not). So you get to decide on the trade-offs there.

Upvotes: 2

Related Questions