1 # Copyright 1999-2018 Gentoo Foundation
2 # Distributed under the terms of the GNU General Public License v2
4 # @ECLASS: multibuild.eclass
6 # Michał Górny <mgorny@gentoo.org>
8 # Author: Michał Górny <mgorny@gentoo.org>
9 # @BLURB: A generic eclass for building multiple variants of packages.
11 # The multibuild eclass aims to provide a generic framework for building
12 # multiple 'variants' of a package (e.g. multilib, Python
17 die "Unsupported EAPI=${EAPI:-0} (too old) for ${ECLASS}"
22 die "Unsupported EAPI=${EAPI} (unknown) for ${ECLASS}"
26 if [[ ! ${_MULTIBUILD} ]]; then
28 # @ECLASS-VARIABLE: MULTIBUILD_VARIANTS
30 # An array specifying all enabled variants which multibuild_foreach*
31 # can execute the process for.
33 # In ebuild, it can be set in global scope. Eclasses should set it
34 # locally in function scope to support nesting properly.
38 # python_foreach_impl() {
39 # local MULTIBUILD_VARIANTS=( python{2_5,2_6,2_7} ... )
40 # multibuild_foreach_variant python_compile
44 # @ECLASS-VARIABLE: MULTIBUILD_VARIANT
46 # The current variant which the function was executed for.
53 # @ECLASS-VARIABLE: MULTIBUILD_ID
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.
59 # It can be used to create variant-unique directories and files.
66 # @ECLASS-VARIABLE: BUILD_DIR
68 # The current build directory. In global scope, it is supposed
69 # to contain an 'initial' build directory. If unset, ${S} is used.
71 # multibuild_foreach_variant() sets BUILD_DIR locally
72 # to variant-specific build directories based on the initial value
77 # ${WORKDIR}/foo-1.3-python2_6
80 # @FUNCTION: multibuild_foreach_variant
83 # Run the passed command repeatedly for each of the enabled package
86 # Each of the runs will have variant-specific BUILD_DIR set, and output
87 # teed to a separate log in ${T}.
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
93 multibuild_foreach_variant() {
94 debug-print-function ${FUNCNAME} "${@}"
96 [[ ${MULTIBUILD_VARIANTS} ]] \
97 || die "MULTIBUILD_VARIANTS need to be set"
99 local bdir=${BUILD_DIR:-${S}}
101 # Avoid writing outside WORKDIR if S=${WORKDIR}.
102 [[ ${bdir%%/} == ${WORKDIR%%/} ]] && bdir=${WORKDIR}/build
104 local prev_id=${MULTIBUILD_ID:+${MULTIBUILD_ID}-}
107 debug-print "${FUNCNAME}: initial build_dir = ${bdir}"
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}
115 # find the first non-private command
117 while [[ ${!i} == _* ]]; do
121 [[ ${i} -le ${#} ]] && einfo "${v}: running ${@:${i}}"
125 _multibuild_run "${@}" \
126 > >(exec tee -a "${T}/build-${MULTIBUILD_ID}.log") 2>&1
129 [[ ${ret} -eq 0 && ${lret} -ne 0 ]] && ret=${lret}
134 # @FUNCTION: multibuild_parallel_foreach_variant
135 # @USAGE: [<argv>...]
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.
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
145 multibuild_parallel_foreach_variant() {
146 debug-print-function ${FUNCNAME} "${@}"
148 [[ ${EAPI} == [45] ]] || die "${FUNCNAME} is banned in EAPI ${EAPI}"
150 multibuild_foreach_variant "${@}"
153 # @FUNCTION: multibuild_for_best_variant
154 # @USAGE: [<argv>...]
156 # Run the passed command once, for the best of the enabled package
159 # The run will have a proper, variant-specificBUILD_DIR set, and output
160 # teed to a separate log in ${T}.
162 # The function returns command exit status.
163 multibuild_for_best_variant() {
164 debug-print-function ${FUNCNAME} "${@}"
166 [[ ${MULTIBUILD_VARIANTS} ]] \
167 || die "MULTIBUILD_VARIANTS need to be set"
169 # bash-4.1 can't handle negative subscripts
170 local MULTIBUILD_VARIANTS=(
171 "${MULTIBUILD_VARIANTS[$(( ${#MULTIBUILD_VARIANTS[@]} - 1 ))]}"
173 multibuild_foreach_variant "${@}"
176 # @FUNCTION: multibuild_copy_sources
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} "${@}"
185 local _MULTIBUILD_INITIAL_BUILD_DIR=${BUILD_DIR:-${S}}
187 einfo "Will copy sources from ${_MULTIBUILD_INITIAL_BUILD_DIR}"
190 if cp --reflink=auto --version &>/dev/null; then
191 # enable reflinking if possible to make this faster
192 cp_args+=( --reflink=auto )
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
201 multibuild_foreach_variant _multibuild_create_source_copy
204 # @FUNCTION: run_in_build_dir
207 # Run the given command in the directory pointed by BUILD_DIR.
209 debug-print-function ${FUNCNAME} "${@}"
212 [[ ${#} -ne 0 ]] || die "${FUNCNAME}: no command specified."
213 [[ ${BUILD_DIR} ]] || die "${FUNCNAME}: BUILD_DIR not set."
215 mkdir -p "${BUILD_DIR}" || die
216 pushd "${BUILD_DIR}" >/dev/null || die
219 popd >/dev/null || die
224 # @FUNCTION: multibuild_merge_root
225 # @USAGE: <src-root> <dest-root>
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() {
236 if use userland_BSD; then
237 # Most of BSD variants fail to copy broken symlinks, #447370
238 # also, they do not support --version
240 tar -C "${src}" -f - -c . \
241 | tar -x -f - -C "${dest}"
242 [[ ${PIPESTATUS[*]} == '0 0' ]]
247 if cp -a --version &>/dev/null; then
250 cp_args+=( -P -R -p )
253 if cp --reflink=auto --version &>/dev/null; then
254 # enable reflinking if possible to make this faster
255 cp_args+=( --reflink=auto )
258 cp "${cp_args[@]}" "${src}"/. "${dest}"/
262 if [[ ${ret} -ne 0 ]]; then
263 die "${MULTIBUILD_VARIANT:-(unknown)}: merging image failed."