diff options
Diffstat (limited to 'eclass')
-rw-r--r-- | eclass/Manifest.gz | bin | 39355 -> 39840 bytes | |||
-rwxr-xr-x | eclass/tests/zig-utils.sh | 320 | ||||
-rw-r--r-- | eclass/toolchain.eclass | 12 | ||||
-rw-r--r-- | eclass/zig-utils.eclass | 538 | ||||
-rw-r--r-- | eclass/zig.eclass | 558 |
5 files changed, 1426 insertions, 2 deletions
diff --git a/eclass/Manifest.gz b/eclass/Manifest.gz Binary files differindex c45c90c387a2..86a7a86682d6 100644 --- a/eclass/Manifest.gz +++ b/eclass/Manifest.gz 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/toolchain.eclass b/eclass/toolchain.eclass index 6eef2a0ec03e..55b2127a4f11 100644 --- a/eclass/toolchain.eclass +++ b/eclass/toolchain.eclass @@ -979,6 +979,9 @@ toolchain_setup_ada() { latest_ada_bootstrap="${latest_ada_bootstrap#dev-lang/ada-bootstrap-}" latest_ada_bootstrap=$(ver_cut 1 ${latest_ada_bootstrap}) ada_bootstrap="${latest_ada_bootstrap}" + + export ADA_INCLUDE_PATH="${BROOT}/usr/lib/ada-bootstrap/usr/lib/gcc/${CHOST}/${ada_bootstrap}/adainclude::${ADA_INCLUDE_PATH}" + export ADA_OBJECTS_PATH="${BROOT}/usr/lib/ada-bootstrap/usr/lib/gcc/${CHOST}/${ada_bootstrap}/adalib:${ADA_OBJECTS_PATH}" fi ada_bootstrap_type=ada-bootstrap @@ -1320,8 +1323,13 @@ toolchain_src_configure() { confgcc+=( --enable-lto ) # Build compiler itself using LTO - if tc_version_is_at_least 9.1 && _tc_use_if_iuse lto ; then - BUILD_CONFIG_TARGETS+=( bootstrap-lto ) + if tc_use_if_iuse lto ; then + # GCC 11 at least has a -Wlto-type-mismatch issue with Ada + if ! tc_version_is_at_least 12.1 && is_ada ; then + :; + elif tc_version_is_at_least 9.1 ; then + BUILD_CONFIG_TARGETS+=( bootstrap-lto ) + fi fi if tc_version_is_at_least 12 && _tc_use_if_iuse cet && [[ -z ${CLANG_DISABLE_CET_HACK} && ${CTARGET} == x86_64-*-gnu* ]] ; then 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 diff --git a/eclass/zig.eclass b/eclass/zig.eclass new file mode 100644 index 000000000000..e838616ef72a --- /dev/null +++ b/eclass/zig.eclass @@ -0,0 +1,558 @@ +# Copyright 2024 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +# @ECLASS: zig.eclass +# @MAINTAINER: +# Eric Joldasov <bratishkaerik@landless-city.net> +# @AUTHOR: +# Alfred Wingate <parona@protonmail.com> +# Violet Purcell <vimproved@inventati.org> +# Eric Joldasov <bratishkaerik@landless-city.net> +# @SUPPORTED_EAPIS: 8 +# @PROVIDES: zig-utils +# @BLURB: Functions for working with ZBS (Zig Build System) +# @DESCRIPTION: +# Functions for working with Zig build system and package manager. +# Supports Zig 0.13+. Exports default functions for convenience. +# +# Note that zig.eclass is mostly tailored for projects that: +# 1) Install something in build.zig steps: "artifacts" (executable, +# libraries, objects), source codes, assets, tests, scripts etc. But +# many authors also use it to write Zig "modules", build logic +# and/or bindings/wrappers for C/C++ libraries. They install nothing +# and are only used at build-time, so it's unneccessary and mostly +# useless to make ebuilds for them. +# 2) Have required `target`, `cpu` and optional `optimize` options in +# build.zig that accept standard Zig-style target and optimize mode. +# They are usually created by calling `b.standardTargetOptions` and +# `b.standardOptimizeOption` functions. +# +# For end-user executables, usually it's recommended to patch to call +# these options and upstream it, but in some cases authors have good +# reasons to not have them, f.e. if it is built only for WASM +# platform with ReleaseSmall, and is not intended to run in /usr/bin/. +# In this case, declare dummy options using `b.option` and ignore +# their values, or else eclass wouldn't work. +# +# Another case is when upstream has `target` option but it has +# custom format and does not accept usual Zig targets, but rather +# something specific to the project like "linux-baseline-lts", or +# combine CPU and target in one option. +# In this case, it's best to rename that option to something like +# `target-custom`, then declare `target` option and make converter +# from one value to other. +# +# For non-executable binaries like C libraries, objects etc. our +# policy is stricter, all 3 options are required and should not +# be ignored, with no exceptions. + +if [[ -z ${_ZIG_ECLASS} ]]; then +_ZIG_ECLASS=1 + +case ${EAPI} in + 8) ;; + *) die "${ECLASS}: EAPI ${EAPI:-0} not supported" ;; +esac + +inherit multiprocessing zig-utils + +# @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.eclass users: +# You need to add Zig and pkgconfig dependencies in your BDEPEND, set +# QA_FLAGS_IGNORED and call all phase functions manually. If you want +# to use "ezig build" directly, call "zig_pkg_setup" before it. +# +# For zig-utils.eclass users: see documentation in +# zig-utils.eclass instead. +if [[ ! ${ZIG_OPTIONAL} ]]; then + BDEPEND="virtual/pkgconfig" + + # See https://github.com/ziglang/zig/issues/3382 + # Zig Build System does not support CFLAGS/LDFLAGS/etc. + QA_FLAGS_IGNORED=".*" +fi + +# @ECLASS_VARIABLE: ZBS_DEPENDENCIES +# @PRE_INHERIT +# @DEFAULT_UNSET +# @DESCRIPTION: +# Bash associative array with all tarballs that will be fetched by +# "ezig fetch" in zig_src_unpack phase. Value is URL where +# tarball is located, key is name under which it would be downloaded +# and renamed. So generally it has effect of "value -> key". +# +# Note: if Zig Build System dependency can't be represented in SRC_URI +# (like direct Git commit URIs), you should do the following +# (zig-ebuilder does archiving automatically for you): +# 1. Archive each folder with dependency content in some tarball, +# so f.e. if you have 2 Git dependencies, create 2 tarballs. +# 2. Archive all previous tarballs into one combined tarball (also +# called tarball-tarball from now on), no subdirs, so that eclass +# can firstly unpack this tarball with "unpack", +# and secondly unpack its content with "zig fetch". +# 3. (zig-ebuilder can't do this) Host this tarball somewhere +# and put URL of this tarball in SRC_URI, and archives in +# ZBS_DEPENDENCIES, keys must be names of archives, values empty. +# +# Example: +# @CODE +# declare -r -A ZBS_DEPENDENCIES=( +# [tarball_a-<long-hash>.tar.gz]='URL_A' +# [tarball_b-<long-hash>.tar.gz]='URL_B' +# +# # If there are Git dependencies: +# [git_c-<long-hash>.tar.gz]='' +# # Tarball-tarball should contain inside above tarball flatly. +# ) +# @CODE + +# @ECLASS_VARIABLE: ZBS_DEPENDENCIES_SRC_URI +# @OUTPUT_VARIABLE +# @DEFAULT_UNSET +# @DESCRIPTION: +# Content of ZBS_DEPENDENCIES converted at inherit-time, to be used in +# SRC_URI. Note that elements with empty keys will be skipped. +# Example: +# @CODE +# SRC_URI=" +# <URL to project sources, patches, non-Zig resources etc.> +# +# # If there are Git dependencies: +# # <URL to tarball-tarball> +# +# ${ZBS_DEPENDENCIES_SRC_URI} +# " +# @CODE + +# @FUNCTION: _zig_set_zbs_uris +# @INTERNAL +# @DESCRIPTION: +# Sets ZBS_DEPENDENCIES_SRC_URI variable based on ZBS_DEPENDENCIES. +_zig_set_zbs_uris() { + # Thanks to Alfred Wingate "parona" for inspiration here: + # https://gitlab.com/Parona/parona-overlay/-/blob/874dcfe03116574a33ed51f469cc993e98db1fa2/eclass/zig.eclass + + ZBS_DEPENDENCIES_SRC_URI= + + local dependency + for dependency in "${!ZBS_DEPENDENCIES[@]}"; do + local uri="${ZBS_DEPENDENCIES[${dependency}]}" + if [[ -n "${uri}" ]]; then + ZBS_DEPENDENCIES_SRC_URI+=" ${uri} -> ${dependency}" + fi + done +} +_zig_set_zbs_uris + +# @ECLASS_VARIABLE: my_zbs_args +# @DESCRIPTION: +# Bash array with ebuild-specified arguments to pass to the +# "zig build" after "src_configure". +# It's appended to the ZBS_ARGS during "src_configure". Note: if you +# need to override default optimize mode of this eclass (ReleaseSafe) +# with your default, please use "--release=small" etc. syntax so that +# user can still override it in ZBS_ARGS_EXTRA. +# +# Example: +# @CODE +# src_configure() { +# local my_zbs_args=( +# -Dpie=true +# ) +# +# zig_src_configure +# } +# @CODE +: "${my_zbs_args:=}" + +# @ECLASS_VARIABLE: ZBS_ARGS_EXTRA +# @USER_VARIABLE +# @DESCRIPTION: +# Bash string with user-specified arguments to pass to the "zig build" +# after "src_configure". +# It's appended to the ZBS_ARGS during "zig_src_configure". +# +# If this does not have amount of jobs, eclass will try to take amount +# of jobs from MAKEOPTS, and if it also does not have them, it will +# default to $(nproc). +# +# Example: +# @CODE +# ZBS_ARGS_EXTRA="-j8 --release=small" +# @CODE +: "${ZBS_ARGS_EXTRA:=}" + +# @ECLASS_VARIABLE: ZBS_VERBOSE +# @USER_VARIABLE +# @DESCRIPTION: +# If enabled, eclass will add "--summary all --verbose" options to +# "ezig build", so that it prints every command before executing, +# and summarry tree at the end of step. If not, will do nothing. +# Enabled by default. Set to OFF to disable these verbose messages. +# +# Note: this variable does not control other options starting with +# "--verbose-", such as "--verbose-link" or "--verbose-cimport". If +# you need them, add them manually to ZBS_ARGS_EXTRA. +: "${ZBS_VERBOSE:=ON}" + +# @ECLASS_VARIABLE: BUILD_DIR +# @DEFAULT_UNSET +# @DESCRIPTION: +# Directory where all "ezig build" calls will be proceeded. +# Defaults to "${WORKDIR}/${P}-build" if not set. +: "${BUILD_DIR:=${WORKDIR}/${P}-build}" + +# @ECLASS_VARIABLE: ZBS_ECLASS_DIR +# @DESCRIPTION: +# Directory where various files used by this eclass are stored. +# They can be supplied by the ebuild or by eclass. +# Currently, it's used only for Zig packages, which are stored in "p/" +# subdirectory. +# Defaults to "${WORKDIR}/zig-eclass" if not set. +# Should be set before calling "zig_src_unpack" or +# "zig_live_fetch". +: "${ZBS_ECLASS_DIR:=${WORKDIR}/zig-eclass}" + +# @FUNCTION: zig_get_jobs +# @DESCRIPTION: +# Returns number of jobs from ZBS_ARGS_EXTRA or MAKEOPTS. +# If there is none, defaults to number of available processing units. +zig_get_jobs() { + local all_args="${MAKEOPTS} ${ZBS_ARGS_EXTRA}" + local default_jobs="$(get_nproc)" + local jobs="$(makeopts_jobs "${all_args}" "${default_jobs}")" + + if [[ "${jobs}" == "0" ]]; then + # Zig build system does not allow "-j0", and does not have + # option for unlimited parallelism. Pass our default number + # of jobs here. + echo "${default_jobs}" + else + echo "${jobs}" + fi +} + +# @FUNCTION: zig_init_base_args +# @DESCRIPTION: +# Stores basic args for future "ezig build" calls in ZBS_ARGS_BASE. +# Package manager option is managed by "zig_src_prepare", +# ebuild and user options are added by "zig_src_configure". +# +# This function is used by "zig_pkg_setup", and it is neccessary +# that args are available as early as possible, so that ebuilds +# could use them in steps like "src_unpack" if neccessary, while +# still having verbosity and amount of jobs from user respected. +# +# +# TODO: currently this function enables "--search-prefix" (1) and +# "--sysroot" (2) only when cross-compiling, should be fixed to +# unconditionally enabling it. +# +# For solving (1) this patch should be reworked and upstreamed: +# https://paste.sr.ht/~bratishkaerik/2ddffe2bf0f8f9d6dfb60403c2e9560334edaa88 +# +# (2) +# "--sysroot" should be passed together with "--search-prefix" above, +# if we pass only "--sysroot" it gives these errors: +# @CODE +# error: unable to find dynamic system library 'zstd' using strategy 'paths_first'. searched paths: none +# @CODE +zig_init_base_args() { + [[ "${ZBS_ARGS_BASE}" ]] && return + + # Sync with the output format of `zig libc`. + # TODO maybe add to upstream to use ZON format instead... + # Will also help "https://github.com/ziglang/zig/issues/20327", + # and hopefully will respect our settings too. + cat <<- _EOF_ > "${T}/zig_libc.txt" || die "Failed to provide Zig libc info" + # Note: they are not prepended by "--sysroot" value, + # so repeat it here. + # Also, no quotes here, they are interpreted verbatim. + include_dir=${ESYSROOT}/usr/include/ + sys_include_dir=${ESYSROOT}/usr/include/ + crt_dir=${ESYSROOT}/usr/$(get_libdir)/ + # Windows with MSVC only. + msvc_lib_dir= + # Windows with MSVC only. + kernel32_lib_dir= + # Haiku only. + gcc_dir= + _EOF_ + + declare -g -a ZBS_ARGS_BASE=( + -j$(zig_get_jobs) + + -Dtarget="${ZIG_TARGET}" + -Dcpu="${ZIG_CPU}" + --release=safe + + --prefix-exe-dir bin/ + --prefix-lib-dir "$(get_libdir)/" + --prefix-include-dir include/ + + # Should be relative path to make other calls easier, + # so remove leading slash here. + --prefix "${EPREFIX:+${EPREFIX#/}/}usr/" + + --libc "${T}/zig_libc.txt" + ) + if [[ "${ZBS_VERBOSE}" != OFF ]]; then + ZBS_ARGS_BASE+=( --summary all --verbose ) + fi + + if tc-is-cross-compiler; then + ZBS_ARGS_BASE+=( + --search-prefix "${ESYSROOT}/usr/" + --sysroot "${ESYSROOT}/" + ) + fi +} + +# @FUNCTION: zig_pkg_setup +# @DESCRIPTION: +# Sets up environmental variables for Zig toolchain +# and basic args for Zig Build System. +zig_pkg_setup() { + [[ "${MERGE_TYPE}" != binary ]] || return 0 + + zig-utils_setup + zig_init_base_args + + mkdir "${T}/zig-cache/" || die + + # Environment variables set by this eclass. + + # Used by Zig Build System to find `pkg-config`. + # UPSTREAM Used only by 9999 for now, should land in future + # 0.14 release. + export PKG_CONFIG="${PKG_CONFIG:-"$(tc-getPKG_CONFIG)"}" + # Used by whole Zig toolchain (most of the sub-commands) + # to find local and global cache directories. + export ZIG_LOCAL_CACHE_DIR="${T}/zig-cache/local/" + export ZIG_GLOBAL_CACHE_DIR="${T}/zig-cache/global/" +} + +# @FUNCTION: zig_live_fetch +# @USAGE: [<args>...] +# @DESCRIPTION: +# Fetches packages, if they exist, to the "ZBS_ECLASS_DIR/p/". +# Adds build file path to ZBS_BASE_ARGS. +# If you have some lazy dependency which is not triggered in default +# configuration, pass options like you would pass them for regular +# "ezig build". Try to cover all of them before "src_configure". +# **Note**: this function will be deprecated once/if +# https://github.com/ziglang/zig/pull/19975 lands. +# +# Example: +# @CODE +# src_unpack() { +# # If there are no lazy dependency: +# zig_live_fetch +# +# # If there are lazy dependencies that can be triggered together: +# zig_live_fetch -Denable-wayland -Denable-xwayland +# +# # If there are 2 lazy dependencies that can't be triggered +# # together in one call because they conflict: +# zig_live_fetch -Dmain-backend=opengl +# zig_live_fetch -Dmain-backend=vulkan +# } +# @CODE +zig_live_fetch() { + # This function will likely be called in src_unpack, + # before [zig_]src_prepare, so this directory might not + # exist yet. + mkdir -p "${BUILD_DIR}" > /dev/null || die + pushd "${BUILD_DIR}" > /dev/null || die + + ZBS_ARGS_BASE+=( --build-file "${S}/build.zig" ) + + local args=( + "${ZBS_ARGS_BASE[@]}" + + --global-cache-dir "${ZBS_ECLASS_DIR}/" + + # Function arguments + "${@}" + ) + + einfo "ZBS: live-fetching with:" + einfo "${args[@]}" + ezig build --help "${args[@]}" > /dev/null + + popd > /dev/null || die +} + +# @FUNCTION: zig_src_unpack +# @DESCRIPTION: +# Unpacks every archive in SRC_URI and ZBS_DEPENDENCIES, +# in that order. Adds build file path to ZBS_BASE_ARGS. +zig_src_unpack() { + # Thanks to Alfred Wingate "parona" for inspiration here: + # https://gitlab.com/Parona/parona-overlay/-/blob/874dcfe03116574a33ed51f469cc993e98db1fa2/eclass/zig.eclass + + ZBS_ARGS_BASE+=( --build-file "${S}/build.zig" ) + + if [[ "${#ZBS_DEPENDENCIES_SRC_URI}" -eq 0 ]]; then + default_src_unpack + return + fi + + local zig_deps=() + for dependency in "${!ZBS_DEPENDENCIES[@]}"; do + zig_deps+=("${dependency}") + done + + # First unpack non-Zig dependencies, so that + # tarball with all Git dependencies tarballs is unpacked early. + local dist + for dist in ${A}; do + if ! has "${dist}" "${zig_deps[@]}"; then + unpack "${dist}" + fi + done + + # Now unpack all Zig dependencies, including those that are + # now unpacked from tarball-tarball. + local zig_dep + for zig_dep in "${zig_deps[@]}"; do + # Hide now-spammy hash from stdout + ezig fetch --global-cache-dir "${ZBS_ECLASS_DIR}/" \ + "${DISTDIR}/${zig_dep}" > /dev/null + done + einfo "ZBS: ${#zig_deps[@]} dependencies unpacked" +} + +# @FUNCTION: zig_src_prepare +# @DESCRIPTION: +# Calls default "src_prepare" function, creates BUILD_DIR directory +# and enables system mode (by adding to ZBS_BASE_ARGS). +# +# System mode is toggled here and not in "src_unpack" because they +# could have been fetched by "live_fetch" in live ebuilds instead. +zig_src_prepare() { + default_src_prepare + + mkdir -p "${BUILD_DIR}" || die + einfo "BUILD_DIR: \"${BUILD_DIR}\"" + + local system_dir="${ZBS_ECLASS_DIR}/p/" + mkdir -p "${system_dir}" || die + ZBS_ARGS_BASE+=( + # Disable network access after ensuring all dependencies + # are unpacked (by "src_unpack" or "live_fetch") + --system "${system_dir}" + ) +} + +# @FUNCTION: zig_src_configure +# @DESCRIPTION: +# Creates ZBS_ARGS array which can be used in all future phases, +# by combining ZBS_ARGS_BASE set previously, my_zbs_args from ebuild, +# and ZBS_ARGS_EXTRA by user, in this order. +# +# Specific flags currently only add support for the cross-compilation. +# They are likely to be extended in the future. +zig_src_configure() { + # Handle quoted whitespace. + eval "local -a ZBS_ARGS_EXTRA=( ${ZBS_ARGS_EXTRA} )" + + # Since most arguments in array are also cached by ZBS, we + # want to reuse array as much as possible, so prevent + # modification of it. + declare -g -a -r ZBS_ARGS=( + # Base arguments from pkg_setup/setup_base_args + "${ZBS_ARGS_BASE[@]}" + + # Arguments from ebuild + "${my_zbs_args[@]}" + + # Arguments from user + "${ZBS_ARGS_EXTRA[@]}" + ) + + einfo "ZBS: configured with:" + einfo "${ZBS_ARGS[@]}" +} + +# @FUNCTION: zig_src_compile +# @USAGE: [<args>...] +# @DESCRIPTION: +# Calls "ezig build" with previously set ZBS_ARGS. +# Args passed to this function will be passed after ZBS_ARGS. +zig_src_compile() { + pushd "${BUILD_DIR}" > /dev/null || die + + local args=( "${ZBS_ARGS[@]}" "${@}" ) + einfo "ZBS: compiling with: ${args[@]}" + nonfatal ezig build "${args[@]}" || die "ZBS: compilation failed" + + popd > /dev/null || die +} + +# @FUNCTION: zig_src_test +# @USAGE: [<args>...] +# @DESCRIPTION: +# If "test" step exist, calls "ezig build test" with previously set +# ZBS_ARGS. +# Args passed to this function will be passed after ZBS_ARGS. +# Note: currently step detection might give false positives in +# very rare cases, it will be improved in the future. +zig_src_test() { + pushd "${BUILD_DIR}" > /dev/null || die + + local args=( "${ZBS_ARGS[@]}" "${@}" ) + + # UPSTREAM std.testing.tmpDir and a lot of other functions + # do not respect --cache-dir or ZIG_LOCAL_CACHE_DIR: + # https://github.com/ziglang/zig/issues/19874 + mkdir ".zig-cache/" || die + + # UPSTREAM Currently, step name can have any characters in it, + # including whitespaces, so splitting names and descriptions + # by whitespaces is not enough for some cases. + # We probably need something like "--list-steps names_only". + # In practice, almost nobody sets such names. + if grep -q '^[ ]*test[ ]' < <( + nonfatal ezig build --list-steps "${args[@]}" || + die "ZBS: listing steps failed" + ); then + einfo "ZBS: testing with: ${args[@]}" + nonfatal ezig build test "${args[@]}" || + die "ZBS: tests failed" + else + einfo "Test step not found, skipping." + fi + + popd > /dev/null || die +} + +# @FUNCTION: zig_src_install +# @USAGE: [<args>...] +# @DESCRIPTION: +# Calls "ezig build" with DESTDIR and previously set ZBS_ARGS. +# Args passed to this function will be passed after ZBS_ARGS. +# Also installs documentation via "einstalldocs". +zig_src_install() { + pushd "${BUILD_DIR}" > /dev/null || die + local args=( "${ZBS_ARGS[@]}" "${@}" ) + einfo "ZBS: installing with: ${args[@]}" + DESTDIR="${D}" nonfatal ezig build "${args[@]}" || + die "ZBS: installing failed" + popd > /dev/null || die + + einstalldocs +} + +fi + +if [[ ! ${ZIG_OPTIONAL} ]]; then + EXPORT_FUNCTIONS pkg_setup src_unpack src_prepare src_configure src_compile src_test src_install +fi |