forked from Mirror/pmbootstrap
This commit adds s390x to the list of supported architectures, to allow users/developers to experiment with it. Part-of: https://gitlab.postmarketos.org/postmarketOS/pmbootstrap/-/merge_requests/2536
245 lines
7.9 KiB
Python
245 lines
7.9 KiB
Python
# Copyright 2023 Oliver Smith
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
from __future__ import annotations
|
|
|
|
import enum
|
|
from pathlib import Path, PosixPath, PurePosixPath
|
|
import platform
|
|
|
|
# Initialised at the bottom
|
|
_cached_native_arch: Arch
|
|
|
|
|
|
class Arch(enum.Enum):
|
|
"""Supported architectures according to the Alpine
|
|
APKBUILD format."""
|
|
|
|
x86 = "x86"
|
|
x86_64 = "x86_64"
|
|
armhf = "armhf"
|
|
armv7 = "armv7"
|
|
aarch64 = "aarch64"
|
|
riscv64 = "riscv64"
|
|
s390x = "s390x"
|
|
ppc64le = "ppc64le"
|
|
# Arches Alpine can build for
|
|
armel = "armel"
|
|
loongarch32 = "loongarch32"
|
|
loongarchx32 = "loongarchx32"
|
|
loongarch64 = "loongarch64"
|
|
mips = "mips"
|
|
mips64 = "mips64"
|
|
mipsel = "mipsel"
|
|
mips64el = "mips64el"
|
|
noarch = "noarch"
|
|
ppc = "ppc"
|
|
ppc64 = "ppc64"
|
|
riscv32 = "riscv32"
|
|
|
|
def __str__(self) -> str:
|
|
return self.value
|
|
|
|
@staticmethod
|
|
def from_str(arch: str) -> Arch:
|
|
try:
|
|
return Arch(arch)
|
|
except ValueError:
|
|
raise ValueError(
|
|
f"Invalid architecture: '{arch}',"
|
|
" expected something like:"
|
|
f" {', '.join(sorted(str(a) for a in Arch.supported()))}"
|
|
)
|
|
|
|
@staticmethod
|
|
def from_machine_type(machine_type: str) -> Arch:
|
|
match machine_type:
|
|
case "i686":
|
|
return Arch.x86
|
|
case "x86_64":
|
|
return Arch.x86_64
|
|
case "aarch64":
|
|
return Arch.aarch64
|
|
case "armv6l":
|
|
return Arch.armhf
|
|
case "armv7l" | "armv8l":
|
|
return Arch.armv7
|
|
case _:
|
|
raise ValueError(f"Unsupported machine type '{machine_type}'")
|
|
|
|
@staticmethod
|
|
def native() -> Arch:
|
|
global _cached_native_arch
|
|
return _cached_native_arch
|
|
|
|
def is_native(self) -> bool:
|
|
return self == Arch.native()
|
|
|
|
@staticmethod
|
|
def supported() -> set[Arch]:
|
|
"""Officially supported host/target architectures for postmarketOS. Only
|
|
specify architectures supported by Alpine here. For cross-compiling,
|
|
we need to generate the "musl-$ARCH" and "gcc-$ARCH" packages (use
|
|
"pmbootstrap aportgen musl-armhf" etc.)."""
|
|
return {
|
|
Arch.armhf,
|
|
Arch.armv7,
|
|
Arch.aarch64,
|
|
Arch.x86_64,
|
|
Arch.x86,
|
|
Arch.riscv64,
|
|
Arch.s390x,
|
|
Arch.ppc64le,
|
|
Arch.native(),
|
|
}
|
|
|
|
# FIXME: we should use pmaports.cfg "supported_arches" instead
|
|
@staticmethod
|
|
def supported_binary() -> set[Arch]:
|
|
"""Officially supported architectures that have a binary repository"""
|
|
return {
|
|
Arch.armhf,
|
|
Arch.armv7,
|
|
Arch.aarch64,
|
|
Arch.x86_64,
|
|
Arch.x86,
|
|
}
|
|
|
|
def kernel(self) -> str:
|
|
match self:
|
|
case Arch.x86:
|
|
return "x86"
|
|
case Arch.x86_64:
|
|
return "x86_64"
|
|
case Arch.armhf | Arch.armv7:
|
|
return "arm"
|
|
case Arch.aarch64:
|
|
return "arm64"
|
|
case Arch.riscv64:
|
|
return "riscv"
|
|
case Arch.ppc64le | Arch.ppc64 | Arch.ppc:
|
|
return "powerpc"
|
|
case Arch.s390x:
|
|
return "s390"
|
|
case _:
|
|
return self.value
|
|
|
|
def qemu(self) -> str:
|
|
match self:
|
|
case Arch.x86:
|
|
return "i386"
|
|
case Arch.armhf | Arch.armv7:
|
|
return "arm"
|
|
case Arch.ppc64le:
|
|
return "ppc64"
|
|
case _:
|
|
return self.value
|
|
|
|
def alpine_triple(self) -> str:
|
|
"""Get the cross compiler triple for this architecture on Alpine."""
|
|
match self:
|
|
case Arch.aarch64:
|
|
return "aarch64-alpine-linux-musl"
|
|
case Arch.armel:
|
|
return "armv5-alpine-linux-musleabi"
|
|
case Arch.armhf:
|
|
return "armv6-alpine-linux-musleabihf"
|
|
case Arch.armv7:
|
|
return "armv7-alpine-linux-musleabihf"
|
|
case Arch.loongarch32:
|
|
return "loongarch32-alpine-linux-musl"
|
|
case Arch.loongarchx32:
|
|
return "loongarchx32-alpine-linux-musl"
|
|
case Arch.loongarch64:
|
|
return "loongarch64-alpine-linux-musl"
|
|
case Arch.mips:
|
|
return "mips-alpine-linux-musl"
|
|
case Arch.mips64:
|
|
return "mips64-alpine-linux-musl"
|
|
case Arch.mipsel:
|
|
return "mipsel-alpine-linux-musl"
|
|
case Arch.mips64el:
|
|
return "mips64el-alpine-linux-musl"
|
|
case Arch.ppc:
|
|
return "powerpc-alpine-linux-musl"
|
|
case Arch.ppc64:
|
|
return "powerpc64-alpine-linux-musl"
|
|
case Arch.ppc64le:
|
|
return "powerpc64le-alpine-linux-musl"
|
|
case Arch.riscv32:
|
|
return "riscv32-alpine-linux-musl"
|
|
case Arch.riscv64:
|
|
return "riscv64-alpine-linux-musl"
|
|
case Arch.s390x:
|
|
return "s390x-alpine-linux-musl"
|
|
case Arch.x86:
|
|
return "i586-alpine-linux-musl"
|
|
case Arch.x86_64:
|
|
return "x86_64-alpine-linux-musl"
|
|
case _:
|
|
raise ValueError(
|
|
f"Can not map Alpine architecture '{self}' to the right hostspec value"
|
|
)
|
|
|
|
def go(self) -> str:
|
|
match self:
|
|
case Arch.armhf | Arch.armv7:
|
|
return "arm"
|
|
case Arch.aarch64:
|
|
return "arm64"
|
|
case Arch.riscv64 | Arch.ppc64le:
|
|
return str(self)
|
|
case Arch.x86:
|
|
return "386"
|
|
case Arch.x86_64:
|
|
return "amd64"
|
|
case _:
|
|
raise ValueError(f"Can not map architecture '{self}' to Go arch")
|
|
|
|
def cpu_emulation_required(self) -> bool:
|
|
# Obvious case: host arch is target arch
|
|
if self == Arch.native():
|
|
return False
|
|
|
|
# Other cases: host arch on the left, target archs on the right
|
|
not_required = {
|
|
Arch.x86_64: [Arch.x86],
|
|
Arch.armv7: [Arch.armel, Arch.armhf],
|
|
Arch.aarch64: [Arch.armv7],
|
|
}
|
|
if Arch.native() in not_required:
|
|
if self in not_required[Arch.native()]:
|
|
return False
|
|
|
|
# No match: then it's required
|
|
return True
|
|
|
|
# Magic to let us use an arch as a Path element
|
|
def __truediv__(self, other: object) -> Path:
|
|
if isinstance(other, PosixPath) or isinstance(other, PurePosixPath):
|
|
# Convert the other path to a relative path
|
|
# FIXME: we should avoid creating absolute paths that we actually want
|
|
# to make relative to the chroot...
|
|
# if other.is_absolute():
|
|
# logging.warning("FIXME: absolute path made relative to Arch??")
|
|
other = other.relative_to("/") if other.is_absolute() else other
|
|
return Path(str(self)).joinpath(other)
|
|
if isinstance(other, str):
|
|
# Let's us do Arch / "whatever.apk" and magically produce a path
|
|
# maybe this is a pattern we should avoid, but it seems somewhat
|
|
# sensible
|
|
return Path(str(self)).joinpath(other.strip("/"))
|
|
|
|
return NotImplemented
|
|
|
|
def __rtruediv__(self, other: object) -> Path:
|
|
if isinstance(other, PosixPath) or isinstance(other, PurePosixPath):
|
|
# Important to produce a new Path object here, otherwise we
|
|
# end up with one object getting shared around and modified
|
|
# and lots of weird stuff happens.
|
|
return Path(other) / str(self)
|
|
# We don't support str / Arch since that is a weird pattern
|
|
|
|
return NotImplemented
|
|
|
|
|
|
_cached_native_arch = Arch.from_machine_type(platform.machine())
|