]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - share/mk/meta.stage.mk
MFV ntp-4.2.8p3 (r284990).
[FreeBSD/FreeBSD.git] / share / mk / meta.stage.mk
1 # $FreeBSD$
2 # $Id: meta.stage.mk,v 1.35 2015/05/20 06:40:33 sjg Exp $
3 #
4 #       @(#) Copyright (c) 2011, Simon J. Gerraty
5 #
6 #       This file is provided in the hope that it will
7 #       be of use.  There is absolutely NO WARRANTY.
8 #       Permission to copy, redistribute or otherwise
9 #       use this file is hereby granted provided that 
10 #       the above copyright notice and this notice are
11 #       left intact. 
12 #      
13 #       Please send copies of changes and bug-fixes to:
14 #       sjg@crufty.net
15 #
16
17 .if !target(__${.PARSEFILE}__)
18 __${.PARSEFILE}__:
19
20 .if ${.MAKE.DEPENDFILE_PREFERENCE:U${.MAKE.DEPENDFILE}:M*.${MACHINE}} != ""
21 # this is generally safer anyway
22 _dirdep = ${RELDIR}.${MACHINE}
23 .else
24 _dirdep = ${RELDIR}
25 .endif
26
27 # this allows us to trace dependencies back to their src dir
28 .dirdep:
29         @echo '${_dirdep}' > $@
30
31 .if defined(NO_POSIX_SHELL) || ${type printf:L:sh:Mbuiltin} == ""
32 _stage_file_basename = `basename $$f`
33 _stage_target_dirname = `dirname $$t`
34 .else
35 _stage_file_basename = $${f\#\#*/}
36 _stage_target_dirname = $${t%/*}
37 .endif
38
39 _OBJROOT ?= ${OBJROOT:U${OBJTOP:H}}
40 .if ${_OBJROOT:M*/} != ""
41 _objroot ?= ${_OBJROOT:tA}/
42 .else
43 _objroot ?= ${_OBJROOT:tA}
44 .endif
45
46 # make sure this is global
47 _STAGED_DIRS ?=
48 .export _STAGED_DIRS
49 # add each dir we stage to to _STAGED_DIRS
50 # and make sure we have absolute paths so that bmake
51 # will match against .MAKE.META.BAILIWICK
52 STAGE_DIR_FILTER = tA:@d@$${_STAGED_DIRS::+=$$d}$$d@
53 # convert _STAGED_DIRS into suitable filters
54 GENDIRDEPS_FILTER += Nnot-empty-is-important \
55         ${_STAGED_DIRS:O:u:M${OBJTOP}*:S,${OBJTOP}/,N,} \
56         ${_STAGED_DIRS:O:u:M${_objroot}*:N${OBJTOP}*:S,${_objroot},,:C,^([^/]+)/(.*),N\2.\1,:S,${HOST_TARGET},.host,}
57
58 LN_CP_SCRIPT = LnCp() { \
59   rm -f $$2 2> /dev/null; \
60   ln $$1 $$2 2> /dev/null || \
61   cp -p $$1 $$2; }
62
63 # a staging conflict should cause an error
64 # a warning is handy when bootstapping different options.
65 STAGE_CONFLICT?= ERROR
66 .if ${STAGE_CONFLICT:tl} == "error"
67 STAGE_CONFLICT_ACTION= exit 1;
68 .else
69 STAGE_CONFLICT_ACTION=
70 .endif
71
72 # it is an error for more than one src dir to try and stage
73 # the same file
74 STAGE_DIRDEP_SCRIPT = ${LN_CP_SCRIPT}; StageDirdep() { \
75   t=$$1; \
76   if [ -s $$t.dirdep ]; then \
77         cmp -s .dirdep $$t.dirdep && return; \
78         echo "${STAGE_CONFLICT}: $$t installed by `cat $$t.dirdep` not ${_dirdep}" >&2; \
79         ${STAGE_CONFLICT_ACTION} \
80   fi; \
81   LnCp .dirdep $$t.dirdep || exit 1; }
82
83 # common logic for staging files
84 # this all relies on RELDIR being set to a subdir of SRCTOP
85 # we use ln(1) if we can, else cp(1)
86 STAGE_FILE_SCRIPT = ${STAGE_DIRDEP_SCRIPT}; StageFiles() { \
87   case "$$1" in "") return;; -m) mode=$$2; shift 2;; *) mode=;; esac; \
88   dest=$$1; shift; \
89   mkdir -p $$dest; \
90   [ -s .dirdep ] || echo '${_dirdep}' > .dirdep; \
91   for f in "$$@"; do \
92         case "$$f" in */*) t=$$dest/${_stage_file_basename};; *) t=$$dest/$$f;; esac; \
93         StageDirdep $$t; \
94         LnCp $$f $$t || exit 1; \
95         [ -z "$$mode" ] || chmod $$mode $$t; \
96   done; :; }
97
98 STAGE_LINKS_SCRIPT = ${STAGE_DIRDEP_SCRIPT}; StageLinks() { \
99   case "$$1" in "") return;; --) shift;; -*) ldest= lnf=$$1; shift;; /*) ldest=$$1/;; esac; \
100   dest=$$1; shift; \
101   mkdir -p $$dest; \
102   [ -s .dirdep ] || echo '${_dirdep}' > .dirdep; \
103   while test $$\# -ge 2; do \
104         l=$$ldest$$1; shift; \
105         t=$$dest/$$1; \
106         case "$$1" in */*) mkdir -p ${_stage_target_dirname};; esac; \
107         shift; \
108         StageDirdep $$t; \
109         rm -f $$t 2>/dev/null; \
110         ln $$lnf $$l $$t || exit 1; \
111   done; :; }
112
113 STAGE_AS_SCRIPT = ${STAGE_DIRDEP_SCRIPT}; StageAs() { \
114   case "$$1" in "") return;; -m) mode=$$2; shift 2;; *) mode=;; esac; \
115   dest=$$1; shift; \
116   mkdir -p $$dest; \
117   [ -s .dirdep ] || echo '${_dirdep}' > .dirdep; \
118   while test $$\# -ge 2; do \
119         s=$$1; shift; \
120         t=$$dest/$$1; \
121         case "$$1" in */*) mkdir -p ${_stage_target_dirname};; esac; \
122         shift; \
123         StageDirdep $$t; \
124         LnCp $$s $$t || exit 1; \
125         [ -z "$$mode" ] || chmod $$mode $$t; \
126   done; :; }
127
128 # this is simple, a list of the "staged" files depends on this,
129 _STAGE_BASENAME_USE:    .USE ${.TARGET:T}
130         @${STAGE_FILE_SCRIPT}; StageFiles ${.TARGET:H:${STAGE_DIR_FILTER}} ${.TARGET:T}
131
132 _STAGE_AS_BASENAME_USE:        .USE ${.TARGET:T}
133         @${STAGE_AS_SCRIPT}; StageAs ${.TARGET:H:${STAGE_DIR_FILTER}} ${.TARGET:T} ${STAGE_AS_${.TARGET:T}:U${.TARGET:T}}
134
135 .if !empty(STAGE_INCSDIR)
136 STAGE_TARGETS += stage_incs
137 STAGE_INCS ?= ${.ALLSRC:N.dirdep}
138
139 stage_includes: stage_incs
140 stage_incs:     .dirdep
141         @${STAGE_FILE_SCRIPT}; StageFiles ${STAGE_INCSDIR:${STAGE_DIR_FILTER}} ${STAGE_INCS}
142         @touch $@
143 .endif
144
145 .if !empty(STAGE_LIBDIR)
146 STAGE_TARGETS += stage_libs
147
148 STAGE_LIBS ?= ${.ALLSRC:N.dirdep}
149
150 stage_libs:     .dirdep
151         @${STAGE_FILE_SCRIPT}; StageFiles ${STAGE_LIBDIR:${STAGE_DIR_FILTER}} ${STAGE_LIBS}
152 .if !defined(NO_SHLIB_LINKS)
153 .if !empty(SHLIB_LINKS)
154         @${STAGE_LINKS_SCRIPT}; StageLinks -s ${STAGE_LIBDIR:${STAGE_DIR_FILTER}} \
155         ${SHLIB_LINKS:@t@${STAGE_LIBS:T:M$t.*} $t@}
156 .elif !empty(SHLIB_LINK) && !empty(SHLIB_NAME)
157         @${STAGE_LINKS_SCRIPT}; StageLinks -s ${STAGE_LIBDIR:${STAGE_DIR_FILTER}} ${SHLIB_NAME} ${SHLIB_LINK} ${SYMLINKS:T}
158 .endif
159 .endif
160         @touch $@
161 .endif
162
163 .if !empty(STAGE_DIR)
164 STAGE_SETS += _default
165 STAGE_DIR._default = ${STAGE_DIR}
166 STAGE_LINKS_DIR._default = ${STAGE_LINKS_DIR:U${STAGE_OBJTOP}}
167 STAGE_SYMLINKS_DIR._default = ${STAGE_SYMLINKS_DIR:U${STAGE_OBJTOP}}
168 STAGE_FILES._default = ${STAGE_FILES}
169 STAGE_LINKS._default = ${STAGE_LINKS}
170 STAGE_SYMLINKS._default = ${STAGE_SYMLINKS}
171 STAGE_FILES ?= ${.ALLSRC:N.dirdep:Nstage_*}
172 STAGE_SYMLINKS ?= ${.ALLSRC:T:N.dirdep:Nstage_*}
173 .endif
174
175 .if !empty(STAGE_SETS)
176 CLEANFILES += ${STAGE_SETS:@s@stage*$s@}
177
178 # some makefiles need to populate multiple directories
179 .for s in ${STAGE_SETS:O:u}
180 STAGE_FILES.$s ?= ${.ALLSRC:N.dirdep}
181 STAGE_SYMLINKS.$s ?= ${.ALLSRC:N.dirdep}
182 STAGE_LINKS_DIR.$s ?= ${STAGE_OBJTOP}
183 STAGE_SYMLINKS_DIR.$s ?= ${STAGE_OBJTOP}
184
185 STAGE_TARGETS += stage_files
186 .if $s != "_default"
187 stage_files:    stage_files.$s
188 stage_files.$s: .dirdep
189 .else
190 stage_files:    .dirdep
191 .endif
192         @${STAGE_FILE_SCRIPT}; StageFiles ${FLAGS.$@} ${STAGE_FILES_DIR.$s:U${STAGE_DIR.$s}:${STAGE_DIR_FILTER}} ${STAGE_FILES.$s}
193         @touch $@
194
195 STAGE_TARGETS += stage_links
196 .if $s != "_default"
197 stage_links:    stage_links.$s
198 stage_links.$s: .dirdep
199 .else
200 stage_links:    .dirdep
201 .endif
202         @${STAGE_LINKS_SCRIPT}; StageLinks ${STAGE_LINKS_DIR.$s:U${STAGE_DIR.$s}:${STAGE_DIR_FILTER}} ${STAGE_LINKS.$s}
203         @touch $@
204
205 STAGE_TARGETS += stage_symlinks
206 .if $s != "_default"
207 stage_symlinks: stage_symlinks.$s
208 stage_symlinks.$s:      .dirdep
209 .else
210 stage_symlinks: .dirdep
211 .endif
212         @${STAGE_LINKS_SCRIPT}; StageLinks -s ${STAGE_SYMLINKS_DIR.$s:U${STAGE_DIR.$s}:${STAGE_DIR_FILTER}} ${STAGE_SYMLINKS.$s}
213         @touch $@
214
215 .endfor
216 .endif
217
218 .if !empty(STAGE_AS_SETS)
219 CLEANFILES += ${STAGE_AS_SETS:@s@stage*$s@}
220
221 STAGE_TARGETS += stage_as
222
223 # sometimes things need to be renamed as they are staged
224 # each ${file} will be staged as ${STAGE_AS_${file:T}}
225 # one could achieve the same with SYMLINKS
226 .for s in ${STAGE_AS_SETS:O:u}
227 STAGE_AS.$s ?= ${.ALLSRC:N.dirdep}
228
229 stage_as:       stage_as.$s
230 stage_as.$s:    .dirdep
231         @${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}}}@}
232         @touch $@
233
234 .endfor
235 .endif
236
237 CLEANFILES += ${STAGE_TARGETS} stage_incs stage_includes
238
239 # stage_*links usually needs to follow any others.
240 .for t in ${STAGE_TARGETS:N*links:O:u}
241 .ORDER: $t stage_links
242 .ORDER: $t stage_symlinks
243 .endfor
244
245 # make sure this exists
246 staging:
247
248 # generally we want staging to wait until everything else is done
249 STAGING_WAIT ?= .WAIT
250
251 .if ${.MAKE.LEVEL} > 0
252 all: ${STAGING_WAIT} staging
253 .endif
254
255 .if exists(${.PARSEDIR}/stage-install.sh) && !defined(STAGE_INSTALL)
256 # this will run install(1) and then followup with .dirdep files.
257 STAGE_INSTALL := sh ${.PARSEDIR:tA}/stage-install.sh INSTALL="${INSTALL}" OBJDIR=${.OBJDIR:tA}
258 .endif
259
260 # if ${INSTALL} gets run during 'all' assume it is for staging?
261 .if ${.TARGETS:Nall} == "" && defined(STAGE_INSTALL)
262 INSTALL := ${STAGE_INSTALL}
263 .if target(beforeinstall)
264 beforeinstall: .dirdep
265 .endif
266 .endif
267 .NOPATH: ${STAGE_FILES}
268
269 .if !empty(STAGE_TARGETS)
270 MK_STALE_STAGED?= no
271 .if ${MK_STALE_STAGED} == "yes"
272 all: stale_staged
273 # get a list of paths that we have just staged
274 # get a list of paths that we have previously staged to those same dirs
275 # anything in the 2nd list but not the first is stale - remove it.
276 stale_staged: staging .NOMETA
277         @egrep '^[WL] .*${STAGE_OBJTOP}' /dev/null ${.MAKE.META.FILES:M*stage_*} | \
278         sed "/\.dirdep/d;s,.* '*\(${STAGE_OBJTOP}/[^ '][^ ']*\).*,\1," | \
279         sort > ${.TARGET}.staged1
280         @grep -l '${_dirdep}' /dev/null ${_STAGED_DIRS:M${STAGE_OBJTOP}*:O:u:@d@$d/*.dirdep@} | \
281         sed 's,\.dirdep,,' | sort > ${.TARGET}.staged2
282         @comm -13 ${.TARGET}.staged1 ${.TARGET}.staged2 > ${.TARGET}.stale
283         @test ! -s ${.TARGET}.stale || { \
284                 echo "Removing stale staged files..."; \
285                 sed 's,.*,& &.dirdep,' ${.TARGET}.stale | xargs rm -f; }
286
287 .endif
288 .endif
289 .endif