• [gentoo-dev] [PATCH 0/5] Handle LTO with static libraries

    From Sam James@21:1/5 to All on Fri May 2 22:20:02 2025
    See the commit message for dot-a.eclass for the details. More packages
    will need to be ported (libpcre2, Qt, ...) later.

    Sam James (5):
    dot-a.eclass: new eclass for handling LTO in static archives
    sys-libs/zlib: use dot-a.eclass for LTO
    dev-libs/glib: use dot-a.eclass for LTO
    dev-util/sysprof-capture: use dot-a.eclass for LTO
    sys-devel/flex: use dot-a.eclass for LTO

    dev-libs/glib/glib-2.78.6.ebuild | 7 +
    dev-libs/glib/glib-2.80.5-r1.ebuild | 7 +
    dev-libs/glib/glib-2.82.5.ebuild | 7 +
    dev-libs/glib/glib-2.84.0.ebuild | 7 +
    dev-libs/glib/glib-2.84.1.ebuild | 9 +-
    .../sysprof-capture-3.48.0.ebuild | 14 +-
    .../sysprof-capture-46.0.ebuild | 12 +-
    .../sysprof-capture-47.2.ebuild | 12 +-
    eclass/dot-a.eclass | 124 +++++++
    eclass/tests/dot-a.sh | 314 ++++++++++++++++++
    sys-devel/flex/flex-2.6.4-r6.ebuild | 7 +-
    sys-libs/zlib/zlib-1.3.1-r1.ebuild | 11 +-
    12 files changed, 521 insertions(+), 10 deletions(-)
    create mode 100644 eclass/dot-a.eclass
    create mode 100755 eclass/tests/dot-a.sh

    --
    2.49.0

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Sam James@21:1/5 to All on Fri May 2 22:20:01 2025
    This means that USE=static-libs doesn't produce a "broken" library
    when built w/ LTO.

    Bug: https://bugs.gentoo.org/818097
    Bug: https://bugs.gentoo.org/889004
    Bug: https://bugs.gentoo.org/927994
    Bug: https://bugs.gentoo.org/939515
    Signed-off-by: Sam James <sam@gentoo.org>
    ---
    .../sysprof-capture/sysprof-capture-3.48.0.ebuild | 14 ++++++++++++--
    .../sysprof-capture/sysprof-capture-46.0.ebuild | 12 +++++++++++-
    .../sysprof-capture/sysprof-capture-47.2.ebuild | 12 +++++++++++-
    3 files changed, 34 insertions(+), 4 deletions(-)

    diff --git a/dev-util/sysprof-capture/sysprof-capture-3.48.0.ebuild b/dev-util/sysprof-capture/sysprof-capture-3.48.0.ebuild
    index 0502a2eca20da..095cff44673d1 100644
    --- a/dev-util/sysprof-capture/sysprof-capture-3.48.0.ebuild
    +++ b/dev-util/sysprof-capture/sysprof-capture-3.48.0.ebuild
    @@ -1,10 +1,10 @@
    -# Copyright 1999-2023 Gentoo Authors
    +# Copyright 1999-2025 Gentoo Authors
    # Distributed under the terms of the GNU General Public License v2

    EAPI=8
    GNOME_ORG_MODULE="sysprof"

    -inherit gnome.org meson-multilib systemd
    +inherit dot-a gnome.org meson-multilib systemd

    DESCRIPTION="Static library for sysprof capture data generation"
    HOMEPAGE="http://sysprof.com/"
    @@ -21,6 +21,11 @@ BDEPEND="
    virtual/pkgconfig
    "
  • From Sam James@21:1/5 to All on Fri May 2 22:20:01 2025
    This means that USE=static-libs doesn't produce a "broken" library
    when built w/ LTO.

    Bug: https://bugs.gentoo.org/927994
    Signed-off-by: Sam James <sam@gentoo.org>
    ---
    dev-libs/glib/glib-2.78.6.ebuild | 7 +++++++
    dev-libs/glib/glib-2.80.5-r1.ebuild | 7 +++++++
    dev-libs/glib/glib-2.82.5.ebuild | 7 +++++++
    dev-libs/glib/glib-2.84.0.ebuild | 7 +++++++
    dev-libs/glib/glib-2.84.1.ebuild | 9 ++++++++-
    5 files changed, 36 insertions(+), 1 deletion(-)

    diff --git a/dev-libs/glib/glib-2.78.6.ebuild b/dev-libs/glib/glib-2.78.6.ebuild
    index e5481fe4d0052..b9609c7c059f2 100644
    --- a/dev-libs/glib/glib-2.78.6.ebuild
    +++ b/dev-libs/glib/glib-2.78.6.ebuild
    @@ -173,6 +173,11 @@ src_prepare() {
    # TODO: python_name sedding for correct python shebang? Might be relevant mainly for glib-utils only
    }

    +src_configure() {
    + lto-guarantee-fat
    + meson-multilib_src_configure
    +}
    +
    multilib_src_configure() {
    # TODO: figure a way to pass appropriate values for all cross properties
    # that glib uses (search for get_cross_property)
    @@ -245,6 +250,8 @@ multilib_src_install() {
    }

    multilib_src_install_all() {
    + strip-lto-bytecode
    +
    # These are in
  • From Sam James@21:1/5 to All on Fri May 2 22:20:02 2025
    This means that USE=static-libs doesn't produce a "broken" library
    when built w/ LTO.

    Signed-off-by: Sam James <sam@gentoo.org>
    ---
    sys-libs/zlib/zlib-1.3.1-r1.ebuild | 11 +++++++++--
    1 file changed, 9 insertions(+), 2 deletions(-)

    diff --git a/sys-libs/zlib/zlib-1.3.1-r1.ebuild b/sys-libs/zlib/zlib-1.3.1-r1.ebuild
    index f81cf5fac8d68..837b8564eec1b 100644
    --- a/sys-libs/zlib/zlib-1.3.1-r1.ebuild
    +++ b/sys-libs/zlib/zlib-1.3.1-r1.ebuild
    @@ -1,4 +1,4 @@
    -# Copyright 1999-2024 Gentoo Authors
    +# Copyright 1999-2025 Gentoo Authors
    # Distributed under the terms of the GNU General Public License v2

    EAPI=8
    @@ -6,7 +6,7 @@ EAPI=8
    # Worth keeping an eye on 'develop' branch upstream for possible backports.
    AUTOTOOLS_AUTO_DEPEND="no"
    VERIFY_SIG_OPENPGP_KEY_PATH=/usr/share/openpgp-keys/madler.asc
    -inherit autotools edo multilib-minimal flag-o-matic verify-sig
    +inherit autotools dot-a edo multilib-minimal flag-o-matic verify-sig

    DESCRIPTION="Standard (de)compression library"
    HOMEPAGE="https://zlib.net/"
    @@ -68,6 +68,11 @@ src_prepare() {
    esac
    }

    +src_configure() {
    + lto-guarantee-fat
    + multilib-minimal_s
  • From Sam James@21:1/5 to All on Fri May 2 22:20:01 2025
    Introduce a new eclass with utility functions for handling LTO bytecode
    (or internal representation, IR) inside static archives (.a files).

    Static libraries when built with LTO will contain LTO bytecode which is
    not portable across compiler versions or compiler vendors. To avoid pessimising the library and always filtering LTO, we can build it with -ffat-lto-objects instead, which builds some components twice. The installed part will then
    have the LTO contents stripped out, leaving the regular objects in the
    static archive.

    It's not feasible to make these work otherwise, as we'd need tracking
    for whether a library was built by a specific compiler and its version,
    and that compatibility can vary based on other factors (e.g. with gcc, sys-devel/gcc[zstd] controls if it supports zstd compression for LTO). We
    also discourage static libraries anyway.

    Provide two functions:

    * lto-guarantee-fat

    If LTO is currently enabled (as determined by `tc-is-lto`, added in
    2aea6c3ff2181ad96187e456a3307609fd288d4c), add `-ffat-lto-objects`
    to CFLAGS and CXXFLAGS if supported.

    This guarantees that produced archives are "fat" (contain both IR
    and regular object files) for later pruning.

    * strip-lto-bytecode

    Process a given static archive (.a file) and remove its IR component,
    leaving a regular object.

    This approach is also taken by Fedora, openSUSE, and Debian/Ubuntu. An honourable mention to `lto-rebuild` which fulfilled the same task for many
    in the LTO overlay too.

    We did consider an alternative approach where we'd relink objects using
    the driver in src_install (or some hook afterwards), but this would be
    more brittle, as we'd need to extract the right arguments to use (see
    e.g. the recent Wireshark issues in fad8ff8a45afc83559f8df695cf96dfec51d3e8a for how this can be subtle) and not PM-agnostic given we don't have portable hooks right now (and even if we did, suspect they wouldn't work in a way
    that facilitated this). It's also not clear if such an approach would've
    worked for Clang.

    All of this wasn't worth pursuing until H. J. Lu's patches for binutils
    landed, which they have now in binutils-2.44 [0], which made bfd's handling
    of mixed objects much more robust.

    [0] https://inbox.sourceware.org/binutils/20250112220244.597636-1-hjl.tools@gmail.com/

    Bug: https://bugs.gentoo.org/926120
    Thanks-to: Arsen Arsenović <arsen@gentoo.org>
    Co-authored-by: Eli Schwartz <eschwartz@gentoo.org>
    Signed-off-by: Sam James <sam@gentoo.org>
    ---
    eclass/dot-a.eclass | 124 +++++++++++++++++
    eclass/tests/dot-a.sh | 314 ++++++++++++++++++++++++++++++++++++++++++
    2 files changed, 438 insertions(+)
    create mode 100644 eclass/dot-a.eclass
    create mode 100755 eclass/tests/dot-a.sh

    diff --git a/eclass/dot-a.eclass b/eclass/dot-a.eclass
    new file mode 100644
    index 0000000000000..20a0fa1dfc206
    --- /dev/null
    +++ b/eclass/dot-a.eclass
    @@ -0,0 +1,124 @@
    +# Copyright 2025 Gentoo Authors
    +# Distributed under the terms of the GNU General Public License v2
    +
    +# @ECLASS: dot-a.eclass
    +# @MAINTAINER:
    +# Toolchain
    +# Toolchain Ninjas <toolchain@gentoo.org>
    +# @AUTHOR:
    +# Sam James <sam@gentoo.org>
    +# Eli Schwartz <eschwartz@gentoo.org>
    +# @SUPPORTED_EAPIS: 8
    +# @BLURB: Functions to handle stripping LTO bytecode out of static archives. +# @DESCRIPTION:
    +# This eclass provides functions to strip LTO bytecode out of static archives +# (.a files).
    +#
    +# Static libraries when built with LTO will contain LTO bytecode which is
    +# not porta
  • From =?UTF-8?Q?Micha=C5=82_G=C3=B3rny?=@21:1/5 to Sam James on Sat May 3 06:30:02 2025
    Hi,

    Sorry for not looking earlier.

    On Fri, 2025-05-02 at 21:13 +0100, Sam James wrote:
    diff --git a/eclass/dot-a.eclass b/eclass/dot-a.eclass
    new file mode 100644
    index 0000000000000..20a0fa1dfc206
    --- /dev/null
    +++ b/eclass/dot-a.eclass
    @@ -0,0 +1,124 @@
    +# Copyright 2025 Gentoo Authors
    +# Distributed under the terms of the GNU General Public License v2
    +
    +# @ECLASS: dot-a.eclass
    +# @MAINTAINER:
    +# Toolchain
    +# Toolchain Ninjas <toolchain@gentoo.org>

    You've got "toolchain" twice.

    +# @AUTHOR:
    +# Sam James <sam@gentoo.org>
    +# Eli Schwartz <eschwartz@gentoo.org>
    +# @SUPPORTED_EAPIS: 8
    +# @BLURB: Functions to handle stripping LTO bytecode out of static archives. +# @DESCRIPTION:
    +# This eclass provides functions to strip LTO bytecode out of static archives
    +# (.a files).
    +#
    +# Static libraries when built with LTO will contain LTO bytecode which is
    +# not portable across compiler versions or compiler vendors. To avoid pessimising
    +# the library and always filtering LTO, we can build it with -ffat-lto-objects
    +# instead, which builds some components twice. The installed part will then +# have the LTO contents stripped out, leaving the regular objects in the
    +# static archive.
    +#
    +# Use should be passing calling lto-guarantee-fat before configure-time
    +# and calling strip-lto-bytecode after installation.

    Do I understand correctly that this is to be always used when you're
    installing static libraries? Or are there more specific criteria?
    Perhaps that'd be worth including in the doc.

    +#
    +# @EXAMPLE:
    +# @CODE
    +#
    +# inherit dot-a
    +#
    +# src_configure() {
    +# lto-guarantee-fat
    +# econf
    +# }
    +#
    +# src_install() {
    +# default
    +# strip-lto-bytecode
    +# }
    +case ${EAPI} in
    + 8) ;;
    + *) die "${ECLASS}: EAPI ${EAPI:-0} not supported" ;;
    +esac
    +
    +if [[ -z ${_DOT_A_ECLASS} ]] ; then
    +_DOT_A_ECLASS=1
    +
    +inherit flag-o-matic toolchain-funcs
    +
    +# TODO: QA check
    +
    +# @FUNCTION: lto-guarantee-fat
    +# @DESCRIPTION:
    +# If LTO is enabled, appends -ffat-lto-objects or any other flags needed
    +# to provide fat LTO objects.
    +lto-guarantee-fat() {
    + tc-is-lto || return
    +
    + # We add this for all languages as LTO obviously can't be done
    + # if different compilers are used for e.g. C vs C++ anyway.
    + append-flags $(test-flags-CC -ffat-lto-objects)
    +}
    +
    +# @FUNCTION: strip-lto-bytecode
    +# @USAGE: [library|directory] [...]
    +# @DESCRIPTION:
    +# Strips LTO bytecode from libraries (static archives) passed as arguments. +# Defaults to operating on ${ED} as a whole if no arguments are passed.
    +#
    +# As an optimisation, if USE=static-libs exists for a package and is disabled,
    +# the default-searching behaviour with no arguments is suppressed. +strip-lto-bytecode() {
    + tc-is-lto || return
    +
    + local files=()
    +
    + if [[ ${#} -eq 0 ]]; then
    + if ! in_iuse static-libs || use static-libs ; then
    + # maybe we are USE=static-libs. Alternatively, maybe the ebuild doesn't
    + # offer such a choice. In both cases, the user specified the function,
    + # so we expect to be called on *something*, but nothing was explicitly
    + # passed. Try scanning ${ED} automatically.
    + set -- "${ED}"
    + fi
    + fi
    +
    + # Check if any of our arguments are directories to be recursed
    + # into.
    + local arg
    + for arg in "$@" ; do
    + if [[ -d ${arg} ]] ; then
    + mapfile -t -d '' -O "${#files[@]}" files < <(find "${arg}" -type f -iname '*.a' -print0)
    + else
    + files+=( "${arg}" )
    + fi
    + done

    Why not just pass all arguments to find(1)? If you pass a file path to
    it, it will just return that file, i.e.:

    mapfile -t -d '' files < <(find -H "${@}" -type f -iname '*.a' -print0)

    ('-H' to follow symbolic links if passed directly in "$@")

    +
    + toolchain_type=
    + tc-is-gcc && toolchain_type=gnu
    + tc-is-clang && toolchain_type=llvm
    +
    + local file
    + for file in "${files[@]}" ; do
    + case ${toolchain_type} in
    + gnu)
    + $(tc-getSTRIP) \
    + -R .gnu.lto_* \
    + -R .gnu.debuglto_* \
    + -N __gnu_lto_v1 \
    + "${file}" || die "Stripping bytecode in ${file} failed"
    + ;;

    Technically, strip accepts multiple files, but I can guess there's
    no point in optimizing the GNU branch here.

    + llvm)
    + llvm-bitcode-strip \
    + -r "${file}" \
    + -o "${file}" || die "Stripping bytecode in ${file} failed"
    + ;;
    + *)
    + ;;
    + esac
    + done
    +}
    +
    +fi

    --
    Best regards,
    Michał Górny


    -----BEGIN PGP SIGNATURE-----

    iQFGBAABCgAwFiEEx2qEUJQJjSjMiybFY5ra4jKeJA4FAmgVm0sSHG1nb3JueUBn ZW50b28ub3JnAAoJEGOa2uIyniQO+k4IAIeeUpQOReUIFYrjP5t2u8hdDAZ8NTU1 yx5iOH/Tu+D6rpoUCbUqQkNk7rY03RGM1v9tbbApkYJ1r4lUCr+ZMIwmr3NAVMeK ipjqhr7z3SL+2eatr/dVuJ00QJ0jBjpJV2F92UuBrN/6asc+4BTBZj2ivA02eMTH bdzRAdQu3kC1isz3tR/Lz2nQitVS5786Tn8VDM5VB1JYA9LGD0+eF1kl/TuGpXBv +M6IQDA2ThmJX3dCOPU5hpuJoP9Cvq6KlEyjloMuFnvpOHKdyrcB1HTLEy77tI1r mGzoTeJ/WLpEWkpIcAvv0mvGghAnQhWC71GzvJLmqfnGvh1zf2cID9s=
    =80bZ
    -----END PGP SIGNATURE-----

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Sam James@21:1/5 to Sam James on Sat May 3 08:50:01 2025
    Sam James <sam@gentoo.org> writes:

    Michał Górny <mgorny@gentoo.org> writes:
    [...]
    + local arg
    + for arg in "$@" ; do
    + if [[ -d ${arg} ]] ; then
    + mapfile -t -d '' -O "${#files[@]}" files < <(find "${arg}" -type f -iname '*.a' -print0)
    + else
    + files+=( "${arg}" )
    + fi
    + done

    Why not just pass all arguments to find(1)? If you pass a file path to
    it, it will just return that file, i.e.:

    mapfile -t -d '' files < <(find -H "${@}" -type f -iname '*.a' -print0)

    ('-H' to follow symbolic links if passed directly in "$@")

    Oh! Good point. Let me try that.

    This breaks some of the tests because we do some direct testing on .o
    files. But I can't think of why a package would do that besides
    toolchain packages where special care will be needed anyway, so I'll
    adjust the tests.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Sam James@21:1/5 to mgorny@gentoo.org on Sat May 3 08:30:01 2025
    Michał Górny <mgorny@gentoo.org> writes:

    Hi,

    Sorry for not looking earlier.


    Thanks for reviewing (and no worries, this has been loooooong overdue).


    On Fri, 2025-05-02 at 21:13 +0100, Sam James wrote:
    diff --git a/eclass/dot-a.eclass b/eclass/dot-a.eclass
    new file mode 100644
    index 0000000000000..20a0fa1dfc206
    --- /dev/null
    +++ b/eclass/dot-a.eclass
    @@ -0,0 +1,124 @@
    +# Copyright 2025 Gentoo Authors
    +# Distributed under the terms of the GNU General Public License v2
    +
    +# @ECLASS: dot-a.eclass
    +# @MAINTAINER:
    +# Toolchain
    +# Toolchain Ninjas <toolchain@gentoo.org>

    You've got "toolchain" twice.

    ACK.


    +# @AUTHOR:
    +# Sam James <sam@gentoo.org>
    +# Eli Schwartz <eschwartz@gentoo.org>
    +# @SUPPORTED_EAPIS: 8
    +# @BLURB: Functions to handle stripping LTO bytecode out of static archives.
    +# @DESCRIPTION:
    +# This eclass provides functions to strip LTO bytecode out of static archives
    +# (.a files).
    +#
    +# Static libraries when built with LTO will contain LTO bytecode which is >> +# not portable across compiler versions or compiler vendors. To avoid pessimising
    +# the library and always filtering LTO, we can build it with -ffat-lto-objects
    +# instead, which builds some components twice. The installed part will then >> +# have the LTO contents stripped out, leaving the regular objects in the
    +# static archive.
    +#
    +# Use should be passing calling lto-guarantee-fat before configure-time
    +# and calling strip-lto-bytecode after installation.

    Do I understand correctly that this is to be always used when you're installing static libraries? Or are there more specific criteria?
    Perhaps that'd be worth including in the doc.

    Correct, with the exception of packages where LTO is currently filtered
    (but people should add it to future-proof unless it's something like
    glibc).

    I'll document that.


    +#
    +# @EXAMPLE:
    +# @CODE
    +#
    +# inherit dot-a
    +#
    +# src_configure() {
    +# lto-guarantee-fat
    +# econf
    +# }
    +#
    +# src_install() {
    +# default
    +# strip-lto-bytecode
    +# }
    +case ${EAPI} in
    + 8) ;;
    + *) die "${ECLASS}: EAPI ${EAPI:-0} not supported" ;;
    +esac
    +
    +if [[ -z ${_DOT_A_ECLASS} ]] ; then
    +_DOT_A_ECLASS=1
    +
    +inherit flag-o-matic toolchain-funcs
    +
    +# TODO: QA check
    +
    +# @FUNCTION: lto-guarantee-fat
    +# @DESCRIPTION:
    +# If LTO is enabled, appends -ffat-lto-objects or any other flags needed
    +# to provide fat LTO objects.
    +lto-guarantee-fat() {
    + tc-is-lto || return
    +
    + # We add this for all languages as LTO obviously can't be done
    + # if different compilers are used for e.g. C vs C++ anyway.
    + append-flags $(test-flags-CC -ffat-lto-objects)
    +}
    +
    +# @FUNCTION: strip-lto-bytecode
    +# @USAGE: [library|directory] [...]
    +# @DESCRIPTION:
    +# Strips LTO bytecode from libraries (static archives) passed as arguments. >> +# Defaults to operating on ${ED} as a whole if no arguments are passed.
    +#
    +# As an optimisation, if USE=static-libs exists for a package and is disabled,
    +# the default-searching behaviour with no arguments is suppressed.
    +strip-lto-bytecode() {
    + tc-is-lto || return
    +
    + local files=()
    +
    + if [[ ${#} -eq 0 ]]; then
    + if ! in_iuse static-libs || use static-libs ; then
    + # maybe we are USE=static-libs. Alternatively, maybe the ebuild doesn't
    + # offer such a choice. In both cases, the user specified the function,
    + # so we expect to be called on *something*, but nothing was explicitly
    + # passed. Try scanning ${ED} automatically.
    + set -- "${ED}"
    + fi
    + fi
    +
    + # Check if any of our arguments are directories to be recursed
    + # into.
    + local arg
    + for arg in "$@" ; do
    + if [[ -d ${arg} ]] ; then
    + mapfile -t -d '' -O "${#files[@]}" files < <(find "${arg}" -type f -iname '*.a' -print0)
    + else
    + files+=( "${arg}" )
    + fi
    + done

    Why not just pass all arguments to find(1)? If you pass a file path to
    it, it will just return that file, i.e.:

    mapfile -t -d '' files < <(find -H "${@}" -type f -iname '*.a' -print0)

    ('-H' to follow symbolic links if passed directly in "$@")

    Oh! Good point. Let me try that.


    +
    + toolchain_type=
    + tc-is-gcc && toolchain_type=gnu
    + tc-is-clang && toolchain_type=llvm
    +
    + local file
    + for file in "${files[@]}" ; do
    + case ${toolchain_type} in
    + gnu)
    + $(tc-getSTRIP) \
    + -R .gnu.lto_* \
    + -R .gnu.debuglto_* \
    + -N __gnu_lto_v1 \
    + "${file}" || die "Stripping bytecode in ${file} failed"
    + ;;

    Technically, strip accepts multiple files, but I can guess there's
    no point in optimizing the GNU branch here.

    I thought about this, and it's so tempting because the GNU case is the
    common one, but it'd uglify the function, and the eclass already feels (unavoidably) complex for something which is simple.


    + llvm)
    + llvm-bitcode-strip \
    + -r "${file}" \
    + -o "${file}" || die "Stripping bytecode in ${file} failed"
    + ;;
    + *)
    + ;;
    + esac
    + done
    +}
    +
    +fi

    thanks,
    sam

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Sam James@21:1/5 to Sam James on Sat May 3 09:20:01 2025
    Sam James <sam@gentoo.org> writes:

    Sam James <sam@gentoo.org> writes:

    Michał Górny <mgorny@gentoo.org> writes:
    [...]
    + local arg
    + for arg in "$@" ; do
    + if [[ -d ${arg} ]] ; then
    + mapfile -t -d '' -O "${#files[@]}" files < <(find "${arg}" -type f -iname '*.a' -print0)
    + else
    + files+=( "${arg}" )
    + fi
    + done

    Why not just pass all arguments to find(1)? If you pass a file path to
    it, it will just return that file, i.e.:

    mapfile -t -d '' files < <(find -H "${@}" -type f -iname '*.a' -print0)

    ('-H' to follow symbolic links if passed directly in "$@")

    Oh! Good point. Let me try that.

    This breaks some of the tests because we do some direct testing on .o
    files. But I can't think of why a package would do that besides
    toolchain packages where special care will be needed anyway, so I'll
    adjust the tests.

    It needs some more thought as .a requires special handling (bug #603594
    and bug #866422). I'll think aobut it more.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)