summaryrefslogtreecommitdiff
path: root/eclass/guile.eclass
diff options
context:
space:
mode:
Diffstat (limited to 'eclass/guile.eclass')
-rw-r--r--eclass/guile.eclass359
1 files changed, 359 insertions, 0 deletions
diff --git a/eclass/guile.eclass b/eclass/guile.eclass
new file mode 100644
index 000000000000..1d4a88caf926
--- /dev/null
+++ b/eclass/guile.eclass
@@ -0,0 +1,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