make-obj.7 (3276B) [raw]
1 .Dd September 28, 2021 2 .Dt MAKE-OBJ 7 3 .Os 4 .Sh NAME 5 .Nm make-obj 6 .Nd out-of-tree builds with BSD 7 .Xr make 1 8 .Sh DESCRIPTION 9 If you've ever built parts of OpenBSD from source, 10 you may know that the sequence of commands recommended by 11 .Xr release 8 12 is: 13 .Pp 14 .Bd -literal -offset indent 15 $ make obj 16 $ make 17 # make install 18 .Ed 19 .Pp 20 If, like me, you've forgotten the 21 .Ql make obj 22 step, 23 you'll find yourself with many derived files in the 24 current directory of whatever program you're building. 25 By running 26 .Ql make obj 27 first, 28 a directory called 29 .Pa obj 30 appears and the derived files 31 (usually 32 .Pa *.o 33 files) are placed there instead. 34 Cleverly, the 35 .Pa obj 36 directory is actually a symlink to 37 another filesystem under 38 .Pa /usr/obj , 39 making it truly an out-of-tree build. 40 .Pp 41 Up until recently, 42 I understood what the 43 .Ql obj 44 target did and why it was useful. 45 However, it wasn't until I tried to replicate it with the 46 build for text.alexkarle.com 47 that I discovered how it worked. 48 I figured I'd document it here in case it helps anyone else. 49 .Sh HOW IT WORKS 50 My discovery of the inner workings of this target was a classic 51 lesson in RTFM. 52 After 10-15 minutes of trying to parse the makefiles in 53 .Pa /usr/share/mk , 54 I finally searched for 55 .Pa obj 56 in the 57 .Xr make 1 58 man page, 59 and sure enough the answer was the first hit! 60 I've copied it for convenience below 61 (licensed under the BSD-3 clause): 62 .Pp 63 .Bl -tag -offset indent 64 .It Va .OBJDIR 65 Path to the directory where targets are built. 66 At startup, 67 .Ic make 68 searches for an alternate directory to place target files. 69 .Ic make 70 tries to 71 .Xr chdir 2 into 72 .Ev MAKEOBJDIR 73 (or 74 .Pa obj 75 if 76 .Ev MAKEOBJDIR 77 is not defined), 78 and sets 79 .Va .OBJDIR 80 accordingly. 81 Should that fail, 82 .Va .OBJDIR 83 is set to 84 .Va .CURDIR . 85 .El 86 .Pp 87 With this new knowledge, 88 getting an out-of-tree build was almost as simple as running 89 .Ql mkdir obj 90 before 91 .Ql make ! 92 .Pp 93 The one catch was that, 94 having chdir'd in, 95 I had to canonicalize the paths to any scripts used in the build recipes. 96 For instance, 97 I have a genpost.sh script in the 98 .Pa bin/ 99 directory of this repo. 100 To call it from the 101 .Pa obj 102 directory, 103 I needed to use its absolute path via the 104 .Va .CURDIR 105 variable: 106 .Pp 107 .Dl $(.CURDIR)/bin/genpost.sh < $< > $@ 108 .Sh PORTABILITY 109 While I mostly build my site on OpenBSD, 110 it's important to me that it builds with GNU make too. 111 .Pp 112 Unfortunately, 113 the 114 .Va .OBJDIR 115 chdir'ing appears to be an extension in OpenBSD's 116 make (and possibly NetBSD too). 117 The good news is that, 118 with one more trick, 119 GNU make support is easy to add 120 (albeit without out-of-tree builds). 121 .Pp 122 The one final hack to support GNU make was to define 123 a portable version of 124 .Va .CURDIR . 125 Since 126 .Va .CURDIR 127 isn't defined in GNU make (which uses 128 .Va CURDIR 129 instead), 130 I had to define the 131 .Va DIR 132 variable that's the concatenation of the two: 133 .Pp 134 .Dl DIR = $(.CURDIR)$(CURDIR) 135 .Pp 136 .Sh CONCLUSION 137 I hope this sheds some light on why 138 .Ql make obj 139 is common practice on OpenBSD as well as 140 how to add similar support to your own projects! 141 .Pp 142 While not as flexible as GNU make's pattern matching 143 inference rules (that allow builds in subdirectories), 144 I find the chdir-ing into 145 .Pa obj 146 a cleverly simple way 147 to obtain a similar end result. 148 .Sh SEE ALSO 149 .Bl -bullet -compact 150 .It 151 .Xr blog 7 152 .It 153 .Xr text-only 7 154 .It 155 .Xr my-old-man 7 156 .El