xref: /freebsd/share/mk/meta.stage.mk (revision f5f7c05209ca2c3748fd8b27c5e80ffad49120eb)
1# $Id: meta.stage.mk,v 1.15 2012/10/14 02:50:38 sjg Exp $
2#
3#	@(#) Copyright (c) 2011, Simon J. Gerraty
4#
5#	This file is provided in the hope that it will
6#	be of use.  There is absolutely NO WARRANTY.
7#	Permission to copy, redistribute or otherwise
8#	use this file is hereby granted provided that
9#	the above copyright notice and this notice are
10#	left intact.
11#
12#	Please send copies of changes and bug-fixes to:
13#	sjg@crufty.net
14#
15
16.if !target(__${.PARSEFILE}__)
17__${.PARSEFILE}__:
18
19.if ${.MAKE.DEPENDFILE_PREFERENCE:U${.MAKE.DEPENDFILE}:M*.${MACHINE}} != ""
20# this is generally safer anyway
21_dirdep = ${RELDIR}.${MACHINE}
22.else
23_dirdep = ${RELDIR}
24.endif
25
26# this allows us to trace dependencies back to their src dir
27.dirdep:
28	@echo '${_dirdep}' > $@
29
30.if defined(NO_POSIX_SHELL) || ${type printf:L:sh:Mbuiltin} == ""
31_stage_file_basename = `basename $$f`
32_stage_target_dirname = `dirname $$t`
33.else
34_stage_file_basename = $${f\#\#*/}
35_stage_target_dirname = $${t%/*}
36.endif
37
38_objroot ?= ${_OBJROOT:tA}
39# make sure this is global
40_STAGED_DIRS ?=
41.export _STAGED_DIRS
42# add each dir we stage to to _STAGED_DIRS
43# and make sure we have absolute paths so that bmake
44# will match against .MAKE.META.BAILIWICK
45STAGE_DIR_FILTER = tA:@d@$${_STAGED_DIRS::+=$$d}$$d@
46# convert _STAGED_DIRS into suitable filters
47GENDIRDEPS_FILTER += Nnot-empty-is-important \
48	${_STAGED_DIRS:O:u:M${OBJTOP}*:S,${OBJTOP}/,N,} \
49	${_STAGED_DIRS:O:u:N${OBJTOP}*:S,${_objroot},,:C,^([^/]+)/(.*),N\2.\1,:S,${HOST_TARGET},.host,}
50
51# it is an error for more than one src dir to try and stage
52# the same file
53STAGE_DIRDEP_SCRIPT = StageDirdep() { \
54  t=$$1; \
55  if [ -s $$t.dirdep ]; then \
56	cmp -s .dirdep $$t.dirdep && return; \
57	echo "ERROR: $$t installed by `cat $$t.dirdep` not ${_dirdep}" >&2; \
58	exit 1; \
59  fi; \
60  ln .dirdep $$t.dirdep 2> /dev/null || \
61  cp .dirdep $$t.dirdep; }
62
63# common logic for staging files
64# this all relies on RELDIR being set to a subdir of SRCTOP
65# we use ln(1) if we can, else cp(1)
66STAGE_FILE_SCRIPT = ${STAGE_DIRDEP_SCRIPT}; StageFiles() { \
67  case "$$1" in -m) mode=$$2; shift 2;; *) mode=;; esac; \
68  dest=$$1; shift; \
69  mkdir -p $$dest; \
70  [ -s .dirdep ] || echo '${_dirdep}' > .dirdep; \
71  for f in "$$@"; do \
72	case "$$f" in */*) t=$$dest/${_stage_file_basename};; *) t=$$dest/$$f;; esac; \
73	StageDirdep $$t; \
74	rm -f $$t; \
75	{ ln $$f $$t 2> /dev/null || \
76	cp -p $$f $$t; }; \
77	$${mode:+chmod $$mode $$t}; \
78  done; :; }
79
80STAGE_LINKS_SCRIPT = ${STAGE_DIRDEP_SCRIPT}; StageLinks() { \
81  case "$$1" in --) shift;; -*) ldest= lnf=$$1; shift;; /*) ldest=$$1/;; esac; \
82  dest=$$1; shift; \
83  mkdir -p $$dest; \
84  [ -s .dirdep ] || echo '${_dirdep}' > .dirdep; \
85  while test $$\# -ge 2; do \
86	l=$$ldest$$1; shift; \
87	t=$$dest/$$1; \
88	case "$$1" in */*) mkdir -p ${_stage_target_dirname};; esac; \
89	shift; \
90	StageDirdep $$t; \
91	rm -f $$t 2>/dev/null; \
92	ln $$lnf $$l $$t; \
93  done; :; }
94
95STAGE_AS_SCRIPT = ${STAGE_DIRDEP_SCRIPT}; StageAs() { \
96  case "$$1" in -m) mode=$$2; shift 2;; *) mode=;; esac; \
97  dest=$$1; shift; \
98  mkdir -p $$dest; \
99  [ -s .dirdep ] || echo '${_dirdep}' > .dirdep; \
100  while test $$\# -ge 2; do \
101	s=$$1; shift; \
102	t=$$dest/$$1; \
103	case "$$1" in */*) mkdir -p ${_stage_target_dirname};; esac; \
104	shift; \
105	StageDirdep $$t; \
106	rm -f $$t; \
107	{ ln $$s $$t 2> /dev/null || \
108	cp -p $$s $$t; }; \
109	$${mode:+chmod $$mode $$t}; \
110  done; :; }
111
112# this is simple, a list of the "staged" files depends on this,
113_STAGE_BASENAME_USE:	.USE ${.TARGET:T}
114	@${STAGE_FILE_SCRIPT}; StageFiles ${.TARGET:H:${STAGE_DIR_FILTER}} ${.TARGET:T}
115
116.if !empty(STAGE_INCSDIR)
117CLEANFILES += stage_incs
118
119STAGE_INCS ?= ${.ALLSRC:N.dirdep}
120
121stage_incs:	.dirdep
122	@${STAGE_FILE_SCRIPT}; StageFiles ${STAGE_INCSDIR:${STAGE_DIR_FILTER}} ${STAGE_INCS}
123	@touch $@
124.endif
125
126.if !empty(STAGE_LIBDIR)
127CLEANFILES += stage_libs
128
129STAGE_LIBS ?= ${.ALLSRC:N.dirdep}
130
131stage_libs:	.dirdep
132	@${STAGE_FILE_SCRIPT}; StageFiles ${STAGE_LIBDIR:${STAGE_DIR_FILTER}} ${STAGE_LIBS}
133.if !empty(SHLIB_LINKS)
134	@${STAGE_LINKS_SCRIPT}; StageLinks -s ${STAGE_LIBDIR:${STAGE_DIR_FILTER}} \
135	${SHLIB_LINKS:@t@${STAGE_LIBS:T:M$t.*} $t@}
136.elif !empty(SHLIB_LINK) && !empty(SHLIB_NAME)
137	@${STAGE_LINKS_SCRIPT}; StageLinks -s ${STAGE_LIBDIR:${STAGE_DIR_FILTER}} ${SHLIB_NAME} ${SHLIB_LINK} ${SYMLINKS:T}
138.endif
139	@touch $@
140.endif
141
142.if !empty(STAGE_DIR)
143STAGE_SETS += _default
144STAGE_DIR._default = ${STAGE_DIR}
145STAGE_LINKS_DIR._default = ${STAGE_LINKS_DIR:U${STAGE_OBJTOP}}
146STAGE_SYMLINKS_DIR._default = ${STAGE_SYMLINKS_DIR:U${STAGE_OBJTOP}}
147STAGE_FILES._default = ${STAGE_FILES}
148STAGE_LINKS._default = ${STAGE_LINKS}
149STAGE_SYMLINKS._default = ${STAGE_SYMLINKS}
150STAGE_FILES ?= ${.ALLSRC:N.dirdep:Nstage_*}
151STAGE_SYMLINKS ?= ${.ALLSRC:T:N.dirdep:Nstage_*}
152.endif
153
154.if !empty(STAGE_SETS)
155
156CLEANFILES += ${STAGE_SETS:@s@stage*$s@}
157
158# some makefiles need to populate multiple directories
159.for s in ${STAGE_SETS:O:u}
160STAGE_FILES.$s ?= ${.ALLSRC:N.dirdep}
161STAGE_SYMLINKS.$s ?= ${.ALLSRC:N.dirdep}
162STAGE_LINKS_DIR.$s ?= ${STAGE_OBJTOP}
163STAGE_SYMLINKS_DIR.$s ?= ${STAGE_OBJTOP}
164
165.if $s != "_default"
166stage_files:	stage_files.$s
167stage_files.$s:	.dirdep
168.else
169stage_files:	.dirdep
170.endif
171	@${STAGE_FILE_SCRIPT}; StageFiles ${FLAGS.$@} ${STAGE_FILES_DIR.$s:U${STAGE_DIR.$s}:${STAGE_DIR_FILTER}} ${STAGE_FILES.$s}
172	@touch $@
173
174.if $s != "_default"
175stage_links:	stage_links.$s
176stage_links.$s:	.dirdep
177.else
178stage_links:	.dirdep
179.endif
180	@${STAGE_LINKS_SCRIPT}; StageLinks ${STAGE_LINKS_DIR.$s:U${STAGE_DIR.$s}:${STAGE_DIR_FILTER}} ${STAGE_LINKS.$s}
181	@touch $@
182
183.if $s != "_default"
184stage_symlinks:	stage_symlinks.$s
185stage_symlinks.$s:	.dirdep
186.else
187stage_symlinks:	.dirdep
188.endif
189	@${STAGE_LINKS_SCRIPT}; StageLinks -s ${STAGE_SYMLINKS_DIR.$s:U${STAGE_DIR.$s}:${STAGE_DIR_FILTER}} ${STAGE_SYMLINKS.$s}
190	@touch $@
191
192.endfor
193.endif
194
195.if !empty(STAGE_AS_SETS)
196
197CLEANFILES += ${STAGE_AS_SETS:@s@stage*$s@}
198
199# sometimes things need to be renamed as they are staged
200# each ${file} will be staged as ${STAGE_AS_${file:T}}
201# one could achieve the same with SYMLINKS
202.for s in ${STAGE_AS_SETS:O:u}
203STAGE_AS.$s ?= ${.ALLSRC:N.dirdep}
204
205stage_as:	stage_as.$s
206stage_as.$s:	.dirdep
207	@${STAGE_AS_SCRIPT}; StageAs ${FLAGS.$@} ${STAGE_FILES_DIR.$s:U${STAGE_DIR.$s}:${STAGE_DIR_FILTER}} ${STAGE_AS.$s:@f@$f ${STAGE_AS_${f:T}:U${f:T}}@}
208	@touch $@
209
210.endfor
211.endif
212
213.endif
214