I would like a makefile where I can call:
'make' / 'make <subdir>' / 'make clean' / 'make <subdir> clean'
But I do not want it to attempt to resolve clean when called on a subdir!
Here's an example of my makefile:
SUBDIRS := a b c
all :
#echo building a b and c
clean :
#echo cleaning a b and c
$(SUBDIRS) :
make - C $# $(MAKECMDGOALS)
All the calls work well except make <subdir> clean which calls make -C <subdir> clean, but then attempts to also resolve target clean separately. How can I get make to stop processing later targets?
To both answers:
thank you for your explanation. it is helpful to know what is and what is not meant to be done. i will not attempt this anymore.
Sigh
Yes, you can do this, but it'll be an ugly hack and totally contrary to the way Make is designed to work.
The set of targets you pass to Make is a set of targets, not a structured command with syntax. Make is expected to build them all. If the makefile includes a recipe for the target foo, then Make should build the target foo a certain way, regardless of whether it is invoked as Make foo or Make foo bar or Make bar foo. What you are attempting to do breaks the accepted behavior of Make, so you should try a different approach.
If you still wanted to do it, you could do it like this:
SUBDIRS := a b c
.PHONY: clean
ifneq ($(filter $(SUBDIRS), $(MAKECMDGOALS)),)
$(SUBDIRS) :
#echo make - C $# $(MAKECMDGOALS)
clean:
#: # do nothing
else
all :
#echo default
clean :
#echo cleaning
endif
I fully agree with Beta's statements on misusing make. Another way of achieving what you want, would be to introduce explicit targets for cleaning the subdirectories. This way, for instance, you can call make clean_<subdir>.
SUBDIRS := a b c
all:
#echo building a b and c
clean:
#echo cleaning a b and c
$(SUBDIRS):
make - C $#
$(addprefix clean_, $(SUBDIRS)): clean_%:
make -C $* clean
Related
I`m using a makefile and call some makefiles in subdirectories.
Can anyony explain me, why this works
$(MAKE) -C stub
$(MAKE) -C source
but this not
SUBDIRS = stub source
$(SUBDIRS):
$(MAKE) -C $#
First time I`m working with makefiles.
When you do not explicitly specify the target(s) to make, it will use the first target whose name doesn't start with a dot. Here, that target is stub.
Apparently, you expect all of the targets of the first rule to be used, but there can only be one default target.
The documentation isn't 100% clear on this.
You will get the desired behavior by prepending the rule:
all: $(SUBDIRS)
In the current system, there was a ghetto hack to initiate a parallel build for the system. For instance, to call a parallel make required make JOBS=8 instead of make -j8. I have since fixed the makefile, however there are a lot of previous dependencies on the JOBS flags within scripts that call make. I was hoping to recursively call make as a workaround as such:
ifdef JOBS
%:
$(MAKE) $(MAKECMDGOALS) JOBS= -j$(JOBS)
endif
This has some odd behavior though. It will first call make JOBS= -j8 as it should, but after this rule is completed it seems to go on and rebuild everything again that is in $(MAKECMDGOALS).
#Example
TARGETS = lib0 lib1 lib2
ifdef JOBS
%:
$(MAKE) $(MAKECMDGOALS) -j$(JOBS) JOBS=
endif
all: $(TARGETS)
lib%:
#echo g++ $#
Cmd: make JOBS=8.
This is fine for most rules, however it keeps wasting time rebuilding PHONY rules, so this should be fixed. Is there a way to completely reroute a make JOBS=N command to make -j$(JOBS) without executing any other rules redundantly in either scope? (meaning nothing executes except a submake in make JOBS=N, and the submake is only called once with all $(MAKECMDGOALS) at once.)
EDIT: I would also like to avoid large ifdef; else; endif statements, at the very most putting a self contained one at the top of the file. I'm starting to think the solution may require something like that though:
TARGETS = lib0 lib1 lib2
ifdef JOBS
%: unique_make
#echo $# built > /dev/null
.PHONY: unique_make
unique_make:
$(MAKE) $(MAKECMDGOALS) -j$(JOBS) JOBS=
else
all: $(TARGETS)
lib%:
#echo g++ $#
endif
In GNU make, you can modify the make flags within a Makefile. Why not try something like this:
ifdef JOBS
MAKEFLAGS+=-j$(JOBS)
endif
I'm trying to get a top-level makefile to call make in a number of subfolders. The top-level has several targets and the important bit is shown below:
MAKE_DIRS := $(dir $(wildcard apps/**/Makefile))
.PHONY: clean_apps apps $(MAKE_DIRS)
clean_apps: TARGET_INFO := clean
apps clean_aps: $(MAKE_DIRS)
$(MAKE_DIRS):
$(MAKE) -C $# $(TARGET_INFO)
Now this works fine when I call the targets independently:
make apps; make clean_apps
However if I call them on the same commandline with:
make clean_apps apps
Then the apps target justs say nothing to do. I guess it's something to do with the dependency on the directories not having changed between invocations, but I thought the .PHONY command would avoid that problem...
I'm happy to know if there's a better way to deal with this.
Thanks,
bob
It is something much more simpler :
SUBDIRS := $(dir $(shell find apps -name "Makefile"))
.PHONY: all clean
all clean:
$(foreach DIR, $(SUBDIRS), $(MAKE) $(MAKEFLAGS) -C $(DIR) $#;)
The question is about parallel making w/ GNU makefile.
Given a folder structure as below, the goal is to deliver a makefile that it supports make release/debug/clean in parallel.
project folder structure:
foo
+-foo1
+-foo2
+-foo3
The makefile may be sth like:
SUBDIR = foo1 foo2 foo3
.PHONY $(SUBDIR) release debug clean
release: $(SUBDIR)
$(SUBDIR):
$(MAKE) -C $# release
debug: $(SUBDIR)
#below is incorrect. $(SUBDIR) is overriden.
$(SUBDIR):
$(MAKE) -C $# debug
..
Sub directory list are set as phony targets for parallel making. but it lost the information of original target (release, debug, clean etc).
One method is to suffix the names for the directories and recover it in commands, but it is weird. another method might be to use variables, but not sure how to work it out.
The questions is:
How to write the rules for directories, that supports parallel making w/ different targets (release/debug/clean)?
Any hints are greatly appreciated.
Setting variables on the command line certainly works. You can also use MAKECMDGOALS (see the GNU make manual):
$(SUBDIR):
$(MAKE) -C $# $(MAKECMDGOALS)
I have a Makefile which includes makefiles from sub-directories.
However, what I want is to include these "sub"-makefiles on base of a selected target.
Background is, that the sub-makefiles define different object files and depending on these object files the target executable should be created.
Assuming sub-makefile1 sets the variable
OBJECTS := foo.o foo1.o
sub-makefile2 sets
OBJECTS := bar.o bar1.o
And the generic rule would be:
lib/%.so: $(OBJECTS)
link $^ -o $#
The targets are (for example):
foo: lib/foo.so
bar: lib/bar.so
whereas target foo should include the foo makefile, target bar the bar-makefile.
Any idea how to handle this situation?
Thanks,
Christian
Beta has mentioned the $(MAKECMDGOALS), but not described it:
ifeq ($(MAKECMDGOALS),foo)
include sub-makefile1
endif
ifeq ($(MAKECMDGOALS),bar)
include sub-makefile2
endif
# Rest of Makefile follows...
This isn't such a great idea, as it will only work when make is called interactively. You can hack around this by making rules for foo and bar that recursively invoke make:
ifeq ($(MAKECMDGOALS),foo)
include sub-makefile1
foo: # ...
# Normal commands to build foo
else
foo:
$(MAKE) $<
endif
ifeq ($(MAKECMDGOALS),bar)
include sub-makefile2
bar: # ...
# Normal commands to build bar
else
bar:
$(MAKE) $<
endif
The specific thing you're asking for -- conditional inclusion -- is difficult in Make. It can be done, but it's not elegant.
There are several ways to get the effect you want. You could use a conditional on MAKECMDGOALS. You could could have your makefile invoke a second makefile, and pass it the name of the subdirectory to use. But (without knowing more about the situation) I think this way is the tidiest:
include sub-makefile1
FOO_OBJECTS := $(OBJECTS)
include sub-makefile2
BAR_OBJECTS := $(OBJECTS)
lib/%.so:
link $^ -o $#
lib/foo.so: $(FOO_OBJECTS)
lib/bar.so: $(BAR_OBJECTS)
foo bar : % : lib/%.so
(You could be clever with variable names like foo_OBJECTS to save a line or two, but I advise against that.)