alexkarle.com

Source for alexkarle.com
git clone git://git.alexkarle.com/alexkarle.com.git
Log | Files | Refs | README | LICENSE

make-obj.txt (3212B) [raw]


      1 # `make obj`: out-of-tree builds with BSD `make(1)`
      2 
      3 _Published: September 28, 2021_
      4 
      5 If you've ever built parts of OpenBSD from source, you may know
      6 that the sequence of commands recommended by
      7 [`release(8)`](https://man.openbsd.org/release.8) is:
      8 
      9 	$ make obj
     10 	$ make
     11 	# make install
     12 
     13 If, like me, you've forgotten the `make obj` step, you'll find
     14 yourself with many derived files in the current directory of
     15 whatever program you're building. By running `make obj` first, a
     16 directory called _obj_ appears and the derived files (usually \*.o
     17 files) are placed there instead.  Cleverly, the _obj_ directory is
     18 actually a symlink to another filesystem under _/usr/obj_,
     19 making it truly an out-of-tree build.
     20 
     21 Up until recently, I understood what the `obj` target did and why
     22 it was useful.  However, it wasn't until I tried to replicate it
     23 with the build for text.alexkarle.com that I discovered how it
     24 worked.  I figured I'd document it here in case it helps anyone
     25 else.
     26 
     27 ## How it Works
     28 
     29 My discovery of the inner workings of this target was a classic
     30 lesson in RTFM.  After 10-15 minutes of trying to parse the
     31 makefiles in _/usr/share/mk_, I finally searched for _obj_ in the
     32 [`make(1)` man page](https://man.openbsd.org/make.1), and sure
     33 enough the answer was the first hit!  I've copied it for
     34 convenience below (licensed under the BSD-3 clause):
     35 
     36 > *`.OBJDIR:`*
     37 > Path to the directory where targets are built.  At
     38 > startup, make searches for an alternate directory to
     39 > place target files. make tries to `chdir(2)` into
     40 > `MAKEOBJDIR` (or obj if `MAKEOBJDIR` is not defined), and
     41 > sets `.OBJDIR` accordingly.  Should that fail, `.OBJDIR`
     42 > is set to `.CURDIR`.
     43 
     44 With this new knowledge, getting an out-of-tree build was almost as
     45 simple as running `mkdir obj` before `make`!
     46 
     47 The one catch was that, having chdir'd in, I had to canonicalize
     48 the paths to any scripts used in the build recipes.  For instance,
     49 I have a genpost.sh script in the bin/ directory of this repo.  To
     50 call it from the obj directory, I needed to use its absolute path
     51 via the .CURDIR variable:
     52 
     53 	$(.CURDIR)/bin/genpost.sh < $< > $@
     54 
     55 ## Portability
     56 
     57 While I mostly build my site on OpenBSD, it's important to me that
     58 it builds with GNU make too.
     59 
     60 Unfortunately, the `.OBJDIR` chdir'ing appears to be an extension in
     61 OpenBSD's make (and possibly NetBSD too). The good news is that,
     62 with one more trick, GNU make support is easy to add (albeit
     63 without out-of-tree builds).
     64 
     65 The one final hack to support GNU make was to define a portable
     66 version of `.CURDIR`.  Since `.CURDIR` isn't defined in GNU make (which
     67 uses `CURDIR` instead), I had to define the `DIR` variable that's the
     68 concatenation of the two:
     69 
     70 	DIR = $(.CURDIR)$(CURDIR)
     71 
     72 ## Conclusion
     73 
     74 I hope this sheds some light on why `make obj` is common practice
     75 on OpenBSD as well as how to add similar support to your own
     76 projects!
     77 
     78 While not as flexible as GNU make's pattern matching inference
     79 rules (that allow builds in subdirectories), I find the chdir-ing
     80 into obj a cleverly simple way to obtain a similar end result.
     81 
     82 ## See Also
     83 
     84 - [text.alexkarle.com's origin story](/blog/text-only.html)
     85 - [writing the blog in mdoc(7)](/blog/my-old-man.html)
     86 
     87 [Back to blog](/blog)