Bug: https://bugs.gentoo.org/689408
Signed-off-by: Arsen Arsenović <ar...@gentoo.org>
---
 eclass/guile-single.eclass | 245 +++++++++++++++++++++++++++++++++++++
 1 file changed, 245 insertions(+)
 create mode 100644 eclass/guile-single.eclass

diff --git a/eclass/guile-single.eclass b/eclass/guile-single.eclass
new file mode 100644
index 000000000000..9ccafa2fdaa7
--- /dev/null
+++ b/eclass/guile-single.eclass
@@ -0,0 +1,245 @@
+# Copyright 2024 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+# @ECLASS: guile-single.eclass
+# @PROVIDES: guile-utils
+# @MAINTAINER:
+# Gentoo Scheme project <sch...@gentoo.org>
+# @AUTHOR:
+# Author: Arsen Arsenović <ar...@gentoo.org>
+# Inspired by prior work in the Gentoo Python ecosystem.
+# @BLURB: Utilities for packages that build against a single Guile.
+# @SUPPORTED_EAPIS: 8
+# @PROVIDES: guile-utils
+# @DESCRIPTION:
+# This eclass facilitates packages building against a single slot of
+# Guile, which is normally something that uses Guile for extending, like
+# GNU Make, or for programs built in Guile, like Haunt.
+#
+# These packages should use guile_gen_cond_dep to generate a dependency
+# string for their Guile package dependencies (i.e. other Guile single-
+# and multi-implementation packages).  They should also utilize
+# GUILE_DEPS and GUILE_REQUIRED_USE to specify a dependency on their
+# Guile versions.
+#
+# They should also bump sources via guile_bump_sources during
+# src_prepare, and unstrip ccache via guile_unstrip_ccache during
+# src_install.
+#
+# If the user of the eclass needs some USE flag on Guile itself, they
+# should provide it via GUILE_REQ_USE.
+#
+# This eclass provides a guile-single_pkg_setup that sets up environment
+# variables needed for Guile and build systems using it.  See the
+# documentation for that function for more details.
+#
+# @EXAMPLE:
+# A Guile program:
+#
+# @CODE
+# # Copyright 2024 Gentoo Authors
+# # Distributed under the terms of the GNU General Public License v2
+#
+# EAPI=8
+#
+# GUILE_COMPAT=( 3-0 2-2 )
+# inherit guile-single
+#
+# DESCRIPTION="Haunt is a simple, functional, hackable static site generator"
+# HOMEPAGE="https://dthompson.us/projects/haunt.html";
+# SRC_URI="https://files.dthompson.us/releases/${PN}/${P}.tar.gz";
+#
+# LICENSE="GPL-3+"
+# SLOT="0"
+# KEYWORDS="~amd64"
+# REQUIRED_USE="${GUILE_REQUIRED_USE}"
+#
+# RDEPEND="
+#      ${GUILE_DEPS}
+#      $(guile_gen_cond_dep '
+#              dev-scheme/guile-reader[${GUILE_MULTI_USEDEP}]
+#              dev-scheme/guile-commonmark[${GUILE_MULTI_USEDEP}]
+#      ')
+# "
+# DEPEND="${RDEPEND}"
+# @CODE
+#
+# A program utilizing Guile for extension (GNU make, irrelevant pieces
+# elided):
+# @CODE
+# GUILE_COMPAT=( 3-0 2-2 2-0 1-8 )
+# inherit flag-o-matic unpacker verify-sig guile-single
+# # ...
+# REQUIRED_USE="guile? ( ${GUILE_REQUIRED_USE} )"
+# DEPEND="
+#      guile? ( ${GUILE_DEPS} )
+# "
+#
+# src_prepare() {
+#      # ...
+#      if use guile; then
+#              guile-single_src_prepare
+#      fi
+# }
+#
+# pkg_setup() {
+#      if use guile; then
+#              guile-single_pkg_setup
+#      fi
+# }
+#
+# src_configure() {
+#      # ...
+#      local myeconfargs=(
+#              $(use_with guile)
+#      )
+#      econf "${myeconfargs[@]}"
+# }
+#
+# src_install() {
+#      # ...
+#      if use guile; then
+#              guile_unstrip_ccache
+#      fi
+# }
+# @CODE
+
+case "${EAPI}" in
+       8) ;;
+       *) die "${ECLASS}: EAPI ${EAPI:-0} not supported" ;;
+esac
+
+if [[ ! "${_GUILE_SINGLE_ECLASS}" ]]; then
+_GUILE_SINGLE_ECLASS=1
+
+inherit guile-utils
+
+# @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 either
+# 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} "${@}"
+
+       # Inhibit generating the GUILE_USEDEP.  This variable is not usable
+       # for single packages.
+       local GUILE_USEDEP
+       guile_generate_depstrings guile_single_target ^^
+}
+
+_guile_setup
+unset -f _guile_setup
+
+# @FUNCTION: guile_gen_cond_dep
+# @USAGE: <dependency> [<pattern>...]
+# @DESCRIPTION:
+# Takes a string that uses (quoted) ${GUILE_SINGLE_USEDEP} and
+# ${GUILE_MULTI_USEDEP} markers as placeholders for the correct USE
+# dependency strings for each compatible slot.
+#
+# If the pattern is provided, it is taken to be list of slots to
+# generate the dependency string for, otherwise, ${GUILE_COMPAT[@]} is
+# taken.
+#
+# @EXAMPLE:
+# Note that the "inner" dependency string is in single quotes!
+# @CODE
+# RDEPEND="
+#      $(guile_gen_cond_dep '
+#              dev-scheme/guile-zstd[${GUILE_MULTI_USEDEP}]
+#              dev-scheme/guile-config[${GUILE_SINGLE_USEDEP}]
+#      ')
+# "
+# @CODE
+guile_gen_cond_dep() {
+       debug-print-function ${FUNCNAME} "${@}"
+
+       local deps="$1"
+       shift
+
+       local candidates=( "$@" )
+       if [[ ${#candidates[@]} -eq 0 ]]; then
+               candidates=( "${GUILE_COMPAT[@]}" )
+       fi
+
+       local candidate
+       for candidate in "${candidates[@]}"; do
+               local s="guile_single_target_${candidate}(-)" \
+                         m="guile_targets_${candidate}(-)" \
+                         subdeps=${deps//\$\{GUILE_SINGLE_USEDEP\}/${s}}
+               subdeps=${subdeps//\$\{GUILE_MULTI_USEDEP\}/${m}}
+               echo "
+               guile_single_target_${candidate}? (
+                       ${subdeps}
+               )
+               "
+       done
+}
+
+# @FUNCTION: guile-single_pkg_setup
+# @DESCRIPTION:
+# Sets up the PKG_CONFIG_PATH with the appropriate GUILE_SINGLE_TARGET,
+# as well as setting up a guile-config and the GUILE, GUILD and
+# GUILESNARF environment variables.  Also sets GUILE_EFFECTIVE_VERSION
+# to the same value as GUILE_SELECTED_TARGET, as build systems sometimes
+# check that variable.
+#
+# For details on the latter three, see guile_export.
+guile-single_pkg_setup() {
+       debug-print-function ${FUNCNAME} "${@}"
+
+       guile_set_common_vars
+
+       GUILE_SELECTED_TARGET=
+       for ver in "${GUILE_COMPAT[@]}"; do
+               debug-print "${FUNCNAME}: checking for ${ver}"
+               use "guile_single_target_${ver}" || continue
+               GUILE_SELECTED_TARGET="${ver/-/.}"
+               break
+       done
+
+       [[ ${GUILE_SELECTED_TARGET} ]] \
+               || die "No GUILE_SINGLE_TARGET specified."
+
+       export PKG_CONFIG_PATH
+       guile_filter_pkgconfig_path "${GUILE_SELECTED_TARGET}"
+       guile_create_temporary_config "${GUILE_SELECTED_TARGET}"
+       local -x GUILE_EFFECTIVE_VERSION="${GUILE_SELECTED_TARGET}"
+       guile_export GUILE GUILD GUILESNARF
+}
+
+# @FUNCTION: guile-single_src_prepare
+# @DESCRIPTION:
+# Runs the default prepare stage, and then bumps Guile sources via
+# guile_bump_sources.
+guile-single_src_prepare() {
+       debug-print-function ${FUNCNAME} "${@}"
+
+       default
+       guile_bump_sources
+}
+
+# @FUNCTION: guile-single_src_install
+# @DESCRIPTION:
+# Runs the default install stage, and then marks ccache files not to be
+# stripped using guile_unstrip_ccache.
+guile-single_src_install() {
+       debug-print-function ${FUNCNAME} "${@}"
+
+       default
+       guile_unstrip_ccache
+}
+
+EXPORT_FUNCTIONS pkg_setup src_prepare src_install
+
+fi  # _GUILE_SINGLE_ECLASS
-- 
2.45.2


Reply via email to