0

I have a makefile which can compile a release build or a debugging build (i.e. with -O3 or -g respectively. The first and default one is release so make is equivalent to make release. Sometimes I make debug but am so used to just typing make that the next time I compile it goes back to release.

Is there a way the makefile could remember the last target specified and default to that if no arguments are given?

This has a similar title, but is really a different question: How does "make" app know default target to build if no target is specified?

Community
  • 1
  • 1
jozxyqk
  • 16,424
  • 12
  • 91
  • 180

2 Answers2

1

This writes the last target name into a file, .default_make_target, which is then used as the default target when no arguments are given. It shows the correct target name in the output and exits with Nothing to be done for 'target'. correctly when its out of date.

DEFAULT_TARGET=debug
LAST_TARGET_FILE=.default_make_target
LAST_TARGET=$(foreach f, $(wildcard $(LAST_TARGET_FILE)), $(shell cat $(f)))

.PHONY: debug release clean

.DEFAULT_GOAL:= $(or $(LAST_TARGET),$(DEFAULT_TARGET))

debug: CFLAG_OPTS+= -g
debug: CHOSEN_TARGET=debug
debug: real_target

release: CFLAG_OPTS+= -O3
release: CHOSEN_TARGET=release
release: real_target

real_target:
    @echo $(CHOSEN_TARGET) > $(LAST_TARGET_FILE)
    echo '$(CFLAG_OPTS)' > real_target #just an example

clean:
    rm -f real_target

Testing...

> make debug
echo '-g' > real_target
> make
make: Nothing to be done for 'debug'.
> make clean
rm -f real_target
> make release
echo '-O3' > real_target
> make
make: Nothing to be done for 'release'.
>

*UPDATED:

  • Previously I had @echo debug > $(LAST_TARGET_FILE) as the body of the phony debug rule (and likewise for release), which meant debug/release were always out of date. Instead, it needs to be run in the body of a real target, for which CHOSEN_TARGET is set.

  • Rather than default: $(if...), using .DEFAULT_GOAL:= now causes the correct target to be printed when up to date. For example make: Nothing to be done for 'release'.

Community
  • 1
  • 1
jozxyqk
  • 16,424
  • 12
  • 91
  • 180
  • Ugly as sin, but also just about the only way to do it. – Jonathan Leffler Jun 23 '15 at 06:54
  • You make like to use `or` make function `$(or $(LAST_TARGET),$(DEFAULT_TARGET))`. – Maxim Egorushkin Jun 23 '15 at 07:49
  • @MaximEgorushkin thanks! getting into a whole world of hurt getting around [this](http://stackoverflow.com/questions/13852535/makefile-dependencies-dont-work-for-phony-target) issue that causes the above to always be out of date. Will fix and update soon. – jozxyqk Jun 23 '15 at 07:59
1

I like this a bit better:

LAST_TARGET_FILE=.last_target
UPDATE_LAST_TARGET=@echo "LAST_TARGET=$@" >$(LAST_TARGET_FILE)

-include $(LAST_TARGET_FILE)

.PHONY: default
default: $(firstword $(LAST_TARGET) release)

.PHONY: debug
debug:
    $(UPDATE_LAST_TARGET)
    echo debug

.PHONY: release
release:
    $(UPDATE_LAST_TARGET)
    echo release
Alex Reece
  • 1,906
  • 22
  • 31
  • Or just put the rule in the file directly, or put an assignment before the include to avoid the `firstword`, or ... – o11c Jun 23 '15 at 07:57