chiark / gitweb /
More work in progress.
[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 ### Scripts.
320
321 SCRIPTS                 += mkbuildchroot
322 SCRIPTS                 += mkchrootconf
323 SCRIPTS                 += install-cross-tools update-cross-tools
324
325 SUBST_SCRIPTS            = $(addprefix $(STATE)/bin/,$(SCRIPTS))
326 all:: $(SUBST_SCRIPTS)
327 $(SUBST_SCRIPTS): $(STATE)/bin/%: bin/% $(STATE)/config.sh
328         $(V_AT)mkdir -p $(dir $@)
329         $(call v_tag,SUBST){ \
330                 sed \
331                 -e '2i### GENERATED by distorted-chroot: do not edit' \
332                 -e '/@@@config@@@/ {' \
333                         -e 'r $(STATE)/config.sh' \
334                         -e 'd'\
335                 -e '}' $<; \
336         } >$@.new && chmod +x $@.new && mv $@.new $@
337
338 ###--------------------------------------------------------------------------
339 ### APT configuration.
340
341 ## In a chroot, `/etc/apt/sources.list' links to
342 ## `/usr/local.schroot/etc/apt/sources.$d' for the appropriate distribution.
343 APT_SOURCES              = $(foreach d,$(DISTS), $(LOCAL)/etc/apt/sources.$d)
344 CLEANFILES              += $(APT_SOURCES)
345 all:: $(APT_SOURCES)
346
347 $(foreach d,$(DISTS), $(STATE)/etc/apt/aptsrc.$d): $(STATE)/etc/apt/aptsrc.%:
348         $(V_AT)mkdir -p $(dir $@)
349         $(call v_tag,GEN){ \
350           echo "### -*-conf-*- GENERATED by distorted-chroot: do not edit"; \
351           echo "subscribe"; \
352           echo "        debian : $*"; \
353         } >$@.new && mv $@.new $@
354
355 $(APT_SOURCES): $(LOCAL)/etc/apt/sources.%: \
356                 $$(APTSRC) $$($$*_APTSRC) $$(STATE)/etc/apt/aptsrc.$$*
357         $(V_AT)mkdir -p $(dir $@)
358         $(call v_tag,GEN)bin/mkaptsrc \
359                 $(APTSRC) $($*_APTSRC) $(STATE)/etc/apt/aptsrc.$* \
360                 >$@.new && mv $@.new $@
361
362 ## In a chroot, a link `/etc/apt/apt.conf.d/FOO' is created for each file in
363 ## `/usr/local.schroot/etc/apt/apt.conf.d/FOO'.
364 APT_CONFIGS            = $(addprefix $(LOCAL)/etc/apt/apt.conf.d/,$(APTCONF))
365 all:: $(APT_CONFIGS)
366 $(APT_CONFIGS): $(LOCAL)/etc/apt/apt.conf.d/%: \
367                 $$(or $$($$*_APTCONFSRC) $$(APTCONF_DIR)/$$*)
368         $(V_AT)mkdir -p $(dir $@)
369         $(call v_tag,COPY)cp $< $@.new && mv $@.new $@
370 clean::; rm -f $(APT_CONFIGS)
371
372 ###--------------------------------------------------------------------------
373 ### Build hacks.
374
375 check::; $(call check-executable,ERR,/usr/bin/eatmydata)
376
377 EATMYDATA_HACKS         += apt-get aptitude dpkg
378 SYMLINK_EATMYDATA_HACKS  = $(addprefix $(LOCAL)/hacks/,$(EATMYDATA_HACKS))
379 all:: $(SYMLINK_EATMYDATA_HACKS)
380 $(SYMLINK_EATMYDATA_HACKS): $(LOCAL)/hacks/%: \
381                 $$(if $$(call symlink-ok-p,$$@,/usr/bin/eatmydata),,_force)
382         $(V_AT)mkdir -p $(dir $@)
383         $(call v_tag,SYMLINK)ln -sf /usr/bin/eatmydata $@.new && mv $@.new $@
384 clean::; rm -f $(SYMLINK_EATMYDATA_HACKS)
385
386 SCRIPT_HACKS            += buildwrap
387 COPY_SCRIPT_HACKS        = $(addprefix $(LOCAL)/hacks/,$(SCRIPT_HACKS))
388 all:: $(COPY_SCRIPT_HACKS)
389 $(COPY_SCRIPT_HACKS): $(LOCAL)/hacks/%: bin/%
390         $(V_AT)mkdir -p $(dir $@)
391         $(call v_tag,COPY)cp $< $@.new && mv $@.new $@
392 clean::; rm -f $(COPY_SCRIPT_HACKS)
393
394 ###--------------------------------------------------------------------------
395 ### `schroot' and `sbuild' configuration.
396
397 all:: schroot-config
398 schroot-config::
399 .PHONY: schroot-config
400
401 check::; $(call check-mountpoint,WARN,/var/lib/sbuild/build)
402 check::; $(call check-symlink,WARN,/build,/var/lib/sbuild/build)
403 check::; $(call check-symlink,ERR,/schroot,/run/schroot/mount)
404
405 %print-varlist           = { \
406         echo "\#\#\# -*-sh-*- GENERATED by distorted-chroot: do not edit"; \
407         $(foreach v,$1, echo $v=\''$(subst ','\'\\\'\'',$($v))'\';) \
408 } #'
409 schroot-config_HASH     := \
410         $(shell $(call %print-varlist,$(CONFIG_VARS)) | \
411                 sha256sum | cut -c1-32)
412 schroot-config_FILE      = $(STATE)/config.sh-$(schroot-config_HASH)
413 $(schroot-config_FILE):
414         $(V_AT)mkdir -p $(STATE)
415         $(V_AT)rm -f $(STATE)/config.sh-*
416         $(call v_tag,STAMP)$(call %print-varlist,$(CONFIG_VARS)) \
417                 >$@.new && mv $@.new $@
418
419 schroot-config:: $(STATE)/config.sh
420 $(STATE)/config.sh: $(schroot-config_FILE)
421         $(call v_tag,SYMLINK)ln -sf $(notdir $<) $@
422
423 schroot-config:: $(STATE)/etc/schroot/sbuild.schroot
424 $(STATE)/etc/schroot/sbuild.schroot: $(STATE)/bin/mkchrootconf
425         $(V_AT)mkdir -p $(dir $@)
426         $(call v_tag,GEN)$(STATE)/bin/mkchrootconf >$@.new && \
427                 $(ROOTLY) chown root:root $@.new && mv $@.new $@
428 check::; $(call check-symlink,WARN,/etc/schroot/chroot.d/sbuild,$(HERE)/$(STATE)/etc/schroot/sbuild.schroot)
429
430 schroot-config:: $(STATE)/etc/schroot/sbuild.profile/copyfiles
431 $(STATE)/etc/schroot/sbuild.profile/copyfiles: $(schroot-config_STAMP)
432         $(V_AT)mkdir -p $(dir $@)
433         $(call v_tag,GEN){ \
434           echo "### -*-conf-*- GENERATED by distorted-chroot: do not edit"; \
435           for i in $(SCHROOT_COPYFILES); do echo "$$i"; done; \
436         } >$@.new && mv $@.new $@
437
438 schroot-config:: $(STATE)/etc/schroot/sbuild.profile/nssdatabases
439 $(STATE)/etc/schroot/sbuild.profile/nssdatabases: $(schroot-config_STAMP)
440         $(V_AT)mkdir -p $(dir $@)
441         $(call v_tag,GEN){ \
442           echo "### -*-conf-*- GENERATED by distorted-chroot: do not edit"; \
443           for i in $(SCHROOT_NSSDATABASES); do echo "$$i"; done; \
444         } >$@.new && mv $@.new $@
445
446 schroot-config:: $(STATE)/etc/schroot/sbuild.profile/fstab
447 $(STATE)/etc/schroot/sbuild.profile/fstab: \
448                 etc/sbuild.fstab.in $(schroot-config_STAMP)
449         $(V_AT)mkdir -p $(dir $@)
450         $(call v_tag,SUBST)$(call subst-file,### -*-conf-*-) \
451                 <$< >$@.new && mv $@.new $@
452
453 check::; $(call check-symlink,WARN,/etc/schroot/sbuild,$(HERE)/$(STATE)/etc/schroot/sbuild.profile)
454
455 schroot-config:: $(STATE)/etc/sbuild.conf
456 $(STATE)/etc/sbuild.conf: etc/sbuild.conf.in $(schroot-config_STAMP)
457         $(V_AT)mkdir -p $(dir $@)
458         $(call v_tag,SUBST)$(call subst-file,### -*-perl-*-) \
459                 <$< >$@.new && mv $@.new $@
460
461 SCHROOT_SCRIPTS         += 11private
462 SCHROOT_SCRIPTS         += 15binfmt
463 SCHROOT_SCRIPTS         += 51chrootenv
464 COPY_SCHROOT_SCRIPTS     = $(addprefix $(STATE)/etc/schroot/setup.d/,$(SCHROOT_SCRIPTS))
465 schroot-config:: $(COPY_SCHROOT_SCRIPTS)
466 $(COPY_SCHROOT_SCRIPTS): \
467                 $(STATE)/etc/schroot/setup.d/%: etc/schroot-scripts/%
468         $(V_AT)mkdir -p $(dir $@)
469         $(call v_tag,COPY)cp $< $@.new && mv $@.new $@
470
471 CHECK_SCHROOT_SCRIPTS    = $(addprefix check-script/,$(SCHROOT_SCRIPTS))
472 check:: $(CHECK_SCHROOT_SCRIPTS)
473 $(CHECK_SCHROOT_SCRIPTS): check-script/%:
474         $(call check-symlink,WARN,/etc/schroot/setup.d/$*,$(HERE)/$(STATE)/etc/schroot/setup.d/$*)
475 .PHONY: $(addprefix check-script/,$(SCHROOT_SCRIPTS))
476
477 ###--------------------------------------------------------------------------
478 ### `/usr/local/' structure.
479
480 LOCAL_COMMON_DIRS        = share/ src/
481 all:: $(foreach d,$(LOCAL_COMMON_DIRS),$(LOCAL)/$d)
482 $(foreach d,$(LOCAL_COMMON_DIRS),$(LOCAL)/$d):
483         $(V_AT)mkdir -p $(dir $(patsubst %/,%,$@))
484         $(call v_tag,MKDIR)mkdir $@
485
486 LOCAL_ARCH_DIRS          = bin/ etc/ games/ include/ lib/ libexec/ sbin/
487 LOCAL_ARCH_LINKS         = man
488 man_LINKDEST             = share/man
489 all:: $(foreach a,$(ALL_ARCHS),\
490         $(LOCAL)/$a/ \
491         $(foreach d,$(LOCAL_ARCH_DIRS),$(LOCAL)/$a/$d) \
492         $(foreach d,$(LOCAL_ARCH_LINKS),$(LOCAL)/$a/$d) \
493         $(foreach d,$(LOCAL_COMMON_DIRS),$(LOCAL)/$a/$d))
494
495 $(foreach a,$(ALL_ARCHS),$(LOCAL)/$a/):
496         $(call v_tag,MKDIR)mkdir $@
497 $(foreach a,$(ALL_ARCHS),\
498   $(foreach d,$(LOCAL_ARCH_DIRS),$(LOCAL)/$a/$d)):
499         $(V_AT)mkdir -p $(dir $(patsubst %/,%,$@))
500         $(call v_tag,MKDIR)mkdir $@
501 $(foreach a,$(ALL_ARCHS),\
502   $(foreach d,$(LOCAL_ARCH_LINKS),$(LOCAL)/$a/$d)): \
503                 $$(if $$(call symlink-ok-p,$$@,$$($$(notdir $$@)_LINKDEST)),,_force)
504         $(V_AT)mkdir -p $(notdir $@)
505         $(call v_tag,SYMLINK)ln -sf $($(notdir $@)_LINKDEST) $@
506 $(foreach a,$(ALL_ARCHS),\
507   $(foreach d,$(LOCAL_COMMON_DIRS),$(LOCAL)/$a/$d)): \
508                 $$(if $$(call symlink-ok-p,$$@,../$$(notdir $$(patsubst %/,%,$$@))),,_force)
509         $(V_AT)mkdir -p $(dir $(patsubst %/,%,$@))
510         $(call v_tag,SYMLINK)ln -sf ../$(notdir $(patsubst %/,%,$@)) $(patsubst %/,%,$@)
511
512 ###--------------------------------------------------------------------------
513 ### Constructing chroots.
514
515 chroot-stamp             = $(addprefix $(STATE)/stamp/chroot.,$1)
516 BUILD_CHROOTS            = $(addprefix chroot/,$(ALL_CHROOTS))
517 CHROOT_STAMPS            = $(call chroot-stamp,$(ALL_CHROOTS))
518 setup-chroots: $(BUILD_CHROOTS)
519 $(BUILD_CHROOTS): chroot/%: $(STATE)/stamp/chroot.%
520 .PHONY: setup-chroots $(BUILD_CHROOTS)
521
522 $(CHROOT_STAMPS): $(STATE)/stamp/chroot.%: \
523                 $$(call chroot-deps,$(STATE)/stamp/cross-tools.,$$*)
524         $(V_AT)mkdir -p $(dir $@) log/
525         $(MAKE) \
526                 $(STATE)/bin/mkbuildchroot $(STATE)/bin/install-cross-tools \
527                 $(STATE)/etc/schroot/sbuild.schroot
528         $(call v_tag,CHROOT)$(call v_log,setup-chroot.$*, \
529                 $(SILENCE_LVM); \
530                 $(ROOTLY) $(STATE)/bin/mkbuildchroot \
531                         $(call chroot-dist,$*) $(call chroot-arch,$*))
532         $(V_AT)touch $@
533
534 UPDATE_CHROOTS           = $(addprefix update/,$(ALL_CHROOTS))
535 update-chroots: $(UPDATE_CHROOTS)
536 $(UPDATE_CHROOTS): update/%: $(STATE)/stamp/chroot.%
537         $(V_AT)mkdir -p log/
538         $(MAKE) $(STATE)/bin/install-cross-tools
539         $(call v_tag,UPDATE)$(call v_log,update-chroot.$*, { \
540                 schroot -uroot -csource:$(LVPREFIX)$* -- \
541                         apt-get update && \
542                 schroot -uroot -csource:$(LVPREFIX)$* -- \
543                         apt-get -y dist-upgrade && \
544                 schroot -uroot -csource:$(LVPREFIX)$* -- \
545                         apt-get -y autoremove && \
546                 schroot -uroot -csource:$(LVPREFIX)$* -- \
547                         apt-get -y clean && \
548                 $(if $(filter $*,$(FOREIGN_CHROOTS)), \
549                         $(ROOTLY) $(STATE)/bin/install-cross-tools \
550                                 $(call chroot-dist,$*) \
551                                 $(call chroot-arch,$*), \
552                         :); \
553         })
554 .PHONY: update-chroots $(UPDATE_CHROOTS)
555
556 cross-tools-stamp        = $(addprefix $(STATE)/stamp/cross-tools.,$1)
557 CROSS_TOOLS              = $(addprefix cross-tools/,$(NATIVE_CHROOTS))
558 UPDATE_CROSS_TOOLS       = $(addprefix update-cross-tools/,$(NATIVE_CHROOTS))
559 cross-tools: $(CROSS_TOOLS)
560 update-cross-tools: $(UPDATE_CROSS_TOOLS)
561 $(CROSS_TOOLS): cross-tools/%: $(STATE)/stamp/cross-tools.%
562 define updcross
563         $(V_AT)mkdir -p log/
564         $(MAKE) $(STATE)/bin/update-cross-tools
565         $(call v_tag,UPDCROSS)$(call v_log,update-cross-tools.$*, \
566                 $(STATE)/bin/update-cross-tools \
567                         $(call chroot-dist,$*) \
568                         $(call chroot-arch,$*))
569         $(V_AT)touch $(call cross-tools-stamp,$*)
570 endef
571 $(call cross-tools-stamp,$(NATIVE_CHROOTS)): $(STATE)/stamp/cross-tools.%: \
572                 $$(call chroot-stamp,$$*)
573         $(V_AT)mkdir -p $(dir $@)
574         $(updcross)
575 $(UPDATE_CROSS_TOOLS): update-cross-tools/%: \
576                 $$(call chroot-stamp,$$*) _force
577         $(updcross)
578 .PHONY: cross-tools update-cross-tools $(CROSS_TOOLS) $(UPDATE_CROSS_TOOLS)
579
580 ###--------------------------------------------------------------------------
581 ### Installing basic custom software.
582
583 $(foreach p,$(LOCALPKGS), $(eval $p_VERSION := $(shell \
584         set -- pkg/$p-[0-9]*.tar.gz; \
585         case $$#,$$1 in \
586           (1,*\**) echo "NOT-FOUND"; exit 2 ;; \
587           (1,*) v=$${1#pkg/$p-}; v=$${v%.tar.gz}; echo "$$v" ;; \
588           (*) echo "AMBIGUOUS"; exit 2 ;; \
589         esac)))
590
591 pkg-stamp                = \
592         $(foreach p,$1,$(STATE)/stamp/package.$p-$($p_VERSION).$2)
593 unpack-pkg-stamp         = \
594         $(foreach p,$1,$(STATE)/stamp/unpack.$p-$($p_VERSION))
595 PACKAGE_STAMPS           = \
596         $(foreach a,$(ALL_ARCHS),$(call pkg-stamp,$(LOCALPKGS),$a))
597 INSTALL_PACKAGES         = $(addprefix install/,$(LOCALPKGS))
598 install-packages: $(INSTALL_PACKAGES)
599 $(INSTALL_PACKAGES): install/%: \
600         $$(foreach a,$$(ALL_ARCHS),$$(call pkg-stamp,$$*,$$a))
601
602 $(foreach p,$(LOCALPKGS),$(call unpack-pkg-stamp,$p)): \
603                 $(STATE)/stamp/unpack.%: pkg/%.tar.gz
604         $(V_AT)mkdir -p $(dir $@) $(LOCAL)/src/
605         $(call v_tag,UNPACK){ \
606                 set -e; \
607                 p=$(call package-dir-name,$*); \
608                 v=$(call package-dir-version,$*); \
609                 cd $(LOCAL)/src/; \
610                 $(ROOTLY) rm -rf $$p-*; \
611                 mkdir $$p-$$v.unpack; \
612                 (cd $$p-$$v.unpack && tar xf $(HERE)/$<); \
613                 mv $$p-$$v.unpack/$$p-$$v $$p-$$v; \
614                 rmdir $$p-$$v.unpack/; \
615                 cd $(HERE); \
616                 touch $@; \
617         }
618
619 $(PACKAGE_STAMPS): $(STATE)/stamp/package.%: \
620                 $$(call unpack-pkg-stamp,$$(call package-name,$$*)) \
621                 $$(call chroot-stamp,$$(PRIMARY_DIST)-$$(call package-arch,$$*))
622         $(V_AT)mkdir -p $(dir $@) log/
623         $(call v_tag,BUILD)$(call v_log,install-package.$*, { \
624                 $(SILENCE_LVM); \
625                 schroot -uroot -c$(LVPREFIX)$(PRIMARY_DIST)-$(call package-arch,$*) -- \
626                 sh -exc ' \
627                         mount -oremount$(comma)rw /usr/local.schroot; \
628                         eatmydata apt-get update; \
629                         eatmydata apt-get -y install pkg-config; \
630                         p=$(call package-name,$*); \
631                         v=$(call package-version,$*); \
632                         a=$(call package-arch,$*); \
633                         cd /usr/local/src/$$p-$$v/; \
634                         rm -rf build.$$a/; \
635                         mkdir build.$$a/; \
636                         cd build.$$a/; \
637                         ../configure PKG_CONFIG_PATH=/usr/local/lib/pkgconfig.hidden; \
638                         make -j4; \
639                         make install; \
640                         mkdir -p /usr/local/lib/pkgconfig.hidden; \
641                         mv /usr/local/lib/pkgconfig/*.pc /usr/local/lib/pkgconfig.hidden || :' && \
642                 schroot -uroot -csource:$(LVPREFIX)$(PRIMARY_DIST)-$(call package-arch,$*) -- \
643                         ldconfig; \
644         })
645         $(V_AT)touch $@
646
647 ###--------------------------------------------------------------------------
648 ### Other maintenance targets.
649
650 show:; : $x
651
652 clean::
653         rm -f $(CLEANFILES)
654         rm -rf $(STATE)
655
656 realclean:: clean
657         rm -rf $(LOCAL)
658
659 ###----- That's all, folks --------------------------------------------------