1/*
2 * source and binary package support
3 *
4 * @(#)package.mk (AT&T Research) 2012-02-14
5 *
6 * usage:
7 *
8 *	cd $INSTALLROOT/lib/package
9 *	nmake -f name [closure] [cyg|exp|lcl|pkg|rpm|tgz] [base|delta] type
10 *
11 * where:
12 *
13 *	name	package description file or component
14 *
15 *	type	source	build source archive, generates
16 *			$(PACKAGEDIR)/name.version.release.suffix
17 *		binary	build binary archive, generates
18 *			$(PACKAGEDIR)/name.version.hosttype.release.suffix
19 *		runtime	build binary archive, generates
20 *			$(PACKAGEDIR)/name-run.version.hosttype.release.suffix
21 *
22 * NOTE: $(PACKAGEDIR) is in the lowest view and is shared among all views
23 *
24 * generated archive member files are $(PACKAGEROOT) relative
25 *
26 * main assertions:
27 *
28 *	NAME [ name=value ] :PACKAGE: component ...
29 *	:OMIT: component ...
30 *	:LICENSE: license-class-pattern
31 *	:CATEGORY: category-id ...
32 *	:COVERS: package ...
33 *	:REQURES: package ...
34 *	:INDEX: index description line
35 *	:DESCRIPTION:
36 *		[ verbose description ]
37 *	:DETAILS: style
38 *		:README:
39 *			readme lines
40 *		:EXPORT:
41 *			name=value
42 *		target :INSTALL: [ source ]
43 *
44 * option variables, shown with default values
45 *
46 *	format=tgz
47 *		archive format
48 *
49 *	version=YYYY-MM-DD
50 *		package base version (overrides current date)
51 *
52 *	release=YYYY-MM-DD
53 *		package delta release (overrides current date)
54 *
55 *	license=type.class
56 *		:LICENSE: type.class pattern override
57 *
58 *	notice=1
59 *		include the conspicuous empty notice file
60 *
61 *	copyright=0
62 *		do not prepend source file copyright notice
63 *
64 *	strip=0
65 *		don't strip non-lcl binary package members
66 *
67 *	variants=pattern
68 *		include variants matching pattern in binary packages
69 *
70 *	incremental=[source:1 binary:0]
71 *		if a base archive is generated then also generate an
72 *		incremental delta archive from the previous base
73 *
74 * NOTE: the Makerules.mk :PACKAGE: operator defers to :package: when
75 *	 a target is specified
76 */
77
78/* these are ast centric -- we'll parameterize another day */
79
80org = ast
81url = http://www.research.att.com/sw/download
82
83/* generic defaults */
84
85base =
86category = utils
87checksum = md5
88closure =
89copyright = 1
90delta =
91format = tgz
92incremental =
93index =
94init = INIT
95license =
96licenses = $(org)
97mamfile = 1
98opt =
99name =
100notice =
101release =
102strip = 0
103style = tgz
104suffix = tgz
105type =
106variants = !(cc-g)
107vendor =
108version = $("":T=R%Y-%m-%d)
109
110SUM = sum
111
112package.notice = ------------ NOTICE -- LICENSED SOFTWARE -- SEE README FOR DETAILS ------------
113
114package.readme = $(@.package.readme.)
115
116.package.readme. :
117	This is a package root directory $PACKAGEROOT. Source and binary
118	packages in this directory tree are controlled by the command
119	$()
120		bin/package
121	$()
122	Binary files may be in this directory or in the install root directory
123	$()
124		INSTALLROOT=$PACKAGEROOT/arch/`bin/package`
125	$()
126	For more information run
127	$()
128		bin/package help
129	$()
130	Many of the packaged commands self-document via the --man and --html
131	options; those that do have no separate man page.
132	$()
133	Each package is covered by one of the license files
134	$()
135		$(PACKAGELIB)/LICENSES/<license>
136	$()
137	where <license> is the license type for the package.  At the top
138	of each license file is a URL; the license covers all software that
139	refers to this URL. For details run
140	$()
141		bin/package license [<package>]
142	$()
143	Any archives, distributions or packages made from source or
144	binaries covered by license(s) must contain the corresponding
145	license file(s)$(notice:?, this README file, and the empty file$$("\n")$$(package.notice)?.?)
146
147.package.licenses. : .FUNCTION
148	local I F L R T all save text
149	L := $(%)
150	while L == "--*"
151		I := $(L:O=1)
152		if I == "--all"
153			all = 1
154		elif I == "--save"
155			save = 1
156		elif I == "--text"
157			text = 1
158		end
159		L := $(L:O>1)
160	end
161	if "$(L)" == "*-*"
162		L += $(L:/[^-]*-//) $(L:/-.*//)
163	end
164	L += $(licenses)
165	for I $(L:U)
166		if I == "gpl"
167			I = gnu
168			all =
169		end
170		if F = "$(I:D=$(PACKAGESRC):B:S=.lic:T=F)"
171			R += $(F)
172			if save || text
173				T := $(.FIND. lib/package .lic $(F):P=W,query=type)
174				R += $(T:D=$(PACKAGESRC)/LICENSES:B)
175			end
176			if save
177				R += $(F:T=I:N=*.def:D=$(PACKAGESRC):B:S:T=F)
178			elif ! all
179				break
180			end
181		end
182	end
183	return $(R)
184
185/*
186 * glob(3) doesn't handle / in alternation -- should it?
187 */
188
189.package.glob. : .FUNCTION
190	local A D I P S
191	for I $(%)
192		if I == "*/*"
193			D := $(I:C,/.*,,)
194			if ! "$(A:N=$(D))"
195				local S.$(D)
196				A += $(D)
197			end
198			S.$(D) += $(I:C,[^/]*/,,)
199		else
200			P := $(P)$(S)$(I)
201		end
202		S = |
203	end
204	if P == "*\|*"
205		P := ($(P))
206	end
207	for I $(A)
208		P += $(I)/$(.package.glob. $(S.$(I)))
209	end
210	return $(P)
211
212
213.MAKEINIT : .package.init
214
215.package.init : .MAKE .VIRTUAL .FORCE
216	local V
217	V := $(VROOT:T=F:P=L*)
218	if ! PACKAGEROOT
219	PACKAGEROOT := $(V:N!=*/arch/+([!/]):O=1)
220	end
221	if V == "$(PACKAGEROOT)"
222		V :=
223	end
224	V += $(INSTALLROOT) $(PACKAGEROOT)
225	PACKAGEVIEW := $(V:H=RU)
226	INSTALLOFFSET := $(INSTALLROOT:C%$(PACKAGEROOT)/%%)
227	if license
228		license := $(license)|none.none
229	end
230
231PACKAGELIB = lib/package
232PACKAGESRC = $(PACKAGEROOT)/$(PACKAGELIB)
233PACKAGEBIN = $(INSTALLROOT)/$(PACKAGELIB)
234PACKAGEDIR = $(PACKAGESRC)/$(style)
235INSTALLOFFSET = $(INSTALLROOT:C%$(PACKAGEROOT)/%%)
236
237package.omit = -|*/$(init)
238package.glob.all = $(INSTALLROOT)/src/*/*/($(MAKEFILES:/:/|/G))
239package.all = $(package.glob.all:P=G:W=O=$(?$(name):A=.VIRTUAL):N!=$(package.omit):T=F:$(PACKAGEVIEW:C,.*,C;^&/;;,:/ /:/G):U)
240package.glob.pkg = $(.package.glob. $(~$(name):P=U):C%.*%$(INSTALLROOT)/src/*/&/($(MAKEFILES:/:/|/G))%) $(~$(name):P=U:N=$(name):?$$(INSTALLROOT)/src/$$(name)/($$(MAKEFILES:/:/|/G))??)
241package.pkg = $(package.glob.pkg:P=G:D:N!=$(package.omit):T=F:$(PACKAGEVIEW:C,.*,C;^&/;;,:/ /:/G):U)
242package.closure = $(closure:?$$(package.all)?$$(package.pkg)?)
243
244package.init = $(.package.glob. $("$(init)$(name)":P=U):C%.*%$(INSTALLROOT)/src/*/&/($(MAKEFILES:/:/|/G))%:P=G:T=F:D::B)
245package.ini = ignore mamprobe manmake package silent
246package.src.pat = $(PACKAGESRC)/($(name).(ini|pkg))
247package.src = $(package.src.pat:P=G) $(.package.licenses. --save $(name))
248package.bin = $(PACKAGEBIN)/$(name).ini
249
250package.mam = --never --force --mam=static --corrupt=accept --clobber --compare --link='lib*.a*' CC=$(CC.DIALECT:N=C++:?CC?cc?) package.license.class=$(license:Q) $(=) 'dontcare test' install test
251
252op = current
253stamp = [0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]
254source = $(PACKAGEDIR)/$(name).$(version)$(release:?.$(release)??).$(suffix)
255binary = $(PACKAGEDIR)/$(name).$(version)$(release:?.$(release)??).$(CC.HOSTTYPE).$(suffix)
256runtime = $(PACKAGEDIR)/$(name)-run.$(version)$(release:?.$(release)??).$(CC.HOSTTYPE).$(suffix)
257old.new.source = $(PACKAGEDIR)/$(name).$(version).$(old.version).$(suffix)
258old.new.binary = $(PACKAGEDIR)/$(name).$(version).$(old.version).$(CC.HOSTTYPE).$(suffix)
259old.new.runtime = $(PACKAGEDIR)/$(name)-run.$(version).$(old.version).$(CC.HOSTTYPE).$(suffix)
260
261source.list = $("$(PACKAGEDIR)/$(name).*$(stamp).$(suffix)":P=G:H=R)
262binary.list = $("$(PACKAGEDIR)/$(name).*$(stamp).$(CC.HOSTTYPE).$(suffix)":P=G:H=R)
263runtime.list = $("$(PACKAGEDIR)/$(name)-run.*$(stamp).$(CC.HOSTTYPE).$(suffix)":P=G:H>)
264
265source.ratz = $("$(INSTALLROOT)/src/cmd/$(init)/ratz.c":T=F)
266binary.ratz = $("$(INSTALLROOT)/src/cmd/$(init)/ratz":T=F)
267
268$(init) : .VIRTUAL $(init)
269
270package.requires = 0
271
272":package:" : .MAKE .OPERATOR
273	local P I R V
274	P := $(<:O=1)
275	$(P) : $(>:V)
276	if ! package.requires
277		if ! name
278			name := $(P)
279			.PACKAGE. := $(P)
280			if name == "$(init)"
281				package.omit = -
282				package.src += $(package.ini:C,^,$(PACKAGEROOT)/bin/,) $(PACKAGESRC)/package.mk
283			else
284				$(P) : $(package.init)
285			end
286			for I $(<:O>1)
287				if I == "*=*"
288					eval
289					$(I)
290					end
291				else
292					version := $(I)
293				end
294			end
295			LICENSEFILEDEFAULT := $(.package.licenses. $(name):@/ /:/G)
296			export LICENSEFILEDEFAULT
297		end
298		if "$(>)"
299			for I $(>:V)
300				$(I) : .VIRTUAL
301				if I == "/*"
302					package.dir += $(I:V)
303				end
304			end
305		end
306		if "$(@)"
307			$(P).README := $(@)
308		else
309			$(P).README := This is the $(P) package.
310		end
311	end
312
313":AUXILIARY:" : .MAKE .OPERATOR
314	package.auxiliary.$(style) += $(>:N=/*:T=F) $(>:N!=/*:C%^%$(INSTALLROOT)/%:T=F)
315
316":CATEGORY:" : .MAKE .OPERATOR
317	if ! package.requires
318		category := $(>)
319	end
320
321.covers. : .FUNCTION
322	local I C D F K=0 L
323	for I $(%)
324		if ! "$(~covers:N=$(I:B))"
325			if F = "$(I:D:B:S=.pkg:T=F)"
326				if D = "$(F:T=I)"
327					covers : $(I:B)
328					for L $(D)
329						if L == ":COVERS:"
330							K = 1
331						elif L == ":*:"
332							if K
333								break
334							end
335						elif K
336							: $(.covers. $(L))
337						end
338					end
339				end
340			else
341				error $(--exec:?3?1?) $(I): unknown package $(I)
342			end
343		end
344	end
345
346":COVERS:" : .MAKE .OPERATOR
347	if ! package.requires
348		: $(.covers. $(>))
349	end
350
351":DESCRIPTION:" : .MAKE .OPERATOR
352	if ! package.requires
353		$(name).README := $(@:V)
354	end
355
356":DETAILS:" : .MAKE .OPERATOR
357	if ! package.requires
358		details.$(>:O=1) := $(@:V)
359	end
360
361":EXPORT:" : .MAKE .OPERATOR
362	if ! package.requires
363		export.$(style) := $(@:/$$("\n")/ /G)
364	end
365
366":INDEX:" : .MAKE .OPERATOR
367	if ! package.requires
368		index := $(>)
369	end
370
371":INSTALL:" : .MAKE .OPERATOR
372	if ! package.requires
373		local T S F X
374		S := $(>)
375		T := $(<)
376		if "$(exe.$(style))" && "$(T)" == "bin/*([!./])"
377			T := $(T).exe
378		end
379		if ! "$(S)"
380			S := $(T)
381		elif "$(exe.$(style))" && "$(S)" == "bin/*([!./])"
382			S := $(S).exe
383		end
384		install.$(style) := $(install.$(style):V)$("\n")install : $$(ROOT)/$(T)$("\n")$$(ROOT)/$(T) : $$(ARCH)/$(S)$("\n\t")cp $< $@
385		if strip && "$(T:N=*.exe)"
386			install.$(style) := $(install.$(style):V)$("\n\t")strip $@ 2>/dev/null
387		end
388		X := $(PACKAGEROOT)/arch/$(CC.HOSTTYPE)/$(S)
389		if strip && "$(X:T=Y)" == "*/?(x-)(dll|exe)"
390			F := filter $(STRIP) $(STRIPFLAGS) $(X)
391		end
392		if "$(filter.$(style):V)"
393			filter.$(style) := $(filter.$(style):V)$$("\n")
394		end
395		filter.$(style) := $(filter.$(style):V);;$(F);$(X);usr/$(T)
396	end
397
398":LICENSE:" : .MAKE .OPERATOR
399	if ! package.requires && ! license
400		license := $(>)
401	end
402
403":OMIT:" : .MAKE .OPERATOR
404	if ! package.requires
405		package.omit := $(package.omit)|$(>:C,^,*/,:/ /|/G)
406	end
407
408":POSTINSTALL:" : .MAKE .OPERATOR
409	if ! package.requires
410		postinstall.$(style) := $(@:V)
411	end
412
413":README:" : .MAKE .OPERATOR
414	if ! package.requires
415		readme.$(style) := $(@:V)
416	end
417
418.requires. : .FUNCTION
419	local I C D F K=0 L V T M=0
420	for I $(%)
421		if ! "$(~requires:N=$(I:B))"
422			if F = "$(I:D:B:S=.pkg:T=F)"
423				if I == "$(init)"
424					package.omit = -
425				else
426					requires : $(I:B)
427				end
428				if V = "$(I:D:B=gen/$(I:B):S=.ver:T=F)"
429					req : $(I:B)
430				else
431					error 1 $(I): package should be written before $(P)
432				end
433				let package.requires = package.requires + 1
434				include "$(F)"
435				let package.requires = package.requires - 1
436			else
437				error 1 $(I): package not found
438			end
439		end
440	end
441
442":REQUIRES:" : .MAKE .OPERATOR
443	: $(.requires. $(>))
444
445":TEST:" : .MAKE .OPERATOR
446	if ! package.requires
447		local T
448		T := $(>)
449		if "$(T)" == "bin/*([!./])"
450			if "$(exe.$(style))"
451				T := $(T).exe
452			end
453			T := $$(PWD)/$$(ARCH)/$(T)
454		end
455		test.$(style) := $(test.$(style):V)$("\n")test : $(T:V)$("\n\t")$(@)
456	end
457
458base delta : .MAKE .VIRTUAL .FORCE
459	op := $(<)
460
461closure : .MAKE .VIRTUAL .FORCE
462	$(<) := 1
463
464cyg exp lcl pkg rpm tgz : .MAKE .VIRTUAL .FORCE
465	style := $(<)
466
467source : .source.init .source.gen .source.$$(style)
468
469.source.init : .MAKE
470	local A B D P V I
471	type := source
472	if ! "$(incremental)"
473		incremental = 1
474	end
475	if "$(source.$(name))"
476		suffix = c
477	end
478	: $(.init.$(style))
479	: $(details.$(style):V:R) :
480	A := $(source.list)
481	B := $(A:N=*.$(stamp).$(suffix):N!=*.$(stamp).$(stamp).*:O=1:T=F)
482	P := $(A:N=*.$(stamp).$(suffix):N!=*.$(stamp).$(stamp).*:O=2:T=F)
483	D := $(A:N=*.$(stamp).$(stamp).$(suffix):O=1:T=F)
484	if op == "delta"
485		if ! B
486			error 3 delta requires a base archive
487		end
488		base := -z $(B)
489		deltaversion := $(B:B:/$(name).//)
490		let deltasince = $(deltaversion:/.*-//) + 1
491		deltasince := $(deltaversion:/[^-]*$/$(deltasince:F=%02d)/)
492		if "$(release)" != "$(stamp)"
493			release := $("":T=R%Y-%m-%d)
494		end
495		source := $(B:D:B:S=.$(release).$(suffix))
496		version := $(source:B:B:/$(name).//)
497	elif B || op == "base"
498		if op == "base"
499			for I $(B) $(P)
500				V := $(I:B:/$(name)\.\([^.]*\).*/\1/)
501				if V == "$(stamp)" && V != "$(version)"
502					old.version := $(V)
503					old.source := $(I)
504					if "$(old.version)" >= "$(version)"
505						error 3 $(name): previous base $(old.version) is newer than $(version)
506					end
507					break
508				end
509			end
510		else
511			source := $(B)
512		end
513		if B == "$(source)"
514			if "$(B:D:B:B)" == "$(D:D:B:B)" && "$(B:B::S)" != "$(D:B::S)"
515				error 3 $(B:B:S): base overwrite would invalidate delta $(D:B:S)
516			end
517			error 1 $(B:B:S): replacing current base
518		end
519		version := $(source:B:S:/^$(name).\(.*\).$(suffix)$/\1/)
520	end
521	PACKAGEGEN := $(PACKAGESRC)/gen
522
523.source.gen : $$(PACKAGEDIR) $$(PACKAGEGEN) $$(PACKAGEGEN)/SOURCE.html $$(PACKAGEGEN)/BINARY.html $$(PACKAGEGEN)/DETAILS.html
524
525BINPACKAGE := $(PATH:/:/ /G:X=package:T=F:O=1)
526
527$$(PACKAGEDIR) $$(PACKAGEGEN) : .IGNORE
528	[[ -d $(<) ]] || mkdir $(<)
529
530$$(PACKAGEGEN)/SOURCE.html : $(BINPACKAGE)
531	$(*) html source > $(<)
532
533$$(PACKAGEGEN)/BINARY.html : $(BINPACKAGE)
534	$(*) html binary > $(<)
535
536$$(PACKAGEGEN)/DETAILS.html : $(BINPACKAGE)
537	$(*) html intro > $(<)
538
539.source.exp .source.pkg .source.rpm : .MAKE
540	error 3 $(style): source package style not supported yet
541
542exe.cyg = .exe
543vendor.cyg = gnu
544
545.name.cyg : .FUNCTION
546	local N
547	N := $(%)
548	if N == "*-*"
549		vendor := $(N:/-.*//)
550		if vendor == "$(vendor.cyg)"
551			vendor :=
552			N := $(N:/[^-]*-//)
553		end
554		N := $(N:/-//G)
555	end
556	return $(N)
557
558.init.cyg : .FUNCTION
559	local N O
560	closure = 1
561	init = .
562	strip = 1
563	suffix = tar.bz2
564	format = tbz
565	vendor := $(licenses:N!=$(vendor.cyg):O=1)
566	package.ini := $(package.ini)
567	package.src.pat := $(package.src.pat)
568	package.src := $(package.src)
569	package.bin := $(package.bin)
570	.source.gen : .CLEAR $(*.source.gen:V:N!=*.html)
571	name.original := $(name)
572	name := $(.name.cyg $(name))
573	if name != "$(name.original)"
574		$(name) : $(~$(name.original))
575		O := $(~covers)
576		covers : .CLEAR
577		for N $(O)
578			covers : $(.name.cyg $(N))
579		end
580	end
581	stamp = [0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]-[0-9]
582	version.original := $(version)
583	version := $(version:/-//G)-1
584	if opt
585		opt := $(opt)/$(vendor)/
586	else
587		opt := $(name)-$(version)/
588	end
589	if type == "source"
590		version := $(version)-src
591		source = $(PACKAGEDIR)/$(name)-$(version)$(release:?.$(release)??).$(suffix)
592	else
593		binary = $(PACKAGEDIR)/$(name)-$(version)$(release:?.$(release)??).$(suffix)
594	end
595
596.source.cyg :
597	if	[[ '$(~$(name))' ]]
598	then	tmp=/tmp/pkg$(tmp)
599		mkdir $tmp
600		{
601			integer m=0 o
602			cat > $tmp/configure <<'!'
603	echo "you didn't have to do that"
604	!
605			chmod +x $tmp/configure
606			echo ";;;$tmp/configure;configure"
607			cat > $tmp/Makefile0 <<'!'
608	HOSTTYPE := $$(shell bin/package)
609	ROOT = ../..
610	ARCH = arch/$$(HOSTTYPE)
611	all :
612		PACKAGEROOT= CYGWIN="$$CYGWIN ntsec binmode" bin/package make $(export.$(style))
613	install : all
614	$(install.$(style):V)
615	$(test.$(style):V)
616	!
617			echo ";;;$tmp/Makefile0;Makefile"
618			cat > $tmp/CYGWIN-README <<'!'
619	$(readme.$(style):@?$$(readme.$$(style))$$("\n\n")??)To build binaries from source into the ./arch/`bin/package` tree run:
620	$()
621		make
622	$()
623	$(test.$(style):@?To test the binaries after building/installing run:$$("\n\n\t")make test$$("\n\n")??)To build and/or install the binaries run:
624	$()
625		make install
626	$()
627	The bin/package command provides a command line interface for all package
628	operations. The $(opt:/.$//) source and binary packages were generated by:
629	$()
630		package write cyg base source version=$(version.original) $(name.original)
631		package write cyg base binary version=$(version.original) $(name.original)
632	$()
633	using the $(org)-base package. To download and install the latest
634	$(org)-base source package in /opt/$(org) run:
635	$()
636		PATH=/opt/$(org)/bin:$PATH
637		cd /opt/$(org)
638		package authorize "NAME" password "PASSWORD" setup flat source $("\\")
639			$(url) $("\\")
640			$(org)-base
641		package make
642	$()
643	and export /opt/$(org)/bin in PATH to use. The NAME and PASSWORD signify your
644	agreement to the software license(s). All users get the same NAME and PASSWORD.
645	See $(url) for details. If multiple architectures may be built under
646	/opt/$(org) then drop "flat" and export /opt/$(org)/arch/`package`/bin in PATH
647	to use. To update previously downloaded packages from the same url simply run:
648	$()
649		cd /opt/$(org)
650		package setup
651		package make
652	$()
653	To download and install the latest $(org)-base binary package in
654	/opt/$(org) change "source" to "binary" and omit "package make".
655	!
656			echo ";;;$tmp/CYGWIN-README;CYGWIN-PATCHES/README"
657			cat > $(source:/-src.$(suffix)//).setup.hint <<'!'
658	category: $(category:/\(.\).*/\1/U)$(category:/.\(.*\)/\1/L)
659	requires: cygwin
660	sdesc: "$(index)"
661	ldesc: "$($(name.original).README)"
662	!
663			echo ";;;$(source:/-src.$(suffix)//).setup.hint;CYGWIN-PATCHES/setup.hint"
664			echo ";;;$(BINPACKAGE);bin/package"
665			cat > $tmp/Makefile <<'!'
666	:MAKE:
667	!
668			echo ";;;$tmp/Makefile;src/Makefile"
669			echo ";;;$tmp/Makefile;src/cmd/Makefile"
670			echo ";;;$tmp/Makefile;src/lib/Makefile"
671			if	[[ '$(mamfile)' == 1 ]]
672			then	cat > $tmp/Mamfile1 <<'!'
673	info mam static
674	note source level :MAKE: equivalent
675	make install
676	make all
677	exec - ${MAMAKE} -r '*/*' ${MAMAKEARGS}
678	done all virtual
679	done install virtual
680	!
681				echo ";;;$tmp/Mamfile1;src/Mamfile"
682				cat > $tmp/Mamfile2 <<'!'
683	info mam static
684	note component level :MAKE: equivalent
685	make install
686	make all
687	exec - ${MAMAKE} -r '*' ${MAMAKEARGS}
688	done all virtual
689	done install virtual
690	!
691				echo ";;;$tmp/Mamfile2;src/cmd/Mamfile"
692				echo ";;;$tmp/Mamfile2;src/lib/Mamfile"
693			fi
694			$(package.src:U:T=F:/.*/echo ";;;&"$("\n")/)
695			echo ";;;$(PACKAGEGEN)/$(name.original).req"
696			set -- $(package.closure)
697			for i
698			do	cd $(INSTALLROOT)/$i
699				if	[[ ! '$(license)' ]] || $(MAKE) --noexec --silent 'exit $$(LICENSECLASS:N=$(license):?0?1?)' .
700				then	if	[[ '$(mamfile)' == 1 ]]
701					then	(( o=m ))
702						s=$( $(MAKE) --noexec --recurse=list recurse 2>/dev/null )
703						if	[[ $s ]]
704						then	for j in $s
705							do	if	[[ -d $j ]]
706								then	cd $j
707									if	[[ ! '$(license)' ]] || $(MAKE) --noexec --silent 'exit $$(LICENSECLASS:N=$(license):?0?1?)' .
708									then	(( m++ ))
709										$(MAKE) $(package.mam) $(export.$(style):Q) > $tmp/$m.mam
710										echo ";;;$tmp/$m.mam;$i/$j/Mamfile"
711									fi
712									cd $(INSTALLROOT)/$i
713								fi
714							done
715							if	(( o != m ))
716							then	(( m++ ))
717								cat > $tmp/$m.mam <<'!'
718	info mam static
719	note subcomponent level :MAKE: equivalent
720	make install
721	make all
722	exec - ${MAMAKE} -r '*' ${MAMAKEARGS}
723	done all virtual
724	done install virtual
725	!
726								echo ";;;$tmp/$m.mam;$i/Mamfile"
727							fi
728						else	(( m++ ))
729							$(MAKE) $(package.mam) $(export.$(style):Q) > $tmp/$m.mam
730							echo ";;;$tmp/$m.mam;$i/Mamfile"
731						fi
732					fi
733					$(MAKE) --noexec $(-) $(=) recurse list.package.$(type) package.license.class=$(license:Q)
734				fi
735			done
736			set -- $(package.dir:P=G)
737			for i
738			do	tw -d $i -e "action:printf(';;;%s;%s\n',path,path);"
739			done
740		} |
741		{
742			: > $tmp/HEAD
743			cat > $tmp/README <<'!'
744	$(package.readme)
745	!
746			echo ";;;$tmp/README;README"
747			sort -t';' -k5,5 -u
748			: > $tmp/TAIL
749			[[ '$(notice)' ]] && echo ";;;$tmp/TAIL;$(package.notice)"
750		} |
751		$(PAX)	--filter=- \
752			--to=ascii \
753			--format=$(format) \
754			--local \
755			-wvf $(source) $(base) \
756			$(PACKAGEVIEW:C%.*%-s",^&/,,"%) \
757			$(vendor:?-s",^[^/],$(opt)&,"??)
758		$(SUM) -x $(checksum) < $(source) > $(source:D:B:S=.$(checksum))
759		rm -rf $tmp
760	fi
761
762.source.lcl :
763	if	[[ '$(~$(name))' ]]
764	then	tmp=/tmp/pkg$(tmp)
765		mkdir $tmp
766		{
767			integer m=0 o
768			$(package.src:U:T=F:/.*/echo ";;;&"$("\n")/)
769			set -- $(package.closure)
770			for i
771			do	cd $(INSTALLROOT)/$i
772				$(MAKE) --noexec $(-) $(=) .FILES.+=Mamfile recurse list.package.local
773			done
774			set -- $(package.dir:P=G)
775			for i
776			do	tw -d $i -e "action:printf(';;;%s;%s\n',path,path);"
777			done
778		} |
779		sort -t';' -k5,5 -u |
780		$(PAX)	--filter=- \
781			--to=ascii \
782			$(op:N=delta:??--format=$(format)?) \
783			--local \
784			-wvf $(source) $(base) \
785			$(op:N=delta:?--format=gzip??) \
786			$(PACKAGEVIEW:C%.*%-s",^&/,,"%)
787		rm -rf $tmp
788	fi
789
790.source.tgz :
791	if	[[ '$(~$(name))' ]]
792	then	tmp=/tmp/pkg$(tmp)
793		mkdir $tmp
794		{
795			integer m=0 o
796			if	[[ '$(init)' == '$(name)' ]]
797			then	cat > $tmp/Makefile <<'!'
798	:MAKE:
799	!
800				$(CMP) $(CMPFLAGS) $tmp/Makefile $(PACKAGEROOT)/src/Makefile && touch -r $(PACKAGEROOT)/src/Makefile $tmp/Makefile
801				echo ";;;$tmp/Makefile;src/Makefile"
802				cp $tmp/Makefile $tmp/Makefile1
803				$(CMP) $(CMPFLAGS) $tmp/Makefile1 $(PACKAGEROOT)/src/cmd/Makefile && touch -r $(PACKAGEROOT)/src/cmd/Makefile $tmp/Makefile1
804				echo ";;;$tmp/Makefile1;src/cmd/Makefile"
805				cp $tmp/Makefile $tmp/Makefile2
806				$(CMP) $(CMPFLAGS) $tmp/Makefile2 $(PACKAGEROOT)/src/lib/Makefile && touch -r $(PACKAGEROOT)/src/lib/Makefile $tmp/Makefile2
807				echo ";;;$tmp/Makefile2;src/lib/Makefile"
808				if	[[ '$(mamfile)' == 1 ]]
809				then	cat > $tmp/Mamfile1 <<'!'
810	info mam static
811	note source level :MAKE: equivalent
812	make install
813	make all
814	exec - ${MAMAKE} -r '*/*' ${MAMAKEARGS}
815	done all virtual
816	done install virtual
817	!
818					$(CMP) $(CMPFLAGS) $tmp/Mamfile1 $(PACKAGEROOT)/src/Mamfile && touch -r $(PACKAGEROOT)/src/Mamfile $tmp/Mamfile1
819					echo ";;;$tmp/Mamfile1;src/Mamfile"
820					cat > $tmp/Mamfile2 <<'!'
821	info mam static
822	note component level :MAKE: equivalent
823	make install
824	make all
825	exec - ${MAMAKE} -r '*' ${MAMAKEARGS}
826	done all virtual
827	done install virtual
828	!
829					$(CMP) $(CMPFLAGS) $tmp/Mamfile2 $(PACKAGEROOT)/src/cmd/Mamfile && touch -r $(PACKAGEROOT)/src/cmd/Mamfile $tmp/Mamfile2
830					echo ";;;$tmp/Mamfile2;src/cmd/Mamfile"
831					cp $tmp/Mamfile2 $tmp/Mamfile3
832					$(CMP) $(CMPFLAGS) $tmp/Mamfile3 $(PACKAGEROOT)/src/lib/Mamfile && touch -r $(PACKAGEROOT)/src/lib/Mamfile $tmp/Mamfile3
833					echo ";;;$tmp/Mamfile3;src/lib/Mamfile"
834				fi
835			fi
836			$(package.src:U:T=F:C%^$(PACKAGEROOT)/%%:C%.*%echo ";;;$(PACKAGEROOT)/&;&"$("\n")%)
837			if	[[ '$(~covers)' ]]
838			then	for i in $(~covers)
839				do	for j in lib pkg
840					do	if	[[ -f $(PACKAGESRC)/$i.$j ]]
841						then	echo ";;;$(PACKAGESRC)/$i.$j;$(PACKAGELIB)/$i.$j"
842						fi
843					done
844					for j in ver req
845					do	if	[[ -f $(PACKAGEGEN)/$i.$j ]]
846						then	echo ";;;$(PACKAGEGEN)/$i.$j;$(PACKAGELIB)/$i.$j"
847						fi
848					done
849				done
850				for i in $(~covers:D=$(PACKAGESRC):B:S=.lic:T=F:T=I:N=*.def:D=$(PACKAGESRC):B:S:T=F:B:S)
851				do	echo ";;;$(PACKAGESRC)/$i;$(PACKAGELIB)/$i"
852				done
853			fi
854			if	[[ '$(PACKAGEDIR:B)' == '$(style)' ]]
855			then	echo $(name) $(version) $(release|version) 1 > $tmp/t
856				$(CMP) $(CMPFLAGS) $tmp/t $(PACKAGEGEN)/$(name).ver || cp $tmp/t $(PACKAGEGEN)/$(name).ver
857				echo ";;;$(PACKAGEGEN)/$(name).ver;$(PACKAGELIB)/$(name).ver"
858				sed 's,1$,0,' $(~req:D=$(PACKAGEGEN):B:S=.ver:T=F) < /dev/null > $tmp/t
859				$(CMP) $(CMPFLAGS) $tmp/t $(PACKAGEGEN)/$(name).req || cp $tmp/t $(PACKAGEGEN)/$(name).req
860				echo ";;;$(PACKAGEGEN)/$(name).req;$(PACKAGELIB)/$(name).req"
861				{
862					echo "name='$(name)'"
863					echo "index='$(index)'"
864					echo "covers='$(~covers)'"
865					echo "requires='$(~req)'"
866				} > $tmp/t
867				$(CMP) $(CMPFLAGS) $tmp/t $(PACKAGEGEN)/$(name).inx || cp $tmp/t $(PACKAGEGEN)/$(name).inx
868				{
869					{
870					echo '$($(name).README)'
871					if	[[ '$(~covers)' ]]
872					then	echo "This package is a superset of the following package$(~covers:O=2:?s??): $(~covers); you won't need $(~covers:O=2:?these?this?) if you download $(name)."
873					fi
874					if	[[ '$(~requires)' ]]
875					then	echo 'It requires the following package$(~requires:O=2:?s??): $(~requires).'
876					fi
877					} | fmt
878					package help source
879					package release $(name)
880				} > $tmp/t
881				$(CMP) $(CMPFLAGS) $tmp/t $(PACKAGEGEN)/$(name).README || cp $tmp/t $(PACKAGEGEN)/$(name).README
882				echo ";;;$(PACKAGEGEN)/$(name).README;$(PACKAGELIB)/$(name).README"
883				{
884					echo '.xx title="$(name) package"'
885					echo '.xx meta.description="$(name) package"'
886					echo '.xx meta.keywords="software, package"'
887					echo '.MT 4'
888					echo '.TL'
889					echo '$(name) package'
890					echo '.H 1 "$(name) package"'
891					echo '$($(name).README)'
892					set -- $(package.closure:C,.*,$(INSTALLROOT)/&/PROMO.mm,:T=F:D::B)
893					hot=
894					for i
895					do	hot="$hot -e s/\\(\\<$i\\>\\)/\\\\h'0*1'\\1\\\\h'0'/"
896					done
897					set -- $(package.closure:B)
898					if	(( $# ))
899					then	echo 'Components in this package:'
900						echo '.P'
901						echo '.TS'
902						echo 'center expand;'
903						echo 'l l l l l l.'
904						if	[[ $hot ]]
905						then	hot="sed $hot"
906						else	hot=cat
907						fi
908						for i
909						do	echo $i
910						done |
911						pr -6 -t -s'	' |
912						$hot
913						echo '.TE'
914					fi
915					echo '.P'
916					if	[[ '$(~covers)' ]]
917					then	echo "This package is a superset of the following package$(~covers:O=2:?s??): $(~covers); you won't need $(~covers:O=2:?these?this?) if you download $(name)."
918					fi
919					if	[[ '$(~requires)' ]]
920					then	echo 'It requires the following package$(~requires:O=2:?s??): $(~requires).'
921					fi
922					set -- $(.package.licenses. --all $(name))
923					case $# in
924					0)	;;
925					*)	case $# in
926						1)	echo 'The software is covered by this license:' ;;
927						*)	echo 'The software is covered by these licenses:' ;;
928						esac
929						echo .BL
930						for j
931						do	i=$( $(PROTO) -l $j -p -h -o type=usage /dev/null | sed -e 's,.*\[-license?\([^]]*\).*,\1,' )
932							echo .LI
933							echo ".xx link=\"$i\""
934						done
935						echo .LE
936						echo 'Individual components may be covered by separate licenses;'
937						echo 'refer to the component source and/or binaries for more information.'
938						echo .P
939						;;
940					esac
941					echo 'A recent'
942					echo '.xx link="release change log"'
943					echo 'is also included.'
944					cat $(package.closure:C,.*,$(INSTALLROOT)/&/PROMO.mm,:T=F) < /dev/null
945					echo '.H 1 "release change log"'
946					echo '.xx index'
947					echo '.nf'
948					package release $(name) |
949					sed -e 's/:::::::: \(.*\) ::::::::/.fi\$("\n").H 1 "\1 changes"\$("\n").nf/'
950					echo '.fi'
951				} |
952				$(MM2HTML) $(MM2HTMLFLAGS) -o nohtml.ident > $tmp/t
953				$(STDED) $(STDEDFLAGS) $tmp/t <<'!'
954	/^<!--LABELS-->$/,/^<!--\/LABELS-->$/s/ changes</</
955	/^<!--LABELS-->$/,/^<!--\/LABELS-->$/m/<A name="release change log">/
956	w
957	q
958	!
959				$(CMP) $(CMPFLAGS) $tmp/t $(PACKAGEGEN)/$(name).html || cp $tmp/t $(PACKAGEGEN)/$(name).html
960				echo ";;;$(PACKAGEGEN)/$(name).html;$(PACKAGELIB)/$(name).html"
961				if	[[ '$(deltasince)' ]]
962				then	{
963					echo '.xx title="$(name) package"'
964					echo '.xx meta.description="$(name) package $(version) delta $(release)"'
965					echo '.xx meta.keywords="software, package, delta"'
966					echo '.MT 4'
967					echo '.TL'
968					echo '$(name) package $(deltaversion) delta $(release)'
969					echo '.H 1 "$(name) package $(deltaversion) delta $(release) changes"'
970					echo '.nf'
971					package release $(deltasince) $(name) |
972					sed -e 's/:::::::: \(.*\) ::::::::/.H 2 \1/'
973					echo '.fi'
974					} |
975					$(MM2HTML) $(MM2HTMLFLAGS) -o nohtml.ident > $tmp/t
976					$(CMP) $(CMPFLAGS) $tmp/t $(PACKAGEGEN)/$(name).$(release).html || cp $tmp/t $(PACKAGEGEN)/$(name).$(release).html
977					echo ";;;$(PACKAGEGEN)/$(name).$(release).html;$(PACKAGELIB)/$(name).$(release).html"
978				fi
979			fi
980			set -- $(package.closure)
981			for i
982			do	cd $(INSTALLROOT)/$i
983				if	[[ ! '$(license)' ]] || $(MAKE) --noexec --silent 'exit $$(LICENSECLASS:N=$(license):?0?1?)' .
984				then	if	[[ '$(mamfile)' == 1 ]]
985					then	(( o=m ))
986						s=$( $(MAKE) --noexec --recurse=list recurse 2>/dev/null )
987						if	[[ $s ]]
988						then	for j in $s
989							do	if	[[ -d $j ]]
990								then	cd $j
991									if	[[ ! '$(license)' ]] || $(MAKE) --noexec --silent 'exit $$(LICENSECLASS:N=$(license):?0?1?)' .
992									then	(( m++ ))
993										$(MAKE) $(package.mam) > $tmp/$m.mam
994										$(CMP) $(CMPFLAGS) $tmp/$m.mam $(PACKAGEROOT)/$i/$j/Mamfile && touch -r $(PACKAGEROOT)/$i/$j/Mamfile $tmp/$m.mam
995										echo ";;;$tmp/$m.mam;$i/$j/Mamfile"
996									fi
997									cd $(INSTALLROOT)/$i
998								fi
999							done
1000							if	(( o != m ))
1001							then	(( m++ ))
1002								cat > $tmp/$m.mam <<'!'
1003	info mam static
1004	note subcomponent level :MAKE: equivalent
1005	make install
1006	make all
1007	exec - ${MAMAKE} -r '*' ${MAMAKEARGS}
1008	done all virtual
1009	done install virtual
1010	!
1011								$(CMP) $(CMPFLAGS) $tmp/$m.mam $(PACKAGEROOT)/$i/Mamfile && touch -r $(PACKAGEROOT)/$i/Mamfile $tmp/$m.mam
1012								echo ";;;$tmp/$m.mam;$i/Mamfile"
1013							fi
1014						else	(( m++ ))
1015							$(MAKE) $(package.mam) > $tmp/$m.mam
1016							$(CMP) $(CMPFLAGS) $tmp/$m.mam $(PACKAGEROOT)/$i/Mamfile && touch -r $(PACKAGEROOT)/$i/Mamfile $tmp/$m.mam
1017							echo ";;;$tmp/$m.mam;$i/Mamfile"
1018						fi
1019					fi
1020					$(MAKE) --noexec $(-) $(=) recurse list.package.$(type) package.license.class=$(license:Q) $(copyright:N=1:??LICENSE=?)
1021				fi
1022			done
1023			set -- $(package.dir:P=G)
1024			for i
1025			do	tw -d $i -e "action:printf(';;;%s;%s\n',path,path);"
1026			done
1027		} |
1028		{
1029			: > $tmp/HEAD
1030			[[ '$(notice)' ]] && echo ";;;$tmp/HEAD;$(package.notice)"
1031			cat > $tmp/README <<'!'
1032	$(package.readme)
1033	!
1034			echo ";;;$tmp/README;README"
1035			$(CMP) $(CMPFLAGS) $tmp/README $(PACKAGEROOT)/README && touch -r $(PACKAGEROOT)/README $tmp/README
1036			sort -t';' -k5,5 -u
1037			: > $tmp/TAIL
1038			[[ '$(notice)' ]] && echo ";;;$tmp/TAIL;$(package.notice)"
1039		} |
1040		$(PAX)	--filter=- \
1041			--to=ascii \
1042			$(op:N=delta:??--format=$(format)?) \
1043			--local \
1044			-wvf $(source) $(base) \
1045			$(op:N=delta:?--format=gzip??) \
1046			$(PACKAGEVIEW:C%.*%-s",^&/,,"%)
1047		$(SUM) -x $(checksum) < $(source) > $(source:D:B:S=.$(checksum))
1048		echo local > $(source:D:B=$(name):S=.tim)
1049		if	[[ '$(incremental)' == 1 && '$(old.source)' ]]
1050		then	$(PAX) -rf $(source) -wvf $(old.new.source) -z $(old.source)
1051			$(SUM) -x $(checksum) < $(old.new.source) > $(old.new.source:D:B:S=.$(checksum))
1052		fi
1053		rm -rf $tmp
1054	else	if	[[ '$(old.source)' ]] && $(CMP) $(CMPFLAGS) $(source.$(name)) $(source)
1055		then	: $(name) is up to date
1056		else	echo $(name) $(version) $(release|version) 1 > $(PACKAGEGEN)/$(name).ver
1057			: > $(PACKAGEGEN)/$(name).req
1058			{
1059				echo "name='$(name)'"
1060				echo "index='$(index)'"
1061				echo "covers='$(~covers)'"
1062				echo "requires='$(~req)'"
1063			} > $(PACKAGEGEN)/$(name).inx
1064			{
1065				echo '.xx title="$(name) package"'
1066				echo '.xx meta.description="$(name) package"'
1067				echo '.xx meta.keywords="software, package"'
1068				echo '.MT 4'
1069				echo '.TL'
1070				echo '$(name) package'
1071				echo '.H 1'
1072				echo '$($(name).README)'
1073			} |
1074			$(MM2HTML) $(MM2HTMLFLAGS) -o nohtml.ident > $(PACKAGEGEN)/$(name).html
1075			if	[[ '$(source.$(name))' ]]
1076			then	{
1077					echo '$($(name).README)'
1078					package help source
1079				} > $(PACKAGEGEN)/$(name).README
1080				cp $(source.$(name)) $(source)
1081				$(SUM) -x $(checksum) < $(source) > $(source:D:B:S=.$(checksum))
1082			fi
1083			echo local > $(source:D:B=$(name):S=.tim)
1084		fi
1085	fi
1086
1087binary : .binary.init .binary.gen .binary.$$(style)
1088
1089.binary.init : .MAKE
1090	local A B D I P V
1091	type := binary
1092	if ! "$(incremental)"
1093		incremental = 0
1094	end
1095	if ! "$(~$(name))"
1096		if name == "ratz"
1097			suffix = exe
1098		else
1099			suffix = gz
1100		end
1101	end
1102	: $(.init.$(style)) :
1103	: $(details.$(style):V:R) :
1104	A := $(binary.list)
1105	B := $(A:N=*.$(stamp).$(CC.HOSTTYPE).$(suffix):N!=*.$(stamp).$(stamp).*:O=1:T=F)
1106	P := $(A:N=*.$(stamp).$(CC.HOSTTYPE).$(suffix):N!=*.$(stamp).$(stamp).*:O=2:T=F)
1107	D := $(A:N=*.$(stamp).$(stamp).$(CC.HOSTTYPE).$(suffix):O=1:T=F)
1108	if op == "delta"
1109		if ! B
1110			error 3 delta requires a base archive
1111		end
1112		base := -z $(B)
1113		if "$(release)" != "$(stamp)"
1114			release := $("":T=R%Y-%m-%d)
1115		end
1116		binary := $(B:/$(CC.HOSTTYPE).$(suffix)$/$(release).&/)
1117		version := $(binary:B:B:/$(name).//)
1118	elif B || op == "base"
1119		if op == "base"
1120			for I $(B) $(P)
1121				V := $(I:B:/$(name)\.\([^.]*\).*/\1/)
1122				if V == "[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]" && V != "$(version)"
1123					old.version := $(V)
1124					old.binary := $(I)
1125					if "$(old.version)" >= "$(version)"
1126						error 3 $(name): previous base $(old.version) is newer than $(version)
1127					end
1128					break
1129				end
1130			end
1131		else
1132			binary := $(B)
1133		end
1134		if B == "$(binary)"
1135			if "$(B:D:B)" == "$(D:D:B)" && "$(B:S)" != "$(D:S)"
1136				error 3 $(B:B:S): base overwrite would invalidate delta $(D:B:S)
1137			end
1138			error 1 $(B:B:S): replacing current base
1139		end
1140		version := $(binary:B:/$(name).//:/\..*//)
1141	end
1142	PACKAGEGEN := $(PACKAGEBIN)/gen
1143
1144.binary.gen : $$(PACKAGEDIR) $$(PACKAGEGEN)
1145
1146.binary.exp .binary.pkg .binary.rpm : .MAKE
1147	error 3 $(style): binary package style not supported yet
1148
1149.binary.cyg :
1150	if	[[ '$(~$(name))' ]]
1151	then	tmp=/tmp/pkg$(tmp)
1152		mkdir $tmp
1153		{
1154			integer m=0 o
1155			{
1156				echo '$($(name.original).README)' | fmt
1157				cat <<'!'
1158	$(readme.$(style):@?$$("\n")$$(readme.$$(style))??)
1159	!
1160			} > $tmp/README1
1161			echo ";;;$tmp/README1;usr/share/doc/Cygwin/$(opt:/.$//).README"
1162			{
1163				echo '$($(name.original).README)' | fmt
1164				cat <<'!'
1165	$()
1166	The remainder of this file is the README from the source package
1167	that was used to generate this binary package. It describes
1168	the source build hierarchy, not the current directory.
1169	$()
1170	$(package.readme)
1171	!
1172			} > $tmp/README2
1173			echo ";;;$tmp/README2;usr/share/doc/$(opt)README"
1174			package release $(name.original) > $tmp/RELEASE
1175			echo ";;;$tmp/RELEASE;usr/share/doc/$(opt)RELEASE"
1176			cat > $(binary:/.$(suffix)//).setup.hint <<'!'
1177	category: $(category:/\(.\).*/\1/U)$(category:/.\(.*\)/\1/L)
1178	requires: cygwin
1179	sdesc: "$(index)"
1180	ldesc: "$($(name.original).README)"
1181	!
1182			set -- $(.package.licenses. --text $(name.original):N!=*.lic)
1183			for i
1184			do	echo ";;;${i};usr/share/doc/$(opt)LICENSE-${i##*/}"
1185			done
1186			cat <<'!'
1187	$(filter.$(style))
1188	!
1189			if	[[ '$(postinstall.$(style):V:O=1:?1??)' ]]
1190			then	cat >$tmp/postinstall <<'!'
1191	$("#")!/bin/sh
1192	$(postinstall.$(style))
1193	!
1194				echo ";;;$tmp/postinstall;etc/postinstall/$(name).sh"
1195			fi
1196		} |
1197		{
1198			: > $tmp/HEAD
1199			[[ '$(notice)' ]] && echo ";;;$tmp/HEAD;$(package.notice)"
1200			sort -t';' -k5,5 -u
1201			: > $tmp/TAIL
1202			[[ '$(notice)' ]] && echo ";;;$tmp/TAIL;$(package.notice)"
1203		} |
1204		$(PAX)	--filter=- \
1205			--to=ascii \
1206			--format=$(format) \
1207			--local \
1208			-wvf $(binary)
1209		$(SUM) -x $(checksum) < $(binary) > $(binary:D:B:S=.$(checksum))
1210		rm -rf $tmp
1211	fi
1212
1213.binary.lcl :
1214	if	[[ '$(~$(name))' ]]
1215	then	tmp=/tmp/pkg$(tmp)
1216		mkdir $tmp
1217		{
1218			$(package.src:U:T=F:/.*/echo ";;;&"$("\n")/)
1219			$(package.bin:U:T=F:/.*/echo ";;;&"$("\n")/)
1220			set -- $(package.closure)
1221			for i
1222			do	cd $(INSTALLROOT)/$i
1223				$(MAKE) --noexec $(-) --variants=$(variants:Q) $(=) recurse list.package.$(type) package.license.class=$(license:Q) cc-
1224			done
1225		} |
1226		$(PAX)	--filter=- \
1227			--to=ascii \
1228			$(op:N=delta:??--format=$(format)?) \
1229			--local \
1230			--checksum=md5:$(PACKAGEGEN)/$(name).sum \
1231			--install=$(PACKAGEGEN)/$(name).ins \
1232			-wvf $(binary) $(base) \
1233			$(op:N=delta:?--format=gzip??) \
1234			-s",^$tmp/,$(INSTALLOFFSET)/," \
1235			$(PACKAGEROOT:C%.*%-s",^&/,,"%)
1236		$(SUM) -x $(checksum) < $(binary) > $(binary:D:B:S=.$(checksum))
1237		echo local > $(binary:D:B=$(name):S=.$(CC.HOSTTYPE).tim)
1238		rm -rf $tmp
1239	fi
1240
1241.binary.tgz :
1242	if	[[ '$(~$(name))' ]]
1243	then	tmp=/tmp/pkg$(tmp)
1244		mkdir $tmp
1245		{
1246			if	[[ '$(init)' == '$(name)' ]]
1247			then	for i in lib32 lib64
1248				do	if	[[ -d $(INSTALLROOT)/$i ]]
1249					then	echo ";physical;;$(INSTALLROOT)/$i"
1250					fi
1251				done
1252			fi
1253			$(package.src:U:T=F:C%^$(PACKAGEROOT)/%%:C%.*%echo ";;;$(PACKAGEROOT)/&;&"$("\n")%)
1254			$(package.bin:U:T=F:C%^$(INSTALLROOT)/%%:C%.*%echo ";;;$(INSTALLROOT)/&;&"$("\n")%)
1255			$(package.auxiliary.$(style):U:T=F:C%^$(INSTALLROOT)/%%:C%.*%echo ";;;$(INSTALLROOT)/&;&"$("\n")%)
1256			if	[[ '$(PACKAGEDIR:B)' == '$(style)' ]]
1257			then	echo $(name) $(version) $(release|version) 1 > $(PACKAGEGEN)/$(name).ver
1258				echo ";;;$(PACKAGEGEN)/$(name).ver;$(PACKAGELIB)/$(name).ver"
1259				if	[[ '$(~covers)' ]]
1260				then	for i in $(~covers)
1261					do	for j in lic pkg
1262						do	if	[[ -f $(PACKAGESRC)/$i.$j ]]
1263							then	echo ";;;$(PACKAGESRC)/$i.$j;$(PACKAGELIB)/$i.$j"
1264							fi
1265						done
1266						for j in ver req
1267						do	if	[[ -f $(PACKAGEGEN)/$i.$j ]]
1268							then	echo ";;;$(PACKAGEGEN)/$i.$j;$(PACKAGELIB)/$i.$j"
1269							fi
1270						done
1271					done
1272					for i in $(~covers:D=$(PACKAGESRC):B:S=.lic:T=F:T=I:N=*.def:D=$(PACKAGESRC):B:S:T=F:B:S)
1273					do	echo ";;;$(PACKAGESRC)/$i;$(PACKAGELIB)/$i"
1274					done
1275				fi
1276				sed 's,1$,0,' $(~req:D=$(PACKAGEGEN):B:S=.ver:T=F) < /dev/null > $(PACKAGEGEN)/$(name).req
1277				echo ";;;$(PACKAGEGEN)/$(name).req;$(PACKAGELIB)/$(name).req"
1278				{
1279					echo "name='$(name)'"
1280					echo "index='$(index)'"
1281					echo "covers='$(~covers)'"
1282					echo "requires='$(~req)'"
1283				} > $(PACKAGEGEN)/$(name).inx
1284				{
1285					{
1286					echo '$($(name).README)'
1287					if	[[ '$(~covers)' ]]
1288					then	echo "This package is a superset of the following package$(~covers:O=2:?s??): $(~covers); you won't need $(~covers:O=2:?these?this?) if you download $(name)."
1289					fi
1290					if	[[ '$(~requires)' ]]
1291					then	echo 'It requires the following package$(~requires:O=2:?s??): $(~requires).'
1292					fi
1293					} | fmt
1294					package help binary
1295					package release $(name)
1296				} > $(PACKAGEGEN)/$(name).README
1297				echo ";;;$(PACKAGEGEN)/$(name).README;$(PACKAGELIB)/$(name).README"
1298			fi
1299			set -- $(package.closure)
1300			for i
1301			do	cd $(INSTALLROOT)/$i
1302				$(MAKE) --noexec $(-) --variants=$(variants:Q) $(=) package.strip=$(strip) recurse list.package.$(type) package.license.class=$(license:Q) cc-
1303			done
1304		} |
1305		{
1306			: > $tmp/HEAD
1307			[[ '$(notice)' ]] && echo ";;;$tmp/HEAD;$(package.notice)"
1308			cat > $tmp/README <<'!'
1309	$(package.readme)
1310	!
1311			echo ";;;$tmp/README;README"
1312			sort -t';' -k5,5 -u
1313			: > $tmp/TAIL
1314			[[ '$(notice)' ]] && echo ";;;$tmp/TAIL;$(package.notice)"
1315		} |
1316		$(PAX)	--filter=- \
1317			--to=ascii \
1318			$(op:N=delta:??--format=$(format)?) \
1319			--local \
1320			--checksum=md5:$(PACKAGEGEN)/$(name).sum \
1321			--install=$(PACKAGEGEN)/$(name).ins \
1322			-wvf $(binary) $(base) \
1323			$(op:N=delta:?--format=gzip??) \
1324			-s",^$tmp/,$(INSTALLOFFSET)/," \
1325			$(PACKAGEROOT:C%.*%-s",^&/,,"%)
1326		echo $(binary) >> $(binary:D:B=PACKAGE:S=.$(CC.HOSTTYPE).lst)
1327		$(SUM) -x $(checksum) < $(binary) > $(binary:D:B:S=.$(checksum))
1328		echo $(binary:D:B:S=.$(checksum)) >> $(binary:D:B=PACKAGE:S=.$(CC.HOSTTYPE).lst)
1329		echo local > $(binary:D:B=$(name):S=.$(CC.HOSTTYPE).tim)
1330		if	[[ '$(incremental)' == 1 && '$(old.binary)' ]]
1331		then	$(PAX) -rf $(binary) -wvf $(old.new.binary) -z $(old.binary)
1332			echo $(old.new.binary) >> $(binary:D:B=PACKAGE:S=.$(CC.HOSTTYPE).lst)
1333			$(SUM) -x $(checksum) < $(old.new.binary) > $(old.new.binary:D:B:S=.$(checksum))
1334			echo $(old.new.binary:D:B:S=.$(checksum)) >> $(binary:D:B=PACKAGE:S=.$(CC.HOSTTYPE).lst)
1335		fi
1336		rm -rf $tmp
1337	else	if	[[ '$(binary.$(name))' ]]
1338		then	exe=$(binary.$(name))
1339		else	exe=$(INSTALLROOT)/bin/$(name)
1340		fi
1341		if	[[ '$(old.binary)' ]] && $(CMP) $(CMPFLAGS) $exe $(binary)
1342		then	: $(name) is up to date
1343		else	echo $(name) $(version) $(release|version) 1 > $(PACKAGEGEN)/$(name).ver
1344			: > $(PACKAGEGEN)/$(name).req
1345			{
1346				echo "name='$(name)'"
1347				echo "index='$(index)'"
1348				echo "covers='$(~covers)'"
1349				echo "requires='$(~req)'"
1350			} > $(PACKAGEGEN)/$(name).inx
1351			{
1352				echo '$($(name).README)'
1353				package help binary
1354			} > $(PACKAGEGEN)/$(name).README
1355			case "$(binary)" in
1356			*.gz)	gzip < $exe > $(binary) ;;
1357			*)	cp $exe $(binary) ;;
1358			esac
1359			$(SUM) -x $(checksum) < $(binary) > $(binary:D:B:S=.$(checksum))
1360			echo local > $(binary:D:B=$(name):S=.$(CC.HOSTTYPE).tim)
1361		fi
1362		echo $(binary) >> $(binary:D:B=PACKAGE:S=.$(CC.HOSTTYPE).lst)
1363		echo $(binary:D:B:S=.$(checksum)) >> $(binary:D:B=PACKAGE:S=.$(CC.HOSTTYPE).lst)
1364	fi
1365
1366runtime : .runtime.init .runtime.gen .runtime.$$(style)
1367
1368.runtime.init : .MAKE
1369	local A B D I P V
1370	type := runtime
1371	if ! "$(incremental)"
1372		incremental = 0
1373	end
1374	if ! "$(~$(name))"
1375		if name == "ratz"
1376			suffix = exe
1377		else
1378			suffix = gz
1379		end
1380	end
1381	: $(.init.$(style)) :
1382	: $(details.$(style):V:R) :
1383	A := $(runtime.list)
1384	B := $(A:N=*.$(stamp).$(CC.HOSTTYPE).$(suffix):N!=*.$(stamp).$(stamp).*:O=1:T=F)
1385	P := $(A:N=*.$(stamp).$(CC.HOSTTYPE).$(suffix):N!=*.$(stamp).$(stamp).*:O=2:T=F)
1386	D := $(A:N=*.$(stamp).$(stamp).$(CC.HOSTTYPE).$(suffix):O=1:T=F)
1387	if op == "delta"
1388		if ! B
1389			error 3 delta requires a base archive
1390		end
1391		base := -z $(B)
1392		if "$(release)" != "$(stamp)"
1393			release := $("":T=R%Y-%m-%d)
1394		end
1395		runtime := $(B:/$(CC.HOSTTYPE).$(suffix)$/$(release).&/)
1396		version := $(runtime:B:B:/$(name).//)
1397	elif B || op == "base"
1398		if op == "base"
1399			for I $(B) $(P)
1400				V := $(I:B:/$(name)-run\.\([^.]*\).*/\1/)
1401				if V == "[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]" && V != "$(version)"
1402					old.version := $(V)
1403					old.runtime := $(I)
1404					if "$(old.version)" >= "$(version)"
1405						error 3 $(name): previous base $(old.version) is newer than $(version)
1406					end
1407					break
1408				end
1409			end
1410		else
1411			runtime := $(B)
1412		end
1413		if B == "$(runtime)"
1414			if "$(B:D:B)" == "$(D:D:B)" && "$(B:S)" != "$(D:S)"
1415				error 3 $(B:B:S): base overwrite would invalidate delta $(D:B:S)
1416			end
1417			error 1 $(B:B:S): replacing current base
1418		end
1419		version := $(runtime:B:/$(name)-run.//:/\..*//)
1420	end
1421	PACKAGEGEN := $(PACKAGESRC)/gen
1422
1423.runtime.gen : $$(PACKAGEDIR) $$(PACKAGEGEN)
1424
1425.runtime.cyg .runtime.exp .runtime.lcl .runtime.pkg .runtime.rpm : .MAKE
1426	error 3 $(style): runtime package style not supported yet
1427
1428.runtime.tgz :
1429	if	[[ '$(~$(name))' ]]
1430	then	tmp=/tmp/pkg$(tmp)
1431		mkdir $tmp
1432		{
1433			if	[[ '$(init)' == '$(name)' ]]
1434			then	for i in lib32 lib64
1435				do	if	[[ -d $(INSTALLROOT)/$i ]]
1436					then	echo ";physical;;$(INSTALLROOT)/$i"
1437					fi
1438				done
1439			fi
1440			$(package.src:U:T=F:C%^$(PACKAGEROOT)/%%:C%.*%echo ";;;$(PACKAGEROOT)/&;&"$("\n")%)
1441			$(package.bin:U:T=F:C%^$(INSTALLROOT)/%%:C%.*%echo ";;;$(INSTALLROOT)/&;&"$("\n")%)
1442			$(package.auxiliary.$(style):U:T=F:C%^$(INSTALLROOT)/%%:C%.*%echo ";;;$(INSTALLROOT)/&;&"$("\n")%)
1443			echo $(name) $(version) $(release|version) 1 > $(PACKAGEGEN)/$(name).ver
1444			echo ";;;$(PACKAGEGEN)/$(name).ver;$(PACKAGELIB)/$(name).ver"
1445			if	[[ '$(~covers)' ]]
1446			then	for i in $(~covers)
1447				do	for j in lic pkg
1448					do	if	[[ -f $(PACKAGESRC)/$i.$j ]]
1449						then	echo ";;;$(PACKAGESRC)/$i.$j;$(PACKAGELIB)/$i.$j"
1450						fi
1451					done
1452					for j in ver req
1453					do	if	[[ -f $(PACKAGEGEN)/$i.$j ]]
1454						then	echo ";;;$(PACKAGEGEN)/$i.$j;$(PACKAGELIB)/$i.$j"
1455						fi
1456					done
1457				done
1458				for i in $(~covers:D=$(PACKAGESRC):B:S=.lic:T=F:T=I:N=*.def:D=$(PACKAGESRC):B:S:T=F:B:S)
1459				do	echo ";;;$(PACKAGESRC)/$i;$(PACKAGELIB)/$i"
1460				done
1461			fi
1462			sed 's,1$,0,' $(~req:D=$(PACKAGEGEN):B:S=.ver:T=F) < /dev/null > $(PACKAGEGEN)/$(name).req
1463			echo ";;;$(PACKAGEGEN)/$(name).req;$(PACKAGELIB)/$(name).req"
1464			{
1465				echo "name='$(name)'"
1466				echo "index='$(index)'"
1467				echo "covers='$(~covers)'"
1468				echo "requires='$(~req)'"
1469			} > $(PACKAGEGEN)/$(name).inx
1470			{
1471				{
1472				echo '$($(name).README)'
1473				if	[[ '$(~covers)' ]]
1474				then	echo
1475					echo "This package is a superset of the following package$(~covers:O=2:?s??): $(~covers); you won't need $(~covers:O=2:?these?this?) if you download $(name)."
1476				fi
1477				if	[[ '$(~requires)' ]]
1478				then	echo
1479					echo 'It requires the following package$(~requires:O=2:?s??): $(~requires).'
1480				fi
1481				echo
1482				echo "To install this $(type) package read the tarball into a directory"
1483				echo "suitable for containing bin and lib subdirectories, and run the"
1484				echo "$(PACKAGELIB)/gen/$(name)-run.ins script to fix up permissions."
1485				echo
1486				echo "To use the package export the bin directory in PATH. The commands and"
1487				echo "libraries use \$PATH to locate dynamic libraries and related data files."
1488				echo
1489				} | fmt
1490			} > $(PACKAGEGEN)/$(name)-run.README
1491			echo ";;;$(PACKAGEGEN)/$(name)-run.README;$(PACKAGELIB)/$(name)-run.README"
1492			set -- $(package.closure)
1493			for i
1494			do	cd $(INSTALLROOT)/$i
1495				$(MAKE) --noexec $(-) --variants=$(variants:Q) $(=) package.strip=$(strip) recurse list.package.$(type) package.license.class=$(license:Q) cc-
1496			done
1497		} |
1498		{
1499			: > $tmp/HEAD
1500			[[ '$(notice)' ]] && echo ";;;$tmp/HEAD;$(package.notice)"
1501			cat > $tmp/README <<'!'
1502	$(package.readme)
1503	!
1504			echo ";;;$tmp/README;README"
1505			sort -t';' -k5,5 -u
1506			: > $tmp/TAIL
1507			[[ '$(notice)' ]] && echo ";;;$tmp/TAIL;$(package.notice)"
1508		} |
1509		$(PAX)	--filter=- \
1510			--to=ascii \
1511			$(op:N=delta:??--format=$(format)?) \
1512			--local \
1513			--checksum=md5:$(PACKAGEGEN)/$(name)-run.sum \
1514			--install=$(PACKAGEGEN)/$(name)-run.ins \
1515			-wvf $(runtime) $(base) \
1516			$(op:N=delta:?--format=gzip??) \
1517			-s",^$tmp/,$(INSTALLOFFSET)/," \
1518			$(PACKAGEROOT:C%.*%-s",^&/,,"%)
1519		echo $(runtime) >> $(runtime:D:B=PACKAGE:S=.$(CC.HOSTTYPE).lst)
1520		$(SUM) -x $(checksum) < $(runtime) > $(runtime:D:B:S=.$(checksum))
1521		echo $(runtime:D:B:S=.$(checksum)) >> $(runtime:D:B=PACKAGE:S=.$(CC.HOSTTYPE).lst)
1522		echo local > $(runtime:D:B=$(name)-run:S=.$(CC.HOSTTYPE).tim)
1523		if	[[ '$(incremental)' == 1 && '$(old.runtime)' ]]
1524		then	$(PAX) -rf $(runtime) -wvf $(old.new.runtime) -z $(old.runtime)
1525			echo $(old.new.runtime) >> $(runtime:D:B=PACKAGE:S=.$(CC.HOSTTYPE).lst)
1526			$(SUM) -x $(checksum) < $(old.new.runtime) > $(old.new.runtime:D:B:S=.$(checksum))
1527			echo $(old.new.runtime:D:B:S=.$(checksum)) >> $(runtime:D:B=PACKAGE:S=.$(CC.HOSTTYPE).lst)
1528		fi
1529		rm -rf $tmp
1530	fi
1531
1532list.installed list.manifest :
1533	set -- $(package.closure)
1534	for i
1535	do	cd $(INSTALLROOT)/$i
1536		ignore $(MAKE) --noexec $(-) $(=) $(<)
1537	done
1538