Recursive nmake target - visual-studio

When recursively invoking nmake, via the $(MAKE) macro, how can I pass on the target specified on the command line to the new instance?
So, say I execute the following from the command line:
c:\nmake clean
I want the recursive call to nmake to pass the 'clean' target to the new nmake instance.

you can write rule like this:
clean all:
cd dir1 && $(MAKE) $*
cd dir2 && $(MAKE) $*
$* will be substituted by target name ("clean" or "clean" in this example)

I'm not sure I understand the question but you normally have the rule by virtue of the fact that your executing a specific part of the makefile, such as:
clean:
cd dir1 && $(MAKE) clean
cd dir2 && $(MAKE) clean
all:
cd dir1 && $(MAKE) all
cd dir2 && $(MAKE) all
If you have some other setup in your makefile, your best bet is to post it so we can do a better analysis.

Related

How to call a bunch of subdirectories Makefile from a top level Makefile with different targets

I have a top level Makefile that define a list of subdirectories containing sub-Makefiles.
Each sub-Makefile define the same targets: all, install, clean, test, verify, style...
How do I make the top level Makefile call all my subdirectories Makefile with the same target ?
It works for the default target, like this:
SUBDIRS = dir1 dir2 dir3
all: subdirs
subdirs: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $#
.PHONY: subdirs $(SUBDIRS)
But how do I extend that to the other non default targets ?
If you use GNU make you could use the MAKECMDGOALS variable and the filter function:
SUBDIRS := dir1 dir2 dir3
TARGETS := all install clean test verify style
$(TARGETS): subdirs
#echo making top $#
subdirs: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $# $(filter $(TARGETS),$(MAKECMDGOALS))
.PHONY: subdirs $(TARGETS) $(SUBDIRS)
%::
#echo making top $#
Demo:
$ make --no-print-directory all install foobar
make -C dir1 all install
make -C dir2 all install
make -C dir3 all install
making top all
making top install
making top foobar
Note that filter is needed to avoid passing top-only goals to the sub-makes.
If, for any reason, this MAKECMDGOALS based solution does not work for you, here are some other, but a bit more complex, solutions.
Target-specific variables
Target-specific variables propagate to prerequisites. So you can define a pattern-specific variable (SUBGOAL) for each of your top-level goals and use it in the subdir's recipe:
SUBDIRS := dir1 dir2 dir3
all: SUBGOAL := all
all: subdirs
#echo making top $#
subdirs: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $# $(SUBGOAL)
.PHONY: subdirs $(SUBDIRS)
If you have many such top-level goals and use GNU make you can factorize a bit with the foreach and eval GNU make functions:
SUBDIRS := dir1 dir2 dir3
TARGETS := all install clean test verify style
$(foreach t,$(TARGETS),$(eval $(t): GOAL := $(t)))
$(TARGETS): subdirs
#echo making top $#
subdirs: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $# $(GOAL)
.PHONY: subdirs $(SUBDIRS) $(TARGETS)
One important drawback is that as you use the same phony subdirectory target (dir1) for several top phony targets (all, install...) you cannot invoke make with several top goals:
$ make --no-print-directory all install
make -C dir1 all
make -C dir2 all
make -C dir3 all
making top all
making top install
will only make all in the subdirectories. If this is a problem you can use the next solution.
One phony target (all-dir1) per top-subdirectory combination
Let's do this programmatically with a 2-variables macro and a foreach-eval-call combination (GNU make only):
SUBDIRS := dir1 dir2 dir3
TARGETS := all install clean test verify style
$(TARGETS): subdirs
#echo making top $#
TARGETS_X_SUBDIRS :=
# $(1): top target
# $(2): subdirectory target
define TARGETS_X_SUBDIRS_RULES
$(1): $(1)-$(2)
$(1)-$(2):
$(MAKE) -C $(2) $(1)
TARGETS_X_SUBDIRS += $(1)-$(2)
endef
$(foreach t,$(TARGETS),$(foreach s,$(SUBDIRS),$(eval $(call TARGETS_X_SUBDIRS_RULES,$(t),$(s)))))
.PHONY: $(TARGETS) $(TARGETS_X_SUBDIRS)
Demo:
$ make --no-print-directory all install
make -C dir1 all
make -C dir2 all
make -C dir3 all
making top all
make -C dir1 install
make -C dir2 install
make -C dir3 install
making top install
Renaud's answer is more complete, but I also found this technique that worked fine for my use case:
all:
%:
make -C dir1 $#
make -C dir2 $#
make -C dir3 $#
In this case, I don't have the subdirs list in a variable, but they are spelled out in the commands for the generic target %:. It requires to add an extra make -C in front of every subdirectory, and a # in the back, but otherwise pretty maintainable and easy to read.
But it probably would not work if there was any other targets specific to the top-level Makefile.

Configure Make to fail immediately with bad target

I am launching multiple builds of a verilog compiler using Make. I am only using Make to take advantage of the -j flag. My file looks something like this
allfpga: fpga0 fpga1 fpga2 fpga3 fpga4 fpga5 fpga6
fpga0:
cd fpgas/$(#)/build && $(MAKE)
fpga1:
cd fpgas/$(#)/build && $(MAKE)
fpga2:
cd fpgas/$(#)/build && $(MAKE)
fpga3:
cd fpgas/$(#)/build && $(MAKE)
fpga4:
cd fpgas/$(#)/build && $(MAKE)
fpga5:
cd fpgas/$(#)/build && $(MAKE)
fpga6:
cd fpgas/$(#)/build && $(MAKE)
And I invoke one of make -j2 allfpga or make -j2 fpga0 fpag3 fpga5 fpga6
However if there is a typo (such as in the command I gave fpag3), in the second make target, the system will happily spend minutes building, and then stop early.
My question, how can I get make to stop initially if some of the targets are not real ones?
There's no good way to get make to "pre-screen" all your requested targets. Make can't know if a target is buildable until it tries to build it (for example it could be created based on some other target using a pattern rule or something).
However, you could do something like this:
ALLFPGAS := fpga0 fpga1 fpga2 fpga3 fpga4 fpga5 fpga6
# Get any command line goal which is not one of ALLFPGAS
unknown := $(filter-out $(ALLFPGAS),$(MAKECMDGOALS))
# If there are any, bail!
$(if $(unknown),$(error Unknown FPGA: $(unknown)))
allfpga: $(ALLFPGAS)
$(ALLFPGAS):
cd fpgas/$#/build && $(MAKE)
.PHONY: allfpga $(ALLFPGAS)

How to avoid code repetition calling recursive Makefiles?

Is it possible to simplify a Makefile of the following form in order to avoid code repetition:
dir1/foo:
make -C dir1 foo
dir1/bar:
make -C dir1 bar
dir2/baz:
make -C dir2 baz
...
clean:
make -C dir1 clean
make -C dir2 clean
...
I imagine I could specify only:
MY_TARGETS=dir1/foo dir1/bar dir2/baz ...
And than have some general rules to derive targets, as presented in the Makefile above.
You haven't given us much information. Recursive Make can be a good solution, if your main makefile is as simple as your example (which I doubt).
You could do this:
%:
$(MAKE) -C $(dir $#) $(notdir $#)
clean:
$(MAKE) -C dir1 clean
$(MAKE) -C dir2 clean
...
If that clean recipe is too long, you can simplify it:
DIRS := dir1 dir2 ...
clean:
#for x in $(DIRS); do $(MAKE) -C $$x clean; done
Or if you don't like having that DIRS list there, you could have Make generate it, depending on whether you want to make clean in all subdirectories, or all that match the dir* pattern, or... you haven't given us enough information.

Cygwin, how to run "make" for all makefiles found in the root directory and any subdirectories?

I have a directory composed of various subdirectories. In each of these subdirectories is a makefile. In the root directory, there is also a make file. I need to perform a make instruction in cygwin that performs "make" on all makefiles in the main directory and any subdirectory. Any ideas how to accomplish this?
This is the common way I have seen it done. Inside of the "main" Makefile would be something similar to this code.
all:
cd library && $(MAKE) all && cd ..
cd programs && $(MAKE) all && cd ..
cd tests && $(MAKE) all && cd ..
ref

Setting target variable for the name of the makefile from a subdirectory

How can I have the variable for $(MAKEFILE) be defined during target execution?
Basically I have a few make files in subdirectories that are named for a specific platform "Makefile.aix" and just Makefile in all other directories. I would like to set a variable for $(MAKEFILE) that gets defined in each subdirectory. Code would look something like this.
MAKEFILE = Makefile
SUBDIR = ./sub ./sub2
ifneq ($(wildcard Makefile),)
MAKEFILE = Makefile
else
MAKEFILE = Makefile.$(PLATFORM)
endif
all:;
#for i in $(SUBDIR);\
do (\
echo Making $$i ...;\
cd $$i;\
make -f $(MAKEFILE)\
); done
Is there just one Makefile.$(PLATFORM) in each subdirectory, or are there several, for different platforms?
In the first case, you could do something like this:
SUBDIR = ./sub ./sub2
define script
cd $(1); \
$(MAKE) -f Makefile*
endef
all:
$(foreach dir, $(SUBDIR), $(call script,$(dir)))
(The empty line inside the define is significant. It can be omitted, if you add a semicolon at the end of the line $(MAKE) ..., leading to one long command line, containing the commands for all directories, which will then be executed in one chunk.)
An alternative script would be (just a matter of personal preference which you like better):
define script
$(MAKE) -C $(1) -f $(notdir $(wildcard $(1)/Makefile*))
endef
If there are several Makefile.$(PLATFORM) files in a directory it becomes more difficult. I'll have to think about that one some more.
UPDATE: In response to your comment, something like this should work:
define script
$(MAKE) -C $(1) -f $(notdir $(wildcard $(1)/Makefile $(1)/Makefile.$(PLATFORM)))
endef
Following your logic, I'd propose update do () section with:
do (\
echo Making $$i ...;\
cd $$i;\
if [ -f Makefile.$(PLATFORM) ] \
then\
make -f Makefile.$(PLATFORM) \
else\
make -f Makefile\
fi\
); done
This is actually not a make style, but I can't suggest anything better without specific of your project
You can do most of this, including the loop over directories, using GNU make's built-in functions. Put the following in a central place, say $(TOP_DIR)/mk/subdir.mk:
makefile-for-dir = \
$(if $(wildcard $(1)/Makefile),Makefile,Makefile.$(PLATFORM))
make-recursive = \
$(foreach _d,$(1),$(MAKE) -C $(_d) -f $(call makefile-for-dir,$(_d)) && ) :
In each makefile that start recursive makes, use
include $(TOP_DIR)/mk/subdir.mk
SUBDIRS = dir1 dir2 dir3
.PHONY: all
all:
+#$(call make-recursive,$(SUBDIRS))

Resources