meta.stage.mk revision 297040
1284345Ssjg# $FreeBSD: head/share/mk/meta.stage.mk 297040 2016-03-18 20:03:09Z sjg $ 2297040Ssjg# $Id: meta.stage.mk,v 1.44 2016/03/16 18:21:23 sjg Exp $ 3284345Ssjg# 4284345Ssjg# @(#) Copyright (c) 2011, Simon J. Gerraty 5284345Ssjg# 6284345Ssjg# This file is provided in the hope that it will 7284345Ssjg# be of use. There is absolutely NO WARRANTY. 8284345Ssjg# Permission to copy, redistribute or otherwise 9284345Ssjg# use this file is hereby granted provided that 10284345Ssjg# the above copyright notice and this notice are 11284345Ssjg# left intact. 12284345Ssjg# 13284345Ssjg# Please send copies of changes and bug-fixes to: 14284345Ssjg# sjg@crufty.net 15284345Ssjg# 16284345Ssjg 17284345Ssjg.if !target(__${.PARSEFILE}__) 18284345Ssjg__${.PARSEFILE}__: 19284345Ssjg 20284345Ssjg.if ${.MAKE.DEPENDFILE_PREFERENCE:U${.MAKE.DEPENDFILE}:M*.${MACHINE}} != "" 21284345Ssjg# this is generally safer anyway 22284345Ssjg_dirdep = ${RELDIR}.${MACHINE} 23284345Ssjg.else 24284345Ssjg_dirdep = ${RELDIR} 25284345Ssjg.endif 26284345Ssjg 27288964SsjgCLEANFILES+= .dirdep 28288964Ssjg 29284345Ssjg# this allows us to trace dependencies back to their src dir 30296637Ssjg.dirdep: .NOPATH 31284345Ssjg @echo '${_dirdep}' > $@ 32284345Ssjg 33284345Ssjg.if defined(NO_POSIX_SHELL) || ${type printf:L:sh:Mbuiltin} == "" 34284345Ssjg_stage_file_basename = `basename $$f` 35284345Ssjg_stage_target_dirname = `dirname $$t` 36284345Ssjg.else 37284345Ssjg_stage_file_basename = $${f\#\#*/} 38284345Ssjg_stage_target_dirname = $${t%/*} 39284345Ssjg.endif 40284345Ssjg 41284345Ssjg_OBJROOT ?= ${OBJROOT:U${OBJTOP:H}} 42284345Ssjg.if ${_OBJROOT:M*/} != "" 43284345Ssjg_objroot ?= ${_OBJROOT:tA}/ 44284345Ssjg.else 45284345Ssjg_objroot ?= ${_OBJROOT:tA} 46284345Ssjg.endif 47284345Ssjg 48284345Ssjg# make sure this is global 49284345Ssjg_STAGED_DIRS ?= 50284345Ssjg.export _STAGED_DIRS 51284345Ssjg# add each dir we stage to to _STAGED_DIRS 52284345Ssjg# and make sure we have absolute paths so that bmake 53284345Ssjg# will match against .MAKE.META.BAILIWICK 54284345SsjgSTAGE_DIR_FILTER = tA:@d@$${_STAGED_DIRS::+=$$d}$$d@ 55284345Ssjg# convert _STAGED_DIRS into suitable filters 56284345SsjgGENDIRDEPS_FILTER += Nnot-empty-is-important \ 57284345Ssjg ${_STAGED_DIRS:O:u:M${OBJTOP}*:S,${OBJTOP}/,N,} \ 58284345Ssjg ${_STAGED_DIRS:O:u:M${_objroot}*:N${OBJTOP}*:S,${_objroot},,:C,^([^/]+)/(.*),N\2.\1,:S,${HOST_TARGET},.host,} 59284345Ssjg 60284345SsjgLN_CP_SCRIPT = LnCp() { \ 61284345Ssjg rm -f $$2 2> /dev/null; \ 62297040Ssjg { [ -z "$$mode" ] && ln $$1 $$2 2> /dev/null; } || \ 63284345Ssjg cp -p $$1 $$2; } 64284345Ssjg 65284478Ssjg# a staging conflict should cause an error 66284478Ssjg# a warning is handy when bootstapping different options. 67284478SsjgSTAGE_CONFLICT?= ERROR 68284478Ssjg.if ${STAGE_CONFLICT:tl} == "error" 69284478SsjgSTAGE_CONFLICT_ACTION= exit 1; 70284478Ssjg.else 71284478SsjgSTAGE_CONFLICT_ACTION= 72284478Ssjg.endif 73284478Ssjg 74284345Ssjg# it is an error for more than one src dir to try and stage 75284345Ssjg# the same file 76284345SsjgSTAGE_DIRDEP_SCRIPT = ${LN_CP_SCRIPT}; StageDirdep() { \ 77284345Ssjg t=$$1; \ 78284345Ssjg if [ -s $$t.dirdep ]; then \ 79284345Ssjg cmp -s .dirdep $$t.dirdep && return; \ 80284478Ssjg echo "${STAGE_CONFLICT}: $$t installed by `cat $$t.dirdep` not ${_dirdep}" >&2; \ 81284478Ssjg ${STAGE_CONFLICT_ACTION} \ 82284345Ssjg fi; \ 83284345Ssjg LnCp .dirdep $$t.dirdep || exit 1; } 84284345Ssjg 85284345Ssjg# common logic for staging files 86284345Ssjg# this all relies on RELDIR being set to a subdir of SRCTOP 87284345Ssjg# we use ln(1) if we can, else cp(1) 88284345SsjgSTAGE_FILE_SCRIPT = ${STAGE_DIRDEP_SCRIPT}; StageFiles() { \ 89284345Ssjg case "$$1" in "") return;; -m) mode=$$2; shift 2;; *) mode=;; esac; \ 90284345Ssjg dest=$$1; shift; \ 91284345Ssjg mkdir -p $$dest; \ 92284345Ssjg [ -s .dirdep ] || echo '${_dirdep}' > .dirdep; \ 93284345Ssjg for f in "$$@"; do \ 94284345Ssjg case "$$f" in */*) t=$$dest/${_stage_file_basename};; *) t=$$dest/$$f;; esac; \ 95284345Ssjg StageDirdep $$t; \ 96284345Ssjg LnCp $$f $$t || exit 1; \ 97284345Ssjg [ -z "$$mode" ] || chmod $$mode $$t; \ 98284345Ssjg done; :; } 99284345Ssjg 100284345SsjgSTAGE_LINKS_SCRIPT = ${STAGE_DIRDEP_SCRIPT}; StageLinks() { \ 101284345Ssjg case "$$1" in "") return;; --) shift;; -*) ldest= lnf=$$1; shift;; /*) ldest=$$1/;; esac; \ 102284345Ssjg dest=$$1; shift; \ 103284345Ssjg mkdir -p $$dest; \ 104284345Ssjg [ -s .dirdep ] || echo '${_dirdep}' > .dirdep; \ 105284345Ssjg while test $$\# -ge 2; do \ 106284345Ssjg l=$$ldest$$1; shift; \ 107284345Ssjg t=$$dest/$$1; \ 108284345Ssjg case "$$1" in */*) mkdir -p ${_stage_target_dirname};; esac; \ 109284345Ssjg shift; \ 110284345Ssjg StageDirdep $$t; \ 111284345Ssjg rm -f $$t 2>/dev/null; \ 112284345Ssjg ln $$lnf $$l $$t || exit 1; \ 113284345Ssjg done; :; } 114284345Ssjg 115284345SsjgSTAGE_AS_SCRIPT = ${STAGE_DIRDEP_SCRIPT}; StageAs() { \ 116284345Ssjg case "$$1" in "") return;; -m) mode=$$2; shift 2;; *) mode=;; esac; \ 117284345Ssjg dest=$$1; shift; \ 118284345Ssjg mkdir -p $$dest; \ 119284345Ssjg [ -s .dirdep ] || echo '${_dirdep}' > .dirdep; \ 120284345Ssjg while test $$\# -ge 2; do \ 121284345Ssjg s=$$1; shift; \ 122284345Ssjg t=$$dest/$$1; \ 123284345Ssjg case "$$1" in */*) mkdir -p ${_stage_target_dirname};; esac; \ 124284345Ssjg shift; \ 125284345Ssjg StageDirdep $$t; \ 126284345Ssjg LnCp $$s $$t || exit 1; \ 127284345Ssjg [ -z "$$mode" ] || chmod $$mode $$t; \ 128284345Ssjg done; :; } 129284345Ssjg 130284345Ssjg# this is simple, a list of the "staged" files depends on this, 131284345Ssjg_STAGE_BASENAME_USE: .USE ${.TARGET:T} 132284345Ssjg @${STAGE_FILE_SCRIPT}; StageFiles ${.TARGET:H:${STAGE_DIR_FILTER}} ${.TARGET:T} 133284345Ssjg 134284345Ssjg_STAGE_AS_BASENAME_USE: .USE ${.TARGET:T} 135284345Ssjg @${STAGE_AS_SCRIPT}; StageAs ${.TARGET:H:${STAGE_DIR_FILTER}} ${.TARGET:T} ${STAGE_AS_${.TARGET:T}:U${.TARGET:T}} 136284345Ssjg 137284345Ssjg.if !empty(STAGE_INCSDIR) 138284345SsjgSTAGE_TARGETS += stage_incs 139288964SsjgSTAGE_INCS ?= ${.ALLSRC:N.dirdep:Nstage_*} 140284345Ssjg 141284345Ssjgstage_includes: stage_incs 142284345Ssjgstage_incs: .dirdep 143284345Ssjg @${STAGE_FILE_SCRIPT}; StageFiles ${STAGE_INCSDIR:${STAGE_DIR_FILTER}} ${STAGE_INCS} 144284345Ssjg @touch $@ 145284345Ssjg.endif 146284345Ssjg 147284345Ssjg.if !empty(STAGE_LIBDIR) 148284345SsjgSTAGE_TARGETS += stage_libs 149284345Ssjg 150288964SsjgSTAGE_LIBS ?= ${.ALLSRC:N.dirdep:Nstage_*} 151284345Ssjg 152284345Ssjgstage_libs: .dirdep 153284345Ssjg @${STAGE_FILE_SCRIPT}; StageFiles ${STAGE_LIBDIR:${STAGE_DIR_FILTER}} ${STAGE_LIBS} 154284345Ssjg.if !defined(NO_SHLIB_LINKS) 155284345Ssjg.if !empty(SHLIB_LINKS) 156284345Ssjg @${STAGE_LINKS_SCRIPT}; StageLinks -s ${STAGE_LIBDIR:${STAGE_DIR_FILTER}} \ 157284345Ssjg ${SHLIB_LINKS:@t@${STAGE_LIBS:T:M$t.*} $t@} 158284345Ssjg.elif !empty(SHLIB_LINK) && !empty(SHLIB_NAME) 159290803Sbdrewery @${STAGE_LINKS_SCRIPT}; StageLinks -s ${STAGE_LIBDIR:${STAGE_DIR_FILTER}} ${SHLIB_NAME} ${SHLIB_LINK} 160284345Ssjg.endif 161284345Ssjg.endif 162284345Ssjg @touch $@ 163284345Ssjg.endif 164284345Ssjg 165284345Ssjg.if !empty(STAGE_DIR) 166284345SsjgSTAGE_SETS += _default 167284345SsjgSTAGE_DIR._default = ${STAGE_DIR} 168284345SsjgSTAGE_LINKS_DIR._default = ${STAGE_LINKS_DIR:U${STAGE_OBJTOP}} 169284345SsjgSTAGE_SYMLINKS_DIR._default = ${STAGE_SYMLINKS_DIR:U${STAGE_OBJTOP}} 170284345SsjgSTAGE_FILES._default = ${STAGE_FILES} 171284345SsjgSTAGE_LINKS._default = ${STAGE_LINKS} 172284345SsjgSTAGE_SYMLINKS._default = ${STAGE_SYMLINKS} 173284345SsjgSTAGE_FILES ?= ${.ALLSRC:N.dirdep:Nstage_*} 174284345SsjgSTAGE_SYMLINKS ?= ${.ALLSRC:T:N.dirdep:Nstage_*} 175284345Ssjg.endif 176284345Ssjg 177284345Ssjg.if !empty(STAGE_SETS) 178284345SsjgCLEANFILES += ${STAGE_SETS:@s@stage*$s@} 179284345Ssjg 180284345Ssjg# some makefiles need to populate multiple directories 181284345Ssjg.for s in ${STAGE_SETS:O:u} 182288964SsjgSTAGE_FILES.$s ?= ${.ALLSRC:N.dirdep:Nstage_*} 183288964SsjgSTAGE_SYMLINKS.$s ?= ${.ALLSRC:N.dirdep:Nstage_*} 184284345SsjgSTAGE_LINKS_DIR.$s ?= ${STAGE_OBJTOP} 185284345SsjgSTAGE_SYMLINKS_DIR.$s ?= ${STAGE_OBJTOP} 186284345Ssjg 187284345SsjgSTAGE_TARGETS += stage_files 188284345Ssjg.if $s != "_default" 189284345Ssjgstage_files: stage_files.$s 190284345Ssjgstage_files.$s: .dirdep 191284345Ssjg.else 192284345Ssjgstage_files: .dirdep 193284345Ssjg.endif 194284345Ssjg @${STAGE_FILE_SCRIPT}; StageFiles ${FLAGS.$@} ${STAGE_FILES_DIR.$s:U${STAGE_DIR.$s}:${STAGE_DIR_FILTER}} ${STAGE_FILES.$s} 195284345Ssjg @touch $@ 196284345Ssjg 197284345SsjgSTAGE_TARGETS += stage_links 198284345Ssjg.if $s != "_default" 199284345Ssjgstage_links: stage_links.$s 200284345Ssjgstage_links.$s: .dirdep 201284345Ssjg.else 202284345Ssjgstage_links: .dirdep 203284345Ssjg.endif 204284345Ssjg @${STAGE_LINKS_SCRIPT}; StageLinks ${STAGE_LINKS_DIR.$s:U${STAGE_DIR.$s}:${STAGE_DIR_FILTER}} ${STAGE_LINKS.$s} 205284345Ssjg @touch $@ 206284345Ssjg 207284345SsjgSTAGE_TARGETS += stage_symlinks 208284345Ssjg.if $s != "_default" 209284345Ssjgstage_symlinks: stage_symlinks.$s 210284345Ssjgstage_symlinks.$s: .dirdep 211284345Ssjg.else 212284345Ssjgstage_symlinks: .dirdep 213284345Ssjg.endif 214284345Ssjg @${STAGE_LINKS_SCRIPT}; StageLinks -s ${STAGE_SYMLINKS_DIR.$s:U${STAGE_DIR.$s}:${STAGE_DIR_FILTER}} ${STAGE_SYMLINKS.$s} 215284345Ssjg @touch $@ 216284345Ssjg 217284345Ssjg.endfor 218284345Ssjg.endif 219284345Ssjg 220284345Ssjg.if !empty(STAGE_AS_SETS) 221284345SsjgCLEANFILES += ${STAGE_AS_SETS:@s@stage*$s@} 222284345Ssjg 223284345SsjgSTAGE_TARGETS += stage_as 224284345Ssjg 225284345Ssjg# sometimes things need to be renamed as they are staged 226284345Ssjg# each ${file} will be staged as ${STAGE_AS_${file:T}} 227284345Ssjg# one could achieve the same with SYMLINKS 228284345Ssjg.for s in ${STAGE_AS_SETS:O:u} 229288964SsjgSTAGE_AS.$s ?= ${.ALLSRC:N.dirdep:Nstage_*} 230284345Ssjg 231284345Ssjgstage_as: stage_as.$s 232284345Ssjgstage_as.$s: .dirdep 233284345Ssjg @${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}}}@} 234284345Ssjg @touch $@ 235284345Ssjg 236284345Ssjg.endfor 237284345Ssjg.endif 238284345Ssjg 239284345SsjgCLEANFILES += ${STAGE_TARGETS} stage_incs stage_includes 240284345Ssjg 241284345Ssjg# stage_*links usually needs to follow any others. 242288964Ssjg# for non-jobs mode the order here matters 243288964Ssjgstaging: ${STAGE_TARGETS:N*_links} ${STAGE_TARGETS:M*_links} 244288964Ssjg 245296637Ssjg.if ${.MAKE.JOBS:U0} > 0 && ${STAGE_TARGETS:U:M*_links} != "" 246288964Ssjg# the above isn't sufficient 247288964Ssjg.for t in ${STAGE_TARGETS:N*links:O:u} 248288964Ssjg.ORDER: $t stage_links 249284345Ssjg.endfor 250288475Sbdrewery.endif 251284345Ssjg 252284345Ssjg# generally we want staging to wait until everything else is done 253284345SsjgSTAGING_WAIT ?= .WAIT 254284345Ssjg 255284345Ssjg.if ${.MAKE.LEVEL} > 0 256284345Ssjgall: ${STAGING_WAIT} staging 257284345Ssjg.endif 258284345Ssjg 259284345Ssjg.if exists(${.PARSEDIR}/stage-install.sh) && !defined(STAGE_INSTALL) 260284345Ssjg# this will run install(1) and then followup with .dirdep files. 261284345SsjgSTAGE_INSTALL := sh ${.PARSEDIR:tA}/stage-install.sh INSTALL="${INSTALL}" OBJDIR=${.OBJDIR:tA} 262284345Ssjg.endif 263284345Ssjg 264284345Ssjg# if ${INSTALL} gets run during 'all' assume it is for staging? 265284345Ssjg.if ${.TARGETS:Nall} == "" && defined(STAGE_INSTALL) 266284345SsjgINSTALL := ${STAGE_INSTALL} 267284345Ssjg.if target(beforeinstall) 268284345Ssjgbeforeinstall: .dirdep 269284345Ssjg.endif 270284345Ssjg.endif 271284345Ssjg.NOPATH: ${STAGE_FILES} 272284345Ssjg 273284345Ssjg.if !empty(STAGE_TARGETS) 274284345SsjgMK_STALE_STAGED?= no 275284345Ssjg.if ${MK_STALE_STAGED} == "yes" 276284345Ssjgall: stale_staged 277284345Ssjg# get a list of paths that we have just staged 278284345Ssjg# get a list of paths that we have previously staged to those same dirs 279284345Ssjg# anything in the 2nd list but not the first is stale - remove it. 280284345Ssjgstale_staged: staging .NOMETA 281284345Ssjg @egrep '^[WL] .*${STAGE_OBJTOP}' /dev/null ${.MAKE.META.FILES:M*stage_*} | \ 282284345Ssjg sed "/\.dirdep/d;s,.* '*\(${STAGE_OBJTOP}/[^ '][^ ']*\).*,\1," | \ 283284345Ssjg sort > ${.TARGET}.staged1 284284345Ssjg @grep -l '${_dirdep}' /dev/null ${_STAGED_DIRS:M${STAGE_OBJTOP}*:O:u:@d@$d/*.dirdep@} | \ 285284345Ssjg sed 's,\.dirdep,,' | sort > ${.TARGET}.staged2 286284345Ssjg @comm -13 ${.TARGET}.staged1 ${.TARGET}.staged2 > ${.TARGET}.stale 287284345Ssjg @test ! -s ${.TARGET}.stale || { \ 288284345Ssjg echo "Removing stale staged files..."; \ 289284345Ssjg sed 's,.*,& &.dirdep,' ${.TARGET}.stale | xargs rm -f; } 290284345Ssjg 291284345Ssjg.endif 292284345Ssjg.endif 293284345Ssjg.endif 294