1321964Ssjg# $Id: meta.stage.mk,v 1.54 2017/07/06 23:20:33 sjg Exp $
2246149Ssjg#
3321964Ssjg#	@(#) Copyright (c) 2011-2017, Simon J. Gerraty
4246149Ssjg#
5246149Ssjg#	This file is provided in the hope that it will
6246149Ssjg#	be of use.  There is absolutely NO WARRANTY.
7246149Ssjg#	Permission to copy, redistribute or otherwise
8246149Ssjg#	use this file is hereby granted provided that 
9246149Ssjg#	the above copyright notice and this notice are
10246149Ssjg#	left intact. 
11246149Ssjg#      
12246149Ssjg#	Please send copies of changes and bug-fixes to:
13246149Ssjg#	sjg@crufty.net
14246149Ssjg#
15246149Ssjg
16321964Ssjg.ifndef NO_STAGING
17321964Ssjg
18246149Ssjg.if !target(__${.PARSEFILE}__)
19321964Ssjg# the guard target is defined later
20246149Ssjg
21246149Ssjg.if ${.MAKE.DEPENDFILE_PREFERENCE:U${.MAKE.DEPENDFILE}:M*.${MACHINE}} != ""
22246149Ssjg# this is generally safer anyway
23246149Ssjg_dirdep = ${RELDIR}.${MACHINE}
24246149Ssjg.else
25246149Ssjg_dirdep = ${RELDIR}
26246149Ssjg.endif
27246149Ssjg
28292068SsjgCLEANFILES+= .dirdep
29292068Ssjg
30246149Ssjg# this allows us to trace dependencies back to their src dir
31321964Ssjg.dirdep:	.NOPATH
32246149Ssjg	@echo '${_dirdep}' > $@
33246149Ssjg
34246149Ssjg.if defined(NO_POSIX_SHELL) || ${type printf:L:sh:Mbuiltin} == ""
35246149Ssjg_stage_file_basename = `basename $$f`
36246149Ssjg_stage_target_dirname = `dirname $$t`
37246149Ssjg.else
38246149Ssjg_stage_file_basename = $${f\#\#*/}
39246149Ssjg_stage_target_dirname = $${t%/*}
40246149Ssjg.endif
41246149Ssjg
42292068Ssjg_OBJROOT ?= ${OBJROOT:U${OBJTOP:H}}
43292068Ssjg.if ${_OBJROOT:M*/} != ""
44292068Ssjg_objroot ?= ${_OBJROOT:tA}/
45292068Ssjg.else
46246149Ssjg_objroot ?= ${_OBJROOT:tA}
47292068Ssjg.endif
48292068Ssjg
49246149Ssjg# make sure this is global
50246149Ssjg_STAGED_DIRS ?=
51246149Ssjg.export _STAGED_DIRS
52246149Ssjg# add each dir we stage to to _STAGED_DIRS
53246149Ssjg# and make sure we have absolute paths so that bmake
54246149Ssjg# will match against .MAKE.META.BAILIWICK
55246149SsjgSTAGE_DIR_FILTER = tA:@d@$${_STAGED_DIRS::+=$$d}$$d@
56246149Ssjg# convert _STAGED_DIRS into suitable filters
57246149SsjgGENDIRDEPS_FILTER += Nnot-empty-is-important \
58246149Ssjg	${_STAGED_DIRS:O:u:M${OBJTOP}*:S,${OBJTOP}/,N,} \
59292068Ssjg	${_STAGED_DIRS:O:u:M${_objroot}*:N${OBJTOP}*:S,${_objroot},,:C,^([^/]+)/(.*),N\2.\1,:S,${HOST_TARGET},.host,}
60246149Ssjg
61249033SsjgLN_CP_SCRIPT = LnCp() { \
62249033Ssjg  rm -f $$2 2> /dev/null; \
63321964Ssjg  { [ -z "$$mode" ] && ${LN:Uln} $$1 $$2 2> /dev/null; } || \
64249033Ssjg  cp -p $$1 $$2; }
65249033Ssjg
66292068Ssjg# a staging conflict should cause an error
67292068Ssjg# a warning is handy when bootstapping different options.
68292068SsjgSTAGE_CONFLICT?= ERROR
69292068Ssjg.if ${STAGE_CONFLICT:tl} == "error"
70292068SsjgSTAGE_CONFLICT_ACTION= exit 1;
71292068Ssjg.else
72292068SsjgSTAGE_CONFLICT_ACTION=
73292068Ssjg.endif
74292068Ssjg
75246149Ssjg# it is an error for more than one src dir to try and stage
76246149Ssjg# the same file
77249033SsjgSTAGE_DIRDEP_SCRIPT = ${LN_CP_SCRIPT}; StageDirdep() { \
78246149Ssjg  t=$$1; \
79246149Ssjg  if [ -s $$t.dirdep ]; then \
80246149Ssjg	cmp -s .dirdep $$t.dirdep && return; \
81292068Ssjg	echo "${STAGE_CONFLICT}: $$t installed by `cat $$t.dirdep` not ${_dirdep}" >&2; \
82292068Ssjg	${STAGE_CONFLICT_ACTION} \
83246149Ssjg  fi; \
84249033Ssjg  LnCp .dirdep $$t.dirdep || exit 1; }
85246149Ssjg
86246149Ssjg# common logic for staging files
87246149Ssjg# this all relies on RELDIR being set to a subdir of SRCTOP
88246149Ssjg# we use ln(1) if we can, else cp(1)
89246149SsjgSTAGE_FILE_SCRIPT = ${STAGE_DIRDEP_SCRIPT}; StageFiles() { \
90249033Ssjg  case "$$1" in "") return;; -m) mode=$$2; shift 2;; *) mode=;; esac; \
91246149Ssjg  dest=$$1; shift; \
92246149Ssjg  mkdir -p $$dest; \
93246149Ssjg  [ -s .dirdep ] || echo '${_dirdep}' > .dirdep; \
94246149Ssjg  for f in "$$@"; do \
95246149Ssjg	case "$$f" in */*) t=$$dest/${_stage_file_basename};; *) t=$$dest/$$f;; esac; \
96246149Ssjg	StageDirdep $$t; \
97249033Ssjg	LnCp $$f $$t || exit 1; \
98249033Ssjg	[ -z "$$mode" ] || chmod $$mode $$t; \
99246149Ssjg  done; :; }
100246149Ssjg
101246149SsjgSTAGE_LINKS_SCRIPT = ${STAGE_DIRDEP_SCRIPT}; StageLinks() { \
102249033Ssjg  case "$$1" in "") return;; --) shift;; -*) ldest= lnf=$$1; shift;; /*) ldest=$$1/;; esac; \
103246149Ssjg  dest=$$1; shift; \
104246149Ssjg  mkdir -p $$dest; \
105246149Ssjg  [ -s .dirdep ] || echo '${_dirdep}' > .dirdep; \
106246149Ssjg  while test $$\# -ge 2; do \
107246149Ssjg	l=$$ldest$$1; shift; \
108246149Ssjg	t=$$dest/$$1; \
109246149Ssjg	case "$$1" in */*) mkdir -p ${_stage_target_dirname};; esac; \
110246149Ssjg	shift; \
111246149Ssjg	StageDirdep $$t; \
112246149Ssjg	rm -f $$t 2>/dev/null; \
113249033Ssjg	ln $$lnf $$l $$t || exit 1; \
114246149Ssjg  done; :; }
115246149Ssjg
116246149SsjgSTAGE_AS_SCRIPT = ${STAGE_DIRDEP_SCRIPT}; StageAs() { \
117249033Ssjg  case "$$1" in "") return;; -m) mode=$$2; shift 2;; *) mode=;; esac; \
118246149Ssjg  dest=$$1; shift; \
119246149Ssjg  mkdir -p $$dest; \
120246149Ssjg  [ -s .dirdep ] || echo '${_dirdep}' > .dirdep; \
121246149Ssjg  while test $$\# -ge 2; do \
122246149Ssjg	s=$$1; shift; \
123246149Ssjg	t=$$dest/$$1; \
124246149Ssjg	case "$$1" in */*) mkdir -p ${_stage_target_dirname};; esac; \
125246149Ssjg	shift; \
126246149Ssjg	StageDirdep $$t; \
127249033Ssjg	LnCp $$s $$t || exit 1; \
128249033Ssjg	[ -z "$$mode" ] || chmod $$mode $$t; \
129246149Ssjg  done; :; }
130246149Ssjg
131246149Ssjg# this is simple, a list of the "staged" files depends on this,
132321964Ssjg_STAGE_BASENAME_USE:	.USE .dirdep ${.TARGET:T}
133246149Ssjg	@${STAGE_FILE_SCRIPT}; StageFiles ${.TARGET:H:${STAGE_DIR_FILTER}} ${.TARGET:T}
134246149Ssjg
135321964Ssjg_STAGE_AS_BASENAME_USE:        .USE .dirdep ${.TARGET:T}
136292068Ssjg	@${STAGE_AS_SCRIPT}; StageAs ${.TARGET:H:${STAGE_DIR_FILTER}} ${.TARGET:T} ${STAGE_AS_${.TARGET:T}:U${.TARGET:T}}
137292068Ssjg
138321964Ssjg
139321964Ssjg.endif				# first time
140321964Ssjg
141321964Ssjg
142246149Ssjg.if !empty(STAGE_INCSDIR)
143321964Ssjg.if !empty(STAGE_INCS)
144321964Ssjgstage_incs: ${STAGE_INCS}
145321964Ssjg.endif
146321964Ssjg.if target(stage_incs) || !empty(.ALLTARGETS:Mstage_includes)
147249033SsjgSTAGE_TARGETS += stage_incs
148292068SsjgSTAGE_INCS ?= ${.ALLSRC:N.dirdep:Nstage_*}
149292068Ssjgstage_includes: stage_incs
150246149Ssjgstage_incs:	.dirdep
151246149Ssjg	@${STAGE_FILE_SCRIPT}; StageFiles ${STAGE_INCSDIR:${STAGE_DIR_FILTER}} ${STAGE_INCS}
152246149Ssjg	@touch $@
153321964Ssjg
154246149Ssjg.endif
155321964Ssjg.endif
156246149Ssjg
157246149Ssjg.if !empty(STAGE_LIBDIR)
158321964Ssjg.if !empty(STAGE_LIBS)
159321964Ssjgstage_libs: ${STAGE_LIBS}
160321964Ssjg.endif
161321964Ssjg.if target(stage_libs)
162249033SsjgSTAGE_TARGETS += stage_libs
163292068SsjgSTAGE_LIBS ?= ${.ALLSRC:N.dirdep:Nstage_*}
164246149Ssjgstage_libs:	.dirdep
165246149Ssjg	@${STAGE_FILE_SCRIPT}; StageFiles ${STAGE_LIBDIR:${STAGE_DIR_FILTER}} ${STAGE_LIBS}
166292068Ssjg.if !defined(NO_SHLIB_LINKS)
167246149Ssjg.if !empty(SHLIB_LINKS)
168246149Ssjg	@${STAGE_LINKS_SCRIPT}; StageLinks -s ${STAGE_LIBDIR:${STAGE_DIR_FILTER}} \
169246149Ssjg	${SHLIB_LINKS:@t@${STAGE_LIBS:T:M$t.*} $t@}
170246149Ssjg.elif !empty(SHLIB_LINK) && !empty(SHLIB_NAME)
171292068Ssjg	@${STAGE_LINKS_SCRIPT}; StageLinks -s ${STAGE_LIBDIR:${STAGE_DIR_FILTER}} ${SHLIB_NAME} ${SHLIB_LINK}
172246149Ssjg.endif
173292068Ssjg.endif
174246149Ssjg	@touch $@
175246149Ssjg.endif
176321964Ssjg.endif
177246149Ssjg
178246149Ssjg.if !empty(STAGE_DIR)
179246149SsjgSTAGE_SETS += _default
180246149SsjgSTAGE_DIR._default = ${STAGE_DIR}
181246149SsjgSTAGE_LINKS_DIR._default = ${STAGE_LINKS_DIR:U${STAGE_OBJTOP}}
182246149SsjgSTAGE_SYMLINKS_DIR._default = ${STAGE_SYMLINKS_DIR:U${STAGE_OBJTOP}}
183246149SsjgSTAGE_FILES._default = ${STAGE_FILES}
184246149SsjgSTAGE_LINKS._default = ${STAGE_LINKS}
185246149SsjgSTAGE_SYMLINKS._default = ${STAGE_SYMLINKS}
186246149Ssjg.endif
187246149Ssjg
188246149Ssjg.if !empty(STAGE_SETS)
189246149SsjgCLEANFILES += ${STAGE_SETS:@s@stage*$s@}
190246149Ssjg
191246149Ssjg# some makefiles need to populate multiple directories
192246149Ssjg.for s in ${STAGE_SETS:O:u}
193321964Ssjg.if !empty(STAGE_FILES.$s)
194321964Ssjgstage_files.$s: ${STAGE_FILES.$s}
195321964Ssjg.endif
196321964Ssjg.if target(stage_files.$s) || target(stage_files${s:S,^,.,:N._default})
197321964SsjgSTAGE_TARGETS += stage_files
198292068SsjgSTAGE_FILES.$s ?= ${.ALLSRC:N.dirdep:Nstage_*}
199321964Ssjg.if !target(.stage_files.$s)
200321964Ssjg.stage_files.$s:
201246149Ssjg.if $s != "_default"
202246149Ssjgstage_files:	stage_files.$s
203246149Ssjgstage_files.$s:	.dirdep
204246149Ssjg.else
205321964SsjgSTAGE_FILES ?= ${.ALLSRC:N.dirdep:Nstage_*}
206246149Ssjgstage_files:	.dirdep
207246149Ssjg.endif
208246149Ssjg	@${STAGE_FILE_SCRIPT}; StageFiles ${FLAGS.$@} ${STAGE_FILES_DIR.$s:U${STAGE_DIR.$s}:${STAGE_DIR_FILTER}} ${STAGE_FILES.$s}
209246149Ssjg	@touch $@
210321964Ssjg.endif
211321964Ssjg.endif
212246149Ssjg
213321964Ssjg.if !empty(STAGE_LINKS.$s)
214321964Ssjgstage_links.$s:
215321964Ssjg.endif
216321964Ssjg.if target(stage_links.$s) || target(stage_links${s:S,^,.,:N._default})
217321964SsjgSTAGE_LINKS_DIR.$s ?= ${STAGE_OBJTOP}
218249033SsjgSTAGE_TARGETS += stage_links
219321964Ssjg.if !target(.stage_links.$s)
220321964Ssjg.stage_links.$s:
221246149Ssjg.if $s != "_default"
222246149Ssjgstage_links:	stage_links.$s
223246149Ssjgstage_links.$s:	.dirdep
224246149Ssjg.else
225246149Ssjgstage_links:	.dirdep
226246149Ssjg.endif
227246149Ssjg	@${STAGE_LINKS_SCRIPT}; StageLinks ${STAGE_LINKS_DIR.$s:U${STAGE_DIR.$s}:${STAGE_DIR_FILTER}} ${STAGE_LINKS.$s}
228246149Ssjg	@touch $@
229321964Ssjg.endif
230321964Ssjg.endif
231246149Ssjg
232321964Ssjg.if !empty(STAGE_SYMLINKS.$s)
233321964Ssjgstage_symlinks.$s:
234321964Ssjg.endif
235321964Ssjg.if target(stage_symlinks.$s) || target(stage_symlinks${s:S,^,.,:N._default})
236321964SsjgSTAGE_SYMLINKS_DIR.$s ?= ${STAGE_OBJTOP}
237249033SsjgSTAGE_TARGETS += stage_symlinks
238321964Ssjg.if !target(.stage_symlinks.$s)
239321964Ssjg.stage_symlinks.$s:
240246149Ssjg.if $s != "_default"
241246149Ssjgstage_symlinks:	stage_symlinks.$s
242246149Ssjgstage_symlinks.$s:	.dirdep
243246149Ssjg.else
244246149Ssjgstage_symlinks:	.dirdep
245246149Ssjg.endif
246246149Ssjg	@${STAGE_LINKS_SCRIPT}; StageLinks -s ${STAGE_SYMLINKS_DIR.$s:U${STAGE_DIR.$s}:${STAGE_DIR_FILTER}} ${STAGE_SYMLINKS.$s}
247246149Ssjg	@touch $@
248321964Ssjg.endif
249321964Ssjg.endif
250246149Ssjg
251246149Ssjg.endfor
252246149Ssjg.endif
253246149Ssjg
254246149Ssjg.if !empty(STAGE_AS_SETS)
255246149SsjgCLEANFILES += ${STAGE_AS_SETS:@s@stage*$s@}
256246149Ssjg
257246149Ssjg# sometimes things need to be renamed as they are staged
258246149Ssjg# each ${file} will be staged as ${STAGE_AS_${file:T}}
259246149Ssjg# one could achieve the same with SYMLINKS
260321964Ssjg# stage_as_and_symlink makes the original name a symlink to the new name
261321964Ssjg# it is the same as using stage_as and stage_symlinks but ensures
262321964Ssjg# both operations happen together
263246149Ssjg.for s in ${STAGE_AS_SETS:O:u}
264321964Ssjg.if !empty(STAGE_AS.$s)
265321964Ssjgstage_as.$s: ${STAGE_AS.$s}
266321964Ssjg.endif
267321964Ssjg.if target(stage_as.$s)
268321964SsjgSTAGE_TARGETS += stage_as
269292068SsjgSTAGE_AS.$s ?= ${.ALLSRC:N.dirdep:Nstage_*}
270321964Ssjg.if !target(.stage_as.$s)
271321964Ssjg.stage_as.$s:
272246149Ssjgstage_as:	stage_as.$s
273246149Ssjgstage_as.$s:	.dirdep
274292068Ssjg	@${STAGE_AS_SCRIPT}; StageAs ${FLAGS.$@} ${STAGE_FILES_DIR.$s:U${STAGE_DIR.$s}:${STAGE_DIR_FILTER}} ${STAGE_AS.$s:@f@$f ${STAGE_AS_${f:tA}:U${STAGE_AS_${f:T}:U${f:T}}}@}
275246149Ssjg	@touch $@
276321964Ssjg.endif
277321964Ssjg.endif
278246149Ssjg
279321964Ssjg.if !empty(STAGE_AS_AND_SYMLINK.$s)
280321964Ssjgstage_as_and_symlink.$s: ${STAGE_AS_AND_SYMLINK.$s}
281321964Ssjg.endif
282321964Ssjg.if target(stage_as_and_symlink.$s)
283321964SsjgSTAGE_TARGETS += stage_as_and_symlink
284321964SsjgSTAGE_AS_AND_SYMLINK.$s ?= ${.ALLSRC:N.dirdep:Nstage_*}
285321964Ssjg.if !target(.stage_as_and_symlink.$s)
286321964Ssjg.stage_as_and_symlink.$s:
287321964Ssjgstage_as_and_symlink:	stage_as_and_symlink.$s
288321964Ssjgstage_as_and_symlink.$s:	.dirdep
289321964Ssjg	@${STAGE_AS_SCRIPT}; StageAs ${FLAGS.$@} ${STAGE_FILES_DIR.$s:U${STAGE_DIR.$s}:${STAGE_DIR_FILTER}} ${STAGE_AS_AND_SYMLINK.$s:@f@$f ${STAGE_AS_${f:tA}:U${STAGE_AS_${f:T}:U${f:T}}}@}
290321964Ssjg	@${STAGE_LINKS_SCRIPT}; StageLinks -s ${STAGE_FILES_DIR.$s:U${STAGE_DIR.$s}:${STAGE_DIR_FILTER}} ${STAGE_AS_AND_SYMLINK.$s:@f@${STAGE_AS_${f:tA}:U${STAGE_AS_${f:T}:U${f:T}}} $f@}
291321964Ssjg	@touch $@
292321964Ssjg.endif
293321964Ssjg.endif
294321964Ssjg
295246149Ssjg.endfor
296246149Ssjg.endif
297246149Ssjg
298292068SsjgCLEANFILES += ${STAGE_TARGETS} stage_incs stage_includes
299249033Ssjg
300321964Ssjg# this lot also only makes sense the first time...
301321964Ssjg.if !target(__${.PARSEFILE}__)
302321964Ssjg__${.PARSEFILE}__:
303321964Ssjg
304249033Ssjg# stage_*links usually needs to follow any others.
305292068Ssjg# for non-jobs mode the order here matters
306292068Ssjgstaging: ${STAGE_TARGETS:N*_links} ${STAGE_TARGETS:M*_links}
307292068Ssjg
308321964Ssjg.if ${.MAKE.JOBS:U0} > 0 && ${STAGE_TARGETS:U:M*_links} != ""
309292068Ssjg# the above isn't sufficient
310249033Ssjg.for t in ${STAGE_TARGETS:N*links:O:u}
311249033Ssjg.ORDER: $t stage_links
312249033Ssjg.endfor
313292068Ssjg.endif
314249033Ssjg
315249033Ssjg# generally we want staging to wait until everything else is done
316249033SsjgSTAGING_WAIT ?= .WAIT
317249033Ssjg
318292068Ssjg.if ${.MAKE.LEVEL} > 0
319249033Ssjgall: ${STAGING_WAIT} staging
320292068Ssjg.endif
321249033Ssjg
322250837Ssjg.if exists(${.PARSEDIR}/stage-install.sh) && !defined(STAGE_INSTALL)
323250837Ssjg# this will run install(1) and then followup with .dirdep files.
324250837SsjgSTAGE_INSTALL := sh ${.PARSEDIR:tA}/stage-install.sh INSTALL="${INSTALL}" OBJDIR=${.OBJDIR:tA}
325246149Ssjg.endif
326250837Ssjg
327250837Ssjg# if ${INSTALL} gets run during 'all' assume it is for staging?
328250837Ssjg.if ${.TARGETS:Nall} == "" && defined(STAGE_INSTALL)
329250837SsjgINSTALL := ${STAGE_INSTALL}
330250837Ssjg.if target(beforeinstall)
331250837Ssjgbeforeinstall: .dirdep
332250837Ssjg.endif
333250837Ssjg.endif
334292068Ssjg.NOPATH: ${STAGE_FILES}
335250837Ssjg
336292068Ssjg.if !empty(STAGE_TARGETS)
337321964Ssjg# for backwards compat make sure they exist
338321964Ssjg${STAGE_TARGETS}:
339321964Ssjg
340321964Ssjg.NOPATH: ${CLEANFILES}
341321964Ssjg
342292068SsjgMK_STALE_STAGED?= no
343292068Ssjg.if ${MK_STALE_STAGED} == "yes"
344292068Ssjgall: stale_staged
345292068Ssjg# get a list of paths that we have just staged
346292068Ssjg# get a list of paths that we have previously staged to those same dirs
347292068Ssjg# anything in the 2nd list but not the first is stale - remove it.
348292068Ssjgstale_staged: staging .NOMETA
349292068Ssjg	@egrep '^[WL] .*${STAGE_OBJTOP}' /dev/null ${.MAKE.META.FILES:M*stage_*} | \
350292068Ssjg	sed "/\.dirdep/d;s,.* '*\(${STAGE_OBJTOP}/[^ '][^ ']*\).*,\1," | \
351292068Ssjg	sort > ${.TARGET}.staged1
352292068Ssjg	@grep -l '${_dirdep}' /dev/null ${_STAGED_DIRS:M${STAGE_OBJTOP}*:O:u:@d@$d/*.dirdep@} | \
353292068Ssjg	sed 's,\.dirdep,,' | sort > ${.TARGET}.staged2
354292068Ssjg	@comm -13 ${.TARGET}.staged1 ${.TARGET}.staged2 > ${.TARGET}.stale
355292068Ssjg	@test ! -s ${.TARGET}.stale || { \
356292068Ssjg		echo "Removing stale staged files..."; \
357292068Ssjg		sed 's,.*,& &.dirdep,' ${.TARGET}.stale | xargs rm -f; }
358292068Ssjg
359250837Ssjg.endif
360292068Ssjg.endif
361292068Ssjg.endif
362321964Ssjg.endif
363