/[gentoo-x86]/eclass/multibuild.eclass
Gentoo

Contents of /eclass/multibuild.eclass

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.11 - (show annotations) (download)
Fri May 24 17:42:05 2013 UTC (17 months, 1 week ago) by mgorny
Branch: MAIN
Changes since 1.10: +2 -2 lines
Fix the race condition in locking code by using $BASHPID instead of $$.

1 # Copyright 1999-2013 Gentoo Foundation
2 # Distributed under the terms of the GNU General Public License v2
3 # $Header: /var/cvsroot/gentoo-x86/eclass/multibuild.eclass,v 1.10 2013/05/23 20:19:28 mgorny Exp $
4
5 # @ECLASS: multibuild
6 # @MAINTAINER:
7 # Michał Górny <mgorny@gentoo.org>
8 # @AUTHOR:
9 # Author: Michał Górny <mgorny@gentoo.org>
10 # @BLURB: A generic eclass for building multiple variants of packages.
11 # @DESCRIPTION:
12 # The multibuild eclass aims to provide a generic framework for building
13 # multiple 'variants' of a package (e.g. multilib, Python
14 # implementations).
15
16 case "${EAPI:-0}" in
17 0|1|2|3|4)
18 die "Unsupported EAPI=${EAPI:-0} (too old) for ${ECLASS}"
19 ;;
20 5)
21 ;;
22 *)
23 die "Unsupported EAPI=${EAPI} (unknown) for ${ECLASS}"
24 ;;
25 esac
26
27 if [[ ! ${_MULTIBUILD} ]]; then
28
29 inherit multiprocessing
30
31 # @ECLASS-VARIABLE: MULTIBUILD_VARIANTS
32 # @DESCRIPTION:
33 # An array specifying all enabled variants which multibuild_foreach*
34 # can execute the process for.
35 #
36 # In ebuild, it can be set in global scope. Eclasses should set it
37 # locally in function scope to support nesting properly.
38 #
39 # Example:
40 # @CODE
41 # python_foreach_impl() {
42 # local MULTIBUILD_VARIANTS=( python{2_5,2_6,2_7} ... )
43 # multibuild_foreach_variant python_compile
44 # }
45 # @CODE
46
47 # @ECLASS-VARIABLE: MULTIBUILD_VARIANT
48 # @DESCRIPTION:
49 # The current variant which the function was executed for.
50 #
51 # Example value:
52 # @CODE
53 # python2_6
54 # @CODE
55
56 # @ECLASS-VARIABLE: MULTIBUILD_ID
57 # @DESCRIPTION:
58 # The unique identifier for a multibuild run. In a simple run, it is
59 # equal to MULTIBUILD_VARIANT. In a nested multibuild environment, it
60 # contains the complete selection tree.
61 #
62 # It can be used to create variant-unique directories and files.
63 #
64 # Example value:
65 # @CODE
66 # amd64-double
67 # @CODE
68
69 # @ECLASS-VARIABLE: BUILD_DIR
70 # @DESCRIPTION:
71 # The current build directory. In global scope, it is supposed
72 # to contain an 'initial' build directory. If unset, ${S} is used.
73 #
74 # multibuild_foreach_variant() sets BUILD_DIR locally
75 # to variant-specific build directories based on the initial value
76 # of BUILD_DIR.
77 #
78 # Example value:
79 # @CODE
80 # ${WORKDIR}/foo-1.3-python2_6
81 # @CODE
82
83 # @FUNCTION: multibuild_foreach_variant
84 # @USAGE: [<argv>...]
85 # @DESCRIPTION:
86 # Run the passed command repeatedly for each of the enabled package
87 # variants.
88 #
89 # Each of the runs will have variant-specific BUILD_DIR set, and output
90 # teed to a separate log in ${T}.
91 #
92 # The function returns 0 if all commands return 0, or the first non-zero
93 # exit status otherwise. However, it performs all the invocations
94 # nevertheless. It is preferred to call 'die' inside of the passed
95 # function.
96 multibuild_foreach_variant() {
97 debug-print-function ${FUNCNAME} "${@}"
98
99 [[ ${MULTIBUILD_VARIANTS} ]] \
100 || die "MULTIBUILD_VARIANTS need to be set"
101
102 local bdir=${BUILD_DIR:-${S}}
103
104 # Avoid writing outside WORKDIR if S=${WORKDIR}.
105 [[ ${bdir%%/} == ${WORKDIR%%/} ]] && bdir=${WORKDIR}/build
106
107 local prev_id=${MULTIBUILD_ID:+${MULTIBUILD_ID}-}
108 local ret=0 lret=0 v
109
110 debug-print "${FUNCNAME}: initial build_dir = ${bdir}"
111
112 for v in "${MULTIBUILD_VARIANTS[@]}"; do
113 local MULTIBUILD_VARIANT=${v}
114 local MULTIBUILD_ID=${prev_id}${v}
115 local BUILD_DIR=${bdir%%/}-${v}
116
117 _multibuild_run() {
118 # find the first non-private command
119 local i=1
120 while [[ ${!i} == _* ]]; do
121 (( i += 1 ))
122 done
123
124 [[ ${i} -le ${#} ]] && einfo "${v}: running ${@:${i}}"
125 "${@}"
126 }
127
128 _multibuild_run "${@}" \
129 > >(exec tee -a "${T}/build-${MULTIBUILD_ID}.log") 2>&1
130 lret=${?}
131 done
132 [[ ${ret} -eq 0 && ${lret} -ne 0 ]] && ret=${lret}
133
134 return ${ret}
135 }
136
137 # @FUNCTION: multibuild_parallel_foreach_variant
138 # @USAGE: [<argv>...]
139 # @DESCRIPTION:
140 # Run the passed command repeatedly for each of the enabled package
141 # variants alike multibuild_foreach_variant. Multiple invocations of the command
142 # will be performed in parallel, up to MULTIBUILD_JOBS tasks.
143 #
144 # The function returns 0 if all commands return 0, or the first non-zero
145 # exit status otherwise. However, it performs all the invocations
146 # nevertheless. It is preferred to call 'die' inside of the passed
147 # function.
148 multibuild_parallel_foreach_variant() {
149 debug-print-function ${FUNCNAME} "${@}"
150
151 local ret lret
152
153 _multibuild_parallel() {
154 (
155 multijob_child_init
156 "${@}"
157 ) &
158 multijob_post_fork
159 }
160
161 local opts
162 if [[ ${MULTIBUILD_JOBS} ]]; then
163 opts=-j${MULTIBUILD_JOBS}
164 else
165 opts=${MAKEOPTS}
166 fi
167
168 multijob_init "${opts}"
169 multibuild_foreach_variant _multibuild_parallel "${@}"
170 ret=${?}
171 multijob_finish
172 lret=${?}
173
174 [[ ${ret} -eq 0 ]] && ret=${lret}
175 return ${ret}
176 }
177
178 # @FUNCTION: multibuild_for_best_variant
179 # @USAGE: [<argv>...]
180 # @DESCRIPTION:
181 # Run the passed command once, for the best of the enabled package
182 # variants.
183 #
184 # The run will have a proper, variant-specificBUILD_DIR set, and output
185 # teed to a separate log in ${T}.
186 #
187 # The function returns command exit status.
188 multibuild_for_best_variant() {
189 debug-print-function ${FUNCNAME} "${@}"
190
191 [[ ${MULTIBUILD_VARIANTS} ]] \
192 || die "MULTIBUILD_VARIANTS need to be set"
193
194 # bash-4.1 can't handle negative subscripts
195 local MULTIBUILD_VARIANTS=(
196 "${MULTIBUILD_VARIANTS[$(( ${#MULTIBUILD_VARIANTS[@]} - 1 ))]}"
197 )
198 multibuild_foreach_variant "${@}"
199 }
200
201 # @FUNCTION: multibuild_copy_sources
202 # @DESCRIPTION:
203 # Create per-variant copies of source tree. The source tree is assumed
204 # to be in ${BUILD_DIR}, or ${S} if the former is unset. The copies will
205 # be placed in directories matching BUILD_DIRs used by
206 # multibuild_foreach().
207 multibuild_copy_sources() {
208 debug-print-function ${FUNCNAME} "${@}"
209
210 local _MULTIBUILD_INITIAL_BUILD_DIR=${BUILD_DIR:-${S}}
211
212 einfo "Will copy sources from ${_MULTIBUILD_INITIAL_BUILD_DIR}"
213
214 _multibuild_create_source_copy() {
215 einfo "${MULTIBUILD_VARIANT}: copying to ${BUILD_DIR}"
216 cp -pr "${_MULTIBUILD_INITIAL_BUILD_DIR}" "${BUILD_DIR}" || die
217 }
218
219 multibuild_foreach_variant _multibuild_create_source_copy
220 }
221
222 # @FUNCTION: run_in_build_dir
223 # @USAGE: <argv>...
224 # @DESCRIPTION:
225 # Run the given command in the directory pointed by BUILD_DIR.
226 run_in_build_dir() {
227 debug-print-function ${FUNCNAME} "${@}"
228 local ret
229
230 [[ ${#} -ne 0 ]] || die "${FUNCNAME}: no command specified."
231 [[ ${BUILD_DIR} ]] || die "${FUNCNAME}: BUILD_DIR not set."
232
233 pushd "${BUILD_DIR}" >/dev/null || die
234 "${@}"
235 ret=${?}
236 popd >/dev/null || die
237
238 return ${ret}
239 }
240
241 # @FUNCTION: multibuild_merge_root
242 # @USAGE: <src-root> <dest-root>
243 # @DESCRIPTION:
244 # Merge the directory tree (fake root) from <src-root> to <dest-root>
245 # (the real root). Both directories have to be real, absolute paths
246 # (i.e. including ${D}). Source root will be removed.
247 #
248 # This functions uses locking to support merging during parallel
249 # installs.
250 multibuild_merge_root() {
251 local src=${1}
252 local dest=${2}
253
254 local lockfile=${T}/.multibuild_merge_lock
255 local lockfile_l=${lockfile}.${BASHPID}
256 local ret
257
258 # Lock the install tree for merge. The touch+ln method ensures race
259 # condition-free locking with maximum portability.
260 touch "${lockfile_l}" || die
261 until ln "${lockfile_l}" "${lockfile}" &>/dev/null; do
262 sleep 1
263 done
264 rm "${lockfile_l}" || die
265
266 if use userland_BSD; then
267 # 'cp -a -n' is broken:
268 # http://www.freebsd.org/cgi/query-pr.cgi?pr=174489
269 # using tar instead which is universal but terribly slow.
270
271 tar -C "${src}" -f - -c . \
272 | tar -x -f - -C "${dest}"
273 [[ ${PIPESTATUS[*]} == '0 0' ]]
274 ret=${?}
275 elif use userland_GNU; then
276 # cp works with '-a -n'.
277
278 cp -a -l -n "${src}"/. "${dest}"/
279 ret=${?}
280 else
281 die "Unsupported userland (${USERLAND}), please report."
282 fi
283
284 # Remove the lock.
285 rm "${lockfile}" || die
286
287 if [[ ${ret} -ne 0 ]]; then
288 die "${MULTIBUILD_VARIANT:-(unknown)}: merging image failed."
289 fi
290
291 rm -rf "${src}"
292 }
293
294 _MULTIBUILD=1
295 fi

  ViewVC Help
Powered by ViewVC 1.1.20