summaryrefslogtreecommitdiff
blob: 075df9218be8bd93d781604f695562a0aca1d640 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
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