public inbox for gentoo-dev@lists.gentoo.org
 help / color / mirror / Atom feed
From: Eric Joldasov <bratishkaerik@landless-city.net>
To: gentoo-dev@lists.gentoo.org
Subject: [gentoo-dev] [PATCH v3 1/5] zig-utils.eclass: new eclass
Date: Sat, 14 Dec 2024 01:07:38 +0500	[thread overview]
Message-ID: <20241213200750.75574-2-bratishkaerik@landless-city.net> (raw)
In-Reply-To: <20241213200750.75574-1-bratishkaerik@landless-city.net>

This eclass handles dependency on Zig toolchain and finds appropriate
versions/slots, converts "CHOST-style and CFLAGS" to "Zig target tuple
and CPU" formats and sets environment variables to be used by other
eclasses and ebuilds.

Most of the projects written in Zig use `build.zig` system and should
use `zig.eclass` from next commit instead. This eclass is more
low-level and can be used when `zig` commands are called from other
build systems directly. For example, when authors use `zig build-exe`
or `zig test` commands in their Makefile/meson.build/Cargo etc.

Signed-off-by: Eric Joldasov <bratishkaerik@landless-city.net>
---
 eclass/tests/zig-utils.sh (new +x) | 320 +++++++++++++++++
 eclass/zig-utils.eclass (new)      | 538 +++++++++++++++++++++++++++++
 2 files changed, 858 insertions(+)

diff --git a/eclass/tests/zig-utils.sh b/eclass/tests/zig-utils.sh
new file mode 100755
index 000000000000..14af1d2105e3
--- /dev/null
+++ b/eclass/tests/zig-utils.sh
@@ -0,0 +1,320 @@
+#!/bin/bash
+# Copyright 2024 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+EAPI=8
+source tests-common.sh || exit
+
+inherit zig-utils
+
+# Set ZIG_TEST_COMPILATION env-var to "1" if you want to test binary
+# compilation and running under QEMU. Assumes "zig" is present in PATH
+# and qemu binfmt is enabled.
+#
+# If CPU is marked with ":no-run", it means program compiled for it
+# successfully but crashed when running under QEMU.
+if [[ "${ZIG_TEST_COMPILATION:-0}" -eq 1 ]]; then
+	MY_WORKDIR="$(mktemp -d)"
+	my_cleanup() {
+		popd > /dev/null
+		rm -rf "${MY_WORKDIR}"
+	}
+	trap 'my_cleanup' EXIT
+
+	pushd "${MY_WORKDIR}" > /dev/null || die
+	cat <<- _EOF_ > main.zig || die
+		const std = @import("std");
+
+		pub fn main() !void {
+			const stdout = std.io.getStdOut();
+			try stdout.writeAll("Hello, Gentoo!\n");
+		}
+	_EOF_
+
+	zig_test_compile_and_run() {
+		eindent
+		einfo "${1}: ${2}"
+		eoutdent
+
+		if [[ "${2}" == native* ]]; then
+			return 0
+		fi
+
+		if [[ "${1}" == arm* ]]; then
+			# Bunch of unimplemented Zig
+			# routines for more "bare-bone" arm.
+			case "${2}" in
+				# Some errors in inline assembly, likely too low baseline
+				generic-soft_float | generic+soft_float) return 0;;
+				# undefined symbol: __sync_fetch_and_add_1
+				# compiler-rt not implemented in upstream for it yet:
+				# https://github.com/ziglang/zig/issues/4959
+				generic+v5te-soft_float) return 0;;
+				*) ;;
+			esac
+		fi
+
+		local ret=0
+
+		local args=(
+			-target "${1}"
+			-mcpu "${2//:no-run/}"
+			main.zig
+		)
+		if ! zig build-exe "${args[@]}" > /dev/null; then
+			eerror "Failed to compile for: ${1}, ${2}"
+			((++ret))
+			return ${ret}
+		fi
+
+		# Can't run macOS binaries in Linux user-mode QEMU emulators
+		if [[ "${1}" == *macos* || "${2}" == *":no-run" ]]; then
+			return ${ret}
+		fi
+
+		if ! ./main > /dev/null; then
+			eerror "Failed to run for: ${1}, ${2}"
+			((++ret))
+		fi
+
+		return ${ret}
+	}
+else
+	zig_test_compile_and_run() { :; }
+fi
+
+test-convert_c_env_to_zig_tuple() {
+	local ret=0
+
+	local -n map=${1}
+
+	local c_tuple
+	for key in "${!map[@]}"; do
+		local expected="${map["${key}"]}"
+
+		local c_tuple
+		local c_flags
+		if [[ "${key}" == *:* ]]; then
+			c_tuple="${key%%:*}"
+			c_flags="${key##*:}"
+		else
+			c_tuple="${key}"
+			c_flags=""
+		fi
+
+		local actual="$(zig-utils_c_env_to_zig_target "${c_tuple}" "${c_flags}")"
+		if [[ "${expected}" != "${actual}" ]]; then
+			eerror "Translating ${c_tuple}: expected ${expected}, found ${actual}"
+			((++ret))
+			continue
+		fi
+
+		local zig_cpu="$(zig-utils_c_env_to_zig_cpu "${c_tuple}" "${c_flags}")"
+		if ! zig_test_compile_and_run "${expected}" "${zig_cpu}"; then
+			((++ret))
+			continue
+		fi
+	done
+
+	return ${ret}
+}
+
+test-convert_c_env_to_zig_cpu() {
+	local ret=0
+
+	local -n map=${1}
+	local chost=${2}
+
+	local c_flags
+	for c_flags in "${!map[@]}"; do
+		local expected="${map["${c_flags}"]}"
+		local actual="$(zig-utils_c_env_to_zig_cpu "${chost}" "${c_flags}")"
+		if [[ "${expected//:no-run/}" != "${actual}" ]]; then
+			eerror "Translating ${c_flags}: expected ${expected//:no-run/}, found ${actual}"
+			((++ret))
+			continue
+		fi
+
+		local zig_target="$(zig-utils_c_env_to_zig_target "${chost}" "${c_flags}")"
+		if ! zig_test_compile_and_run "${zig_target}" "${expected}"; then
+			((++ret))
+			continue
+		fi
+	done
+
+	return ${ret}
+}
+
+tbegin '"C tuple to Zig tuple"'
+declare -A c_to_zig_map=(
+	# Just remove "vendor" field
+	[aarch64-unknown-linux-gnu]=aarch64-linux-gnu
+	[arm-unknown-linux-musleabi]=arm-linux-musleabi
+	[x86_64-pc-linux-gnu]=x86_64-linux-gnu
+	[loongarch64-unknown-linux-gnu]=loongarch64-linux-gnu
+	[powerpc64le-unknown-linux-gnu]=powerpc64le-linux-gnu
+
+	# ARM big-endian
+	[armeb-unknown-linux-gnueabi]=armeb-linux-gnueabi
+
+	# https://bugs.gentoo.org/924920
+	[armv7a-unknown-linux-gnueabihf]=arm-linux-gnueabihf
+
+	# ARM to Thumb
+	[arm-unknown-linux-musleabi:"-march=armv7e-m"]=thumb-linux-musleabi
+
+	# ARM families
+	[armv6j-unknown-linux-gnueabihf]=arm-linux-gnueabihf
+	[armv6j-linux-gnueabihf]=arm-linux-gnueabihf
+	[armv7a-softfp-linux-gnueabi]=arm-linux-gnueabi
+	[armv7a-linux-gnueabi]=arm-linux-gnueabi
+
+	# X86 (32-bit) families
+	[i486-pc-linux-gnu]=x86-linux-gnu
+	[i686-linux-gnu]=x86-linux-gnu
+
+	# MacOS
+	[x86_64-apple-darwin15]=x86_64-macos-none
+	[arm64-apple-darwin24]=aarch64-macos-none
+)
+test-convert_c_env_to_zig_tuple c_to_zig_map
+tend ${?}
+
+tbegin '"CFLAGS to Zig CPU for ARM"'
+CHOST="armv7a-unknown-linux-musleabihf"
+c_to_zig_map=(
+	[" "]="generic-soft_float"
+	["-mcpu=native"]="native-soft_float"
+	["-mcpu=cortex-a9"]="cortex_a9-soft_float"
+
+	["-mcpu=cortex-a9 -march=iwmmxt2"]="cortex_a9+iwmmxt2-soft_float"
+
+	["-march=armv7e-m"]="generic+v7em-soft_float"
+	["-march=armv5te"]="generic+v5te-soft_float"
+	["-march=armv6j -mfpu=vfp"]="generic+v6j+vfp2-soft_float"
+	["-march=armv7-a -mfpu=vfpv3-d16"]="generic+v7a+vfp3d16-soft_float"
+	["-march=armv7-a -mfpu=crypto-neon-fp-armv8"]="generic+v7a+crypto+neon+fp_armv8-soft_float"
+
+	# https://bugs.gentoo.org/924920
+	["-march=armv7-a -mfpu=vfpv3-d16 -mfloat-abi=hard"]=generic+v7a+vfp3d16-soft_float
+)
+test-convert_c_env_to_zig_cpu c_to_zig_map "${CHOST}"
+tend ${?}
+
+tbegin '"CFLAGS to Zig CPU for AARCH64"'
+CHOST="aarch64-unknown-linux-gnu"
+c_to_zig_map=(
+	[" "]="generic"
+	["-mcpu=native"]="native"
+	["-mcpu=cortex-a78"]="cortex_a78"
+
+	["-march=armv8.3-a"]="generic+v8_3a"
+	["-mcpu=cortex-a78 -march=armv8.3-a"]="cortex_a78+v8_3a"
+)
+test-convert_c_env_to_zig_cpu c_to_zig_map "${CHOST}"
+tend ${?}
+
+tbegin '"CFLAGS to Zig CPU for X86"'
+CHOST="i686-pc-linux-gnu"
+c_to_zig_map=(
+	[" "]="i686"
+	["-march=native"]="native"
+
+	["-march=i486"]="i486"
+	["-march=i586"]="i586"
+	["-march=i686"]="i686"
+	["-O2 -pipe -march=pentium-m"]="pentium_m"
+)
+test-convert_c_env_to_zig_cpu c_to_zig_map "${CHOST}"
+tend ${?}
+
+tbegin '"CFLAGS to Zig CPU for X86-64"'
+CHOST="x86_64-pc-linux-gnu"
+c_to_zig_map=(
+	[" "]="x86_64"
+	["-march=native"]="native"
+
+	["-march=x86-64-v2"]="x86_64_v2"
+	["-march=x86-64"]="x86_64"
+	["-march=znver2"]="znver2"
+)
+test-convert_c_env_to_zig_cpu c_to_zig_map "${CHOST}"
+tend ${?}
+
+tbegin '"CFLAGS to Zig CPU for RISCV32"'
+CHOST="riscv32-unknown-linux-gnu"
+c_to_zig_map=(
+	[" "]="generic_rv32"
+	["-mcpu=native"]="native"
+	["-mcpu=sifive-e31"]="sifive_e31"
+
+	["-mabi=ilp32d -march=rv32imafdc"]="generic_rv32+i+m+a+f+d+c+d"
+	["-mcpu=native -mabi=ilp32 -march=rv32imac"]="native+i+m+a+c"
+)
+test-convert_c_env_to_zig_cpu c_to_zig_map "${CHOST}"
+tend ${?}
+
+tbegin '"CFLAGS to Zig CPU for RISCV64"'
+CHOST="riscv64-unknown-linux-gnu"
+c_to_zig_map=(
+	[" "]="generic_rv64"
+	["-mcpu=native"]="native"
+	["-mcpu=sifive-u74"]="sifive_u74"
+
+	["-mabi=lp64 -march=rv64imac"]="generic_rv64+i+m+a+c"
+	["-mabi=lp64d -march=rv64gc"]="generic_rv64+i+m+a+f+d+zicsr+zifencei+c+d"
+	["-march=rv64gcv"]="generic_rv64+i+m+a+f+d+zicsr+zifencei+c+v"
+	["-march=rv64imafdc -mcpu=sifive-u74"]="sifive_u74+i+m+a+f+d+c"
+	["-mcpu=native -mabi=lp64 -march=rv64imac"]="native+i+m+a+c"
+)
+test-convert_c_env_to_zig_cpu c_to_zig_map "${CHOST}"
+tend ${?}
+
+tbegin '"CFLAGS to Zig CPU for LoongArch64"'
+CHOST="loongarch64-unknown-linux-gnu"
+c_to_zig_map=(
+	[" "]="generic_la64"
+	["-march=native"]="native"
+	["-march=la664"]="la664"
+
+	["-march=loongarch64 -mabi=lp64d"]="loongarch64+d"
+	["-mabi=lp64f"]="generic_la64+f"
+)
+test-convert_c_env_to_zig_cpu c_to_zig_map "${CHOST}"
+tend ${?}
+
+tbegin '"CFLAGS to Zig CPU for PowerPC"'
+CHOST="powerpc-unknown-linux-gnu"
+c_to_zig_map=(
+	[" "]="ppc"
+	["-mcpu=native"]="native"
+
+	["-mcpu=G5"]="g5"
+
+	# qemu: uncaught target signal 4 (Illegal instruction) - core dumped
+	["-mcpu=power7"]="pwr7:no-run"
+	["-mcpu=power8"]="pwr8:no-run"
+
+	["-mcpu=powerpc"]="ppc"
+	["-mcpu=powerpcle"]="ppc"
+)
+test-convert_c_env_to_zig_cpu c_to_zig_map "${CHOST}"
+tend ${?}
+
+tbegin '"CFLAGS to Zig CPU for PowerPC64"'
+CHOST="powerpc64-unknown-linux-gnu"
+c_to_zig_map=(
+	[" "]="ppc64"
+	["-mcpu=native"]="native"
+
+	# qemu: uncaught target signal 4 (Illegal instruction) - core dumped
+	["-mcpu=power10"]="pwr10:no-run"
+
+	["-mcpu=power9"]="pwr9"
+	["-mcpu=powerpc64"]="ppc64"
+	["-mcpu=powerpc64le"]="ppc64le"
+)
+test-convert_c_env_to_zig_cpu c_to_zig_map "${CHOST}"
+tend ${?}
+
+texit
diff --git a/eclass/zig-utils.eclass b/eclass/zig-utils.eclass
new file mode 100644
index 000000000000..ca72e89ed6ea
--- /dev/null
+++ b/eclass/zig-utils.eclass
@@ -0,0 +1,538 @@
+# Copyright 2024 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+# @ECLASS: zig-utils.eclass
+# @MAINTAINER:
+# Eric Joldasov <bratishkaerik@landless-city.net>
+# @AUTHOR:
+# Eric Joldasov <bratishkaerik@landless-city.net>
+# @SUPPORTED_EAPIS: 8
+# @BLURB: Prepare Zig toolchain and set global variables
+# @DESCRIPTION:
+# Prepare Zig toolchain and set global variables.
+# Supports Zig 0.13+.
+# Does not set any default function, ebuilds must call them manually.
+# Generally, only "zig-utils_setup" is needed.
+#
+# Intended to be used by ebuilds that call "zig build-exe/lib/obj"
+# or "zig test" directly and by "dev-lang/zig".
+# For ebuilds with ZBS (Zig Build System), it's usually better
+# to inherit zig.eclass instead, as it has default phases-functions.
+
+if [[ -z ${_ZIG_UTILS_ECLASS} ]]; then
+_ZIG_UTILS_ECLASS=1
+
+case ${EAPI} in
+	8) ;;
+	*) die "${ECLASS}: EAPI ${EAPI:-0} not supported" ;;
+esac
+
+inherit edo flag-o-matic linux-info
+
+# @ECLASS_VARIABLE: ZIG_SLOT
+# @PRE_INHERIT
+# @REQUIRED
+# @DESCRIPTION:
+# Zig slot that will be used in "ezig" function.  Also, if
+# ZIG_OPTIONAL is empty, adds dev-lang/zig and dev-lang/zig-bin
+# dependency to BDEPEND.  Must be >= "0.13".
+#
+# Example:
+# @CODE
+# ZIG_SLOT="0.13"
+# @CODE
+#
+# When a new Zig release occurs, it is advisable for maintainers to
+# check whether their ebuild supports that new version.  If yes, they
+# they should bump ZIG_SLOT to the latest version; if not supported,
+# they need to patch any issues with new version and again bump
+# ZIG_SLOT.  This helps to reduce dependencies on outdated Zig
+# versions.
+#
+# This policy of "1 exclusive Zig slot" will work until it
+# stabilizes enough (probably near 1.0), then it will be re-evaluated
+# and most likely changed to more common in other eclasses ZIG_MIN/
+# ZIG_MAX form.
+
+# @ECLASS_VARIABLE: ZIG_OPTIONAL
+# @PRE_INHERIT
+# @DEFAULT_UNSET
+# @DESCRIPTION:
+# If set to a non-empty value, all logic in zig-utils and
+# zig eclasses will be considered optional.  No dependencies
+# will be added and no phase functions will be exported.
+#
+# For zig-utils.eclass users:
+# You have to add Zig dependency in your BDEPEND manually and call
+# at least "zig-utils_setup" before using "ezig".
+#
+# For zig.eclass users: see documentation in zig.eclass
+# instead.
+if [[ ! ${ZIG_OPTIONAL} ]]; then
+	BDEPEND="
+		|| (
+			dev-lang/zig:${ZIG_SLOT}
+			dev-lang/zig-bin:${ZIG_SLOT}
+		)
+	"
+fi
+
+# @ECLASS_VARIABLE: ZIG_TARGET
+# @DEFAULT_UNSET
+# @DESCRIPTION:
+# Zig target tuple to use.  Has the following format:
+# arch-os[.os_version_range]-abi[.abi_version]
+# Can be passed as:
+# * "-target " option in "zig test" or "zig build-exe/lib/obj",
+# * "-Dtarget=" option in "zig build"
+#   (if project uses "std.Build.standardTargetOptions").
+#
+# Can be set by user in make.conf.  If not set, then auto-generated by
+# "zig-utils_setup".
+#
+# Example:
+# @CODE
+# # Autodetected by Zig:
+# ZIG_TARGET="native"
+# # Machine running Linux x86_64 system, with glibc:
+# ZIG_TARGET="x86_64-linux-gnu"
+# # Similar to above, but versions are passed explicitly:
+# ZIG_TARGET="x86_64-linux.6.1.12...6.6.16-gnu.2.38"
+# # Machine running Linux PPC64 little-endian system, with musl
+# ZIG_TARGET="powerpc64le-linux-musl"
+# @CODE
+#
+# Note for eclass users: it is discouraged to overwrite ZIG_TARGET
+# value by ebuilds.  In most cases, if you need to hardcode value for
+# -Dtarget, it's better to change "build.zig" code instead to use
+# appropriate values.  For example, if some build-time executable
+# intented for host is compiled for cross-platform target, change in
+# build.zig "target" for that executable to be "b.graph.host".
+#
+# In rare cases, if you really need to hardcode ZIG_TARGET, use this
+# syntax before calling `zig-utils_setup` (or `zig_pkg_setup`) to
+# allow user override:
+# @CODE
+# pkg_setup() {
+# 	: "${ZIG_TARGET:=aarch64-freestanding-none}"
+# 	zig_pkg_setup
+# }
+# @CODE
+
+# @ECLASS_VARIABLE: ZIG_CPU
+# @DEFAULT_UNSET
+# @DESCRIPTION:
+# Zig target CPU and features to use.  Has the following format:
+# family_name(\+enable_feature|\-disable_feature)*
+# Can be passed as:
+# * "-mcpu " option in "zig test" or "zig build-exe/lib/obj",
+# * "-Dcpu=" option in "zig build"
+#   (if project uses "std.Build.standardTargetOptions").
+#
+# Can be set by user in make.conf.  If not set, then auto-generated by
+# "zig-utils_setup".
+#
+# Example:
+# @CODE
+# # Autodetected by Zig:
+# ZIG_CPU="native"
+# # AMD Zen 2 processor
+# ZIG_CPU="znver2"
+# # x86_64 processor, X87 support enabled, SSE2 support disabled
+# ZIG_CPU="x86_64+x87-sse2"
+# @CODE
+#
+# Note for eclass users: it is discouraged to overwrite ZIG_CPU
+# value by ebuilds.  In most cases, if you need to hardcode value for
+# -Dcpu, it's better to change "build.zig" code instead to use
+# appropriate values.  For example, if some build-time executable
+# intented for host is compiled for cross-platform target, change in
+# build.zig "target" for that executable to be "b.graph.host".
+#
+# In rare cases, if you really need to hardcode ZIG_CPU, use this
+# syntax before calling `zig-utils_setup` (or `zig_pkg_setup`) to
+# allow user override:
+# @CODE
+# pkg_setup() {
+# 	: "${ZIG_CPU:=apple_m1}"
+# 	zig_pkg_setup
+# }
+# @CODE
+
+# @ECLASS_VARIABLE: ZIG_EXE
+# @OUTPUT_VARIABLE
+# @DESCRIPTION:
+# Absolute path to the used Zig executable.
+# Set by "zig-utils_setup"/"zig-utils_find_installation".
+#
+# Please note that when passing one flag several times with different
+# values:
+# * (only "zig build") in "-Dbar=false -Dbar" form:
+#   errors due to conflict of flags,
+# * (only "zig build") in "-Dbar=false -Dbar=true" form:
+#   "bar" becomes a list, which is likely not what you want,
+# * in "-fbar -fno-bar" form:
+#   latest value overwrites values before.
+# Example above shows only boolean option, but it is same with other
+# types of options (enums, "std.zig.BuildId", "std.SemanticVersion",
+# integers, strings, etc.).
+
+# @ECLASS_VARIABLE: ZIG_VER
+# @OUTPUT_VARIABLE
+# @DESCRIPTION:
+# Zig version as reported in dev-lang/zig-${PV} PV part.
+# Set by "zig-utils_setup"/"zig-utils_find_installation".
+#
+# Example:
+# @CODE
+# 0.13.0
+# @CODE
+
+# @FUNCTION: zig-utils_c_env_to_zig_target
+# @USAGE: <C-style target tuple> <CFLAGS>
+# @DESCRIPTION:
+# Translates C-style target tuple (like CHOST) and CFLAGS to Zig-style
+# target tuple.  For full information "zig-utils_c_env_to_zig_cpu" is
+# needed, because some information is located in different places in C
+# and Zig, for example:
+# * Moved from C target to Zig CPU: x86 and ARM families,
+# * Moved from CFLAGS to Zig tuple: ARM Thumb mode.
+#
+# Mostly used during cross-compilation to get target triple if user
+# did not set ZIG_TARGET variable, and always during bootstraping Zig.
+#
+# See ZIG_TARGET description for more information.
+zig-utils_c_env_to_zig_target() {
+	if [[ ${#} -ne 2 ]]; then
+		die "${FUNCNAME[0]}: expected 2 arguments, got ${#}"
+	fi
+	local c_tuple="${1}"
+	local c_arch="${c_tuple%%-*}"
+	local c_abi="${c_tuple##*-}"
+
+	local c_flags="${2}"
+	local c_flags_march="$(CFLAGS="${c_flags}" get-flag march)"
+
+	local arch os abi
+
+	case "${c_arch}" in
+		i?86) arch=x86;;
+		arm64) arch=aarch64;;
+		arm*)
+			if [[ "${c_flags_march}" == *-m ]]; then
+				arch=thumb
+			else
+				arch=arm
+			fi
+
+			if [[ "${c_arch}" == *eb ]]; then
+				arch+="eb"
+			fi
+			;;
+		*) arch="${c_arch}";;
+	esac
+
+	case "${c_tuple}" in
+		*-linux*) os=linux;;
+		*-apple*) os=macos;;
+	esac
+
+	case "${c_abi}" in
+		darwin*) abi=none;;
+		*) abi="${c_abi}";;
+	esac
+
+	echo "${arch}-${os}-${abi}"
+}
+
+# @FUNCTION: zig-utils_c_env_to_zig_cpu
+# @USAGE: <C-style target tuple> <CFLAGS>
+# @DESCRIPTION:
+# Translates C-style target tuple (like CHOST) and CFLAGS to Zig-style
+# target CPU and features.  For full information
+# "zig-utils_c_env_to_zig_target" is needed, because some information
+# is located in different places in C and Zig, for example:
+# * Moved from C target to Zig CPU: x86 and ARM families,
+# * Moved from CFLAGS to Zig tuple: ARM Thumb mode.
+#
+# Used to get target CPU if user did not set ZIG_CPU variable.
+#
+# See ZIG_CPU description for more information.
+zig-utils_c_env_to_zig_cpu() {
+	if [[ ${#} -ne 2 ]]; then
+		die "${FUNCNAME[0]}: expected 2 arguments, got ${#}"
+	fi
+	local c_tuple="${1}"
+	local c_arch="${c_tuple%%-*}"
+
+	local c_flags="${2}"
+	local c_flags_mabi="$(CFLAGS="${c_flags}" get-flag mabi)"
+	local c_flags_march="$(CFLAGS="${c_flags}" get-flag march)"
+	local c_flags_mcpu="$(CFLAGS="${c_flags}" get-flag mcpu)"
+	local c_flags_mfpu="$(CFLAGS="${c_flags}" get-flag mfpu)"
+
+	local base_cpu features=""
+
+	case "${c_arch}" in
+		x86_64 | i?86)
+			local c_cpu="${c_flags_march}"
+			case "${c_cpu}" in
+				"") base_cpu="${c_arch}";;
+				*) base_cpu="${c_cpu//[-.]/_}";;
+			esac
+			;;
+		aarch64 | aarch64_be | arm*)
+			local c_cpu="${c_flags_mcpu}"
+			case "${c_cpu}" in
+				"") base_cpu=generic;;
+				*) base_cpu="${c_cpu//[-.]/_}";;
+			esac
+
+			case "${c_flags_march}" in
+				"") ;;
+				armv*)
+					local c_arm_family="${c_flags_march##arm}"
+					c_arm_family="${c_arm_family//./_}"
+					c_arm_family="${c_arm_family//-/}"
+					features+="+${c_arm_family}"
+					;;
+				*) features+="+${c_flags_march}";;
+			esac
+
+			if [[ "${c_arch}" != aarch64* && "${c_arch}" != arm64 ]]; then
+				if [[ "${c_flags_mfpu}" == crypto-* ]]; then
+					c_flags_mfpu="${c_flags_mfpu##crypto-}"
+					features+="+crypto"
+				fi
+				if [[ "${c_flags_mfpu}" == neon-* ]]; then
+					c_flags_mfpu="${c_flags_mfpu##neon-}"
+					features+="+neon"
+				fi
+
+				case "${c_flags_mfpu}" in
+					"" | auto) ;;
+					neon) features+="+neon";;
+					fp16) features+="+fp16";;
+					fp-armv8) features+="+fp_armv8";;
+
+					vfp | vfpv2) features+="+vfp2";;
+
+					vfp3 | vfpv3) features+="+vfp3";;
+					vfpv3-fp16) features+="+vfp3sp";;
+					vfpv3-d16) features+="+vfp3d16";;
+					vfpv3-d16-fp16) features+="+vfp3d16sp";;
+					vfpv3xd) features+="+vfp3d16sp";;
+					vfpv3xd-fp16) features+="+vfp3d16sp+fp16";;
+
+					vfpv4) features+="+vfp4";;
+					vfpv4-fp16) features+="+vfp4sp";;
+					vfpv4-d16) features+="+vfp4d16";;
+					fpv4-sp-fp16) features+="+vfp4d16sp";;
+
+					fpv5-d16) features+="+fp_armv8d16+fp64";;
+					*) die -n "Unknown ARM FPU: ${c_flags_mfpu}";;
+				esac
+
+				local is_softfloat="$(CTARGET="${c_tuple}" tc-tuple-is-softfloat)"
+				case "${is_softfloat}" in
+					only | yes) features+="+soft_float";;
+					softfp | no) features+="-soft_float";;
+					*) die -n "tc-tuple-is-softfloat returned unexpected value: ${is_softfloat}"
+				esac
+			fi
+			;;
+		riscv32 | riscv64)
+			local c_cpu="${c_flags_mcpu}"
+			case "${c_cpu}" in
+				"")
+					case "${c_arch}" in
+						riscv32) base_cpu=generic_rv32;;
+						riscv64) base_cpu=generic_rv64;;
+					esac
+					;;
+				*) base_cpu="${c_cpu//[-.]/_}";;
+			esac
+
+			local base_isa="${c_flags_march:0:4}"
+			local extensions="${c_flags_march:4}"
+
+			case "${base_isa}" in
+				"" | rv32 | rv64) ;;
+				*) die -n "Unknown RISC-V architecture: ${base_isa}";;
+			esac
+
+			local extension
+			while read -n 1 extension; do
+				case "${extension}" in
+					"") ;;
+					g) features+="+i+m+a+f+d+zicsr+zifencei";;
+					_) die -n "Can't translate multi-letter RISC-V extensions yet";;
+					*) features+="+${extension}";;
+				esac
+			done <<< "${extensions}"
+
+			case "${c_flags_mabi}" in
+				ilp32d | lp64d) features+="+d";;
+				ilp32e | lp64e) features+="+e";;
+				ilp32f | lp64f) features+="+f";;
+				"" | ilp32 | lp64) ;;
+				*) die -n "Unknown RISC-V ABI: ${c_flags_mabi}";;
+			esac
+			;;
+		loongarch64)
+			local c_cpu="${c_flags_march}"
+			case "${c_cpu}" in
+				"") base_cpu=generic_la64;;
+				*) base_cpu="${c_cpu//[-.]/_}";;
+			esac
+
+			case "${c_flags_mabi}" in
+				lp64d) features+="+d";;
+				lp64f) features+="+f";;
+				lp64s | "") ;;
+				*) die -n "Unknown LoongArch ABI: ${c_flags_mabi}";;
+			esac
+			;;
+		powerpc | powerpcle | powerpc64 | powerpc64le)
+			local c_cpu="${c_flags_mcpu}"
+			case "${c_cpu}" in
+				"")
+					case "${c_arch}" in
+						powerpc | powerpcle) base_cpu=ppc;;
+						powerpc64 | powerpc64le) base_cpu=ppc64;;
+					esac
+					;;
+				G*) base_cpu="${c_cpu//G/g}";;
+				powerpcle) base_cpu=ppc;;
+				powerpc*) base_cpu="${c_cpu//powerpc/ppc}";;
+				power*) base_cpu="${c_cpu//power/pwr}";;
+				*) base_cpu="${c_cpu//[-.]/_}";;
+			esac
+			;;
+		*) base_cpu=generic;;
+	esac
+
+	echo "${base_cpu}${features}"
+}
+
+# @FUNCTION: zig-utils_find_installation
+# @DESCRIPTION:
+# Detects suitable Zig installation and sets ZIG_VER and ZIG_EXE
+# variables.
+#
+# See ZIG_EXE and ZIG_VER descriptions for more information.
+zig-utils_find_installation() {
+	# Adapted from https://github.com/gentoo/gentoo/pull/28986
+	# Many thanks to Florian Schmaus (Flowdalic)!
+
+	[[ -n "${ZIG_SLOT}" ]] || die "${FUNCNAME[0]}: ZIG_SLOT must be set"
+	if ver_test "${ZIG_SLOT}" -lt "0.13"; then
+		die "${ECLASS}: ZIG_SLOT must be >= 0.13, found ${ZIG_SLOT}"
+	fi
+
+	einfo "Searching Zig ${ZIG_SLOT}..."
+
+	local zig_supported_versions=(
+		"9999"
+		"0.13.1"
+		"0.13.0"
+	)
+
+	local base_path="${BROOT}/usr/bin"
+
+	local selected_path selected_ver
+	for selected_ver in "${zig_supported_versions[@]}"; do
+		# Check if candidate satisfies ZIG_SLOT condition.
+		if [[ "${selected_ver}" != "${ZIG_SLOT}"* ]]; then
+			continue
+		fi
+
+		# Prefer "dev-lang/zig" over "dev-lang/zig-bin"
+		local candidate_path
+		for candidate_path in "${base_path}"/zig{,-bin}-"${selected_ver}"; do
+			if [[ -x "${candidate_path}" ]]; then
+				selected_path="${candidate_path}"
+				break 2
+			fi
+		done
+	done
+
+	if [[ -z "${selected_path}" ]]; then
+		die "Could not find (suitable) Zig at \"${base_path}\""
+	fi
+
+	declare -g ZIG_EXE="${selected_path}"
+	declare -g ZIG_VER="${selected_ver}"
+	# Sanity check, comment from upstream:
+	# > Check libc++ linkage to make sure Zig was built correctly,
+	# > but only for "env" and "version" to avoid affecting the
+	# > startup time for build-critical commands
+	# > (check takes about ~10 μs)
+	"${ZIG_EXE}" version > /dev/null ||
+		die "Sanity check failed for \"${ZIG_EXE}\""
+}
+
+# @FUNCTION: zig-utils_setup
+# @DESCRIPTION:
+# Checks if running Linux kernel version is supported by Zig.
+# Populates ZIG_TARGET, ZIG_CPU, ZIG_EXE and ZIG_VER global
+# variables with detected values, or, if user set them already,
+# leaves as-is.
+zig-utils_setup() {
+	# Should be first because it sets ZIG_VER which might be used
+	# in the future when setting ZIG_TARGET and ZIG_CPU variables
+	# for incompatible versions.
+	if [[ -z "${ZIG_EXE}" ]]; then
+		zig-utils_find_installation
+	fi
+
+	: "${ZIG_CPU:=$(zig-utils_c_env_to_zig_cpu "${CHOST}" "${CFLAGS}")}"
+	if tc-is-cross-compiler; then
+		: "${ZIG_TARGET:=$(zig-utils_c_env_to_zig_target "${CHOST}" "${CFLAGS}")}"
+	else
+		: "${ZIG_TARGET:=native}"
+	fi
+	declare -g ZIG_CPU ZIG_TARGET
+
+	einfo "ZIG_EXE:    \"${ZIG_EXE}\""
+	einfo "ZIG_VER:     ${ZIG_VER}"
+	einfo "ZIG_TARGET:  ${ZIG_TARGET}"
+	einfo "ZIG_CPU:     ${ZIG_CPU}"
+}
+
+# @FUNCTION: ezig
+# @USAGE: [<args>...]
+# @DESCRIPTION:
+# Runs ZIG_EXE with supplied arguments.  Dies if ZIG_EXE is not set or
+# if command exits with error.  Respects `nonfatal`.
+#
+# Always disables progress tree.  By default enables ANSI escape codes
+# (colors, etc.), user can set NO_COLOR environment variable to
+# disable them.
+#
+# Note that color support also determines how compile errors will be
+# printed: source code lines and reference traces are not available
+# when colors are disabled.
+ezig() {
+	# Sync description above and comments below with upstream's
+	# "std.io.tty.detectConfig".
+	debug-print-function "${FUNCNAME[0]}" "${@}"
+
+	if [[ -z "${ZIG_EXE}" ]] ; then
+		die "${FUNCNAME[0]}: ZIG_EXE is not set. Was 'zig-utils_setup' called before using ezig?"
+	fi
+
+	# Progress tree is helpful indicator in TTY, but unfortunately
+	# they make Portage logs harder to read in plaintext.
+	#
+	# We don't have global toggle for all Zig commands to disable
+	# progress tree, however we can emulate this using 2 steps.
+
+	# Disable progress tree and colors. Errors are now less detailed.
+	local -x TERM=dumb
+	# Re-enable colors. Errors are now yet again detailed for reading.
+	local -x CLICOLOR_FORCE=1
+	# User's NO_COLOR has more priority and can disable colors again.
+	"${ZIG_EXE}" "${@}" || die -n "Failed to run command: ${ZIG_EXE} ${@}"
+}
+fi
-- 
2.47.0


  reply	other threads:[~2024-12-13 20:08 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-10-24  1:46 [gentoo-dev] [PATCH 0/5] Ziglang eclasses for 0.13+ Eric Joldasov
2024-10-24  1:46 ` [gentoo-dev] [PATCH 1/5] zig-toolchain.eclass: new eclass Eric Joldasov
2024-10-24  7:32   ` Ulrich Müller
2024-10-24  7:38     ` Matt Jolly
2024-10-24  8:50       ` Florian Schmaus
2024-10-24 13:00         ` Michael Orlitzky
2024-10-24  1:46 ` [gentoo-dev] [PATCH 2/5] zig-build.eclass: " Eric Joldasov
2024-10-24  9:16   ` Maciej Barć
2024-10-24  1:46 ` [gentoo-dev] [PATCH 3/5] dev-lang/zig: add 0.13.0-r1 Eric Joldasov
2024-10-24  1:46 ` [gentoo-dev] [PATCH 4/5] dev-lang/zig: sync 9999 with 0.13.0-r1 Eric Joldasov
2024-10-24  1:46 ` [gentoo-dev] [PATCH 5/5] sys-fs/ncdu: add 2.6-r1 Eric Joldasov
2024-10-25 21:20 ` [gentoo-dev] [PATCH 0/5] Ziglang eclasses for 0.13+ Eric Joldasov
2024-10-25 21:20   ` [gentoo-dev] [PATCH 1/5] zig-toolchain.eclass: new eclass Eric Joldasov
2024-10-25 21:20   ` [gentoo-dev] [PATCH 2/5] zig-build.eclass: " Eric Joldasov
2024-10-25 21:20   ` [gentoo-dev] [PATCH 3/5] dev-lang/zig: add 0.13.0-r1 Eric Joldasov
2024-10-25 21:20   ` [gentoo-dev] [PATCH 4/5] dev-lang/zig: sync 9999 with 0.13.0-r1 Eric Joldasov
2024-10-25 21:20   ` [gentoo-dev] [PATCH 5/5] sys-fs/ncdu: add 2.6-r1 Eric Joldasov
2024-10-25 21:33 ` [gentoo-dev] [PATCH v2 0/5] Ziglang eclasses for 0.13+ Eric Joldasov
2024-10-25 21:33   ` [gentoo-dev] [PATCH v2 1/5] zig-toolchain.eclass: new eclass Eric Joldasov
2024-10-25 21:33   ` [gentoo-dev] [PATCH v2 2/5] zig-build.eclass: " Eric Joldasov
2024-10-25 21:33   ` [gentoo-dev] [PATCH v2 3/5] dev-lang/zig: add 0.13.0-r1 Eric Joldasov
2024-10-25 21:33   ` [gentoo-dev] [PATCH v2 4/5] dev-lang/zig: sync 9999 with 0.13.0-r1 Eric Joldasov
2024-10-25 21:33   ` [gentoo-dev] [PATCH v2 5/5] sys-fs/ncdu: add 2.6-r1 Eric Joldasov
2024-12-13 20:07 ` [gentoo-dev] [PATCH v3 0/5] Zig: new eclasses, rewrite existing ebuilds to use them Eric Joldasov
2024-12-13 20:07   ` Eric Joldasov [this message]
2024-12-13 20:07   ` [gentoo-dev] [PATCH v3 2/5] zig.eclass: new eclass Eric Joldasov
2024-12-13 20:07   ` [gentoo-dev] [PATCH v3 3/5] dev-lang/zig: add 0.13.0-r2 Eric Joldasov
2024-12-13 20:07   ` [gentoo-dev] [PATCH v3 4/5] dev-lang/zig: sync 9999 with 0.13.0-r2 Eric Joldasov
2024-12-13 20:07   ` [gentoo-dev] [PATCH v3 5/5] sys-fs/ncdu: add 2.7-r1 Eric Joldasov

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=20241213200750.75574-2-bratishkaerik@landless-city.net \
    --to=bratishkaerik@landless-city.net \
    --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