Make file warning, overriding commands for target
Like the OP (James Leonard), I would like to suppress or avoid warnings about overriding Makefile
targets. However, my situation and goals are different.
I want Makefile
to include base.mk
, and I want Makefile
to be able to override targets from base.mk
without any warning messages. I am using GNU Make.
The GNU Make documentation describes one way of doing this:
Create Makefile
as follows:
foo:
echo 'bar' > foo
%: force
@$(MAKE) -f base.mk $@
force: ;
Source: https://www.gnu.org/software/make/manual/html_node/Overriding-Makefiles.html
The above method has the (potentially serious) disadvantage that it will invoke a separate instance of $(MAKE)
, meaning that (some or all?) variables may (will?) not be shared between the parent and child invocations of make.
Happily, I found a better solution, as outlined below:
Create base.mk
as follows:
foo-default:
echo 'foo-default'
bar-default:
echo 'bar-default'
%: %-default
@ true
Create Makefile
as follows:
include base.mk
foo:
echo 'foo Makefile'
Example output:
$ make foo
echo 'foo Makefile'
foo Makefile
$ make bar
echo 'bar-default'
bar-default
Note that you need to be able to control the names of the targets in base.mk
so that you can name them <target>-default
. In other words, you cannot use this approach to extend arbitrary base makefiles. However, if you control both base.mk
and Makefile
, this approach will allow you to create one base.mk
and then many customizations of it.
To avoid including the same file many times, you can use a C-style header 'directive':
ifeq ($(_MY_MAKEFILE_),)
_MY_MAKEFILE_ := defined
...
endif
ifeq
here is just saying "is the value empty"- it's possible something similar can be done with
ifndef
but I got this working first - the value "defined" is just anything that isn't blank
One of the most common ways for doing this is to put the release objects and the debug objects in separate subdirectories. That way you don't get redefinitions for the rules for an object, since they will have different names. Something like this:
D_OBJECTS=$(SRC:%.cpp=debug/%.o)
R_OBJECTS=$(SRC:%.cpp=release/%.o)
RTARGET = a.out
DTARGET = a.out.debug
all : dirs $(RTARGET)
debug : dirs $(DTARGET)
dirs :
@mkdir -p debug release
debug/%.o : %.c
$(CC) $(DEBUG_CFLAGS) -o $@ -c $<
release/%.o : %.c
$(CC) $(RELEASE_CFLAGS) -o $@ -c $<
$(DTARGET) : $(D_OBJECTS)
$(CC) $(DEBUG_CFLAGS) -o $@ $(D_OBJECTS)
$(RTARGET) : $(R_OBJECTS)
$(CC) $(RELEASE_CFLAGS) -o $@ $(R_OBJECTS)