summaryrefslogtreecommitdiff
path: root/eclass
diff options
context:
space:
mode:
authorV3n3RiX <venerix@koprulu.sector>2024-02-10 17:34:25 +0000
committerV3n3RiX <venerix@koprulu.sector>2024-02-10 17:34:25 +0000
commit0bb42730e8fc9c8e571f12e3189c6c6f8d532c24 (patch)
treecba6032fbed30be2b0764494607c3ec9dda0c18a /eclass
parentcc901a8ce7c6bfe97e3b4f048619693d360ae348 (diff)
gentoo auto-resync : 10:02:2024 - 17:34:25
Diffstat (limited to 'eclass')
-rw-r--r--eclass/Manifest.gzbin39123 -> 39761 bytes
-rw-r--r--eclass/dotnet-pkg-base.eclass124
-rw-r--r--eclass/dotnet-pkg.eclass69
-rw-r--r--eclass/llvm-r1.eclass250
-rw-r--r--eclass/llvm-utils.eclass153
-rw-r--r--eclass/llvm.eclass117
-rw-r--r--eclass/nuget.eclass47
-rwxr-xr-xeclass/tests/llvm-r1.sh151
-rwxr-xr-xeclass/tests/llvm-utils.sh118
9 files changed, 869 insertions, 160 deletions
diff --git a/eclass/Manifest.gz b/eclass/Manifest.gz
index 33e99f13acc7..cb928087604c 100644
--- a/eclass/Manifest.gz
+++ b/eclass/Manifest.gz
Binary files differ
diff --git a/eclass/dotnet-pkg-base.eclass b/eclass/dotnet-pkg-base.eclass
index 1a9d311208e2..a2d95f15a2fb 100644
--- a/eclass/dotnet-pkg-base.eclass
+++ b/eclass/dotnet-pkg-base.eclass
@@ -1,4 +1,4 @@
-# Copyright 1999-2023 Gentoo Authors
+# Copyright 1999-2024 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2
# @ECLASS: dotnet-pkg-base.eclass
@@ -68,13 +68,19 @@ if [[ ${CATEGORY}/${PN} != dev-dotnet/dotnet-runtime-nugets ]] ; then
die "${ECLASS}: DOTNET_PKG_COMPAT not set"
fi
- DOTNET_PKG_RDEPS+=" virtual/dotnet-sdk:${DOTNET_PKG_COMPAT} "
- DOTNET_PKG_BDEPS+=" ${DOTNET_PKG_RDEPS} "
+ DOTNET_PKG_RDEPS+="
+ virtual/dotnet-sdk:${DOTNET_PKG_COMPAT}
+ "
+ DOTNET_PKG_BDEPS+="
+ ${DOTNET_PKG_RDEPS}
+ "
# Special package "dev-dotnet/csharp-gentoodotnetinfo" used for information
# gathering, example for usage see the "dotnet-pkg-base_info" function.
if [[ ${CATEGORY}/${PN} != dev-dotnet/csharp-gentoodotnetinfo ]] ; then
- DOTNET_PKG_BDEPS+=" dev-dotnet/csharp-gentoodotnetinfo "
+ DOTNET_PKG_BDEPS+="
+ dev-dotnet/csharp-gentoodotnetinfo
+ "
fi
IUSE+=" debug "
@@ -222,28 +228,27 @@ dotnet-pkg-base_get-runtime() {
#
# Used by "dotnet-pkg_pkg_setup" from the "dotnet-pkg" eclass.
dotnet-pkg-base_setup() {
- local dotnet_compat_impl
- local dotnet_compat_impl_path
- for dotnet_compat_impl in dotnet{,-bin}-${DOTNET_PKG_COMPAT} ; do
- dotnet_compat_impl_path="$(type -P "${dotnet_compat_impl}")"
+ local -a impl_dirs=(
+ "${EPREFIX}/usr/$(get_libdir)/dotnet-sdk-${DOTNET_PKG_COMPAT}"
+ "${EPREFIX}/opt/dotnet-sdk-bin-${DOTNET_PKG_COMPAT}"
+ )
+ local impl_exe
+
+ local impl_dir
+ for impl_dir in "${impl_dirs[@]}" ; do
+ impl_exe="${impl_dir}/dotnet"
+
+ if [[ -d "${impl_dir}" ]] && [[ -x "${impl_exe}" ]] ; then
+ DOTNET_PKG_EXECUTABLE="${impl_exe}"
+ DOTNET_ROOT="${impl_dir}"
- if [[ -n ${dotnet_compat_impl_path} ]] ; then
- DOTNET_PKG_EXECUTABLE="${dotnet_compat_impl}"
break
fi
done
- # Link "DOTNET_PKG_EXECUTABLE" to "dotnet" only for the package build.
- local dotnet_spoof_path="${T}/dotnet_spoof/${DOTNET_PKG_COMPAT}"
- mkdir -p "${dotnet_spoof_path}" || die
- ln -s "${dotnet_compat_impl_path}" "${dotnet_spoof_path}/dotnet" || die
- export PATH="${dotnet_spoof_path}:${PATH}"
-
- einfo "Using dotnet SDK \"${DOTNET_PKG_EXECUTABLE}\" from \"${dotnet_compat_impl_path}\"."
-
- # The picked "DOTNET_PKG_EXECUTABLE" should set "DOTNET_ROOT" internally
- # and not rely upon this environment variable.
- unset DOTNET_ROOT
+ einfo "Setting .NET SDK \"DOTNET_ROOT\" to \"${DOTNET_ROOT}\""
+ export DOTNET_ROOT
+ export PATH="${DOTNET_ROOT}:${PATH}"
DOTNET_PKG_RUNTIME="$(dotnet-pkg-base_get-runtime)"
DOTNET_PKG_CONFIGURATION="$(dotnet-pkg-base_get-configuration)"
@@ -304,6 +309,21 @@ dotnet-pkg-base_info() {
fi
}
+# @FUNCTION: dotnet-pkg-base_sln-remove
+# @USAGE: <solution> <project>
+# @DESCRIPTION:
+# Remove a project from a given solution file.
+#
+# Used by "dotnet-pkg_remove-bad" from the "dotnet-pkg" eclass.
+dotnet-pkg-base_sln-remove() {
+ debug-print-function "${FUNCNAME[0]}" "${@}"
+
+ [[ -z ${1} ]] && die "${FUNCNAME[0]}: no solution file specified"
+ [[ -z ${2} ]] && die "${FUNCNAME[0]}: no project file specified"
+
+ edotnet sln "${1}" remove "${2}"
+}
+
# @FUNCTION: dotnet-pkg-base_foreach-solution
# @USAGE: <directory> <args> ...
# @DESCRIPTION:
@@ -354,7 +374,7 @@ dotnet-pkg-base_restore() {
edotnet restore "${restore_args[@]}"
}
-# @FUNCTION: dotnet-pkg-base_restore_tools
+# @FUNCTION: dotnet-pkg-base_restore-tools
# @USAGE: [config-file] [args] ...
# @DESCRIPTION:
# Restore dotnet tools for a project in the current directory.
@@ -364,7 +384,7 @@ dotnet-pkg-base_restore() {
#
# Additionally any number of "args" maybe be given, they are appended to
# the "dotnet" command invocation.
-dotnet-pkg-base_restore_tools() {
+dotnet-pkg-base_restore-tools() {
debug-print-function "${FUNCNAME[0]}" "${@}"
local -a tool_restore_args=(
@@ -381,6 +401,14 @@ dotnet-pkg-base_restore_tools() {
edotnet tool restore "${tool_restore_args[@]}"
}
+# @FUNCTION: dotnet-pkg-base_restore_tools
+# @USAGE: [config-file] [args] ...
+# @DESCRIPTION:
+# DEPRECATED, use "dotnet-pkg-base_restore-tools" instead.
+dotnet-pkg-base_restore_tools() {
+ dotnet-pkg-base_restore-tools "${@}"
+}
+
# @FUNCTION: dotnet-pkg-base_build
# @USAGE: [args] ...
# @DESCRIPTION:
@@ -388,8 +416,8 @@ dotnet-pkg-base_restore_tools() {
# Build is performed in current directory unless a different directory is
# passed via "args".
#
-# Additionally any number of "args" maybe be given, they are appended to
-# the "dotnet" command invocation.
+# Any number of "args" maybe be given, they are appended to the "dotnet"
+# command invocation.
#
# Used by "dotnet-pkg_src_compile" from the "dotnet-pkg" eclass.
dotnet-pkg-base_build() {
@@ -420,27 +448,19 @@ dotnet-pkg-base_build() {
}
# @FUNCTION: dotnet-pkg-base_test
-# @USAGE: [directory] [args] ...
+# @USAGE: [args] ...
# @DESCRIPTION:
# Test the package using "dotnet test" in a specified directory.
+# Test is performed in current directory unless a different directory is
+# passed via "args".
#
-# Optional "directory" argument defaults to the current directory path.
-#
-# Additionally any number of "args" maybe be given, they are appended to
-# the "dotnet" command invocation.
+# Any number of "args" maybe be given, they are appended to the "dotnet"
+# command invocation.
#
# Used by "dotnet-pkg_src_test" from the "dotnet-pkg" eclass.
dotnet-pkg-base_test() {
debug-print-function "${FUNCNAME[0]}" "${@}"
- local directory
- if [[ -n "${1}" ]] ; then
- directory="${1}"
- shift
- else
- directory="$(pwd)"
- fi
-
local -a test_args=(
--configuration "${DOTNET_PKG_CONFIGURATION}"
--no-restore
@@ -448,7 +468,7 @@ dotnet-pkg-base_test() {
"${@}"
)
- edotnet test "${test_args[@]}" "${directory}"
+ edotnet test "${test_args[@]}"
}
# @FUNCTION: dotnet-pkg-base_install
@@ -482,7 +502,7 @@ dotnet-pkg-base_launcherinto() {
_DOTNET_PKG_LAUNCHERDEST="${1}"
}
-# @FUNCTION: dotnet-pkg-base_append_launchervar
+# @FUNCTION: dotnet-pkg-base_append-launchervar
# @USAGE: <variable-setting>
# @DESCRIPTION:
# Appends a given variable setting to the "_DOTNET_PKG_LAUNCHERVARS".
@@ -498,7 +518,7 @@ dotnet-pkg-base_launcherinto() {
# @CODE
#
# For more info see the "_DOTNET_PKG_LAUNCHERVARS" variable.
-dotnet-pkg-base_append_launchervar() {
+dotnet-pkg-base_append-launchervar() {
debug-print-function "${FUNCNAME[0]}" "${@}"
[[ -z ${1} ]] && die "${FUNCNAME[0]}: no variable setting specified"
@@ -506,6 +526,14 @@ dotnet-pkg-base_append_launchervar() {
_DOTNET_PKG_LAUNCHERVARS+=( "${1}" )
}
+# @FUNCTION: dotnet-pkg-base_append_launchervar
+# @USAGE: <variable-setting>
+# @DESCRIPTION:
+# DEPRECATED, use "dotnet-pkg-base_append-launchervar" instead.
+dotnet-pkg-base_append_launchervar() {
+ dotnet-pkg-base_append-launchervar "${@}"
+}
+
# @FUNCTION: dotnet-pkg-base_dolauncher
# @USAGE: <executable-path> [filename]
# @DESCRIPTION:
@@ -573,7 +601,7 @@ dotnet-pkg-base_dolauncher() {
doexe "${executable_target}"
}
-# @FUNCTION: dotnet-pkg-base_dolauncher_portable
+# @FUNCTION: dotnet-pkg-base_dolauncher-portable
# @USAGE: <dll-path> <filename>
# @DESCRIPTION:
# Make a wrapper script to launch a .NET DLL file built from a .NET package.
@@ -584,12 +612,12 @@ dotnet-pkg-base_dolauncher() {
#
# Example:
# @CODE
-# dotnet-pkg-base_dolauncher_portable \
+# dotnet-pkg-base_dolauncher-portable \
# /usr/share/${P}/GentooDotnetInfo.dll gentoo-dotnet-info
# @CODE
#
# The path is prepended by "EPREFIX".
-dotnet-pkg-base_dolauncher_portable() {
+dotnet-pkg-base_dolauncher-portable() {
debug-print-function "${FUNCNAME[0]}" "${@}"
local dll_path="${1}"
@@ -615,4 +643,12 @@ dotnet-pkg-base_dolauncher_portable() {
doexe "${executable_target}"
}
+# @FUNCTION: dotnet-pkg-base_dolauncher_portable
+# @USAGE: <dll-path> <filename>
+# @DESCRIPTION:
+# DEPRECATED, use "dotnet-pkg-base_dolauncher-portable" instead.
+dotnet-pkg-base_dolauncher_portable() {
+ dotnet-pkg-base_dolauncher-portable "${@}"
+}
+
fi
diff --git a/eclass/dotnet-pkg.eclass b/eclass/dotnet-pkg.eclass
index 9d78f463be77..59a8ae799f86 100644
--- a/eclass/dotnet-pkg.eclass
+++ b/eclass/dotnet-pkg.eclass
@@ -1,4 +1,4 @@
-# Copyright 1999-2023 Gentoo Authors
+# Copyright 1999-2024 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2
# @ECLASS: dotnet-pkg.eclass
@@ -48,6 +48,24 @@ inherit dotnet-pkg-base
RDEPEND+=" ${DOTNET_PKG_RDEPS} "
BDEPEND+=" ${DOTNET_PKG_BDEPS} "
+# @ECLASS_VARIABLE: DOTNET_PKG_BAD_PROJECTS
+# @DESCRIPTION:
+# List of projects to remove from all found solution (".sln") files.
+# The projects are removed in the "dotnet-pkg_src_prepare" function.
+#
+# This variable should be set after inheriting "dotnet-pkg.eclass".
+#
+# Default value is an empty array.
+#
+# Example:
+# @CODE
+# DOTNET_PKG_BAD_PROJECTS=( "${S}/BrokenTests" )
+# DOTNET_PKG_PROJECTS=( "${S}/DotnetProject" )
+# @CODE
+#
+# For more info see: "dotnet-pkg_remove-bad" function.
+DOTNET_PKG_BAD_PROJECTS=()
+
# @ECLASS_VARIABLE: DOTNET_PKG_PROJECTS
# @DEFAULT_UNSET
# @DESCRIPTION:
@@ -138,6 +156,29 @@ DOTNET_PKG_BUILD_EXTRA_ARGS=()
# For more info see the "DOTNET_PROJECT" variable and "dotnet-pkg_src_test".
DOTNET_PKG_TEST_EXTRA_ARGS=()
+# @FUNCTION: dotnet-pkg_force-compat
+# @DESCRIPTION:
+# This function appends special options to all "DOTNET_PKG_*_EXTRA_ARGS"
+# variables in an attempt to force compatibility to the picked
+# "DOTNET_PKG_COMPAT" .NET SDK version.
+#
+# Call this function post-inherit.
+dotnet-pkg_force-compat() {
+ if [[ -z ${DOTNET_PKG_COMPAT} ]] ; then
+ die "DOTNET_PKG_COMPAT is not set"
+ fi
+
+ local -a force_extra_args=(
+ -p:RollForward=Major
+ -p:TargetFramework="net${DOTNET_PKG_COMPAT}"
+ -p:TargetFrameworks="net${DOTNET_PKG_COMPAT}"
+ )
+
+ DOTNET_PKG_RESTORE_EXTRA_ARGS+=( "${force_extra_args[@]}" )
+ DOTNET_PKG_BUILD_EXTRA_ARGS+=( "${force_extra_args[@]}" )
+ DOTNET_PKG_TEST_EXTRA_ARGS+=( "${force_extra_args[@]}" )
+}
+
# @FUNCTION: dotnet-pkg_pkg_setup
# @DESCRIPTION:
# Default "pkg_setup" for the "dotnet-pkg" eclass.
@@ -161,14 +202,38 @@ dotnet-pkg_src_unpack() {
nuget_unpack-non-nuget-archives
}
+# @FUNCTION: dotnet-pkg_remove-bad
+# @USAGE: <solution>
+# @DESCRIPTION:
+# Remove all projects specified by "DOTNET_PKG_BAD_PROJECTS" from a given
+# solution file.
+#
+# Used by "dotnet-pkg_src_prepare".
+dotnet-pkg_remove-bad() {
+ debug-print-function "${FUNCNAME[0]}" "${@}"
+
+ [[ -z ${1} ]] && die "${FUNCNAME[0]}: no solution file specified"
+
+ local bad_project
+ for bad_project in "${DOTNET_PKG_BAD_PROJECTS[@]}" ; do
+ nonfatal dotnet-pkg-base_sln-remove "${1}" "${bad_project}"
+ done
+}
+
# @FUNCTION: dotnet-pkg_src_prepare
# @DESCRIPTION:
# Default "src_prepare" for the "dotnet-pkg" eclass.
# Prepare the package sources.
#
-# Run "dotnet-pkg-base_remove-global-json".
+# Run "dotnet-pkg-base_remove-global-json", "dotnet-pkg-base_remove-bad"
+# for each found solution file and prepare for using Nuget.
dotnet-pkg_src_prepare() {
dotnet-pkg-base_remove-global-json
+ dotnet-pkg-base_foreach-solution "$(pwd)" dotnet-pkg_remove-bad
+
+ find "$(pwd)" -maxdepth 1 -iname "nuget.config" -delete ||
+ die "${FUNCNAME[0]}: failed to remove unwanted \"NuGet.config\" config files"
+ nuget_writeconfig "$(pwd)/"
default
}
diff --git a/eclass/llvm-r1.eclass b/eclass/llvm-r1.eclass
new file mode 100644
index 000000000000..658946a1ecbd
--- /dev/null
+++ b/eclass/llvm-r1.eclass
@@ -0,0 +1,250 @@
+# Copyright 2024 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+# @ECLASS: llvm-r1.eclass
+# @MAINTAINER:
+# Michał Górny <mgorny@gentoo.org>
+# @AUTHOR:
+# Michał Górny <mgorny@gentoo.org>
+# @SUPPORTED_EAPIS: 8
+# @PROVIDES: llvm-utils
+# @BLURB: Provide LLVM_SLOT to build against slotted LLVM
+# @DESCRIPTION:
+# An eclass to reliably depend on a set of LLVM-related packages
+# in a matching slot. To use the eclass:
+#
+# 1. Set LLVM_COMPAT to the list of supported LLVM slots.
+# 2. Use llvm_gen_dep and/or LLVM_USEDEP to add appropriate
+# dependencies.
+# 3. Use llvm-r1_pkg_setup, get_llvm_prefix or LLVM_SLOT.
+#
+# The eclass sets IUSE and REQUIRED_USE. The flag corresponding
+# to the newest supported stable LLVM slot (or the newest testing,
+# if no stable slots are supported) is enabled by default.
+#
+# Example:
+# @CODE
+# LLVM_COMPAT=( {16..18} )
+#
+# inherit llvm-r1
+#
+# DEPEND="
+# dev-libs/libfoo[${LLVM_USEDEP}]
+# $(llvm_gen_dep '
+# sys-devel/clang:${LLVM_SLOT}
+# sys-devel/llvm:${LLVM_SLOT}
+# ')
+# "
+# @CODE
+
+case ${EAPI} in
+ 8) ;;
+ *) die "${ECLASS}: EAPI ${EAPI:-0} not supported" ;;
+esac
+
+if [[ ! ${_LLVM_R1_ECLASS} ]]; then
+_LLVM_R1_ECLASS=1
+
+inherit llvm-utils
+
+# == internal control knobs ==
+
+# @ECLASS_VARIABLE: _LLVM_OLDEST_SLOT
+# @INTERNAL
+# @DESCRIPTION:
+# Oldest supported LLVM slot. This is used to automatically filter out
+# unsupported LLVM_COMPAT values.
+_LLVM_OLDEST_SLOT=15
+
+# @ECLASS_VARIABLE: _LLVM_NEWEST_STABLE
+# @INTERNAL
+# @DESCRIPTION:
+# The newest stable LLVM version. Versions newer than that won't
+# be automatically enabled via USE defaults.
+_LLVM_NEWEST_STABLE=17
+
+# == control variables ==
+
+# @ECLASS_VARIABLE: LLVM_COMPAT
+# @PRE_INHERIT
+# @REQUIRED
+# @DESCRIPTION:
+# A list of LLVM slots supported by the package, oldest to newest.
+#
+# Example:
+# @CODE
+# LLVM_COMPAT=( {15..17} )
+# @CODE
+
+# @ECLASS_VARIABLE: LLVM_OPTIONAL
+# @PRE_INHERIT
+# @DEFAULT_UNSET
+# @DESCRIPTION:
+# If set to a non-empty value, disables setting REQUIRED_USE
+# and exporting pkg_setup. You have to add LLVM_REQUIRED_USE and call
+# pkg_setup manually, with appropriate USE conditions.
+
+# == global metadata ==
+
+# @ECLASS_VARIABLE: LLVM_REQUIRED_USE
+# @OUTPUT_VARIABLE
+# @DESCRIPTION:
+# An eclass-generated REQUIRED_USE string that enforces selecting
+# exactly one slot. It LLVM_OPTIONAL is set, it needs to be copied
+# into REQUIRED_USE, under appropriate USE conditions. Otherwise,
+# it is added automatically.
+
+# @ECLASS_VARIABLE: LLVM_USEDEP
+# @OUTPUT_VARIABLE
+# @DESCRIPTION:
+# An eclass-generated USE dependency string that can be applied to other
+# packages using the same eclass, to enforce a LLVM slot match.
+
+_llvm_set_globals() {
+ debug-print-function ${FUNCNAME} "${@}"
+
+ if [[ ${LLVM_COMPAT@a} != *a* ]]; then
+ die "LLVM_COMPAT must be set to an array before inheriting ${ECLASS}"
+ fi
+
+ local stable=() unstable=()
+ local x
+ for x in "${LLVM_COMPAT[@]}"; do
+ if [[ ${x} -gt ${_LLVM_NEWEST_STABLE} ]]; then
+ unstable+=( "${x}" )
+ elif [[ ${x} -ge ${_LLVM_OLDEST_SLOT} ]]; then
+ stable+=( "${x}" )
+ fi
+ done
+
+ _LLVM_SLOTS=( "${stable[@]}" "${unstable[@]}" )
+ if [[ ! ${_LLVM_SLOTS[@]} ]]; then
+ die "LLVM_COMPAT does not contain any valid versions (all older than ${_LLVM_OLDEST_SLOT}?)"
+ fi
+
+ if [[ ${stable[@]} ]]; then
+ IUSE="+llvm_slot_${stable[-1]}"
+ unset 'stable[-1]'
+ else
+ IUSE="+llvm_slot_${unstable[-1]}"
+ unset 'unstable[-1]'
+ fi
+ local nondefault=( "${stable[@]}" "${unstable[@]}" )
+ IUSE+=" ${nondefault[*]/#/llvm_slot_}"
+
+ local flags=( "${_LLVM_SLOTS[@]/#/llvm_slot_}" )
+ LLVM_REQUIRED_USE="^^ ( ${flags[*]} )"
+ local usedep_flags=${flags[*]/%/(-)?}
+ LLVM_USEDEP=${usedep_flags// /,}
+ readonly LLVM_REQUIRED_USE LLVM_USEDEP
+
+ if [[ ! ${LLVM_OPTIONAL} ]]; then
+ REQUIRED_USE=${LLVM_REQUIRED_USE}
+ fi
+}
+_llvm_set_globals
+unset -f _llvm_set_globals
+
+# == metadata helpers ==
+
+# @FUNCTION: llvm_gen_dep
+# @USAGE: <dependency>
+# @DESCRIPTION:
+# Output a dependency block, repeating "<dependency>" conditionally
+# to all llvm_slot_* USE flags. Any occurences of '${LLVM_SLOT}'
+# within the block will be substituted for the respective slot.
+#
+# Example:
+# @CODE
+# DEPEND="
+# $(llvm_gen_dep '
+# sys-devel/clang:${LLVM_SLOT}
+# sys-devel/llvm:${LLVM_SLOT}
+# ')
+# "
+# @CODE
+llvm_gen_dep() {
+ debug-print-function ${FUNCNAME} "${@}"
+
+ [[ ${#} -ne 1 ]] && die "Usage: ${FUNCNAME} <dependency>"
+
+ local dep=${1}
+
+ local slot
+ for slot in "${_LLVM_SLOTS[@]}"; do
+ echo "llvm_slot_${slot}? ( ${dep//\$\{LLVM_SLOT\}/${slot}} )"
+ done
+}
+
+# == ebuild helpers ==
+
+# @FUNCTION: get_llvm_prefix
+# @USAGE: [-b|-d]
+# @DESCRIPTION:
+# Output the path to the selected LLVM slot.
+#
+# With no option or "-d", the path is prefixed by ESYSROOT. LLVM
+# dependencies should be in DEPEND then.
+#
+# With "-b" option, the path is prefixed by BROOT. LLVM dependencies
+# should be in BDEPEND then.
+get_llvm_prefix() {
+ debug-print-function ${FUNCNAME} "${@}"
+
+ [[ ${#} -gt 1 ]] && die "Usage: ${FUNCNAME} [-b|-d]"
+
+ local prefix
+ case ${1--d} in
+ -d)
+ prefix=${ESYSROOT}
+ ;;
+ -b)
+ prefix=${BROOT}
+ ;;
+ *)
+ die "${FUNCNAME}: invalid option: ${1}"
+ ;;
+ esac
+
+ echo "${prefix}/usr/lib/llvm/${LLVM_SLOT}"
+}
+
+# @FUNCTION: llvm-r1_pkg_setup
+# @DESCRIPTION:
+# Prepend the appropriate executable directory for the selected LLVM
+# slot to PATH.
+#
+# The PATH manipulation is only done for source builds. The function
+# is a no-op when installing a binary package.
+#
+# If any other behavior is desired, the contents of the function
+# should be inlined into the ebuild and modified as necessary.
+#
+# Note that this function is not exported if LLVM_OPTIONAL is set.
+# In that case, it needs to be called manually.
+llvm-r1_pkg_setup() {
+ debug-print-function ${FUNCNAME} "${@}"
+
+ if [[ ${MERGE_TYPE} != binary ]]; then
+ [[ -z ${LLVM_SLOT} ]] && die "LLVM_SLOT unset (broken USE_EXPAND?)"
+
+ llvm_fix_clang_version CC CPP CXX
+ # keep in sync with profiles/features/llvm/make.defaults!
+ llvm_fix_tool_path ADDR2LINE AR AS LD NM OBJCOPY OBJDUMP RANLIB
+ llvm_fix_tool_path READELF STRINGS STRIP
+
+ # Set LLVM_CONFIG to help Meson (bug #907965) but only do it
+ # for empty ESYSROOT (as a proxy for "are we cross-compiling?").
+ if [[ -z ${ESYSROOT} ]] ; then
+ llvm_fix_tool_path LLVM_CONFIG
+ fi
+
+ llvm_prepend_path "${LLVM_SLOT}"
+ fi
+}
+
+fi
+
+if [[ ! ${LLVM_OPTIONAL} ]]; then
+ EXPORT_FUNCTIONS pkg_setup
+fi
diff --git a/eclass/llvm-utils.eclass b/eclass/llvm-utils.eclass
new file mode 100644
index 000000000000..532e609679b8
--- /dev/null
+++ b/eclass/llvm-utils.eclass
@@ -0,0 +1,153 @@
+# Copyright 2024 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+# @ECLASS: llvm-utils.eclass
+# @MAINTAINER:
+# Michał Górny <mgorny@gentoo.org>
+# @AUTHOR:
+# Michał Górny <mgorny@gentoo.org>
+# @SUPPORTED_EAPIS: 7 8
+# @BLURB: Common utility functions for building against installed LLVM
+# @DESCRIPTION:
+# The utility eclass providing shared functions reused between
+# llvm.eclass and llvm-r1.eclass. It may also be used directly
+# in ebuilds.
+
+case ${EAPI} in
+ 7|8) ;;
+ *) die "${ECLASS}: EAPI ${EAPI:-0} not supported" ;;
+esac
+
+if [[ ! ${_LLVM_UTILS_ECLASS} ]]; then
+_LLVM_UTILS_ECLASS=1
+
+# @FUNCTION: llvm_tuple_to_target
+# @USAGE: [<tuple>]
+# @DESCRIPTION:
+# Translate a tuple into a target suitable for LLVM_TARGETS.
+# Defaults to ${CHOST} if not specified.
+llvm_tuple_to_target() {
+ debug-print-function ${FUNCNAME} "${@}"
+
+ [[ ${#} -gt 1 ]] && die "Usage: ${FUNCNAME} [<tuple>]"
+
+ case ${1:-${CHOST}} in
+ aarch64*) echo "AArch64";;
+ amdgcn*) echo "AMDGPU";;
+ arc*) echo "ARC";;
+ arm*) echo "ARM";;
+ avr*) echo "AVR";;
+ bpf*) echo "BPF";;
+ csky*) echo "CSKY";;
+ loong*) echo "LoongArch";;
+ m68k*) echo "M68k";;
+ mips*) echo "Mips";;
+ msp430*) echo "MSP430";;
+ nvptx*) echo "NVPTX";;
+ powerpc*) echo "PowerPC";;
+ riscv*) echo "RISCV";;
+ sparc*) echo "Sparc";;
+ s390*) echo "SystemZ";;
+ x86_64*|i?86*) echo "X86";;
+ xtensa*) echo "Xtensa";;
+ *) die "Unknown LLVM target for tuple ${1:-${CHOST}}"
+ esac
+}
+
+# @FUNCTION: llvm_fix_clang_version
+# @USAGE: <variable-name>...
+# @DESCRIPTION:
+# Fix the clang compiler name in specified variables to include
+# the major version, to prevent PATH alterations from forcing an older
+# clang version being used.
+llvm_fix_clang_version() {
+ debug-print-function ${FUNCNAME} "${@}"
+
+ local shopt_save=$(shopt -p -o noglob)
+ set -f
+ local var
+ for var; do
+ local split=( ${!var} )
+ case ${split[0]} in
+ *clang|*clang++|*clang-cpp)
+ local version=()
+ read -r -a version < <("${split[0]}" --version)
+ local major=${version[-1]%%.*}
+ if [[ -n ${major//[0-9]} ]]; then
+ die "${var}=${!var} produced invalid --version: ${version[*]}"
+ fi
+
+ split[0]+=-${major}
+ if ! type -P "${split[0]}" &>/dev/null; then
+ die "${split[0]} does not seem to exist"
+ fi
+ declare -g "${var}=${split[*]}"
+ ;;
+ esac
+ done
+ ${shopt_save}
+}
+
+# @FUNCTION: llvm_fix_tool_path
+# @USAGE: <variable-name>...
+# @DESCRIPTION:
+# Fix the LLVM tools referenced in the specified variables to their
+# current location, to prevent PATH alterations from forcing older
+# versions being used.
+llvm_fix_tool_path() {
+ debug-print-function ${FUNCNAME} "${@}"
+
+ local shopt_save=$(shopt -p -o noglob)
+ set -f
+ local var
+ for var; do
+ local split=( ${!var} )
+ local path=$(type -P ${split[0]} 2>/dev/null)
+ # if it resides in one of the LLVM prefixes, it's an LLVM tool!
+ if [[ ${path} == "${BROOT}/usr/lib/llvm"* ]]; then
+ split[0]=${path}
+ declare -g "${var}=${split[*]}"
+ fi
+ done
+ ${shopt_save}
+}
+
+# @FUNCTION: llvm_prepend_path
+# @USAGE: <slot>
+# @DESCRIPTION:
+# Prepend the path to the specified LLVM slot to PATH variable,
+# and reexport it.
+llvm_prepend_path() {
+ debug-print-function ${FUNCNAME} "${@}"
+
+ [[ ${#} -ne 1 ]] && die "Usage: ${FUNCNAME} <slot>"
+ local slot=${1}
+
+ local llvm_path=${ESYSROOT}/usr/lib/llvm/${slot}/bin
+ local IFS=:
+ local split_path=( ${PATH} )
+ local new_path=()
+ local x added=
+
+ for x in "${split_path[@]}"; do
+ if [[ ${x} == */usr/lib/llvm/*/bin ]]; then
+ # prepend new path in front of the first LLVM version found
+ if [[ ! ${added} ]]; then
+ new_path+=( "${llvm_path}" )
+ added=1
+ fi
+ # remove duplicate copies of the same path
+ if [[ ${x} == ${llvm_path} ]]; then
+ # deduplicate
+ continue
+ fi
+ fi
+ new_path+=( "${x}" )
+ done
+ # ...or to the end of PATH
+ [[ ${added} ]] || new_path+=( "${llvm_path}" )
+
+ export PATH=${new_path[*]}
+}
+
+fi
diff --git a/eclass/llvm.eclass b/eclass/llvm.eclass
index 91cc68d966fe..e297fe992c9f 100644
--- a/eclass/llvm.eclass
+++ b/eclass/llvm.eclass
@@ -7,6 +7,7 @@
# @AUTHOR:
# Michał Górny <mgorny@gentoo.org>
# @SUPPORTED_EAPIS: 7 8
+# @PROVIDES: llvm-utils
# @BLURB: Utility functions to build against slotted LLVM
# @DESCRIPTION:
# The llvm.eclass provides utility functions that can be used to build
@@ -64,6 +65,8 @@ esac
if [[ ! ${_LLVM_ECLASS} ]]; then
_LLVM_ECLASS=1
+inherit llvm-utils
+
# make sure that the versions installing straight into /usr/bin
# are uninstalled
DEPEND="!!sys-devel/llvm:0"
@@ -174,95 +177,6 @@ get_llvm_prefix() {
echo "${prefix}/usr/lib/llvm/$(get_llvm_slot "${@}")"
}
-# @FUNCTION: llvm_tuple_to_target
-# @USAGE: [<tuple>]
-# @DESCRIPTION:
-# Translate a tuple into a target suitable for LLVM_TARGETS.
-# Defaults to ${CHOST} if not specified.
-llvm_tuple_to_target() {
- debug-print-function ${FUNCNAME} "${@}"
-
- case ${1:-${CHOST}} in
- aarch64*) echo "AArch64";;
- amdgcn*) echo "AMDGPU";;
- arc*) echo "ARC";;
- arm*) echo "ARM";;
- avr*) echo "AVR";;
- bpf*) echo "BPF";;
- csky*) echo "CSKY";;
- loong*) echo "LoongArch";;
- m68k*) echo "M68k";;
- mips*) echo "Mips";;
- msp430*) echo "MSP430";;
- nvptx*) echo "NVPTX";;
- powerpc*) echo "PowerPC";;
- riscv*) echo "RISCV";;
- sparc*) echo "Sparc";;
- s390*) echo "SystemZ";;
- x86_64*|i?86*) echo "X86";;
- xtensa*) echo "Xtensa";;
- *) die "Unknown LLVM target for tuple ${1:-${CHOST}}"
- esac
-}
-
-# @FUNCTION: llvm_fix_clang_version
-# @USAGE: <variable-name>...
-# @DESCRIPTION:
-# Fix the clang compiler name in specified variables to include
-# the major version, to prevent PATH alterations from forcing an older
-# clang version being used.
-llvm_fix_clang_version() {
- debug-print-function ${FUNCNAME} "${@}"
-
- local shopt_save=$(shopt -p -o noglob)
- set -f
- local var
- for var; do
- local split=( ${!var} )
- case ${split[0]} in
- *clang|*clang++|*clang-cpp)
- local version=()
- read -r -a version < <("${split[0]}" --version)
- local major=${version[-1]%%.*}
- if [[ -n ${major//[0-9]} ]]; then
- die "${var}=${!var} produced invalid --version: ${version[*]}"
- fi
-
- split[0]+=-${major}
- if ! type -P "${split[0]}" &>/dev/null; then
- die "${split[0]} does not seem to exist"
- fi
- declare -g "${var}=${split[*]}"
- ;;
- esac
- done
- ${shopt_save}
-}
-
-# @FUNCTION: llvm_fix_tool_path
-# @USAGE: <variable-name>...
-# @DESCRIPTION:
-# Fix the LLVM tools referenced in the specified variables to their
-# current location, to prevent PATH alterations from forcing older
-# versions being used.
-llvm_fix_tool_path() {
- debug-print-function ${FUNCNAME} "${@}"
-
- local shopt_save=$(shopt -p -o noglob)
- set -f
- local var
- for var; do
- local split=( ${!var} )
- local path=$(type -P ${split[0]} 2>/dev/null)
- # if it resides in one of the LLVM prefixes, it's an LLVM tool!
- if [[ ${path} == "${BROOT}/usr/lib/llvm"* ]]; then
- split[0]=${path}
- declare -g "${var}=${split[*]}"
- fi
- done
- ${shopt_save}
-}
-
# @FUNCTION: llvm_pkg_setup
# @DESCRIPTION:
# Prepend the appropriate executable directory for the newest
@@ -298,30 +212,7 @@ llvm_pkg_setup() {
llvm_fix_tool_path LLVM_CONFIG
fi
- local prefix=${ESYSROOT}
- local llvm_path=${prefix}/usr/lib/llvm/${LLVM_SLOT}/bin
- local IFS=:
- local split_path=( ${PATH} )
- local new_path=()
- local x added=
-
- # prepend new path before first LLVM version found
- for x in "${split_path[@]}"; do
- if [[ ${x} == */usr/lib/llvm/*/bin ]]; then
- if [[ ${x} != ${llvm_path} ]]; then
- new_path+=( "${llvm_path}" )
- elif [[ ${added} && ${x} == ${llvm_path} ]]; then
- # deduplicate
- continue
- fi
- added=1
- fi
- new_path+=( "${x}" )
- done
- # ...or to the end of PATH
- [[ ${added} ]] || new_path+=( "${llvm_path}" )
-
- export PATH=${new_path[*]}
+ llvm_prepend_path "${LLVM_SLOT}"
fi
}
diff --git a/eclass/nuget.eclass b/eclass/nuget.eclass
index 669e21300ef2..ac8629848eca 100644
--- a/eclass/nuget.eclass
+++ b/eclass/nuget.eclass
@@ -1,4 +1,4 @@
-# Copyright 1999-2023 Gentoo Authors
+# Copyright 1999-2024 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2
# @ECLASS: nuget.eclass
@@ -226,6 +226,51 @@ nuget_unpack-non-nuget-archives() {
done
}
+# @FUNCTION: nuget_writeconfig
+# @USAGE: <path>
+# @DESCRIPTION:
+# Create a "NuGet.config" config file that can be used to overwrite any other
+# Nuget configuration file in order to prevent Nuget executable from accessing
+# the network or undesired NuPkg package sources.
+#
+# If given path ends with a slash, a file name "NuGet.config" is assumed,
+# otherwise contents are written to specified file path exactly.
+#
+# Created configuration file clears all other NuPkg sources and inserts
+# "NUGET_PACKAGES" as the only one source.
+#
+# This function is used inside "dotnet-pkg_src_prepare"
+# from the "dotnet-pkg" eclass.
+#
+# This function is used inside "dotnet-pkg_src_prepare"
+# from the "dotnet-pkg" eclass.
+nuget_writeconfig() {
+ debug-print-function "${FUNCNAME[0]}" "${@}"
+
+ case "${1}" in
+ "" ) die "${FUNCNAME[0]}: no directory/file path specified" ;;
+ */ ) mkdir -p "${1}" || die ;;
+ esac
+
+ local nuget_config_path
+
+ if [[ -d "${1}" ]] ; then
+ nuget_config_path="${1}/NuGet.config"
+ else
+ nuget_config_path="${1}"
+ fi
+
+ cat <<-EOF > "${nuget_config_path}" || die
+ <?xml version="1.0" encoding="utf-8"?>
+ <configuration>
+ <packageSources>
+ <clear />
+ <add key="nuget" value="${NUGET_PACKAGES}" />
+ </packageSources>
+ </configuration>
+ EOF
+}
+
# @FUNCTION: nuget_donuget
# @USAGE: <nuget-path> ...
# @DESCRIPTION:
diff --git a/eclass/tests/llvm-r1.sh b/eclass/tests/llvm-r1.sh
new file mode 100755
index 000000000000..9958f5bba420
--- /dev/null
+++ b/eclass/tests/llvm-r1.sh
@@ -0,0 +1,151 @@
+#!/bin/bash
+# Copyright 2024 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+source tests-common.sh || exit
+
+EAPI=8
+
+test_globals() {
+ local compat=${1}
+ local expected_iuse=${2}
+ local expected_required_use=${3}
+ local expected_usedep=${4}
+ local x
+
+ tbegin "LLVM_COMPAT=( ${compat} )"
+
+ (
+ local fail=0
+ local LLVM_COMPAT=( ${compat} )
+
+ inherit llvm-r1
+
+ if [[ ${IUSE%% } != ${expected_iuse} ]]; then
+ eerror " IUSE: ${IUSE%% }"
+ eerror "does not match: ${expected_iuse}"
+ fail=1
+ fi
+
+ if [[ ${REQUIRED_USE} != ${expected_required_use} ]]; then
+ eerror " REQUIRED_USE: ${REQUIRED_USE}"
+ eerror "does not match: ${expected_required_use}"
+ fail=1
+ fi
+
+ if [[ ${LLVM_USEDEP} != ${expected_usedep} ]]; then
+ eerror " LLVM_USEDEP: ${LLVM_USEDEP}"
+ eerror "does not match: ${expected_usedep}"
+ fail=1
+ fi
+
+ exit "${fail}"
+ )
+
+ tend "${?}"
+}
+
+test_gen_dep() {
+ local arg=${1}
+ local expected
+ read -r -d '' expected
+
+ tbegin "llvm_gen_dep ${arg}"
+ local value=$(llvm_gen_dep "${arg}")
+
+ if [[ ${value} != ${expected} ]]; then
+ eerror "python_get_usedep ${arg}"
+ eerror "gave:"
+ eerror " ${value}"
+ eerror "expected:"
+ eerror " ${expected}"
+ fi
+ tend ${?}
+}
+
+test_fix_clang_version() {
+ local var=${1}
+ local tool=${2}
+ local version=${3}
+ local expected=${4}
+
+ eval "${tool}() {
+ cat <<-EOF
+ clang version ${version}
+ Target: x86_64-pc-linux-gnu
+ Thread model: posix
+ InstalledDir: /usr/lib/llvm/17/bin
+ Configuration file: /etc/clang/x86_64-pc-linux-gnu-clang.cfg
+ EOF
+ }"
+
+ declare -g ${var}=${tool}
+ tbegin "llvm_fix_clang_version ${var}=${tool} for ${version}"
+ llvm_fix_clang_version "${var}"
+ if [[ ${!var} != ${expected} ]]; then
+ eerror "llvm_fix_clang_version ${var}"
+ eerror " gave: ${!var}"
+ eerror "expected: ${expected}"
+ fi
+ tend ${?}
+}
+
+test_fix_tool_path() {
+ local var=${1}
+ local tool=${2}
+ local expected_subst=${3}
+ local expected=${tool}
+
+ tbegin "llvm_fix_tool_path ${1}=${2} (from llvm? ${expected_subst})"
+
+ local matches=( "${BROOT}"/usr/lib/llvm/*/bin/"${tool}" )
+ if [[ ${expected_subst} == 1 ]]; then
+ if [[ ! -x ${matches[0]} ]]; then
+ ewarn "- skipping, test requires ${tool}"
+ return
+ fi
+
+ expected=${matches[0]}
+ local -x PATH=${matches[0]%/*}
+ else
+ local -x PATH=
+ fi
+
+ declare -g ${var}=${tool}
+ llvm_fix_tool_path "${var}"
+ if [[ ${!var} != ${expected} ]]; then
+ eerror "llvm_fix_tool_path ${var}"
+ eerror " gave: ${!var}"
+ eerror "expected: ${expected}"
+ fi
+ tend ${?}
+}
+
+test_globals '14 15 16 17 18' \
+ "+llvm_slot_17 llvm_slot_15 llvm_slot_16 llvm_slot_18" \
+ "^^ ( llvm_slot_15 llvm_slot_16 llvm_slot_17 llvm_slot_18 )" \
+ "llvm_slot_15(-)?,llvm_slot_16(-)?,llvm_slot_17(-)?,llvm_slot_18(-)?"
+test_globals '14 15 16' \
+ "+llvm_slot_16 llvm_slot_15" \
+ "^^ ( llvm_slot_15 llvm_slot_16 )" \
+ "llvm_slot_15(-)?,llvm_slot_16(-)?"
+test_globals '15 18' \
+ "+llvm_slot_15 llvm_slot_18" \
+ "^^ ( llvm_slot_15 llvm_slot_18 )" \
+ "llvm_slot_15(-)?,llvm_slot_18(-)?"
+test_globals '18' \
+ "+llvm_slot_18" \
+ "^^ ( llvm_slot_18 )" \
+ "llvm_slot_18(-)?"
+
+LLVM_COMPAT=( {14..18} )
+inherit llvm-r1
+
+test_gen_dep 'sys-devel/llvm:${LLVM_SLOT} sys-devel/clang:${LLVM_SLOT}' <<-EOF
+ llvm_slot_15? ( sys-devel/llvm:15 sys-devel/clang:15 )
+ llvm_slot_16? ( sys-devel/llvm:16 sys-devel/clang:16 )
+ llvm_slot_17? ( sys-devel/llvm:17 sys-devel/clang:17 )
+ llvm_slot_18? ( sys-devel/llvm:18 sys-devel/clang:18 )
+EOF
+
+texit
diff --git a/eclass/tests/llvm-utils.sh b/eclass/tests/llvm-utils.sh
new file mode 100755
index 000000000000..6fe3da3eda13
--- /dev/null
+++ b/eclass/tests/llvm-utils.sh
@@ -0,0 +1,118 @@
+#!/bin/bash
+# Copyright 2024 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+source tests-common.sh || exit
+
+EAPI=8
+
+inherit llvm-utils
+
+test_fix_clang_version() {
+ local var=${1}
+ local tool=${2}
+ local version=${3}
+ local expected=${4}
+
+ eval "${tool}() {
+ cat <<-EOF
+ clang version ${version}
+ Target: x86_64-pc-linux-gnu
+ Thread model: posix
+ InstalledDir: /usr/lib/llvm/17/bin
+ Configuration file: /etc/clang/x86_64-pc-linux-gnu-clang.cfg
+ EOF
+ }"
+
+ declare -g ${var}=${tool}
+ tbegin "llvm_fix_clang_version ${var}=${tool} for ${version}"
+ llvm_fix_clang_version "${var}"
+ if [[ ${!var} != ${expected} ]]; then
+ eerror "llvm_fix_clang_version ${var}"
+ eerror " gave: ${!var}"
+ eerror "expected: ${expected}"
+ fi
+ tend ${?}
+}
+
+test_fix_tool_path() {
+ local var=${1}
+ local tool=${2}
+ local expected_subst=${3}
+ local expected=${tool}
+
+ tbegin "llvm_fix_tool_path ${1}=${2} (from llvm? ${expected_subst})"
+
+ local matches=( "${BROOT}"/usr/lib/llvm/*/bin/"${tool}" )
+ if [[ ${expected_subst} == 1 ]]; then
+ if [[ ! -x ${matches[0]} ]]; then
+ ewarn "- skipping, test requires ${tool}"
+ return
+ fi
+
+ expected=${matches[0]}
+ local -x PATH=${matches[0]%/*}
+ else
+ local -x PATH=
+ fi
+
+ declare -g ${var}=${tool}
+ llvm_fix_tool_path "${var}"
+ if [[ ${!var} != ${expected} ]]; then
+ eerror "llvm_fix_tool_path ${var}"
+ eerror " gave: ${!var}"
+ eerror "expected: ${expected}"
+ fi
+ tend ${?}
+}
+
+test_prepend_path() {
+ local slot=${1}
+ local -x PATH=${2}
+ local expected=${3}
+
+ tbegin "llvm_prepend_path ${slot} to PATH=${PATH}"
+ llvm_prepend_path "${slot}"
+ if [[ ${PATH} != ${expected} ]]; then
+ eerror "llvm_prepend_path ${var}"
+ eerror " gave: ${PATH}"
+ eerror "expected: ${expected}"
+ fi
+ tend ${?}
+}
+
+test_fix_clang_version CC clang 19.0.0git78b4e7c5 clang-19
+test_fix_clang_version CC clang 17.0.6 clang-17
+test_fix_clang_version CXX clang++ 17.0.6 clang++-17
+test_fix_clang_version CC x86_64-pc-linux-gnu-clang 17.0.6 \
+ x86_64-pc-linux-gnu-clang-17
+test_fix_clang_version CC clang-17 n/a clang-17
+test_fix_clang_version CC gcc n/a gcc
+
+test_fix_tool_path AR llvm-ar 1
+test_fix_tool_path RANLIB llvm-ranlib 1
+test_fix_tool_path AR ar 1
+test_fix_tool_path AR ar 0
+
+ESYSROOT=
+test_prepend_path 17 /usr/bin /usr/bin:/usr/lib/llvm/17/bin
+test_prepend_path 17 /usr/lib/llvm/17/bin:/usr/bin /usr/lib/llvm/17/bin:/usr/bin
+test_prepend_path 17 /usr/bin:/usr/lib/llvm/17/bin /usr/bin:/usr/lib/llvm/17/bin
+test_prepend_path 17 /usr/lib/llvm/17/bin:/usr/bin:/usr/lib/llvm/17/bin \
+ /usr/lib/llvm/17/bin:/usr/bin
+test_prepend_path 17 /usr/lib/llvm/17/bin:/usr/lib/llvm/17/bin:/usr/bin \
+ /usr/lib/llvm/17/bin:/usr/bin
+test_prepend_path 17 /usr/bin:/usr/lib/llvm/17/bin:/usr/lib/llvm/17/bin \
+ /usr/bin:/usr/lib/llvm/17/bin
+test_prepend_path 18 /usr/lib/llvm/17/bin:/usr/bin \
+ /usr/lib/llvm/18/bin:/usr/lib/llvm/17/bin:/usr/bin
+test_prepend_path 18 /usr/bin:/usr/lib/llvm/17/bin \
+ /usr/bin:/usr/lib/llvm/18/bin:/usr/lib/llvm/17/bin
+test_prepend_path 18 /usr/lib/llvm/17/bin:/usr/lib/llvm/16/bin:/usr/bin \
+ /usr/lib/llvm/18/bin:/usr/lib/llvm/17/bin:/usr/lib/llvm/16/bin:/usr/bin
+test_prepend_path 18 /usr/bin:/usr/lib/llvm/17/bin:/usr/lib/llvm/16/bin \
+ /usr/bin:/usr/lib/llvm/18/bin:/usr/lib/llvm/17/bin:/usr/lib/llvm/16/bin
+test_prepend_path 18 /usr/lib/llvm/17/bin:/usr/bin:/usr/lib/llvm/16/bin \
+ /usr/lib/llvm/18/bin:/usr/lib/llvm/17/bin:/usr/bin:/usr/lib/llvm/16/bin
+
+texit