summaryrefslogtreecommitdiff
path: root/eclass/gap-pkg.eclass
diff options
context:
space:
mode:
authorMichael Orlitzky <mjo@gentoo.org>2023-12-21 09:32:59 -0500
committerMichael Orlitzky <mjo@gentoo.org>2024-01-22 06:28:56 -0500
commit413143b47ecb7545af4e537eb706e54278ea2240 (patch)
treea0e4bb96bf54cbcd106ef4b30c3fa7ef532aec58 /eclass/gap-pkg.eclass
parent61447179735f6dc2be6f7da74307eaccd01c96c8 (diff)
downloadgentoo-413143b47ecb7545af4e537eb706e54278ea2240.tar.gz
gentoo-413143b47ecb7545af4e537eb706e54278ea2240.tar.bz2
gentoo-413143b47ecb7545af4e537eb706e54278ea2240.zip
gap-pkg.eclass: new eclass for GAP packages
Signed-off-by: Michael Orlitzky <mjo@gentoo.org>
Diffstat (limited to 'eclass/gap-pkg.eclass')
-rw-r--r--eclass/gap-pkg.eclass408
1 files changed, 408 insertions, 0 deletions
diff --git a/eclass/gap-pkg.eclass b/eclass/gap-pkg.eclass
new file mode 100644
index 000000000000..96e713a654a1
--- /dev/null
+++ b/eclass/gap-pkg.eclass
@@ -0,0 +1,408 @@
+# Copyright 2024 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+# @ECLASS: gap-pkg.eclass
+# @MAINTAINER:
+# François Bissey <frp.bissey@gmail.com>
+# Michael Orlitzky <mjo@gentoo.org>
+# @AUTHOR:
+# François Bissey <frp.bissey@gmail.com>
+# Michael Orlitzky <mjo@gentoo.org>
+# @SUPPORTED_EAPIS: 8
+# @BLURB: Simplify the installation of GAP packages.
+# @DESCRIPTION:
+# The main purpose of this eclass is to build and install GAP packages
+# that typically occupy the dev-gap category. Most GAP packages do not
+# support an install target out of the box, so the default installation
+# is "by hand," with attention paid to those directories that are part
+# of the recommended layout. The prepare, configure, and compile phases
+# do however try to support packages having a real build system.
+#
+# GAP itself has four "required" packages that are packaged separately,
+# making dependencies between them somewhat weird. The four required
+# packages are,
+#
+# * dev-gap/gapdoc
+# * dev-gap/primgrp
+# * dev-gap/smallgrp
+# * dev-gap/transgrp
+#
+# Those four packages will have only sci-mathematics/gap added to
+# RDEPEND. All other packages will have the four required packages above
+# added to RDEPEND in addition to sci-mathematics/gap. In theory it
+# would be better to list all dependencies explicitly rather than
+# grouping together the "required" four, but this is how upstream GAP
+# works, and is what all GAP packages expect; for example, most test
+# suites fail without the required packages but make no attempt to load
+# them.
+#
+# If you need a version constraint on sci-mathematics/gap, you'll have
+# to specify it yourself. Compiled packages will likely need
+# sci-mathematics/gap in DEPEND as well, and may also want a subslot
+# dependency.
+
+case ${EAPI} in
+ 8) ;;
+ *) die "${ECLASS}: EAPI ${EAPI:-0} not supported" ;;
+esac
+
+# Some packages have additional homepages, but pretty much every GAP
+# package can be found at this URL.
+HOMEPAGE="https://www.gap-system.org/Packages/${PN}.html"
+
+# _GAP_PKG_IS_REQUIRED is an internal variable that indicates whether or
+# not $PN is one of the four "required" GAP packages that are always
+# loaded, even when GAP is started with the "-A" flag. We treat this
+# four somewhat differently since they are implicit dependencies of
+# everything else in the GAP ecosystem.
+_GAP_PKG_IS_REQUIRED=no
+case "${PN}" in
+ gapdoc|smallgrp|primgrp|transgrp)
+ _GAP_PKG_IS_REQUIRED=yes
+ ;;
+ *)
+ ;;
+esac
+
+# _GAP_PKG_RDEPEND is an internal variable to hold the RDEPEND entries
+# added by this eclass. We use a separate variable for this because we
+# need its contents later in gap-pkg_enable_tests, and that function is
+# called from an ebuild context where the list of RDEPEND is maintained
+# separately. Basically: the values we add to RDEPEND here do not appear
+# in RDEPEND when gap-pkg_enable_tests is called.
+_GAP_PKG_RDEPEND="sci-mathematics/gap"
+
+# The four "required" packages depend only on GAP itself, while every
+# other package depends (also) on the four required ones.
+if [[ "${_GAP_PKG_IS_REQUIRED}" = "no" ]]; then
+ _GAP_PKG_RDEPEND+="
+ dev-gap/gapdoc
+ dev-gap/smallgrp
+ dev-gap/primgrp
+ dev-gap/transgrp"
+fi
+RDEPEND="${_GAP_PKG_RDEPEND}"
+
+# @FUNCTION: gap-pkg_dir
+# @USAGE:
+# @DESCRIPTION:
+# The directory into which the gap package should be installed. The
+# accepted current location is /usr/$(get_libdir)/gap/pkg, but
+# technically this depends on the econf call in sci-mathematics/gap.
+gap-pkg_dir() {
+ echo "/usr/$(get_libdir)/gap/pkg/${PN}"
+}
+
+# @FUNCTION: _gap-pkg_gaproot
+# @INTERNAL
+# @USAGE:
+# @DESCRIPTION:
+# The directory containing sysinfo.gap. This is frequently passed to GAP
+# packages via ./configure --with-gaproot or as a positional argument to
+# the old-style fake configure scripts. We also use it to find the value
+# of $GAParch, which is contained in sysinfo.gap. The "gaproot" is
+# implicitly determined by the econf call in sci-mathematics/gap. As a
+# result, calling this function requires sci-mathematics/gap at
+# build-time.
+_gap-pkg_gaproot() {
+ echo "${ESYSROOT}/usr/$(get_libdir)/gap"
+}
+
+# @FUNCTION: _gap-pkg_gaparch
+# @INTERNAL
+# @USAGE:
+# @DESCRIPTION:
+# Return the variable $GAParch from sysinfo.gap. GAP packages put their
+# executables and libraries in bin/$GAParch, and to accomplish that, we
+# sometimes need to pass $GAParch to the build system.
+_gap-pkg_gaparch() {
+ # Use a subshell so we don't pollute the environment.
+ ( . $(_gap-pkg_gaproot)/sysinfo.gap && echo "${GAParch}" )
+}
+
+# @FUNCTION: gap-pkg_econf
+# @USAGE: [extra econf args]
+# @DESCRIPTION:
+# Call econf with the standard GAP package arguments that should be
+# passed to a real ./configure script:
+#
+# 1. GAP uses the ABI variable internally so we have to unset it.
+# 2. We pass the value of _gap-pkg_gaproot to --with-gaproot.
+# 3. We set both bindir and libdir to bin/$GAParch within the
+# gap-pkg_dir. This is where Makefile.gappkg stores both
+# types of binaries, and is therefore where GAP expects to
+# find them.
+#
+# All arguments to gap-pkg_econf are passed through to econf.
+#
+# @EXAMPLE
+# src_configure() {
+# gap-pkg_econf --with-external-libsemigroups
+# }
+#
+gap-pkg_econf() {
+ econf \
+ --with-gaproot=$(_gap-pkg_gaproot) \
+ --bindir="$(gap-pkg_dir)/bin/$(_gap-pkg_gaparch)" \
+ --libdir="$(gap-pkg_dir)/bin/$(_gap-pkg_gaparch)" \
+ "${@}"
+}
+
+# @FUNCTION: gap-pkg_src_configure
+# @USAGE:
+# @DESCRIPTION:
+# Handle both "real" configure script and the fake "old-style" ones
+# still used by many GAP packages. We determine which one we're dealing
+# with by running ./configure --help; an autoconf configure script will
+# mention "PREFIX" in the output, a fake one will not.
+#
+# Real configure scripts are configured using gap-pkg_econf, fake ones
+# are executed directly with _gap-pkg_gaproot as their sole positional
+# argument.
+gap-pkg_src_configure() {
+ local _configure="${ECONF_SOURCE:-.}/configure"
+ if [[ -x ${_configure} ]] ; then
+ if ${_configure} --help | grep PREFIX &>/dev/null; then
+ # This is a real ./configure script
+ gap-pkg_econf
+ else
+ # It's an "old-style" handwritten script that does
+ # not print usage information with --help.
+ ${_configure} $(_gap-pkg_gaproot) || die
+ fi
+ fi
+}
+
+# @FUNCTION: gap-pkg_src_compile
+# @USAGE:
+# @DESCRIPTION:
+# The default src_compile with the addition of V=1 to emake. The
+# Makefile.gappkg used to build most C packages defaults to a quiet
+# build without this.
+gap-pkg_src_compile() {
+ if [[ -f Makefile ]] || [[ -f GNUmakefile ]] || [[ -f makefile ]]; then
+ emake V=1 || die "emake failed"
+ fi
+}
+
+# @FUNCTION: gap-pkg_enable_tests
+# @USAGE:
+# @DESCRIPTION:
+# Amend IUSE, RESTRICT, and BDEPEND for a package with a test suite.
+# This is modeled on similar functions in the distutils-r1 and
+# elisp-common eclasses, except here only a single default testing
+# strategy is supported. All runtime and post-merge dependencies are
+# added as build dependencies if USE=test is set.
+gap-pkg_enable_tests() {
+ IUSE+=" test "
+ RESTRICT+=" !test? ( test ) "
+
+ # Use the internal variable here, too, because the RDEPEND list from
+ # the ebuild is maintained separately by the package manager. We add
+ # PDEPEND too because we use it to break some circular dependencies
+ # between e.g. polycyclic and alnuth.
+ BDEPEND+=" test? ( ${_GAP_PKG_RDEPEND} ${RDEPEND} ${PDEPEND} ) "
+}
+
+# @FUNCTION: gap-pkg_src_test
+# @USAGE:
+# @DESCRIPTION:
+# Run this package's test suite if it has one. The GAP TestPackage
+# function is the standard way to do this, but it does rely on the
+# package itself to get a few things right, like running the tests
+# verbosely and exiting with the appropriate code. The alternative would
+# be run TestDirectory ourselves on "tst", but that has its own issues;
+# in particular many packages have set-up code that is run only with
+# TestPackage. YMMV.
+gap-pkg_src_test() {
+ [[ -f PackageInfo.g ]] || return
+
+ # We would prefer --bare to -A so that we can test (say) primgrp
+ # after installing only gapdoc and not smallgrp or transgrp. But,
+ # that would cause problems for basically every non-required
+ # package, because they usually don't explicitly load the four
+ # "required" packages in their test suites. So we use -A unless
+ # this is one of the chosen four.
+ local bareflag="--bare"
+ if [[ "${_GAP_PKG_IS_REQUIRED}" = "no" ]]; then
+ bareflag="-A"
+ fi
+
+ # Run GAP non-interactively to test the just-built package. We omit
+ # the "-r" flag here because we use the UserGapRoot directory to
+ # store AtlasRep data, and without it, the atlasrep tests (and the
+ # tests of any packages depending on it) will fail.
+ local gapcmd="gap -R ${bareflag} --nointeract -c TestPackage(\"${PN}\");"
+
+ # Fake the directory structure that GAP needs to be able to find
+ # packages with a symlink under ${T}, then prepend ${T} to the list
+ # of search paths so that if this package is already installed, we
+ # load the just-built copy first.
+ ln -s "${WORKDIR}" "${T}/pkg" || die
+ gapcmd+=" --roots ${T}/; "
+
+ # False negatives can occur if GAP fails to start, or if there are
+ # syntax errors:
+ #
+ # https://github.com/gap-system/gap/issues/5541
+ #
+ # There's nothing you can do about that, but now you know.
+ #
+ # The pipe to tee is more important than it looks. Any test suite
+ # involving dev-gap/browse is likely to bork the user's terminal.
+ # The "browse" package is however smart enough to figure out when
+ # stdout is not a tty, and avoids breaking it in that case. So by
+ # piping to tee, we encourage it not to do anything too crazy.
+ ${gapcmd} | tee test-suite.log \
+ || die "test suite failed, see test-suite.log"
+}
+
+# @ECLASS_VARIABLE GAP_PKG_EXTRA_INSTALL
+# @DEFAULT_UNSET
+# @DESCRIPTION
+# A bash array of extra files and directories to install recursively at
+# the root of this package's directory tree. For example, if you have a
+# package that mostly follows the suggested layout (described in the
+# gap-pkg_src_install documentation) but also includes a "data"
+# directory, you should set
+#
+# GAP_PKG_EXTRA_INSTALL=( data )
+#
+# to install the data directory without having to override the entire
+# src_install phase.
+
+# @ECLASS_VARIABLE GAP_PKG_HTML_DOCDIR
+# @DEFAULT_UNSET
+# @DESCRIPTION
+# The directory inside the tarball where the HTML documentation is
+# located. This is _usually_ "doc", which conforms to the suggested
+# GAPDoc layout and is where we look if this variable is left
+# unset. Many packages however use a top-level "htm" directory
+# instead. The named directory will be installed to gap-pkg_dir and
+# symlinked to the usual location under /usr/share/doc. As a result, you
+# should only use this for directories referenced by PackageInfo.g or by
+# some other part of the package. HTML documentation whose location
+# doesn't need to be known to the package at runtime should instead be
+# installed with HTML_DOCS or a similar mechanism.
+
+# @FUNCTION: gap-pkg_src_install
+# @USAGE:
+# @DESCRIPTION:
+# Install a GAP package that follows the suggested layout,
+#
+# https://docs.gap-system.org/doc/ref/chap76.html
+#
+# In particular:
+#
+# 1. All GAP source files (*.g) in $S are installed.
+#
+# 2. If a library directory named "gap" or "lib" exists,
+# it is installed.
+#
+# 3. If a binary directory "bin" exists, it is installed.
+#
+# 4. If a "doc" directory exists, we assume GAPDoc conventions
+# (https://docs.gap-system.org/pkg/gapdoc/doc/chap5.html) and install
+# what we find there. Unfortunately for us, each package's
+# PackageInfo.g contains a "PackageDoc" section that points to this
+# documentation, and we can't break the paths it references. Instead,
+# we try to dosym the human-readable parts of the documentation (PDF
+# manuals) into appropriate Gentoo locations.
+#
+# 5. We consult GAP_PKG_HTML_DOCDIR for the HTML documentation and repeat
+# the process above.
+#
+# A few GAP packages have autotools build systems with working "make
+# install" routines, but most don't. So for the time being we omit that
+# step. It's harder to work around the packages that don't support it
+# than the other way around.
+gap-pkg_src_install() {
+ einstalldocs
+
+ # Install the "normal" documentation: pdf, six, and txt files under doc/
+ if [[ -d doc ]]; then
+ pushd doc > /dev/null || die
+
+ local docdir="$(gap-pkg_dir)/doc"
+ insinto "${docdir}"
+
+ # These files are needed by the GAP interface. We don't symlink
+ # these because they're not meant for direct human consumption;
+ # the text files are not *plain* text -- they contain color
+ # codes. I'm not sure if the BibTeX files are actually used,
+ # but the GAP packaging documentation mentions specifically
+ # that they should be included. XML files are included in case
+ # the bibliography is in BibXMLext format, but you may wind up
+ # with some additional GAPDoc (XML) source files as a result.
+ for f in *.{bib,lab,six,tex,txt,xml}; do
+ # The -f test avoids needing nullglob when no files match.
+ [[ -f "${f}" ]] && doins "${f}"
+ done
+
+ # The PDF docs are also potentially used by the interface, since
+ # they appear in PackageInfo.g, so we install them "as is." But
+ # then afterwards we symlink them to their proper Gentoo
+ # locations
+ for f in *.pdf; do
+ if [[ -f "${f}" ]]; then
+ doins "${f}"
+ dosym -r "${docdir}/${f}" "/usr/share/doc/${PF}/${f}"
+ fi
+ done
+
+ popd > /dev/null || die
+ fi
+
+ # Install the HTML documentation. The procedure is basically the
+ # same as for the PDF docs. Default to "doc" as the location if
+ # nothing else was specified.
+ : "${GAP_PKG_HTML_DOCDIR:=doc}"
+ if [[ -d "${GAP_PKG_HTML_DOCDIR}" ]]; then
+ pushd "${GAP_PKG_HTML_DOCDIR}" > /dev/null || die
+
+ local docdir="$(gap-pkg_dir)/${GAP_PKG_HTML_DOCDIR}"
+ insinto "${docdir}"
+
+ # See above
+ for f in *.{htm,html,css,js,png}; do
+ if [[ -f "${f}" ]]; then
+ doins "${f}"
+ dosym -r "${docdir}/${f}" "/usr/share/doc/${PF}/html/${f}"
+ fi
+ done
+
+ popd > /dev/null || die
+ fi
+
+ # Any GAP source files that live in the top-level directory.
+ insinto $(gap-pkg_dir)
+ for f in *.g; do
+ [[ -f "${f}" ]] && doins "${f}"
+ done
+
+ # The gap and lib dirs that usually also contain GAP code.
+ [[ -d gap ]] && doins -r gap
+ [[ -d lib ]] && doins -r lib
+
+ # Any additional user-specified files or directories.
+ for f in "${GAP_PKG_EXTRA_INSTALL[@]}"; do
+ doins -r "${f}"
+ done
+
+ # The bin dir, that contains shared libraries but also sometimes
+ # regular executables in an arch-specific subdirectory. We do
+ # this last because it messes with insopts -- doexe doesn't work
+ # recursively and we don't care what the subdirectory structure is.
+ if [[ -d bin ]]; then
+ insopts -m0755
+ doins -r bin
+
+ # Find and remove .la files from this package's bindir. The
+ # usual "find" command doesn't work here because occasionally we
+ # find *.la files in GAP packages that are not libtool archives
+ # and should not be deleted.
+ find "${ED%/}$(gap-pkg_dir)/bin" -type f -name '*.la' -delete
+ fi
+}
+
+EXPORT_FUNCTIONS src_configure src_compile src_test src_install