public inbox for gentoo-dev@lists.gentoo.org
 help / color / mirror / Atom feed
From: "Michał Górny" <mgorny@gentoo.org>
To: gentoo-dev@lists.gentoo.org
Cc: "Michał Górny" <mgorny@gentoo.org>
Subject: [gentoo-dev] [PATCH v2] llvm-r1.eclass: Initial version
Date: Thu,  8 Feb 2024 20:07:11 +0100	[thread overview]
Message-ID: <20240208190731.157614-1-mgorny@gentoo.org> (raw)
In-Reply-To: <20240207203515.17640-6-mgorny@gentoo.org>

See-Also: https://bugs.gentoo.org/923228
See-Also: https://bugs.gentoo.org/880671
Closes: https://bugs.gentoo.org/821955
Closes: https://bugs.gentoo.org/919150
Signed-off-by: Michał Górny <mgorny@gentoo.org>
---
 eclass/llvm-r1.eclass   | 225 ++++++++++++++++++++++++++++++++++++++++
 eclass/tests/llvm-r1.sh | 151 +++++++++++++++++++++++++++
 2 files changed, 376 insertions(+)
 create mode 100644 eclass/llvm-r1.eclass
 create mode 100755 eclass/tests/llvm-r1.sh

Changes in v2: docstring fixes.

diff --git a/eclass/llvm-r1.eclass b/eclass/llvm-r1.eclass
new file mode 100644
index 000000000000..1b520f05e981
--- /dev/null
+++ b/eclass/llvm-r1.eclass
@@ -0,0 +1,225 @@
+# 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
+
+# == global metadata ==
+
+# @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_}" )
+	REQUIRED_USE="^^ ( ${flags[*]} )"
+	local usedep_flags=${flags[*]/%/(-)?}
+	LLVM_USEDEP=${usedep_flags// /,}
+	readonly LLVM_USEDEP
+}
+_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.
+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
+
+EXPORT_FUNCTIONS pkg_setup
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
-- 
2.43.0



  reply	other threads:[~2024-02-08 19:07 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-02-07 20:11 [gentoo-dev] [PATCH 0/8] llvm-r1.eclass + llvm-utils.eclass: new eclasses to sort out LLVM mess Michał Górny
2024-02-07 20:11 ` [gentoo-dev] [PATCH 1/8] llvm-utils.eclass: Introduce an eclass for common helpers Michał Górny
2024-02-07 20:11 ` [gentoo-dev] [PATCH 2/8] llvm-utils.eclass: Split out PATH prepending logic Michał Górny
2024-02-07 20:11 ` [gentoo-dev] [PATCH 3/8] llvm-utils.eclass: Fix llvm_prepend_path to avoid duplicates Michał Górny
2024-02-08 19:06   ` [gentoo-dev] [PATCH] " Michał Górny
2024-02-07 20:11 ` [gentoo-dev] [PATCH 4/8] profiles: Introduce LLVM_SLOT USE_EXPAND variable Michał Górny
2024-02-07 20:11 ` [gentoo-dev] [PATCH 5/8] llvm-r1.eclass: Initial version Michał Górny
2024-02-08 19:07   ` Michał Górny [this message]
2024-02-09 16:59   ` [gentoo-dev] [PATCH v3] " Michał Górny
2024-02-09 23:49     ` Sam James
2024-02-07 20:11 ` [gentoo-dev] [PATCH 6/8] dev-util/intel_clc: Migrate to llvm-r1 Michał Górny
2024-02-08  7:00   ` Sam James
2024-02-08 12:35     ` Arsen Arsenović
2024-02-07 20:11 ` [gentoo-dev] [PATCH 7/8] media-libs/mesa: " Michał Górny
2024-02-07 20:11 ` [gentoo-dev] [PATCH 8/8] sys-devel/lld: Migrate to llvm-utils.eclass Michał Górny

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240208190731.157614-1-mgorny@gentoo.org \
    --to=mgorny@gentoo.org \
    --cc=gentoo-dev@lists.gentoo.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox