From 6c869809927d3b3d35be224dd8dfe5c8aba490ee Mon Sep 17 00:00:00 2001 From: Marek Szuba Date: Wed, 30 Sep 2020 18:03:54 +0200 Subject: lua-single.eclass: new eclass for single-implementation Lua ebuilds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With many thanks to Michał Górny and other authors of python-single-r1.eclass. Signed-off-by: Marek Szuba --- eclass/lua-single.eclass | 510 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 510 insertions(+) create mode 100644 eclass/lua-single.eclass (limited to 'eclass/lua-single.eclass') diff --git a/eclass/lua-single.eclass b/eclass/lua-single.eclass new file mode 100644 index 000000000000..2233fdd33b6e --- /dev/null +++ b/eclass/lua-single.eclass @@ -0,0 +1,510 @@ +# Copyright 1999-2020 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +# @ECLASS: lua-single.eclass +# @MAINTAINER: +# William Hubbs +# Marek Szuba +# @AUTHOR: +# Marek Szuba +# Based on python-single-r1.eclass by Michał Górny et al. +# @SUPPORTED_EAPIS: 7 +# @BLURB: An eclass for Lua packages not installed for multiple implementations. +# @DESCRIPTION: +# An extension of lua.eclass suite for packages which don't support being +# installed for multiple Lua implementations. This mostly includes software +# embedding Lua. +# +# This eclass sets correct IUSE. It also provides LUA_DEPS +# and LUA_REQUIRED_USE that need to be added to appropriate ebuild +# metadata variables. +# +# The eclass exports LUA_SINGLE_USEDEP that is suitable for depending +# on other packages using the eclass. Dependencies on packages using +# lua.eclass should be created via lua_gen_cond_dep() function, using +# LUA_USEDEP placeholder. +# +# Please note that packages support multiple Lua implementations +# (using lua.eclass) cannot depend on packages not supporting +# them (using this eclass). +# +# Note that since this eclass always inherits lua-utils as well, in ebuilds +# using the former there is no need to explicitly inherit the latter in order +# to use helper functions such as lua_get_CFLAGS. + +case ${EAPI:-0} in + 0|1|2|3|4|5|6) + die "Unsupported EAPI=${EAPI} (too old) for ${ECLASS}" + ;; + 7) + ;; + *) + die "Unsupported EAPI=${EAPI} (unknown) for ${ECLASS}" + ;; +esac + +if [[ ! ${_LUA_SINGLE_R0} ]]; then + +if [[ ${_LUA_R0} ]]; then + die 'lua-single.eclass cannot be used with lua.eclass.' +fi + +inherit lua-utils + +fi + +EXPORT_FUNCTIONS pkg_setup + +# @ECLASS-VARIABLE: LUA_COMPAT +# @REQUIRED +# @PRE_INHERIT +# @DESCRIPTION: +# This variable contains a list of Lua implementations the package +# supports. It must be set before the `inherit' call. It has to be +# an array. +# +# Example: +# @CODE +# LUA_COMPAT=( lua5-1 lua5-2 lua5-3 ) +# @CODE +# +# Please note that you can also use bash brace expansion if you like: +# @CODE +# LUA_COMPAT=( lua5-{1..3} ) +# @CODE + +# @ECLASS-VARIABLE: LUA_COMPAT_OVERRIDE +# @USER_VARIABLE +# @DEFAULT_UNSET +# @DESCRIPTION: +# This variable can be used when working with ebuilds to override +# the in-ebuild LUA_COMPAT. It is a string listing all +# the implementations which package will be built for. It need be +# specified in the calling environment, and not in ebuilds. +# +# It should be noted that in order to preserve metadata immutability, +# LUA_COMPAT_OVERRIDE does not affect IUSE nor dependencies. +# The state of LUA_TARGETS is ignored, and all the implementations +# in LUA_COMPAT_OVERRIDE are built. Dependencies need to be satisfied +# manually. +# +# Example: +# @CODE +# LUA_COMPAT_OVERRIDE='lua5-2' emerge -1v dev-lua/foo +# @CODE + +# @ECLASS-VARIABLE: LUA_REQ_USE +# @DEFAULT_UNSET +# @PRE_INHERIT +# @DESCRIPTION: +# The list of USE flags required to be enabled on the chosen Lua +# implementations, formed as a USE-dependency string. It should be valid +# for all implementations in LUA_COMPAT, so it may be necessary to +# use USE defaults. +# This must be set before calling `inherit'. +# +# Example: +# @CODE +# LUA_REQ_USE="deprecated" +# @CODE +# +# It will cause the Lua dependencies to look like: +# @CODE +# lua_targets_luaX-Y? ( dev-lang/lua:X.Y[deprecated] ) +# @CODE + +# @ECLASS-VARIABLE: LUA_DEPS +# @OUTPUT_VARIABLE +# @DESCRIPTION: +# This is an eclass-generated Lua dependency string for all +# implementations listed in LUA_COMPAT. +# +# Example use: +# @CODE +# RDEPEND="${LUA_DEPS} +# dev-foo/mydep" +# DEPEND="${RDEPEND}" +# @CODE +# +# Example value: +# @CODE +# lua_targets_lua5-1? ( dev-lang/lua:5.1 ) +# lua_targets_lua5-2? ( dev-lang/lua:5.2 ) +# @CODE + +# @ECLASS-VARIABLE: LUA_REQUIRED_USE +# @OUTPUT_VARIABLE +# @DESCRIPTION: +# This is an eclass-generated required-use expression which ensures at +# least one Lua implementation has been enabled. +# +# This expression should be utilized in an ebuild by including it in +# REQUIRED_USE, optionally behind a use flag. +# +# Example use: +# @CODE +# REQUIRED_USE="lua? ( ${LUA_REQUIRED_USE} )" +# @CODE +# +# Example value: +# @CODE +# || ( lua_targets_lua5-1 lua_targets_lua5-2 ) +# @CODE + +# @ECLASS-VARIABLE: LUA_SINGLE_USEDEP +# @OUTPUT_VARIABLE +# @DESCRIPTION: +# This is an eclass-generated USE-dependency string which can be used +# to depend on another lua-single package being built for the same +# Lua implementations. +# +# If you need to depend on a multi-impl (lua.eclass) package, use +# lua_gen_cond_dep with LUA_USEDEP placeholder instead. +# +# Example use: +# @CODE +# RDEPEND="dev-lua/foo[${LUA_SINGLE_USEDEP}]" +# @CODE +# +# Example value: +# @CODE +# lua_single_target_lua5-1(-)? +# @CODE + +# @ECLASS-VARIABLE: LUA_USEDEP +# @OUTPUT_VARIABLE +# @DESCRIPTION: +# This is an eclass-generated USE-dependency string which can be used to +# depend on another Lua package being built for the same Lua +# implementations. +# +# Example use: +# @CODE +# RDEPEND="dev-lua/foo[${LUA_USEDEP}]" +# @CODE +# +# Example value: +# @CODE +# lua_targets_lua5-1(-)?,lua_targets_lua5-2(-)? +# @CODE + +# @FUNCTION: _lua_single_set_globals +# @INTERNAL +# @DESCRIPTION: +# Sets all the global output variables provided by this eclass. +# This function must be called once, in global scope. +_lua_single_set_globals() { + _lua_set_impls + + local flags=( "${_LUA_SUPPORTED_IMPLS[@]/#/lua_single_target_}" ) + + if [[ ${#_LUA_SUPPORTED_IMPLS[@]} -eq 1 ]]; then + # if only one implementation is supported, use IUSE defaults + # to avoid requesting the user to enable it + IUSE="+${flags[0]}" + else + IUSE="${flags[*]}" + fi + + local requse="^^ ( ${flags[*]} )" + local single_flags="${flags[@]/%/(-)?}" + local single_usedep=${single_flags// /,} + + local deps= i PYTHON_PKG_DEP + for i in "${_LUA_SUPPORTED_IMPLS[@]}"; do + _lua_export "${i}" LUA_PKG_DEP + deps+="lua_single_target_${i}? ( ${LUA_PKG_DEP} ) " + done + + if [[ ${LUA_DEPS+1} ]]; then + if [[ ${LUA_DEPS} != "${deps}" ]]; then + eerror "LUA_DEPS have changed between inherits (LUA_REQ_USE?)!" + eerror "Before: ${LUA_DEPS}" + eerror "Now : ${deps}" + die "LUA_DEPS integrity check failed" + fi + + # these two are formality -- they depend on LUA_COMPAT only + if [[ ${LUA_REQUIRED_USE} != ${requse} ]]; then + eerror "LUA_REQUIRED_USE have changed between inherits!" + eerror "Before: ${LUA_REQUIRED_USE}" + eerror "Now : ${requse}" + die "LUA_REQUIRED_USE integrity check failed" + fi + + if [[ ${LUA_SINGLE_USEDEP} != "${single_usedep}" ]]; then + eerror "LUA_SINGLE_USEDEP have changed between inherits!" + eerror "Before: ${LUA_SINGLE_USEDEP}" + eerror "Now : ${single_usedep}" + die "LUA_SINGLE_USEDEP integrity check failed" + fi + else + LUA_DEPS=${deps} + LUA_REQUIRED_USE=${requse} + LUA_SINGLE_USEDEP=${single_usedep} + LUA_USEDEP='%LUA_USEDEP-NEEDS-TO-BE-USED-IN-LUA_GEN_COND_DEP%' + readonly LUA_DEPS LUA_REQUIRED_USE LUA_SINGLE_USEDEP LUA_USEDEP + fi +} + +_lua_single_set_globals +unset -f _lua_single_set_globals + +if [[ ! ${_LUA_SINGLE_R0} ]]; then + +# @FUNCTION: _lua_gen_usedep +# @USAGE: [...] +# @INTERNAL +# @DESCRIPTION: +# Output a USE dependency string for Lua implementations which +# are both in LUA_COMPAT and match any of the patterns passed +# as parameters to the function. +# +# The patterns can be fnmatch-style patterns (matched via bash == operator +# against LUA_COMPAT values). Remember to escape or quote the fnmatch +# patterns to prevent accidental shell filename expansion. +# +# This is an internal function used to implement lua_gen_cond_dep. +_lua_gen_usedep() { + debug-print-function ${FUNCNAME} "${@}" + + local impl matches=() + + _lua_verify_patterns "${@}" + for impl in "${_LUA_SUPPORTED_IMPLS[@]}"; do + if _lua_impl_matches "${impl}" "${@}"; then + matches+=( + "lua_single_target_${impl}(-)?" + ) + fi + done + + [[ ${matches[@]} ]] || die "No supported implementations match lua_gen_usedep patterns: ${@}" + + local out=${matches[@]} + echo "${out// /,}" +} + +# @FUNCTION: _lua_impl_matches +# @USAGE: [...] +# @INTERNAL +# @DESCRIPTION: +# Check whether the specified matches at least one +# of the patterns following it. Return 0 if it does, 1 otherwise. +# Matches if no patterns are provided. +# +# can be in LUA_COMPAT or ELUA form. The patterns can be +# fnmatch-style patterns, e.g. 'lua5*', '.. +_lua_impl_matches() { + [[ ${#} -ge 1 ]] || die "${FUNCNAME}: takes at least 1 parameter" + [[ ${#} -eq 1 ]] && return 0 + + local impl=${1} pattern + shift + + for pattern; do + # unify value style to allow lax matching + if [[ ${impl/./-} == ${pattern/./-} ]]; then + return 0 + fi + done + + return 1 +} + +# @FUNCTION: _lua_verify_patterns +# @USAGE: ... +# @INTERNAL +# @DESCRIPTION: +# Verify whether the patterns passed to the eclass function are correct +# (i.e. can match any valid implementation). Dies on wrong pattern. +_lua_verify_patterns() { + debug-print-function ${FUNCNAME} "${@}" + + local impl pattern + for pattern; do + for impl in "${_LUA_ALL_IMPLS[@]}"; do + [[ ${impl} == ${pattern/./-} ]] && continue 2 + done + + die "Invalid implementation pattern: ${pattern}" + done +} + +# @FUNCTION: lua_gen_cond_dep +# @USAGE: [...] +# @DESCRIPTION: +# Output a list of -ies made conditional to USE flags +# of Lua implementations which are both in LUA_COMPAT and match +# any of the patterns passed as the remaining parameters. +# +# The patterns can be fnmatch-style patterns (matched via bash == operator +# against LUA_COMPAT values). Remember to escape or quote the fnmatch +# patterns to prevent accidental shell filename expansion. +# +# In order to enforce USE constraints on the packages, verbatim +# '${LUA_SINGLE_USEDEP}' and '${LUA_USEDEP}' (quoted!) may +# be placed in the dependency specification. It will get expanded within +# the function into a proper USE dependency string. +# +# Example: +# @CODE +# LUA_COMPAT=( lua5-{1..3} ) +# RDEPEND="$(lua_gen_cond_dep \ +# 'dev-lua/backported_core_module[${LUA_USEDEP}]' lua5-1 lua5-2 )" +# @CODE +# +# It will cause the variable to look like: +# @CODE +# RDEPEND="lua_single_target_lua5-1? ( +# dev-lua/backported_core_module[lua_targets_lua5-1(-)?,...] ) +# lua_single_target_lua5-2? ( +# dev-lua/backported_core_module[lua_targets_lua5-2(-)?,...] )" +# @CODE +lua_gen_cond_dep() { + debug-print-function ${FUNCNAME} "${@}" + + local impl matches=() + + local dep=${1} + shift + + _lua_verify_patterns "${@}" + for impl in "${_LUA_SUPPORTED_IMPLS[@]}"; do + if _lua_impl_matches "${impl}" "${@}"; then + # substitute ${LUA_SINGLE_USEDEP} if used + # (since lua_gen_usedep() will not return + # ${LUA_SINGLE_USEDEP}, the code is run at most once) + if [[ ${dep} == *'${LUA_SINGLE_USEDEP}'* ]]; then + local usedep=$(_lua_gen_usedep "${@}") + dep=${dep//\$\{LUA_SINGLE_USEDEP\}/${usedep}} + fi + local multi_usedep="lua_targets_${impl}(-)" + + local subdep=${dep//\$\{LUA_MULTI_USEDEP\}/${multi_usedep}} + matches+=( "lua_single_target_${impl}? ( + ${subdep//\$\{LUA_USEDEP\}/${multi_usedep}} )" ) + fi + done + + echo "${matches[@]}" +} + +# @FUNCTION: lua_gen_impl_dep +# @USAGE: [ [...]] +# @DESCRIPTION: +# Output a dependency on Lua implementations with the specified USE +# dependency string appended, or no USE dependency string if called +# without the argument (or with empty argument). If any implementation +# patterns are passed, the output dependencies will be generated only +# for the implementations matching them. +# +# The patterns can be fnmatch-style patterns (matched via bash == operator +# against LUA_COMPAT values). Remember to escape or quote the fnmatch +# patterns to prevent accidental shell filename expansion. +# +# Use this function when you need to request different USE flags +# on the Lua interpreter depending on package's USE flags. If you +# only need a single set of interpreter USE flags, just set +# LUA_REQ_USE and use ${LUA_DEPS} globally. +# +# Example: +# @CODE +# LUA_COMPAT=( lua5-{1..3} ) +# RDEPEND="foo? ( $(lua_gen_impl_dep 'deprecated(+)' lua5-3 ) )" +# @CODE +# +# It will cause the variable to look like: +# @CODE +# RDEPEND="foo? ( +# lua_single_target_lua5-3? ( dev-lang/lua:5.3[deprecated(+)] ) +# )" +# @CODE +lua_gen_impl_dep() { + debug-print-function ${FUNCNAME} "${@}" + + local impl + local matches=() + + local LUA_REQ_USE=${1} + shift + + _lua_verify_patterns "${@}" + for impl in "${_LUA_SUPPORTED_IMPLS[@]}"; do + if _lua_impl_matches "${impl}" "${@}"; then + local LUA_PKG_DEP + _lua_export "${impl}" LUA_PKG_DEP + matches+=( "lua_single_target_${impl}? ( ${LUA_PKG_DEP} )" ) + fi + done + + echo "${matches[@]}" +} + +# @FUNCTION: lua_setup +# @DESCRIPTION: +# Determine what the selected Lua implementation is and set +# the Lua build environment up for it. +lua_setup() { + debug-print-function ${FUNCNAME} "${@}" + + unset ELUA + + # support developer override + if [[ ${LUA_COMPAT_OVERRIDE} ]]; then + local impls=( ${LUA_COMPAT_OVERRIDE} ) + [[ ${#impls[@]} -eq 1 ]] || die "LUA_COMPAT_OVERRIDE must name exactly one implementation for lua-single" + + ewarn "WARNING: LUA_COMPAT_OVERRIDE in effect. The following Lua" + ewarn "implementation will be used:" + ewarn + ewarn " ${LUA_COMPAT_OVERRIDE}" + ewarn + ewarn "Dependencies won't be satisfied, and LUA_SINGLE_TARGET flags will be ignored." + + _lua_export "${impls[0]}" ELUA LUA + _lua_wrapper_setup + einfo "Using ${ELUA} to build" + return + fi + + local impl + for impl in "${_LUA_SUPPORTED_IMPLS[@]}"; do + if use "lua_single_target_${impl}"; then + if [[ ${ELUA} ]]; then + eerror "Your LUA_SINGLE_TARGET setting lists more than a single Lua" + eerror "implementation. Please set it to just one value. If you need" + eerror "to override the value for a single package, please use package.env" + eerror "or an equivalent solution (man 5 portage)." + echo + die "More than one implementation in LUA_SINGLE_TARGET." + fi + + _lua_export "${impl}" ELUA LUA + _lua_wrapper_setup + einfo "Using ${ELUA} to build" + fi + done + + if [[ ! ${ELUA} ]]; then + eerror "No Lua implementation selected for the build. Please set" + eerror "the LUA_SINGLE_TARGET variable in your make.conf to one" + eerror "of the following values:" + eerror + eerror "${_LUA_SUPPORTED_IMPLS[@]}" + echo + die "No supported Lua implementation in LUA_SINGLE_TARGET." + fi +} + +# @FUNCTION: lua-single_pkg_setup +# @DESCRIPTION: +# Runs lua_setup. +lua-single_pkg_setup() { + debug-print-function ${FUNCNAME} "${@}" + + [[ ${MERGE_TYPE} != binary ]] && lua_setup +} + +_LUA_SINGLE_R0=1 +fi -- cgit v1.2.3-65-gdbad