calling sub makefiles in an easy way fails - gcc

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)

Related

How to handle dependencies from recursive Makefile invocations?

I have a C project that consists of a fairly large number of source files, and to make some sense of them, I have put them into subdirectories (with subdirectories). The whole project results in only one executable file, however.
In order to build this project, then, I am using recursive Makefiles, where the Makefile in each non-toplevel directory links all the object files produced in that directory into a concatenated lib.o file (using ld -r, that is). I do have a Makefile system that can build this and works rather fine for what it is, but it cannot support parallel make, which I would like to fix.
The problem is that I cannot figure out a proper way to both force make to descend into each directory's subdirectories, but also have the local lib.o target depend on that without being forced to rebuild even when nothing has changed.
This is how it works, somewhat abbreviated (leaving out CFLAGS and whatnot):
default: build
SUBOBJECTS = $(patsubst %,%/lib.o,$(SUBDIRS))
.PHONY: $(SUBDIRS)
$(SUBDIRS):
#$(MAKE) -C $#
build: $(SUBDIRS) lib.o
lib.o: $(OBJECTS) $(SUBOBJECTS)
$(LD) $(LDFLAGS) -r -o $# $^
This is from a Makefile.common which all other Makefiles include. Every other Makefile would also define their own SUBDIRS and OBJECTS. It might look like this, for instance:
SUBDIRS = dir1 dir2
OBJECTS = object1.o object2.o
include ../Makefile.common # Or ../../Makefile.common, &c.
As you can see from this, the main target is really the build target, which depends on the subdirectories and lib.o. If I invoke parallel make on this, it won't know that lib.o cannot be built until make has already run recursively on the subdirectories and will sometimes attempt that, causing errors. However, if I make lib.o depend on the subdirectories, then lib.o will always be unnecessarily rebuilt on each invocation, in each directory.
Is there a way to solve this? I've wrecked my brains on this for quite a while now without being able to find a way out. I'm only using GNU make, so don't worry too much about being POSIX-compatible.

How to handle different targets for same directories in parallel making

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)

Canonical 'simple project' makefile

Your small C/C++ project has reached a point where it's no longer practical to have all your code in one file. You want to split out a few components. So you make a src/ directory, and then... you have to write a real Makefile. Something more than hello: hello.o. Uh-oh... was it $# or $< or $^? Crap. You don't remember (I never do).
Do you have a 'one-size fits all' simple Makefile that can deal with straightforward source trees? If so, what's in it and why? I'm looking for the smallest, simplest Makefile that can compile a directory full of C files nicely without me having to edit the Makefile every time I add a file. Here's what I have so far:
CXX = clang++
CXXFLAGS = ...
LDFLAGS = ...
EXENAME = main
SRCS = $(wildcard src/*.cc)
OBJS = $(patsubst src%.cc,build%.o, $(SRCS))
all: $(EXENAME)
build/%.o: src/%.cc
#mkdir -p $(dir $#)
$(CXX) -c -o $# $^ $(CXXFLAGS)
$(EXENAME): $(OBJS)
$(CXX) -o $# $^ $(LDFLAGS)
clean:
rm -rf $(EXENAME) build/
This Makefile builds all the .cc files in the src/ directory into .o files in the build/ directory, then links them up into the parent directory.
What would you do differently?
I would reconsider you decision not to have an explicit list of sources-- I think it may cause you trouble in the long run. But if that's your decision, this makefile is pretty good.
In the %.o rule I would use $< instead of $^, so that later you can add dependencies like
build/foo.o: bar.h
And when you're ready, you can take a look at Advanced Auto-Dependency Generation.
I've never used CMake, so I really can't say anything about that. The best that I can offer is a program that we have at school called 'makemake', which automatically makes Makefiles - http://www.cs.rit.edu/~swm/makemake/ It's not a very advanced program, but it gets the job done. On the plus side, it's incredibly easy to use - simply do 'makemake > Makefile' in the directory and you have a Makefile which will build and link all the source files in that directory(C and C++). On the bright side, if you ever add more files, you just run makemake again and you have a new makefile. On the downside, there's no way to keep any custom targets that you've done from one generated makefile to the next.
As for 'one size fits all' makefiles, while you could definitely do that, it takes away from the purpose of the 'make' command in the first place - which is to keep track of the files last modified time, and thus only re-compile the files that have recently changed, or depend on header files that have just changed(although to generate the correct you can use 'makedepend' - http://www.x.org/archive/X11R7.5/doc/man/man1/makedepend.1.html ). You could use what you currently have plus makedepend in order to make a self-updating makefile.
Use automake tools. Its easy to make changes and less burden to the developer. Its as simple as specifying the SOURCES, LDLIBS, LDFLAGS as variables. At first it may seem like a bit weird. But it becomes your favorite as you do more on it.

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.

making all rules depend on the Makefile itself

When I change a Makefile, its rules may have changed, so they should be reevaluated, but make doesn't seem to think so.
Is there any way to say, in a Makefile, that all of its targets, no matter which, depend on the Makefile itself?
(Regardless of its name.)
I'm using GNU make.
This looks like one more simple, useful, logical thing that Make should be able to do, but isn't.
Here is a workaround. If the clean rule is set up correctly, Make can execute it whenever the makefile has been altered, using an empty dummy file as a marker.
-include dummy
dummy: Makefile
#touch $#
#$(MAKE) -s clean
This will work for most targets, that is targets that are actual files and that are removed by clean, and any targets that depend on them. Side-effect targets and some PHONY targets will slip through the net.
Since GNU make version 4.3 it is now possible with the use of those two special variable:
.EXTRA_PREREQS
To add new prerequisite to every target
MAKEFILE_LIST
To get the path of the make file
To have every target depend on the current make file:
Put near the top of the file (before any include since it would affect the MAKEFILE_LIST) the following line:
.EXTRA_PREREQS:= $(abspath $(lastword $(MAKEFILE_LIST)))
To have every target depend on the current make file and also the make files which were included
Put the following line at the end of your file:
.EXTRA_PREREQS+=$(foreach mk, ${MAKEFILE_LIST},$(abspath ${mk}))
The only answer I know to this is to add makefile explicitly to the dependencies. For example,
%.o: %.c makefile
$(CC) $(CFLAGS) -c $<

Resources