Is it possible to add a dependency to another Makefile? - makefile

I'm not asking if it is possible to call Makefile from another Makefile.
Suppose I have a rule for generating an executable which looks like this:
my-prog: some.o local.o dependencies.o
Note that I'm exploiting built-in rules here.
Now suppose I start using a third-party library. I'd like to keep this built-in syntax and just add the external rule to the dependency list:
my-prog: some.o local.o dependencies.o somelib/libsomelib.a
But that won't work:
No rule to make target 'somelib/libsomelib.a', needed by 'my-prog'.
I know that I can solve this issue by calling explicitly the other Makefile:
my-prog: some.o local.o dependencies.o
$(MAKE) -C somelib/ libsomelib.a
$(CC) $(LDFLAGS) -o $# $^ somelib/libsomelib.a
But that's what I'm trying to avoid. Any ideas?

In select cases it might be possible to just include the other Makefile, but in those cases they could likely have been written as one in the first place, so...failing that, the best you can do to make the dependency tracking work is to extend the recursive make approach -- your own makefile can't track the dependencies of somelib/libsomelib.a, so you will have to ask the other Makefile to do it for you every time. I'm afraid there's no way around that.
You can, however, enable yourself to keep using the implicit rules and shift the dependency tracking of foreign libs to the other makefile. I'm thinking along the lines of phony targets for these foreign builds like so:
somelib/libsomelib.a:
$(MAKE) -C somelib/ libsomelib.a
# This target needs to be phony so it is run every time because only the other
# makefile can determine that there's nothing to be done.
.PHONY: somelib/libsomelib.a
# then you can use it as a dependency just like locally built targets
my-prog: some.o local.o dependencies.o somelib/libsomelib.a
This can be extended to multiple foreign targets like this:
# list foreign targets here
FOREIGN_TARGETS = \
somelib/libsomelib.a \
foo/libfoo.a \
bar/libbar.a
$(FOREIGN_TARGETS):
# split the target into directory and file path. This assumes that all
# targets directory/filename are built with $(MAKE) -C directory filename
$(MAKE) -C $(dir $#) $(notdir $#)
.PHONY: $(FOREIGN_TARGETS)

Related

Passing all object files in the project directory tree to a rule in makefile

I have a makefile that looks like this
CC=gcc
CFLAGS=-pedantic -ansi -Wall -O2
TARGET=assembler
SUBDIRS = utils preprocessor parser symbols
.PHONY: clean all subdirs $(SUBDIRS)
subdirs: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $#
all: subdirs
clean:
for dir in $(SUBDIRS); do \
$(MAKE) -C $$dir clean; \
done
And I want to add
$(TARGET): subdirs $(TARGET).c
$(CC) $(CFLAGS) $(TARGET).c -o $#
But then I get linking error because the objects files from the subdirs aren't found. Is there a way to pass all object files under the project root directory?
Is there a way to pass all object files under the project root directory?
Usage of the word "pass" suggests that you have altogether the wrong mental model of makefiles and make operation. Makefiles are specifications, not scripts, and the rules within are not functions and do not operate like functions. Among other things, the targets and prerequisites of explicit rules are determined when the makefile is parsed, not dynamically at the time of (consideration of) rule execution.
It follows that what you propose to do is altogether unworkable, because you cannot rely on any of the object files -- they being built files -- to exist when make starts. You have a chicken and egg problem.
I fully agree with #Andreas that using globbing and similar dynamic target or prerequisite detection in a makefile is bad.* Targets and prerequisites that are named at all should be named explicitly (not to preclude assigning them to a variable or using substitution references or similar). But if you nevertheless do use globbing or another form of dynamic detection to locate files, then you should be locating files distributed with the project, not built ones.
If you want to maintain the modularity of your recursive make build system (which is not by any means a clear win), then one reasonable alternative would be for the make in each subdirectory to build a static archive named after the directory name. The top-level makefile then does not need to know any of the details of the subdirectory makes; it just includes the static library resulting from each one in the link.
*There are multiple reasons for this, but they are tangential to the question at hand.

GNU Make: Using the filter function in prerequisites

I want to compile some C++ files and I absolutely have to put all object files in a separate build directory, but stored completely flat, i.e., without any further subdirectories. I know the common solution using VPATH, which goes something like this:
SOURCES = foo/one.cpp \
foo/bar/two.cpp \
foo/bar/sub/three.cpp
OBJDIR = obj
VPATH=$(dir $(SOURCES))
OBJECTS = $(addprefix $(OBJDIR)/, $(notdir $(SOURCES:%.cpp=%.o)))
$(OBJDIR)/%.o : %.cpp
#echo Should compile: $(filter %/$*.cpp, $(SOURCES))
#echo Compiling $<
all: $(OBJECTS)
This example pretty much works: I get three object files one.o, two.o, three.o in the 'obj' subdirectory (you can assume it just exists).
Now here's the catch when using VPATH: If there happens to be a file 'foo/three.cpp', then this will be compiled instead of the 'foo/bar/sub/three.cpp' which is named in the SOURCES variable. And no, I cannot rename either file; this name clash simply exists and I cannot do anything about that.
So my question is: How can I tell Make to only use '.cpp' files which appear in the SOURCES variable? I think the best solution would be to use that 'filter' statement in the target's prerequisite. I think this should be possible using secondary expansion, but I don't know what to do with the '%'. For example, I tried
.SECONDEXPANSION:
$(OBJDIR)/%.o : $$(filter %/$$*.cpp, $(SOURCES))
but that doesn't work.
UPDATE: With the help of tripleee, I managed to get this working using the following:
define make-deps
$(OBJDIR)/$(notdir $(1:%.cpp=%.o)): $1
endef
$(foreach d, $(SOURCES), $(eval $(call make-deps,$d)))
%.o :
#echo Should compile $^ into $#
#echo Compiling $^
I suspect the easiest solution to your problem would be to get rid of VPATH and document each dependency explicitly. This can easily be obtained from your SOURCES definition; perhaps you want to define a function, but it really boils down to this:
obj/one.o: foo/one.cpp
obj/two.o: foo/bar/two.cpp
obj/three.o: foo/bar/sub/three.cpp
The actual rule can remain, only it should no longer contain the dependencies in-line, and you can skip the obj/ subdirectory, because it's declared explicitly in each dependency:
%.o : # Dependencies declared above
#echo Should compile $^ into $#
#echo Compiling $^
I changed the rule to use $^ instead of $< in case you ever have more than a single dependency. This may be right or wrong for your circumstances; revert the change if it's not what you need.
In order to not need to maintain the dependencies by hand, you might want to generate %.d for each %.cpp file. See the GNU Make manual. (I tried to do this by using a define, but it seems you cannot declare dependencies with a foreach loop.)
In response to the question in the comment, this should not affect parallel builds in any way; it merely disambiguates the dependencies where your original Makefile was ambiguous when there were multiple biuld candidates with the same name in the VPATH. There are no new dependencies and no new rules.

makefile conditionals

Note: using MinGW's make (should be GNU make)
i have a couple of -include statements in my makefile to import dependencies which were generated using g++ -MM. However I would like to only do this when necessary. I have several different build targets and I don't want all of their respective dependency files to be included since this takes a while (suppose I'm running make clean: no need to include them in this case)
Here's the format of my makefile.
DEPS_debug = $(patsubst %.cpp,build_debug/%.d,$(SRC))
OBJ_debug = $(patsubst %.cpp,build_debug/%.o,$(SRC))
all: program_debug
-include $(DEPS_debug) #make: include: Command not found
program_debug: $(OBJ_debug)
$(CC) $(CFLAGS) $(OBJ_debug) -o $#
If you really don't want to include those files needlessly, you have a couple of options:
You can put in a conditional as Diego Sevilla suggests (but I would recommend using MAKECMDGOALS so that you can write a more flexible version, specific to targets, e.g. you'll include foo.d if and only if you're making foo.o).
You can use make recursively (heresy!), invoking $(MAKE) for each target object, using a makefile that includes that target's dependencies.
But actually including the file takes negligible time, it's the rebuilding of the file (automatic for any included file that's out of date) that takes time.
If needless rebuilding is what you want to avoid, you can use a very clever trick. When must foo.d be rebuilt? Only when something about foo has changed. But in that case foo.o must also be rebuilt. So don't have a seperate rule for foo.d, just rebuild it as a side effect of making foo.o. That way you can include all dependency files and not waste time rebuilding them if they aren't needed.
EDIT:
I'm astounded that merely including these files can add 2-3 seconds to make clean. My last paragraph is off the mark, so let me expand on the first two options.
If all is the only target for which these files should be included, and you make all from the command line (and not e.g. make all tests tarball install kitchenSink), then this will do it:
ifeq ($(MAKECMDGOALS),all)
-include $(DEPS_debug)
endif
Note that this will not include foo.d if you make foo.o. You can write a more sophisticated conditional, something like
$(foreach targ,$(MAKECMDGOALS),$(eval $(call include_deps $(targ)))...
but that's pretty advanced, so let's get a simple version working first.
If you'd rather avoid the conditional and use recursive Make, the simplest way is to split the makefile in two:
makefile:
all:
$(MAKE) -f makefile.all
clean:
rm whatever
...other rules
makefile.all:
DEPS_debug = $(patsubst %.cpp,build_debug/%.d,$(SRC))
OBJ_debug = $(patsubst %.cpp,build_debug/%.o,$(SRC))
-include $(DEPS_debug)
all: program_debug
program_debug: $(OBJ_debug)
$(CC) $(CFLAGS) $(OBJ_debug) -o $#
Indenting a line by a TAB makes make think it's a command to be passed to the shell (as you found out). It doesn't work that way.
The - in front of include suppresses errors that might result from DEPS_debug not existing (e.g. when running clean or release without having had a dependency-file-generating call first). Since DEPS_debug is not a dependency of those rules (clean / release), your dependency files do not get generated when you call them, and everything is fine. I don't really see the problem you're having - you don't have to make the include conditional.
Perhaps you'd like to change your approach, though. Instead of having a seperate *.d target, with a seperate -M preprocessor pass, you might want to try something like -MMD -MP which generates the dependency files inline during code generation, in your standard *.c -> *.o pass.
(I know this sounds completely wrong at first, but when you think about it, it makes sense. Makefile logic is a bit backwards that way, unless you're familiar with functional programming.)
includes are independent of the rules, as they are makefile indications, not compilation indications. You can, however, use makefile conditionals based on special makefile variables such as MAKECMDGOALS, that is set to the default goal:
ifeq ($(MAKECMDGOALS),all)
-include whatever
endif
This is included when no default goal is specified. You can change the condition to specify the exact goal you want to check to include other sub-makefiles.

What is wrong in doing this (considering a parallel make)?

I have 2 dirs A and within A I have B.
Makefile in directory A looks like :
include rules.mk //defines common rules for generating *.o from *.cpp *.c
OBJECTS = test.o \
B\test1.o \
B\test2.o
test.lo : $(OBJECTS)
$(LD) $(LD_OPTS) -o $# $^
$(CREATE_CXX_SO)
As is B doesn't have a Makefile defined within it.
Is it mandatory for having Makefiles within the subdirs as well? For serial makes this doesn't seem to pose a problem but while doing parallel makes at times $(LD) tries making conn.lo even before B/test1.o and B/test2.o are compiled.
If what I am doing above is wrong, what are the options that I have?
I read an excellent article about the recursive use of make at... you guessed it, Recursive Make Considered Harmful. This article details the problems with the distressingly common recursive use of make, and how to build your Makefile such that it can run better and more reliably in parallel.
Or, you can use SCons which works brilliantly.

Makefile trickery using VPATH and include

I'm playing around with make files and the VPATH variable. Basically, I'm grabbing source files from a few different places (specified by the VPATH), and compile them into the current directory using simply a list of .o-files that I want.
So far so good, now I'm generating dependency information into a file called '.depend' and including that. Gnumake will attempt to use the rules defined so far to create the included file if it doesn't exist, so that's ok. Basically, my makefile looks like this.
VPATH=A/source:B/source:C/source
objects=first.o second.o third.o
executable: $(objects)
.depend: $(objects:.o=.c)
$(CC) -MM $^ > $#
include .depend
Now for the real question, can I suppress the generation of the .depend file in any way? I'm currently working in a clearcase environment -> sloooow, so I'd prefer to have it a bit more under control when to update the dependency information.
It's more or less an academic exercise as I could just wrap the thing in a script which is touching the .depend file before executing make (thus making it more recent than any source file), but it'd interesting to know if I can somehow suppress it using 'pure' make.
I cannot remove the dependency to the source files (i.e. using simply .depend:), as I'm depending on the $^ variable to do the VPATH resolution for me.
If there'd be any way to only update dependencies as a result of updated #include directives, that'd be even better of course.. But I'm not holding my breath for that one.. :)
If you don't want to remake .depend every time, you mustn't have a rule for it. Note that whenever you really need to remake the dependencies file, you must also remake an object file (this is not my insight, it comes from Advanced Auto-Dependency Generation, and it took me some time to grasp it). So construct .depend in the linking rule, using a PHONY target:
DEPEND_FILE = .depend
# put this command in the executable rule
$(MAKE) DEPENDENCIES
.PHONY: DEPENDENCIES
DEPENDENCIES: $(objects:.o=.c)
$(CC) -MM $^ > $(DEPEND_FILE)
-include $(DEPEND_FILE)
You can make things more efficient by having seperate depend files, one for each object, so that when one changes you don't have to recalculate the dependencies of all the objects:
# put this command in the %.o rule
$(CC) -MM $< > $*.d
-include *.d
(EDIT: just corrected a dumb mistake.)

Resources