Reputation: 635
I'm currently facing following problem:
How can I create one global Makefile to build different applications(maybe using the same or different libraries) from my source tree? At the moment I have only one application and all what I do is:
include $(ROOT)/SETUP.MAK
SUBDIRS = \
lib1 \
lib2 \
app1
include $(ROOT)/RULES.MAK
The application is built as it should be. But now I'm going to have more applications and maybe additional libraries. I don't want to create a seperate Makefile for every single application, because the libraries/code base are the same for the different applications. This is what I tried:
include $(ROOT)/SETUP.MAK
ifeq ($(strip $(MAKECMDGOALS)),proj1)
SUBDIRS = \
lib1 \
lib2 \
app1
endif
ifeq ($(strip $(MAKECMDGOALS)),proj2)
SUBDIRS = \
lib1 \
lib2 \
lib3 \
app2
endif
.PHONY: proj1
proj1: $(SUBDIRS)
.PHONY: proj2
proj2: $(SUBDIRS)
include $(ROOT)/RULES.MAK
But the problem is make enters the first directory which is here "lib1" and tries to build "lib1", but there is no rule for "proj1" in "lib1". How is this done correctly? I invoke make at the command line with "make proj1".
Note: the make rule for SUBDIRS is in the file RULES.MAK
EDIT 1: Here is the rule for SUBDIRS:
# entering dir c; calculating deps; leaving dir c; entering dir c; making blah; leaving dir c
$(SUBDIRS) :
# call as make NOT_RECURSIVE=1 to avoid recursion
ifndef NOT_RECURSIVE
ifneq ($(MAKEFILE_DIR),./) # some makefile path given
$(VERBOSE) $(MKDIR) $@
ifneq ($(call isabspath, $(MAKEFILE_DIR)),) # absolute makefile path
@$(MAKE) -C $@ -f $(MAKEFILE_DIR)$@/$(MAKEFILE_NOTDIR) $(MAKECMDGOALS)
else # relative makefile path
@$(MAKE) -C $@ -f ../$(MAKEFILE_DIR)$@/$(MAKEFILE_NOTDIR) $(MAKECMDGOALS)
endif
else # no makefile path given
@$(MAKE) -C $@ $(MAKECMDGOALS)
endif
endif
Upvotes: 1
Views: 1650
Reputation: 99134
You're using Make in a very un-Make-like way, and causing yourself a lot of unnecessary trouble.
Look at lib1
. Presently you use a rule that works out to
lib1:
$(MAKE) -C lib1 proj1
(We'll assume the "no makefile path given" mode for now.) I presume that the files in lib1/
add up to a library, and that that library does not have to be built with a specific project in mind. So there's no need to pass "proj1" to the Make process running in lib1/
. And Make doesn't require an explicit target; if invoked without a target, Make will try to build the default target, which is (usually) the first target in the makefile, which in this case should be the library (lib1/lib1.a
or something). So we can simplify the rule:
lib1:
@$(MAKE) -C lib1
Or better:
lib1:
@$(MAKE) -C $@
In fact, we can generalize this to all subdirectories that we use the same way:
lib1 lib2 lib3 app1 app2:
@$(MAKE) -C $@
If we use "SUBDIRS" to mean all subdirs we treat this way, and spell out the proj
prereqs, the global makefile gets a lot simpler:
SUBDIRS = lib1 lib2 lib3 app1 app2
.PHONY: proj1
proj1: lib1 lib2 app1
.PHONY: proj2
proj2: lib1 lib2 lib3 app2
Further improvements are possible, but this answer is getting long. (As for the "makefile path given" mode, you can simplify that a good deal too, and get rid of much or all of the branching, but it seems to be entangled with parameters set in SETUP.MAK
, and maybe details of your OS.) So maybe it's best to leave them for another day.
Upvotes: 1
Reputation: 1405
If you call make proj1, make will enter in this condition clause :
ifeq ($(strip $(MAKECMDGOALS)),proj1)
SUBDIRS = \
lib1 \
lib2 \
app1
endif
so SUBDIRS is defined as "lib1 lib2 app1". Don't know the content of SETUP.MAK but in case where no makefile path is given make enter in the last if clause :
else # no makefile path given
@$(MAKE) -C $@ $(MAKECMDGOALS)
make interpret this command by : make -C lib1 proj1
Your Makefile hasn't any proj1 rule.
You should create a generic all
rule in lib1/Makefile creating your lib (.a / .so) from lib1/Makefile, project's name has not to be specified.
Try with
else # no makefile path given
@$(MAKE) -C $@
(or remove others $(MAKECMDGOALS)
in your IFs clauses)
Upvotes: 1