chiark / gitweb /
src/jobclient.c: Low-level magic for GNU Make's jobserver protocol.
[distorted-chroot] / Makefile
1 ### -*-makefile-*-
2 ###
3 ### Main maintenance script for chroots
4 ###
5 ### (c) 2018 Mark Wooding
6 ###
7
8 ###----- Licensing notice ---------------------------------------------------
9 ###
10 ### This file is part of the distorted.org.uk chroot maintenance tools.
11 ###
12 ### distorted-chroot is free software: you can redistribute it and/or
13 ### modify it under the terms of the GNU General Public License as
14 ### published by the Free Software Foundation; either version 2 of the
15 ### License, or (at your option) any later version.
16 ###
17 ### distorted-chroot is distributed in the hope that it will be useful,
18 ### but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20 ### General Public License for more details.
21 ###
22 ### You should have received a copy of the GNU General Public License
23 ### along with distorted-chroot.  If not, write to the Free Software
24 ### Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
25 ### USA.
26
27 all::
28 clean::
29 check::
30 .PHONY: all clean check
31 .SECONDEXPANSION: #sorry
32
33 ###--------------------------------------------------------------------------
34 ### Configuration.
35
36 CONFIG_VARS              =
37
38 ## Level of pickiness to aspire to.
39 NOTIFY_FATAL             = 1
40
41 ## Path to this working tree.
42 CONFIG_VARS             += HERE
43 HERE                     = $(abspath .)
44
45 ## Volume group from which to allocate chroot volumes and snapshots.
46 CONFIG_VARS             += VG LVPREFIX
47 VG                       = vg-$(shell hostname)
48 LVPREFIX                 =
49
50 ## Logical volume size, as an LVM option.
51 CONFIG_VARS             += LVSZ SNAPOPT
52 LVSZ                     = -L8G
53 SNAPOPT                  = -L8G
54
55 ## Debian mirror.
56 CONFIG_VARS             += DEBMIRROR
57 DEBMIRROR                = http://deb.debian.org/debian/
58
59 ## APT sources configurations.  (Also, $($d_APTSRC) for each $d in $(DISTS).)
60 CONFIG_VARS             += APTSRC
61 APTSRC                   = etc/aptsrc.conf $(wildcard etc/aptsrc.local.conf)
62
63 ## APT configuration fragment names.  These will be linked into
64 ## `/etc/apt/apt.conf.d' in each chroot.  To put a fragment f in a surprising
65 ## place, set $($f_APTCONFSRC).
66 CONFIG_VARS             += APTCONF
67 APTCONF_DIR              = etc/apt-conf.d
68 APTCONF                  = $(notdir $(wildcard $(APTCONF_DIR)/[0-9]*[!~]))
69
70 ## Proxy setting.
71 CONFIG_VARS             += PROXY
72 PROXY                   := $(shell \
73         eval $$(apt-config $(foreach a,$(APTCONF), -c$(APTCONF_DIR)/$a) \
74                 shell proxy Acquire::http::proxy); \
75         case $${proxy+t} in (t) echo "$$proxy" ;; (*) echo nil ;; esac)
76
77 ## Debian distributions to support.
78 CONFIG_VARS             += PRIMARY_DIST DISTS
79 PRIMARY_DIST             = stretch
80 DISTS                    = $(PRIMARY_DIST) buster bullseye sid
81
82 ## Host's native architecture(s).
83 CONFIG_VARS             += MYARCH NATIVE_ARCHS
84 MYARCH                   = $(shell dpkg --print-architecture)
85 OTHERARCHS               = $(shell dpkg --print-foreign-architectures)
86 NATIVE_ARCHS             = $(MYARCH) $(OTHERARCHS)
87
88 ## Foreign (emulated) architectures to support.
89 CONFIG_VARS             += FOREIGN_ARCHS
90 FOREIGN_ARCHS            =
91
92 ## Master lists of chroots to build and maintain.
93 NATIVE_CHROOTS           = $(foreach a,$(NATIVE_ARCHS), \
94                                 $(foreach d,$(or $($a_DISTS) $(DISTS)), \
95                                         $d-$a))
96 FOREIGN_CHROOTS          = $(foreach a,$(FOREIGN_ARCHS), \
97                                 $(foreach d,$(or $($a_DISTS) $(DISTS)), \
98                                         $d-$a))
99
100 ## Extra packages to be installed in chroots.
101 CONFIG_VARS             += BASE_PACKAGES NATIVE_BASE_PACKAGES FOREIGN_BASE_PACKAGES
102 BASE_PACKAGES            = ccache
103 BASE_PACKAGES           += eatmydata fakeroot
104 BASE_PACKAGES           += locales tzdata
105 BASE_PACKAGES           += libfile-fcntllock-perl
106 NATIVE_BASE_PACKAGES     = build-essential
107 FOREIGN_BASE_PACKAGES    =
108
109 ## Local packages to be compiled and installed in chroots.  Archives can be
110 ## found in `pkg/'.
111 LOCALPKGS                = mLib checkpath
112
113 ## Which host architecture to use for foreign architectures.  It turns out
114 ## that it's best to use a Qemu with the same host bitness as the target
115 ## architecture; otherwise it has to do a difficult job of converting
116 ## arguments and results between kernel ABI flavours.
117 32BIT_QEMUHOST           = $(or $(filter i386,$(NATIVE_ARCHS)),$(TOOLSARCH))
118 64BIT_QEMUHOST           = $(or $(filter amd64,$(NATIVE_ARCHS)),$(TOOLSARCH))
119
120 CONFIG_VARS             += $(foreach a,$(FOREIGN_ARCHS), $a_QEMUHOST)
121 armel_QEMUHOST           = $(32BIT_QEMUHOST)
122 armhf_QEMUHOST           = $(32BIT_QEMUHOST)
123 arm64_QEMUHOST           = $(64BIT_QEMUHOST)
124 i386_QEMUHOST            = $(32BIT_QEMUHOST)
125 amd64_QEMUHOST           = $(64BIT_QEMUHOST)
126
127 ## Qemu architecture names.  These tell us which Qemu binary to use for a
128 ## particular Debian architecture.
129 CONFIG_VARS             += $(foreach a,$(FOREIGN_ARCHS), $a_QEMUARCH)
130 armel_QEMUARCH           = arm
131 armhf_QEMUARCH           = arm
132 arm64_QEMUARCH           = aarch64
133 i386_QEMUARCH            = i386
134 amd64_QEMUARCH           = x86_64
135
136 ## Alias mapping for chroots.
137 CONFIG_VARS             += $(foreach d,$(DISTS), $d_ALIASES)
138 stretch_ALIASES          = oldstable
139 buster_ALIASES           = stable
140 bullseye_ALIASE          = testing
141 sid_ALIASES              = unstable
142
143 ## Which host architecture to use for commonly used tools in foreign chroots.
144 CONFIG_VARS             += TOOLSARCH
145 TOOLSARCH                = $(MYARCH)
146
147 ## A directory in which we can maintain private files and state.
148 CONFIG_VARS             += STATE
149 STATE                    = state
150
151 ## A directory which will be spliced into chroots as `/usr/local.schroot/'.
152 ## This will be our primary point of contact with the chroot.
153 CONFIG_VARS             += LOCAL
154 LOCAL                    = local.schroot
155
156 ## How to run a command as a privileged user.
157 ROOTLY                   = sudo
158
159 ## Files to be copied into a chroot from the host.
160 SCHROOT_COPYFILES        = /etc/resolv.conf
161 SCHROOT_NSSDATABASES     = passwd shadow group gshadow
162
163 ## Local configuration hook.
164 -include local.mk
165
166 ## All chroot names.
167 CONFIG_VARS             += ALL_ARCHS ALL_CHROOTS
168 ALL_ARCHS                = $(NATIVE_ARCHS) $(FOREIGN_ARCHS)
169 ALL_CHROOTS              = $(NATIVE_CHROOTS) $(FOREIGN_CHROOTS)
170
171 ###--------------------------------------------------------------------------
172 ### Utilities.
173
174 ## Hack to force rebuilding.
175 _force:
176 .PHONY: _force
177
178 ## Hack to not delimit function arguments.  (Ugh!)
179 comma                    = ,
180
181 ## Silent-rules machinery.
182 V                        = 0
183 V_AT                     = $(V_AT_$V)
184 V_AT_0                   = @
185 v_print                  = $(call v_print_$V,$1,$2)
186 v_print_0                = printf "  %-8s %s\n" "$1" $(call squote,$2);
187 v_tag                    = $(V_AT)$(call v_print,$1,$@)
188 v_log                    = $(call v_log_$V,$1,$2)
189 v_log_                   = $(call v_log_1,$1,$2)
190 v_log_0                  = $2 >log/$1.log 2>&1
191 v_log_1                  = $(call catchrc,$(call throwrc,$2) 2>&1 | tee log/$1.log)
192 v_echo                   = $(call v_echo_$V,$1)
193 v_echo_0                 = :
194 v_echo_1                 = printf "%s\n" $1
195 CLEANFILES              += log/*.log
196
197 ## Oh, shut up.
198 SILENCE_LVM              = \
199         LVM_SUPPRESS_FD_WARNINGS=1; export LVM_SUPPRESS_FD_WARNINGS
200
201 ##      $(call catchrc,...$(call throwrc,CMD)...)
202 ##
203 ## Catch the exit status of some subpart of a complicated shell rune.
204 catchrc                  = (exec 3>&1; exit $$({ $1; } 4>&1 >&3 3>&-))
205 throwrc                  = { $1; echo $$? >&4; }
206
207 ##      $(call squote,TXT)
208 ##
209 ## Single-quote TXT.
210 squote                   = '$(subst ','\\'',$1)'
211
212 ##      $(call chroot-dist,D-A) -> D
213 ##      $(call chroot-arch,D-A) -> A
214 ##
215 ## Parse chroot descriptions.
216 chroot-dist              = $(patsubst %/,%,$(dir $(subst -,/,$1)))
217 chroot-arch              = $(notdir $(subst -,/,$1))
218
219 ##      $(call package-dir-name,P-V) -> P
220 ##      $(call package-dir-version,P-V) -> V
221 ##
222 ## Parse (source) package directory names.
223 package-dir-name         = $(sort $(foreach p,$(LOCALPKGS),$(if $(filter $p-$($p_VERSION),$1),$p)))
224 package-dir-version      = $($(call package-dir-name,$1)_VERSION)
225
226 ##      $(call package-dir,P-V.A) -> P-V
227 ##      $(call package-name,P-V.A) -> P
228 ##      $(call package-version,P-V.A) -> V
229 ##      $(call package-arch,P-V.A) -> A
230 ##
231 ## Parse package stamp names.
232 package-dir              = $(basename $1)
233 package-name             = $(call package-dir-name,$(call package-dir,$1))
234 package-version          = $(call package-dir-version,$(call package-dir,$1))
235 package-arch             = $(patsubst .%,%,$(suffix $1))
236
237 ##      $(call native-chroot-p,D-A) -> D | <empty>
238 ##
239 ## Answer whether D-A is a native chroot.
240 native-chroot-p          = $(filter $(call chroot-arch,$1),$(NATIVE_ARCHS))
241
242 ##      $(call chroot-qemuhost,D-A) -> AA
243 ##
244 ## Answer the apporopriate Qemu host architecture for foreign chroot D-A.
245 chroot-qemuhost          = $($(call chroot-arch,$1)_QEMUHOST)
246
247 ##      $(call chroot-deps,PRE,D-A) -> PREDD-AA ... | <empty>
248 ##
249 ## Answer a list of additional dependencies for the chroot D-A: specifically,
250 ## if D-A is foreign then include PRE/DD-AA entries for the tools
251 ## architecture, and Qemu host architecture (if that's different).
252 chroot-deps              = $(if $(call native-chroot-p,$2),, \
253                                 $(addprefix $1$(call chroot-dist,$2)-,\
254                                         $(sort $(TOOLSARCH) \
255                                                $(call chroot-qemuhost,$2))))
256
257 ## Substituting placeholders in files.
258 SUBSTITUTIONS           := local=$(shell realpath $(LOCAL))
259 SUBSTITUTIONS           += primary-dist=$(PRIMARY_DIST)
260 subst-file               = { \
261         echo "$1 GENERATED by distorted-chroot: do not edit"; \
262         substs=""; \
263         for v in $(SUBSTITUTIONS); do \
264           var=$${v%%=*} value=$${v\#*=}; \
265           substs="$$substs s\a@$$var@\a$$value\ag;"; \
266         done; \
267         sed "$$substs"; \
268 }
269
270 ###     $(call symlink-ok-p,LINK,DEST)
271 ###
272 ### Expand to `t' if LINK is a symbolic link to DEST, and empty otherwise.
273 symlink-ok-p             = $(shell \
274         case $$(readlink 2>/dev/null $(patsubst %/,%,$1)) in ($2) echo t ;; esac)
275
276 ###     $(call general-notify,SEV,COLOUR,PREFIX,MSG)
277 ###
278 ### Report a message, highlighted in the right way, and maybe fail
279 general-notify           = { \
280         echo "$$(tput bold; tput setaf $2)$3 "$4"$$(tput sgr0; tput op)"; \
281         if [ "$1" -le "$(NOTIFY_FATAL)" ]; then exit 2; fi; \
282 }
283
284 ###     $(call report/SEV,MSG)
285 ###
286 ### Report a notification of a particular severity.
287 notify/INFO              = $(call general-notify,3,6,---,$1)
288 notify/WARN              = $(call general-notify,2,5,???,$1)
289 notify/ERR               = $(call general-notify,1,1,!!!,$1)
290
291 ##      $(call check,SEV,MSG,UNLESS)
292 ##
293 ## If UNLESS completes successfully, all is OK; otherwise print MSG to stderr
294 ## and fail.
295 check                    = @{ \
296         $(call v_echo,'check: '$(call squote,$3)''); \
297         if ! { $3; }; then $(call notify/$1,$2); fi; \
298 }
299
300 ##      $(call check-executable,SEV,PATH)
301 ##
302 ## Verify that PATH is an executable program.
303 check-executable         = $(call check,$1,"\`$2' is not an executable", \
304         [ -x "$2" ])
305
306 ##      $(call check-mountpoint,SEV,DIR)
307 ##
308 ## Verify that DIR is a mountpoint.
309 check-mountpoint         = $(call check,$1,"\`$2' is not a mount point", \
310         mountpoint -q "$2")
311
312 ##      $(call check-symlink,SEV,LINK,DEST)
313 ##
314 ## Verify that LINK is a symbolic link pointing to DEST.
315 check-symlink            = $(call check,$1,"\`$2' is not a link to \`$3'", \
316         [ -L "$2" ] && [ "$$(readlink "$2")" = "$3" ])
317
318 ###--------------------------------------------------------------------------
319 ### Python extensions.
320
321 CC                       = gcc
322 CFLAGS                   = -O2 -g -Wall
323
324 LD                       = $(CC)
325 LDFLAGS                  =
326
327 c-source                 = $(foreach c,$1,src/$c)
328 c-object                 = $(foreach c,$1,$(STATE)/obj/$(basename $c).o)
329
330 PYEXT_PKGFLAGS          := $(shell pkg-config --cflags python2)
331 PYEXT_CFLAGS             = -fPIC -fno-strict-aliasing $(PYEXT_PKGFLAGS)
332 PYEXT_LDFLAGS            = -shared
333
334 PYEXTS                  += jobclient
335 jobclient_SOURCES        = jobclient.c
336
337 PYEXT_ALLSRC             = $(foreach x,$(PYEXTS),\
338                                 $(call c-source,$($x_SOURCES)))
339 PYEXT_ALLOBJ             = $(foreach x,$(PYEXTS),\
340                                 $(call c-object,$($x_SOURCES)))
341 $(PYEXT_ALLOBJ): $(STATE)/obj/%.o: src/%.c
342         $(V_AT)mkdir -p $(dir $@)
343         $(call v_tag,CC)$(CC) -c $(CFLAGS) $(PYEXT_CFLAGS) -o$@ $<
344
345 PYMODULES                = $(foreach x,$(PYEXTS),$(STATE)/lib/python/$x.so)
346 all:: $(PYMODULES)
347 $(PYMODULES): $(STATE)/lib/python/%.so: $$(call c-object,$$($$*_SOURCES))
348         $(V_AT)mkdir -p $(dir $@)
349         $(call v_tag,LD)$(LD) $(LDFLAGS) $(PYEXT_LDFLAGS) -o$@ $^
350
351 ###--------------------------------------------------------------------------
352 ### Scripts.
353
354 SCRIPTS                 += mkbuildchroot
355 SCRIPTS                 += mkchrootconf
356 SCRIPTS                 += install-cross-tools update-cross-tools
357
358 SUBST_SCRIPTS            = $(addprefix $(STATE)/bin/,$(SCRIPTS))
359 all:: $(SUBST_SCRIPTS)
360 $(SUBST_SCRIPTS): $(STATE)/bin/%: bin/% $(STATE)/config.sh
361         $(V_AT)mkdir -p $(dir $@)
362         $(call v_tag,SUBST){ \
363                 sed \
364                 -e '2i### GENERATED by distorted-chroot: do not edit' \
365                 -e '/@@@config@@@/ {' \
366                         -e 'r $(STATE)/config.sh' \
367                         -e 'd'\
368                 -e '}' $<; \
369         } >$@.new && chmod +x $@.new && mv $@.new $@
370
371 ###--------------------------------------------------------------------------
372 ### APT configuration.
373
374 ## In a chroot, `/etc/apt/sources.list' links to
375 ## `/usr/local.schroot/etc/apt/sources.$d' for the appropriate distribution.
376 APT_SOURCES              = $(foreach d,$(DISTS), $(LOCAL)/etc/apt/sources.$d)
377 CLEANFILES              += $(APT_SOURCES)
378 all:: $(APT_SOURCES)
379
380 $(foreach d,$(DISTS), $(STATE)/etc/apt/aptsrc.$d): $(STATE)/etc/apt/aptsrc.%:
381         $(V_AT)mkdir -p $(dir $@)
382         $(call v_tag,GEN){ \
383           echo "### -*-conf-*- GENERATED by distorted-chroot: do not edit"; \
384           echo "subscribe"; \
385           echo "        debian : $*"; \
386         } >$@.new && mv $@.new $@
387
388 $(APT_SOURCES): $(LOCAL)/etc/apt/sources.%: \
389                 $$(APTSRC) $$($$*_APTSRC) $$(STATE)/etc/apt/aptsrc.$$*
390         $(V_AT)mkdir -p $(dir $@)
391         $(call v_tag,GEN)bin/mkaptsrc \
392                 $(APTSRC) $($*_APTSRC) $(STATE)/etc/apt/aptsrc.$* \
393                 >$@.new && mv $@.new $@
394
395 ## In a chroot, a link `/etc/apt/apt.conf.d/FOO' is created for each file in
396 ## `/usr/local.schroot/etc/apt/apt.conf.d/FOO'.
397 APT_CONFIGS            = $(addprefix $(LOCAL)/etc/apt/apt.conf.d/,$(APTCONF))
398 all:: $(APT_CONFIGS)
399 $(APT_CONFIGS): $(LOCAL)/etc/apt/apt.conf.d/%: \
400                 $$(or $$($$*_APTCONFSRC) $$(APTCONF_DIR)/$$*)
401         $(V_AT)mkdir -p $(dir $@)
402         $(call v_tag,COPY)cp $< $@.new && mv $@.new $@
403 clean::; rm -f $(APT_CONFIGS)
404
405 ###--------------------------------------------------------------------------
406 ### Build hacks.
407
408 check::; $(call check-executable,ERR,/usr/bin/eatmydata)
409
410 EATMYDATA_HACKS         += apt-get aptitude dpkg
411 SYMLINK_EATMYDATA_HACKS  = $(addprefix $(LOCAL)/hacks/,$(EATMYDATA_HACKS))
412 all:: $(SYMLINK_EATMYDATA_HACKS)
413 $(SYMLINK_EATMYDATA_HACKS): $(LOCAL)/hacks/%: \
414                 $$(if $$(call symlink-ok-p,$$@,/usr/bin/eatmydata),,_force)
415         $(V_AT)mkdir -p $(dir $@)
416         $(call v_tag,SYMLINK)ln -sf /usr/bin/eatmydata $@.new && mv $@.new $@
417 clean::; rm -f $(SYMLINK_EATMYDATA_HACKS)
418
419 SCRIPT_HACKS            += buildwrap
420 COPY_SCRIPT_HACKS        = $(addprefix $(LOCAL)/hacks/,$(SCRIPT_HACKS))
421 all:: $(COPY_SCRIPT_HACKS)
422 $(COPY_SCRIPT_HACKS): $(LOCAL)/hacks/%: bin/%
423         $(V_AT)mkdir -p $(dir $@)
424         $(call v_tag,COPY)cp $< $@.new && mv $@.new $@
425 clean::; rm -f $(COPY_SCRIPT_HACKS)
426
427 ###--------------------------------------------------------------------------
428 ### `schroot' and `sbuild' configuration.
429
430 all:: schroot-config
431 schroot-config::
432 .PHONY: schroot-config
433
434 check::; $(call check-mountpoint,WARN,/var/lib/sbuild/build)
435 check::; $(call check-symlink,WARN,/build,/var/lib/sbuild/build)
436 check::; $(call check-symlink,ERR,/schroot,/run/schroot/mount)
437
438 %print-varlist           = { \
439         echo "\#\#\# -*-sh-*- GENERATED by distorted-chroot: do not edit"; \
440         $(foreach v,$1, echo $v=\''$(subst ','\'\\\'\'',$($v))'\';) \
441 } #'
442 schroot-config_HASH     := \
443         $(shell $(call %print-varlist,$(CONFIG_VARS)) | \
444                 sha256sum | cut -c1-32)
445 schroot-config_FILE      = $(STATE)/config.sh-$(schroot-config_HASH)
446 $(schroot-config_FILE):
447         $(V_AT)mkdir -p $(STATE)
448         $(V_AT)rm -f $(STATE)/config.sh-*
449         $(call v_tag,STAMP)$(call %print-varlist,$(CONFIG_VARS)) \
450                 >$@.new && mv $@.new $@
451
452 schroot-config:: $(STATE)/config.sh
453 $(STATE)/config.sh: $(schroot-config_FILE)
454         $(call v_tag,SYMLINK)ln -sf $(notdir $<) $@
455
456 schroot-config:: $(STATE)/etc/schroot/sbuild.schroot
457 $(STATE)/etc/schroot/sbuild.schroot: $(STATE)/bin/mkchrootconf
458         $(V_AT)mkdir -p $(dir $@)
459         $(call v_tag,GEN)$(STATE)/bin/mkchrootconf >$@.new && \
460                 $(ROOTLY) chown root:root $@.new && mv $@.new $@
461 check::; $(call check-symlink,WARN,/etc/schroot/chroot.d/sbuild,$(HERE)/$(STATE)/etc/schroot/sbuild.schroot)
462
463 schroot-config:: $(STATE)/etc/schroot/sbuild.profile/copyfiles
464 $(STATE)/etc/schroot/sbuild.profile/copyfiles: $(schroot-config_STAMP)
465         $(V_AT)mkdir -p $(dir $@)
466         $(call v_tag,GEN){ \
467           echo "### -*-conf-*- GENERATED by distorted-chroot: do not edit"; \
468           for i in $(SCHROOT_COPYFILES); do echo "$$i"; done; \
469         } >$@.new && mv $@.new $@
470
471 schroot-config:: $(STATE)/etc/schroot/sbuild.profile/nssdatabases
472 $(STATE)/etc/schroot/sbuild.profile/nssdatabases: $(schroot-config_STAMP)
473         $(V_AT)mkdir -p $(dir $@)
474         $(call v_tag,GEN){ \
475           echo "### -*-conf-*- GENERATED by distorted-chroot: do not edit"; \
476           for i in $(SCHROOT_NSSDATABASES); do echo "$$i"; done; \
477         } >$@.new && mv $@.new $@
478
479 schroot-config:: $(STATE)/etc/schroot/sbuild.profile/fstab
480 $(STATE)/etc/schroot/sbuild.profile/fstab: \
481                 etc/sbuild.fstab.in $(schroot-config_STAMP)
482         $(V_AT)mkdir -p $(dir $@)
483         $(call v_tag,SUBST)$(call subst-file,### -*-conf-*-) \
484                 <$< >$@.new && mv $@.new $@
485
486 check::; $(call check-symlink,WARN,/etc/schroot/sbuild,$(HERE)/$(STATE)/etc/schroot/sbuild.profile)
487
488 schroot-config:: $(STATE)/etc/sbuild.conf
489 $(STATE)/etc/sbuild.conf: etc/sbuild.conf.in $(schroot-config_STAMP)
490         $(V_AT)mkdir -p $(dir $@)
491         $(call v_tag,SUBST)$(call subst-file,### -*-perl-*-) \
492                 <$< >$@.new && mv $@.new $@
493 check::; $(call check-symlink,WARN,/etc/sbuild/sbuild.conf,$(HERE)/$(STATE)/etc/sbuild.conf)
494 check::; $(call check-executable,WARN,/usr/local.schroot/hacks/apt-get)
495
496 SCHROOT_SCRIPTS         += 11private
497 SCHROOT_SCRIPTS         += 15binfmt
498 SCHROOT_SCRIPTS         += 51chrootenv
499 COPY_SCHROOT_SCRIPTS     = $(addprefix $(STATE)/etc/schroot/setup.d/,$(SCHROOT_SCRIPTS))
500 schroot-config:: $(COPY_SCHROOT_SCRIPTS)
501 $(COPY_SCHROOT_SCRIPTS): \
502                 $(STATE)/etc/schroot/setup.d/%: etc/schroot-scripts/%
503         $(V_AT)mkdir -p $(dir $@)
504         $(call v_tag,COPY)cp $< $@.new && mv $@.new $@
505
506 CHECK_SCHROOT_SCRIPTS    = $(addprefix check-script/,$(SCHROOT_SCRIPTS))
507 check:: $(CHECK_SCHROOT_SCRIPTS)
508 $(CHECK_SCHROOT_SCRIPTS): check-script/%:
509         $(call check-symlink,WARN,/etc/schroot/setup.d/$*,$(HERE)/$(STATE)/etc/schroot/setup.d/$*)
510 .PHONY: $(addprefix check-script/,$(SCHROOT_SCRIPTS))
511
512 ###--------------------------------------------------------------------------
513 ### `/usr/local/' structure.
514
515 LOCAL_COMMON_DIRS        = share/ src/
516 all:: $(foreach d,$(LOCAL_COMMON_DIRS),$(LOCAL)/$d)
517 $(foreach d,$(LOCAL_COMMON_DIRS),$(LOCAL)/$d):
518         $(V_AT)mkdir -p $(dir $(patsubst %/,%,$@))
519         $(call v_tag,MKDIR)mkdir $@
520
521 LOCAL_ARCH_DIRS          = bin/ etc/ games/ include/ lib/ libexec/ sbin/
522 LOCAL_ARCH_LINKS         = man
523 man_LINKDEST             = share/man
524 all:: $(foreach a,$(ALL_ARCHS),\
525         $(LOCAL)/$a/ \
526         $(foreach d,$(LOCAL_ARCH_DIRS),$(LOCAL)/$a/$d) \
527         $(foreach d,$(LOCAL_ARCH_LINKS),$(LOCAL)/$a/$d) \
528         $(foreach d,$(LOCAL_COMMON_DIRS),$(LOCAL)/$a/$d))
529
530 $(foreach a,$(ALL_ARCHS),$(LOCAL)/$a/):
531         $(call v_tag,MKDIR)mkdir $@
532 $(foreach a,$(ALL_ARCHS),\
533   $(foreach d,$(LOCAL_ARCH_DIRS),$(LOCAL)/$a/$d)):
534         $(V_AT)mkdir -p $(dir $(patsubst %/,%,$@))
535         $(call v_tag,MKDIR)mkdir $@
536 $(foreach a,$(ALL_ARCHS),\
537   $(foreach d,$(LOCAL_ARCH_LINKS),$(LOCAL)/$a/$d)): \
538                 $$(if $$(call symlink-ok-p,$$@,$$($$(notdir $$@)_LINKDEST)),,_force)
539         $(V_AT)mkdir -p $(notdir $@)
540         $(call v_tag,SYMLINK)ln -sf $($(notdir $@)_LINKDEST) $@
541 $(foreach a,$(ALL_ARCHS),\
542   $(foreach d,$(LOCAL_COMMON_DIRS),$(LOCAL)/$a/$d)): \
543                 $$(if $$(call symlink-ok-p,$$@,../$$(notdir $$(patsubst %/,%,$$@))),,_force)
544         $(V_AT)mkdir -p $(dir $(patsubst %/,%,$@))
545         $(call v_tag,SYMLINK)ln -sf ../$(notdir $(patsubst %/,%,$@)) $(patsubst %/,%,$@)
546
547 ###--------------------------------------------------------------------------
548 ### Constructing chroots.
549
550 chroot-stamp             = $(addprefix $(STATE)/stamp/chroot.,$1)
551 BUILD_CHROOTS            = $(addprefix chroot/,$(ALL_CHROOTS))
552 CHROOT_STAMPS            = $(call chroot-stamp,$(ALL_CHROOTS))
553 setup-chroots: $(BUILD_CHROOTS)
554 $(BUILD_CHROOTS): chroot/%: $(STATE)/stamp/chroot.%
555 .PHONY: setup-chroots $(BUILD_CHROOTS)
556
557 $(CHROOT_STAMPS): $(STATE)/stamp/chroot.%:
558         $(V_AT)mkdir -p $(dir $@) log/
559         $(MAKE) \
560                 $(STATE)/bin/mkbuildchroot $(STATE)/bin/install-cross-tools \
561                 $(STATE)/etc/schroot/sbuild.schroot \
562                 $$(call chroot-deps,$(STATE)/stamp/cross-tools.,$$*)
563         $(call v_tag,CHROOT)$(call v_log,setup-chroot.$*, \
564                 $(SILENCE_LVM); \
565                 $(ROOTLY) $(STATE)/bin/mkbuildchroot \
566                         $(call chroot-dist,$*) $(call chroot-arch,$*))
567         $(V_AT)touch $@
568
569 UPDATE_CHROOTS           = $(addprefix update/,$(ALL_CHROOTS))
570 update-chroots: $(UPDATE_CHROOTS)
571 $(UPDATE_CHROOTS): update/%: $(STATE)/stamp/chroot.%
572         $(V_AT)mkdir -p log/
573         $(MAKE) $(STATE)/bin/install-cross-tools
574         $(call v_tag,UPDATE)$(call v_log,update-chroot.$*, { \
575                 schroot -uroot -csource:$(LVPREFIX)$* -- \
576                         apt-get update && \
577                 schroot -uroot -csource:$(LVPREFIX)$* -- \
578                         apt-get -y dist-upgrade && \
579                 schroot -uroot -csource:$(LVPREFIX)$* -- \
580                         apt-get -y autoremove && \
581                 schroot -uroot -csource:$(LVPREFIX)$* -- \
582                         apt-get -y clean && \
583                 $(if $(filter $*,$(FOREIGN_CHROOTS)), \
584                         $(ROOTLY) $(STATE)/bin/install-cross-tools \
585                                 $(call chroot-dist,$*) \
586                                 $(call chroot-arch,$*), \
587                         :); \
588         })
589 .PHONY: update-chroots $(UPDATE_CHROOTS)
590
591 cross-tools-stamp        = $(addprefix $(STATE)/stamp/cross-tools.,$1)
592 CROSS_TOOLS              = $(addprefix cross-tools/,$(NATIVE_CHROOTS))
593 UPDATE_CROSS_TOOLS       = $(addprefix update-cross-tools/,$(NATIVE_CHROOTS))
594 cross-tools: $(CROSS_TOOLS)
595 update-cross-tools: $(UPDATE_CROSS_TOOLS)
596 $(CROSS_TOOLS): cross-tools/%: $(STATE)/stamp/cross-tools.%
597 define updcross
598         $(V_AT)mkdir -p log/
599         $(MAKE) $(STATE)/bin/update-cross-tools
600         $(call v_tag,UPDCROSS)$(call v_log,update-cross-tools.$*, \
601                 $(STATE)/bin/update-cross-tools \
602                         $(call chroot-dist,$*) \
603                         $(call chroot-arch,$*))
604         $(V_AT)touch $(call cross-tools-stamp,$*)
605 endef
606 $(call cross-tools-stamp,$(NATIVE_CHROOTS)): $(STATE)/stamp/cross-tools.%: \
607                 $$(call chroot-stamp,$$*)
608         $(V_AT)mkdir -p $(dir $@)
609         $(updcross)
610 $(UPDATE_CROSS_TOOLS): update-cross-tools/%: \
611                 $$(call chroot-stamp,$$*) _force
612         $(updcross)
613 .PHONY: cross-tools update-cross-tools $(CROSS_TOOLS) $(UPDATE_CROSS_TOOLS)
614
615 ###--------------------------------------------------------------------------
616 ### Installing basic custom software.
617
618 $(foreach p,$(LOCALPKGS), $(eval $p_VERSION := $(shell \
619         set -- pkg/$p-[0-9]*.tar.gz; \
620         case $$#,$$1 in \
621           (1,*\**) echo "NOT-FOUND"; exit 2 ;; \
622           (1,*) v=$${1#pkg/$p-}; v=$${v%.tar.gz}; echo "$$v" ;; \
623           (*) echo "AMBIGUOUS"; exit 2 ;; \
624         esac)))
625
626 pkg-stamp                = \
627         $(foreach p,$1,$(STATE)/stamp/package.$p-$($p_VERSION).$2)
628 unpack-pkg-stamp         = \
629         $(foreach p,$1,$(STATE)/stamp/unpack.$p-$($p_VERSION))
630 PACKAGE_STAMPS           = \
631         $(foreach a,$(ALL_ARCHS),$(call pkg-stamp,$(LOCALPKGS),$a))
632 INSTALL_PACKAGES         = $(addprefix install/,$(LOCALPKGS))
633 install-packages: $(INSTALL_PACKAGES)
634 $(INSTALL_PACKAGES): install/%: \
635         $$(foreach a,$$(ALL_ARCHS),$$(call pkg-stamp,$$*,$$a))
636
637 $(foreach p,$(LOCALPKGS),$(call unpack-pkg-stamp,$p)): \
638                 $(STATE)/stamp/unpack.%: pkg/%.tar.gz
639         $(V_AT)mkdir -p $(dir $@) $(LOCAL)/src/
640         $(call v_tag,UNPACK){ \
641                 set -e; \
642                 p=$(call package-dir-name,$*); \
643                 v=$(call package-dir-version,$*); \
644                 cd $(LOCAL)/src/; \
645                 $(ROOTLY) rm -rf $$p-*; \
646                 mkdir $$p-$$v.unpack; \
647                 (cd $$p-$$v.unpack && tar xf $(HERE)/$<); \
648                 mv $$p-$$v.unpack/$$p-$$v $$p-$$v; \
649                 rmdir $$p-$$v.unpack/; \
650                 cd $(HERE); \
651                 touch $@; \
652         }
653
654 $(PACKAGE_STAMPS): $(STATE)/stamp/package.%: \
655                 $$(call unpack-pkg-stamp,$$(call package-name,$$*)) \
656                 $$(call chroot-stamp,$$(PRIMARY_DIST)-$$(call package-arch,$$*))
657         $(V_AT)mkdir -p $(dir $@) log/
658         $(call v_tag,BUILD)$(call v_log,install-package.$*, { \
659                 $(SILENCE_LVM); \
660                 schroot -uroot -c$(LVPREFIX)$(PRIMARY_DIST)-$(call package-arch,$*) -- \
661                 sh -exc ' \
662                         mount -oremount$(comma)rw /usr/local.schroot; \
663                         eatmydata apt-get update; \
664                         eatmydata apt-get -y install pkg-config; \
665                         p=$(call package-name,$*); \
666                         v=$(call package-version,$*); \
667                         a=$(call package-arch,$*); \
668                         cd /usr/local/src/$$p-$$v/; \
669                         rm -rf build.$$a/; \
670                         mkdir build.$$a/; \
671                         cd build.$$a/; \
672                         ../configure PKG_CONFIG_PATH=/usr/local/lib/pkgconfig.hidden; \
673                         make -j4; \
674                         make install; \
675                         mkdir -p /usr/local/lib/pkgconfig.hidden; \
676                         mv /usr/local/lib/pkgconfig/*.pc /usr/local/lib/pkgconfig.hidden || :' && \
677                 schroot -uroot -csource:$(LVPREFIX)$(PRIMARY_DIST)-$(call package-arch,$*) -- \
678                         ldconfig; \
679         })
680         $(V_AT)touch $@
681
682 ###--------------------------------------------------------------------------
683 ### Other maintenance targets.
684
685 show:; : $x
686
687 clean::
688         rm -f $(CLEANFILES)
689         rm -rf $(STATE)
690
691 realclean:: clean
692         rm -rf $(LOCAL)
693
694 ###----- That's all, folks --------------------------------------------------