summaryrefslogtreecommitdiff
blob: 1d4a88caf9264d469047a3014d384737e962b337 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
# Copyright 2023-2024 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2

# @ECLASS: guile.eclass
# @MAINTAINER:
# Gentoo Scheme project <scheme@gentoo.org>
# @AUTHOR:
# Author: Arsen Arsenović <arsen@gentoo.org>
# Inspired by prior work in the Gentoo Python ecosystem.
# @SUPPORTED_EAPIS: 8
# @PROVIDES: guile-utils
# @BLURB: Utilities for packages multi-implementation Guile packages.
# @DESCRIPTION:
# This eclass facilitates building against many Guile implementations,
# useful for Guile libraries.  Each ebuild must set GUILE_COMPAT to a
# list of versions they support, which will be intersected with
# GUILE_TARGETS to pick which versions to install.  The eclass will
# generate a GUILE_DEPS based on the configured GUILE_COMPAT, as well as
# a GUILE_REQUIRED_USE, that the user must use.
#
# If the user of the eclass needs some USE flag on Guile itself, they
# should provide it via GUILE_REQ_USE.
#
# This ebuild provides multibuild functionality.  Use guile_foreach_impl
# to run a given command for each enabled Guile version.  The command
# provided will be ran in a modified environment, see the description of
# that function for more details.
#
# This package provides some stage functions written assuming a
# conventional GNU Build System-based Guile library and may or may not
# work.
#
# For each Guile target, a Guile library should have at least compiled
# .go files in the ccache or %site-ccache-dir.  It must also have
# corresponding sources installed in %site-dir.
#
# If your package has some steps that should only happen for one
# implementation (e.g. installing a program), you can utilize
# guile_for_best_impl.
#
# Due to http://debbugs.gnu.org/cgi/bugreport.cgi?bug=38112, Guile
# packages ought to bump their sources before building.  To this end,
# the src_prepare this eclass provides will call guile_bump_sources of
# the guile-utils eclass.
#
# When installing, the packages using this eclass ought to use
# guile_foreach_impl and its SLOTTED_{,E}D, followed by merging roots
# via guile_merge_roots and unstripping ccache objects via
# guile_unstrip_ccache.  See descriptions of those functions for
# details.
#
# Ebuild authors, please pay attention for potential conflicts between
# slots.  As an example, dev-scheme/guile-lib installs a pkg-config file
# that depends on the Guile version it is installed for.  This is not
# acceptable, as it means revdeps will only ever see the version of the
# file for the best Guile implementation in GUILE_TARGETS.
#
# @EXAMPLE:
# The following example demonstrates a simple package relying entirely
# on the setup of this eclass.  For each enabled, compatible target, the
# ebuild will bump sources (see description), and run the default
# configure, compile and test stages (per PMS, meaning GNU Build
# System), and an install stage modified such that it installs each
# variant into SLOTTED_D followed by merging roots and unstripping.
#
# @CODE
# EAPI=8
#
# GUILE_COMPAT=( 2-2 3-0 )
# inherit guile
#
# DESCRIPTION="iCalendar/vCard parser for GNU Guile"
# HOMEPAGE="https://github.com/artyom-poptsov/guile-ics"
# SRC_URI="https://github.com/artyom-poptsov/${PN}/releases/download/v${PV}/${P}.tar.gz"
#
# LICENSE="GPL-3+"
# SLOT="0"
# KEYWORDS="~amd64"
# REQUIRED_USE="${GUILE_REQUIRED_USE}"
#
# RDEPEND="
# 	${GUILE_DEPS}
# 	dev-scheme/guile-smc[${GUILE_USEDEP}]
# "
# DEPEND="${RDEPEND}"
# @CODE

case "${EAPI}" in
	8) ;;
	*) die "${ECLASS}: EAPI ${EAPI:-0} not supported" ;;
esac

if [[ ! "${_GUILE_ECLASS}" ]]; then
_GUILE_ECLASS=1

inherit guile-utils multibuild

# @ECLASS_VARIABLE: GUILE_USEDEP
# @OUTPUT_VARIABLE
# @DESCRIPTION:
# USE dependency string that can be applied to Guile
# multi-implementation dependencies.
#
# @EXAMPLE:
# RDEPEND="
# 	${GUILE_DEPS}
# 	dev-scheme/bytestructures[${GUILE_USEDEP}]
# 	>=dev-libs/libgit2-1:=
# "
# DEPEND="${RDEPEND}"

# @ECLASS_VARIABLE: GUILE_COMPAT
# @REQUIRED
# @PRE_INHERIT
# @DESCRIPTION:
# List of acceptable versions of Guile.  For instance, setting this
# variable like below will allow the package to be built against both
# Guile 2.2 or 3.0:
#
# @CODE
# GUILE_COMPAT=( 2-2 3-0 )
# @CODE
#
# Please keep in ascending order.

_guile_setup() {
	debug-print-function ${FUNCNAME} "$@"

	guile_generate_depstrings guile_targets '||'
}

_guile_setup
unset -f _guile_setup

# @ECLASS_VARIABLE: GUILE_SELECTED_TARGETS
# @INTERNAL
# @DESCRIPTION:
# Contains the intersection of GUILE_TARGETS and GUILE_COMPAT.
# Generated in guile_pkg_setup.

# @FUNCTION: guile_pkg_setup
# @DESCRIPTION:
# Sets up eclass-internal variables for this build.
guile_pkg_setup() {
	debug-print-function ${FUNCNAME} "$@"

	guile_set_common_vars
	GUILE_SELECTED_TARGETS=()
	for ver in "${GUILE_COMPAT[@]}"; do
		debug-print "${FUNCNAME}: checking for ${ver}"
		use "guile_targets_${ver}" || continue
		GUILE_SELECTED_TARGETS+=("${ver/-/.}")
	done
	if [[ "${#GUILE_SELECTED_TARGETS[@]}" -eq 0 ]]; then
		die "No GUILE_TARGETS specified."
	fi
}

# @FUNCTION: guile_copy_sources
# @DESCRIPTION:
# Create a single copy of the package sources for each selected Guile
# implementation.
guile_copy_sources() {
	debug-print-function ${FUNCNAME} "$@"

	local MULTIBUILD_VARIANTS
	MULTIBUILD_VARIANTS=("${GUILE_SELECTED_TARGETS[@]}")

	multibuild_copy_sources
}

# @FUNCTION: _guile_multibuild_wrapper
# @USAGE: <command> [<argv>...]
# @INTERNAL
# @DESCRIPTION:
# Initialize the environment for a single build variant.  See
# guile_foreach_impl.
_guile_multibuild_wrapper() {
	local GUILE_CURRENT_VERSION="${MULTIBUILD_VARIANT}"
	debug-print-function ${FUNCNAME} "$@" "on ${MULTIBUILD_VARIANT}"

	local -x PATH="${PATH}"
	guile_create_temporary_config "${GUILE_CURRENT_VERSION}"
	guile_export GUILE GUILD GUILESNARF

	local -x PKG_CONFIG_PATH="${PKG_CONFIG_PATH}"
	guile_filter_pkgconfig_path "${MULTIBUILD_VARIANT}"
	local ECONF_SOURCE="${S}"
	local -x SLOTTED_D="${T}/dests/image${MULTIBUILD_ID}"
	local -x SLOTTED_ED="${SLOTTED_D}${EPREFIX}/"
	local -x GUILE_EFFECTIVE_VERSION="${GUILE_CURRENT_VERSION}"
	mkdir -p "${BUILD_DIR}" || die
	pushd "${BUILD_DIR}" >/dev/null || die
	"$@"
	popd >/dev/null || die
}

# @VARIABLE: SLOTTED_D
# @DESCRIPTION:
# In functions ran by guile_foreach_impl, this variable is set to a new
# ${D} value that the variant being installed should use.

# @VARIABLE: SLOTTED_ED
# @DESCRIPTION:
# In functions ran by guile_foreach_impl, this variable is set to a new
# ${ED} value that the variant being installed should use.  It is
# equivalent to "${SLOTTED_D%/}${EPREFIX}/".

# @VARIABLE: ECONF_SOURCE
# @DESCRIPTION:
# In functions ran by guile_foreach_impl, this variable is set to ${S},
# for convenience.

# @VARIABLE: PKG_CONFIG_PATH
# @DESCRIPTION:
# In functions ran by guile_foreach_impl, PKG_CONFIG_PATH is filtered to
# contain only the current ${MULTIBUILD_VARIANT}.

# @VARIABLE: BUILD_DIR
# @DESCRIPTION:
# In functions ran by guile_foreach_impl, this variable is set to a
# newly-generated build directory for this variant.

# @FUNCTION: guile_foreach_impl
# @USAGE: <command> [<argv>...]
# @DESCRIPTION:
# Runs the given command for each of the selected Guile implementations.
#
# The function will return 0 status if all invocations succeed.
# Otherwise, the return code from first failing invocation will
# be returned.
#
# Each invocation will have PKG_CONFIG_DIR altered to contain only one
# Guile implementation, as well as a SLOTTED_D, SLOTTED_ED for
# installation purposes, and a new BUILD_DIR, in which the wrapped
# function will be executed, with a pre-configured ECONF_SOURCE.  A
# temporary program called 'guile-config' is generated and inserted into
# the PATH.
#
# Also automatically exported are GUILE, GUILD, and GUILESNARF - see
# guile_export for details - as well as GUILE_CURRENT_VERSION and
# GUILE_EFFECTIVE_VERSION, which are set to the same value (the current
# version).
#
# This combination should cover Guile detection of a large amount of
# packages out of the box.
guile_foreach_impl() {
	debug-print-function ${FUNCNAME} "$@"

	local MULTIBUILD_VARIANTS
	MULTIBUILD_VARIANTS=("${GUILE_SELECTED_TARGETS[@]}")

	debug-print "${FUNCNAME}: Running for each of:" \
				"${GUILE_SELECTED_TARGETS[@]}"

	multibuild_foreach_variant _guile_multibuild_wrapper "${@}"
}

# @FUNCTION: _guile_merge_single_root
# @INTERNAL
# @DESCRIPTION:
# Runs a single merge_root step for guile_merge_roots.
_guile_merge_single_root() {
	debug-print-function ${FUNCNAME} "$@"

	multibuild_merge_root "${SLOTTED_D}" "${D}"
}

# @FUNCTION: guile_merge_roots
# @DESCRIPTION:
# Merges install roots from all slots, diagnosing conflicts.
guile_merge_roots() {
	debug-print-function ${FUNCNAME} "$@"

	guile_foreach_impl _guile_merge_single_root
}

# @FUNCTION: guile_for_best_impl
# @DESCRIPTION:
# Runs the passed command once, for the best installed Guile
# implementation.
guile_for_best_impl() {
	debug-print-function ${FUNCNAME} "$@"

	multibuild_for_best_variant _guile_multibuild_wrapper "${@}"
}

# Default implementations for a GNU Build System based Guile package.

# @FUNCTION: guile_src_prepare
# @DESCRIPTION:
# Bumps SCM sources runs the default src_prepare and bumps all *.scm
# files.  See guile_bump_sources of guile-utils.eclass.
guile_src_prepare() {
	debug-print-function ${FUNCNAME} "$@"

	default
	guile_bump_sources
}

# @FUNCTION: guile_src_configure
# @DESCRIPTION:
# Runs the default src_configure for each selected variant target.
guile_src_configure() {
	debug-print-function ${FUNCNAME} "$@"

	guile_foreach_impl default
}

# @FUNCTION: guile_src_compile
# @DESCRIPTION:
# Runs the default src_compile for each selected variant target.
guile_src_compile() {
	debug-print-function ${FUNCNAME} "$@"

	guile_foreach_impl default
}

# @FUNCTION: guile_src_test
# @DESCRIPTION:
# Runs the default src_test phase for each implementation.
guile_src_test() {
	debug-print-function ${FUNCNAME} "$@"

	guile_foreach_impl default
}

# @FUNCTION: _guile_default_install_slot
# @INTERNAL
# @DESCRIPTION:
# Imitates the default build system install "substep", but for a given
# ${SLOTTED_D} rather than the usual ${D}.  See guile_src_install.
_guile_default_install_slot() {
	debug-print-function ${FUNCNAME} "$@"

	if [[ -f Makefile ]] || [[ -f GNUmakefile ]] || [[ -f makefile ]]; then
		emake DESTDIR="${SLOTTED_D}" install
	fi
}

# @FUNCTION: guile_src_install
# @DESCRIPTION:
# Runs the an imitation of the default src_install that does the right
# thing for a GNU Build System based Guile package, for each selected
# variant target.  Merges roots after completing the installs.
guile_src_install() {
	debug-print-function ${FUNCNAME} "$@"

	guile_foreach_impl _guile_default_install_slot
	guile_merge_roots
	guile_unstrip_ccache

	einstalldocs
}

fi  # _GUILE_ECLASS

EXPORT_FUNCTIONS pkg_setup src_prepare src_configure src_compile \
				src_install src_test