meta.stage.mk revision 288964
146283Sdfr# $FreeBSD: head/share/mk/meta.stage.mk 288964 2015-10-07 00:24:27Z sjg $
298944Sobrien# $Id: meta.stage.mk,v 1.35 2015/05/20 06:40:33 sjg Exp $
346283Sdfr#
498944Sobrien#	@(#) Copyright (c) 2011, Simon J. Gerraty
546283Sdfr#
698944Sobrien#	This file is provided in the hope that it will
798944Sobrien#	be of use.  There is absolutely NO WARRANTY.
898944Sobrien#	Permission to copy, redistribute or otherwise
998944Sobrien#	use this file is hereby granted provided that 
1046283Sdfr#	the above copyright notice and this notice are
1198944Sobrien#	left intact. 
1298944Sobrien#      
1398944Sobrien#	Please send copies of changes and bug-fixes to:
1498944Sobrien#	sjg@crufty.net
1546283Sdfr#
1698944Sobrien
1798944Sobrien.if !target(__${.PARSEFILE}__)
1898944Sobrien__${.PARSEFILE}__:
1998944Sobrien
2046283Sdfr.if ${.MAKE.DEPENDFILE_PREFERENCE:U${.MAKE.DEPENDFILE}:M*.${MACHINE}} != ""
2146283Sdfr# this is generally safer anyway
2246283Sdfr_dirdep = ${RELDIR}.${MACHINE}
2346283Sdfr.else
2446283Sdfr_dirdep = ${RELDIR}
2546283Sdfr.endif
2646283Sdfr
2746283SdfrCLEANFILES+= .dirdep
2846283Sdfr
2946283Sdfr# this allows us to trace dependencies back to their src dir
3098944Sobrien.dirdep:
3198944Sobrien	@echo '${_dirdep}' > $@
3246283Sdfr
3398944Sobrien.if defined(NO_POSIX_SHELL) || ${type printf:L:sh:Mbuiltin} == ""
3498944Sobrien_stage_file_basename = `basename $$f`
3598944Sobrien_stage_target_dirname = `dirname $$t`
3698944Sobrien.else
3798944Sobrien_stage_file_basename = $${f\#\#*/}
3898944Sobrien_stage_target_dirname = $${t%/*}
3946283Sdfr.endif
4098944Sobrien
4146283Sdfr_OBJROOT ?= ${OBJROOT:U${OBJTOP:H}}
4246283Sdfr.if ${_OBJROOT:M*/} != ""
4346283Sdfr_objroot ?= ${_OBJROOT:tA}/
4446283Sdfr.else
4546283Sdfr_objroot ?= ${_OBJROOT:tA}
4646283Sdfr.endif
4746283Sdfr
4846283Sdfr# make sure this is global
4946283Sdfr_STAGED_DIRS ?=
5046283Sdfr.export _STAGED_DIRS
5146283Sdfr# add each dir we stage to to _STAGED_DIRS
5246283Sdfr# and make sure we have absolute paths so that bmake
5398944Sobrien# will match against .MAKE.META.BAILIWICK
5446283SdfrSTAGE_DIR_FILTER = tA:@d@$${_STAGED_DIRS::+=$$d}$$d@
5546283Sdfr# convert _STAGED_DIRS into suitable filters
5646283SdfrGENDIRDEPS_FILTER += Nnot-empty-is-important \
5746283Sdfr	${_STAGED_DIRS:O:u:M${OBJTOP}*:S,${OBJTOP}/,N,} \
5846283Sdfr	${_STAGED_DIRS:O:u:M${_objroot}*:N${OBJTOP}*:S,${_objroot},,:C,^([^/]+)/(.*),N\2.\1,:S,${HOST_TARGET},.host,}
5946283Sdfr
6046283SdfrLN_CP_SCRIPT = LnCp() { \
6146283Sdfr  rm -f $$2 2> /dev/null; \
6246283Sdfr  ln $$1 $$2 2> /dev/null || \
6346283Sdfr  cp -p $$1 $$2; }
6446283Sdfr
6546283Sdfr# a staging conflict should cause an error
6646283Sdfr# a warning is handy when bootstapping different options.
6746283SdfrSTAGE_CONFLICT?= ERROR
6846283Sdfr.if ${STAGE_CONFLICT:tl} == "error"
6946283SdfrSTAGE_CONFLICT_ACTION= exit 1;
7046283Sdfr.else
7146283SdfrSTAGE_CONFLICT_ACTION=
7246283Sdfr.endif
7346283Sdfr
7446283Sdfr# it is an error for more than one src dir to try and stage
7546283Sdfr# the same file
7646283SdfrSTAGE_DIRDEP_SCRIPT = ${LN_CP_SCRIPT}; StageDirdep() { \
7746283Sdfr  t=$$1; \
7846283Sdfr  if [ -s $$t.dirdep ]; then \
7946283Sdfr	cmp -s .dirdep $$t.dirdep && return; \
8046283Sdfr	echo "${STAGE_CONFLICT}: $$t installed by `cat $$t.dirdep` not ${_dirdep}" >&2; \
8146283Sdfr	${STAGE_CONFLICT_ACTION} \
8246283Sdfr  fi; \
8346283Sdfr  LnCp .dirdep $$t.dirdep || exit 1; }
8446283Sdfr
8598944Sobrien# common logic for staging files
8698944Sobrien# this all relies on RELDIR being set to a subdir of SRCTOP
8798944Sobrien# we use ln(1) if we can, else cp(1)
8846283SdfrSTAGE_FILE_SCRIPT = ${STAGE_DIRDEP_SCRIPT}; StageFiles() { \
89130803Smarcel  case "$$1" in "") return;; -m) mode=$$2; shift 2;; *) mode=;; esac; \
90130803Smarcel  dest=$$1; shift; \
9146283Sdfr  mkdir -p $$dest; \
9246283Sdfr  [ -s .dirdep ] || echo '${_dirdep}' > .dirdep; \
9346283Sdfr  for f in "$$@"; do \
9446283Sdfr	case "$$f" in */*) t=$$dest/${_stage_file_basename};; *) t=$$dest/$$f;; esac; \
9546283Sdfr	StageDirdep $$t; \
9646283Sdfr	LnCp $$f $$t || exit 1; \
9746283Sdfr	[ -z "$$mode" ] || chmod $$mode $$t; \
9846283Sdfr  done; :; }
9946283Sdfr
10046283SdfrSTAGE_LINKS_SCRIPT = ${STAGE_DIRDEP_SCRIPT}; StageLinks() { \
10146283Sdfr  case "$$1" in "") return;; --) shift;; -*) ldest= lnf=$$1; shift;; /*) ldest=$$1/;; esac; \
10246283Sdfr  dest=$$1; shift; \
10346283Sdfr  mkdir -p $$dest; \
10446283Sdfr  [ -s .dirdep ] || echo '${_dirdep}' > .dirdep; \
10546283Sdfr  while test $$\# -ge 2; do \
10646283Sdfr	l=$$ldest$$1; shift; \
10746283Sdfr	t=$$dest/$$1; \
10846283Sdfr	case "$$1" in */*) mkdir -p ${_stage_target_dirname};; esac; \
10946283Sdfr	shift; \
11046283Sdfr	StageDirdep $$t; \
11146283Sdfr	rm -f $$t 2>/dev/null; \
11246283Sdfr	ln $$lnf $$l $$t || exit 1; \
11346283Sdfr  done; :; }
11446283Sdfr
11546283SdfrSTAGE_AS_SCRIPT = ${STAGE_DIRDEP_SCRIPT}; StageAs() { \
11646283Sdfr  case "$$1" in "") return;; -m) mode=$$2; shift 2;; *) mode=;; esac; \
11746283Sdfr  dest=$$1; shift; \
11846283Sdfr  mkdir -p $$dest; \
11946283Sdfr  [ -s .dirdep ] || echo '${_dirdep}' > .dirdep; \
12046283Sdfr  while test $$\# -ge 2; do \
12146283Sdfr	s=$$1; shift; \
12246283Sdfr	t=$$dest/$$1; \
12346283Sdfr	case "$$1" in */*) mkdir -p ${_stage_target_dirname};; esac; \
12446283Sdfr	shift; \
12546283Sdfr	StageDirdep $$t; \
12698944Sobrien	LnCp $$s $$t || exit 1; \
12746283Sdfr	[ -z "$$mode" ] || chmod $$mode $$t; \
12846283Sdfr  done; :; }
12946283Sdfr
13046283Sdfr# this is simple, a list of the "staged" files depends on this,
13146283Sdfr_STAGE_BASENAME_USE:	.USE ${.TARGET:T}
13246283Sdfr	@${STAGE_FILE_SCRIPT}; StageFiles ${.TARGET:H:${STAGE_DIR_FILTER}} ${.TARGET:T}
13346283Sdfr
13446283Sdfr_STAGE_AS_BASENAME_USE:        .USE ${.TARGET:T}
13546283Sdfr	@${STAGE_AS_SCRIPT}; StageAs ${.TARGET:H:${STAGE_DIR_FILTER}} ${.TARGET:T} ${STAGE_AS_${.TARGET:T}:U${.TARGET:T}}
13646283Sdfr
13746283Sdfr.if !empty(STAGE_INCSDIR)
13846283SdfrSTAGE_TARGETS += stage_incs
13946283SdfrSTAGE_INCS ?= ${.ALLSRC:N.dirdep:Nstage_*}
14046283Sdfr
14146283Sdfrstage_includes: stage_incs
14246283Sdfrstage_incs:	.dirdep
14346283Sdfr	@${STAGE_FILE_SCRIPT}; StageFiles ${STAGE_INCSDIR:${STAGE_DIR_FILTER}} ${STAGE_INCS}
14446283Sdfr	@touch $@
14546283Sdfr.endif
14646283Sdfr
14746283Sdfr.if !empty(STAGE_LIBDIR)
14846283SdfrSTAGE_TARGETS += stage_libs
14946283Sdfr
15046283SdfrSTAGE_LIBS ?= ${.ALLSRC:N.dirdep:Nstage_*}
15198944Sobrien
15246283Sdfrstage_libs:	.dirdep
15346283Sdfr	@${STAGE_FILE_SCRIPT}; StageFiles ${STAGE_LIBDIR:${STAGE_DIR_FILTER}} ${STAGE_LIBS}
15498944Sobrien.if !defined(NO_SHLIB_LINKS)
15598944Sobrien.if !empty(SHLIB_LINKS)
15698944Sobrien	@${STAGE_LINKS_SCRIPT}; StageLinks -s ${STAGE_LIBDIR:${STAGE_DIR_FILTER}} \
15798944Sobrien	${SHLIB_LINKS:@t@${STAGE_LIBS:T:M$t.*} $t@}
15898944Sobrien.elif !empty(SHLIB_LINK) && !empty(SHLIB_NAME)
15998944Sobrien	@${STAGE_LINKS_SCRIPT}; StageLinks -s ${STAGE_LIBDIR:${STAGE_DIR_FILTER}} ${SHLIB_NAME} ${SHLIB_LINK} ${SYMLINKS:T}
16046283Sdfr.endif
16146283Sdfr.endif
16246283Sdfr	@touch $@
16346283Sdfr.endif
16446283Sdfr
16546283Sdfr.if !empty(STAGE_DIR)
16646283SdfrSTAGE_SETS += _default
16746283SdfrSTAGE_DIR._default = ${STAGE_DIR}
16846283SdfrSTAGE_LINKS_DIR._default = ${STAGE_LINKS_DIR:U${STAGE_OBJTOP}}
169130803SmarcelSTAGE_SYMLINKS_DIR._default = ${STAGE_SYMLINKS_DIR:U${STAGE_OBJTOP}}
17046283SdfrSTAGE_FILES._default = ${STAGE_FILES}
17146283SdfrSTAGE_LINKS._default = ${STAGE_LINKS}
17246283SdfrSTAGE_SYMLINKS._default = ${STAGE_SYMLINKS}
17346283SdfrSTAGE_FILES ?= ${.ALLSRC:N.dirdep:Nstage_*}
174130803SmarcelSTAGE_SYMLINKS ?= ${.ALLSRC:T:N.dirdep:Nstage_*}
17546283Sdfr.endif
17646283Sdfr
17746283Sdfr.if !empty(STAGE_SETS)
17846283SdfrCLEANFILES += ${STAGE_SETS:@s@stage*$s@}
17946283Sdfr
18098944Sobrien# some makefiles need to populate multiple directories
18198944Sobrien.for s in ${STAGE_SETS:O:u}
18298944SobrienSTAGE_FILES.$s ?= ${.ALLSRC:N.dirdep:Nstage_*}
18398944SobrienSTAGE_SYMLINKS.$s ?= ${.ALLSRC:N.dirdep:Nstage_*}
18498944SobrienSTAGE_LINKS_DIR.$s ?= ${STAGE_OBJTOP}
18598944SobrienSTAGE_SYMLINKS_DIR.$s ?= ${STAGE_OBJTOP}
18698944Sobrien
18798944SobrienSTAGE_TARGETS += stage_files
18846283Sdfr.if $s != "_default"
18946283Sdfrstage_files:	stage_files.$s
19046283Sdfrstage_files.$s:	.dirdep
19146283Sdfr.else
19246283Sdfrstage_files:	.dirdep
19346283Sdfr.endif
19446283Sdfr	@${STAGE_FILE_SCRIPT}; StageFiles ${FLAGS.$@} ${STAGE_FILES_DIR.$s:U${STAGE_DIR.$s}:${STAGE_DIR_FILTER}} ${STAGE_FILES.$s}
19546283Sdfr	@touch $@
19646283Sdfr
19746283SdfrSTAGE_TARGETS += stage_links
19846283Sdfr.if $s != "_default"
19946283Sdfrstage_links:	stage_links.$s
20046283Sdfrstage_links.$s:	.dirdep
20146283Sdfr.else
20298944Sobrienstage_links:	.dirdep
20346283Sdfr.endif
20446283Sdfr	@${STAGE_LINKS_SCRIPT}; StageLinks ${STAGE_LINKS_DIR.$s:U${STAGE_DIR.$s}:${STAGE_DIR_FILTER}} ${STAGE_LINKS.$s}
20546283Sdfr	@touch $@
20646283Sdfr
20746283SdfrSTAGE_TARGETS += stage_symlinks
20846283Sdfr.if $s != "_default"
20946283Sdfrstage_symlinks:	stage_symlinks.$s
21046283Sdfrstage_symlinks.$s:	.dirdep
21146283Sdfr.else
21246283Sdfrstage_symlinks:	.dirdep
21346283Sdfr.endif
21446283Sdfr	@${STAGE_LINKS_SCRIPT}; StageLinks -s ${STAGE_SYMLINKS_DIR.$s:U${STAGE_DIR.$s}:${STAGE_DIR_FILTER}} ${STAGE_SYMLINKS.$s}
21546283Sdfr	@touch $@
21646283Sdfr
21746283Sdfr.endfor
21846283Sdfr.endif
219130803Smarcel
22046283Sdfr.if !empty(STAGE_AS_SETS)
22146283SdfrCLEANFILES += ${STAGE_AS_SETS:@s@stage*$s@}
22246283Sdfr
22346283SdfrSTAGE_TARGETS += stage_as
22446283Sdfr
22546283Sdfr# sometimes things need to be renamed as they are staged
22646283Sdfr# each ${file} will be staged as ${STAGE_AS_${file:T}}
22746283Sdfr# one could achieve the same with SYMLINKS
22898944Sobrien.for s in ${STAGE_AS_SETS:O:u}
22998944SobrienSTAGE_AS.$s ?= ${.ALLSRC:N.dirdep:Nstage_*}
23098944Sobrien
23146283Sdfrstage_as:	stage_as.$s
23246283Sdfrstage_as.$s:	.dirdep
23346283Sdfr	@${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}}}@}
23446283Sdfr	@touch $@
23546283Sdfr
23646283Sdfr.endfor
23746283Sdfr.endif
23846283Sdfr
23946283SdfrCLEANFILES += ${STAGE_TARGETS} stage_incs stage_includes
24046283Sdfr
24146283Sdfr# stage_*links usually needs to follow any others.
24246283Sdfr# for non-jobs mode the order here matters
24346283Sdfrstaging: ${STAGE_TARGETS:N*_links} ${STAGE_TARGETS:M*_links}
24446283Sdfr
24546283Sdfr.if ${.MAKE.JOBS:U0} > 0 && ${STAGE_TARGETS:M*_links} != ""
24646283Sdfr# the above isn't sufficient
24746283Sdfr.for t in ${STAGE_TARGETS:N*links:O:u}
24846283Sdfr.ORDER: $t stage_links
24946283Sdfr.endfor
25046283Sdfr.endif
25146283Sdfr
25246283Sdfr# generally we want staging to wait until everything else is done
25346283SdfrSTAGING_WAIT ?= .WAIT
25446283Sdfr
25546283Sdfr.if ${.MAKE.LEVEL} > 0
25646283Sdfrall: ${STAGING_WAIT} staging
25746283Sdfr.endif
25898944Sobrien
25946283Sdfr.if exists(${.PARSEDIR}/stage-install.sh) && !defined(STAGE_INSTALL)
26046283Sdfr# this will run install(1) and then followup with .dirdep files.
26146283SdfrSTAGE_INSTALL := sh ${.PARSEDIR:tA}/stage-install.sh INSTALL="${INSTALL}" OBJDIR=${.OBJDIR:tA}
26246283Sdfr.endif
26346283Sdfr
26446283Sdfr# if ${INSTALL} gets run during 'all' assume it is for staging?
26546283Sdfr.if ${.TARGETS:Nall} == "" && defined(STAGE_INSTALL)
26646283SdfrINSTALL := ${STAGE_INSTALL}
26746283Sdfr.if target(beforeinstall)
26846283Sdfrbeforeinstall: .dirdep
26946283Sdfr.endif
27046283Sdfr.endif
27146283Sdfr.NOPATH: ${STAGE_FILES}
27246283Sdfr
27346283Sdfr.if !empty(STAGE_TARGETS)
27446283SdfrMK_STALE_STAGED?= no
27546283Sdfr.if ${MK_STALE_STAGED} == "yes"
27646283Sdfrall: stale_staged
27746283Sdfr# get a list of paths that we have just staged
27846283Sdfr# get a list of paths that we have previously staged to those same dirs
27998944Sobrien# anything in the 2nd list but not the first is stale - remove it.
28046283Sdfrstale_staged: staging .NOMETA
28146283Sdfr	@egrep '^[WL] .*${STAGE_OBJTOP}' /dev/null ${.MAKE.META.FILES:M*stage_*} | \
28246283Sdfr	sed "/\.dirdep/d;s,.* '*\(${STAGE_OBJTOP}/[^ '][^ ']*\).*,\1," | \
28346283Sdfr	sort > ${.TARGET}.staged1
28446283Sdfr	@grep -l '${_dirdep}' /dev/null ${_STAGED_DIRS:M${STAGE_OBJTOP}*:O:u:@d@$d/*.dirdep@} | \
28546283Sdfr	sed 's,\.dirdep,,' | sort > ${.TARGET}.staged2
28646283Sdfr	@comm -13 ${.TARGET}.staged1 ${.TARGET}.staged2 > ${.TARGET}.stale
28746283Sdfr	@test ! -s ${.TARGET}.stale || { \
28846283Sdfr		echo "Removing stale staged files..."; \
28946283Sdfr		sed 's,.*,& &.dirdep,' ${.TARGET}.stale | xargs rm -f; }
29046283Sdfr
29146283Sdfr.endif
29246283Sdfr.endif
29346283Sdfr.endif
29446283Sdfr