I am writing up a Makefile
and I would like to separate the build and source directories. My initial thought was just “Oh, I can write my rules prepending the source path to the filename and be done with it.”
The problem is that this solution would be super repetitive and doesn't look very nice. What would be the best approach for writing myself a Makefile
that stores targets in a directory distinct from the directory holding my sources.
The program bsdmake has a very good support for storing the built targets in a directory distinct form the one holding the sources. A
Makefile
using this functionality might be a bit harder to write, so I will review the most important techniques in my answer.Choosing a directory to store built targets
The built-in variable
.OBJDIR
contains the name of a directory where targets are built. It is determined like this (excerpt from theman
page):The program
make
willchdir(2)
to.OBJDIR
and setPWD
to that directory before executing any targets. In the absence of any adequate preparation.OBJDIR
is.CURDIR
, therefore we need to create the desired directory — or tree structure — before runningmake
to build our targets.Assume, you choose to rely on the first mechanism to set
.OBJDIR
, you can then organise your build system so that, before runningmake
to build your targets,MAKEOBJDIRPREFIX
is set to suitable value.make
target) prepares the necessary directory or directories under${MAKEOBJDIRPREFIX}
.Makefiles arrangements
We consider a simple
Makefile
and describe arrangements necessary for the previous setup to work.Before building
a.o
the programmake
willchdir(2)
to${.OBJDIR}
and run the compilercc
from that directory. Since the sourcea.c
is located in another directory, the compilercc
will not find it and the compilation will fail. This issue is solved by using the local variables defined bymake
, the previousMakefile
therefore translates to:Note how globbing patterns are used in the last recipe to appropriately select pieces of the sources at the various locations of the command line.
Examples
The build system for freebsd — and possibly netbsd and openbsd — use this functionality to be able to build simultaneously the operating system for various architectures. (It also make cleaning easier!) You could study these Makefiles to gain a better understanding of the techniques involved.
My portable macros bsdowl for bdsmake also support this functionality of
bsdmake
, you could look at the filebps.objdir.mk
and the ocaml examples.