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