forked from Mirror/pmbootstrap
Move pmb/parse/arch.py over to core and refactor it as an Arch type, similar to how Chroot was done. Fix all the uses (that I can find) of arch in the codebase that need adjusting. The new Arch type is an Enum, making it clear what architectures can be represented and making it much easier to reason about. Since we support ~5 (kinda) different representations of an Architecture (Alpine, Kernel, target triple, platform, and QEMU), we now formalise that the Alpine format is what we represent internally, with methods to convert to any of the others as-needed. Signed-off-by: Caleb Connolly <caleb@postmarketos.org>
191 lines
5.9 KiB
Python
191 lines
5.9 KiB
Python
# Copyright 2023 Oliver Smith
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
import enum
|
|
from pathlib import Path, PosixPath, PurePosixPath
|
|
import platform
|
|
from typing import Set
|
|
|
|
# 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"
|
|
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}")
|
|
|
|
|
|
@staticmethod
|
|
def from_machine_type(machine_type: str) -> "Arch":
|
|
mapping = {
|
|
"i686": Arch.x86,
|
|
"x86_64": Arch.x86_64,
|
|
"aarch64": Arch.aarch64,
|
|
"arm64": Arch.aarch64,
|
|
"armv6l": Arch.armhf,
|
|
"armv7l": Arch.armv7,
|
|
"armv8l": Arch.armv7,
|
|
}
|
|
return mapping[machine_type]
|
|
|
|
|
|
@staticmethod
|
|
def native() -> "Arch":
|
|
global _cached_native_arch
|
|
return _cached_native_arch
|
|
|
|
|
|
def is_native(self):
|
|
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.)."""
|
|
# FIXME: cache?
|
|
return set([
|
|
Arch.armhf,
|
|
Arch.armv7,
|
|
Arch.aarch64,
|
|
Arch.x86_64,
|
|
Arch.x86,
|
|
Arch.riscv64,
|
|
Arch.native(),
|
|
])
|
|
|
|
|
|
def kernel(self):
|
|
mapping = {
|
|
Arch.x86: "x86",
|
|
Arch.x86_64: "x86_64",
|
|
Arch.armhf: "arm",
|
|
Arch.aarch64: "arm64",
|
|
Arch.riscv64: "riscv",
|
|
Arch.ppc64le: "powerpc",
|
|
Arch.s390x: "s390",
|
|
}
|
|
return mapping.get(self, self.value)
|
|
|
|
def qemu(self):
|
|
mapping = {
|
|
Arch.x86: "i386",
|
|
Arch.armhf: "arm",
|
|
Arch.armv7: "arm",
|
|
Arch.ppc64le: "ppc64",
|
|
}
|
|
return mapping.get(self, self.value)
|
|
|
|
|
|
def alpine_triple(self):
|
|
mapping = {
|
|
Arch.aarch64: "aarch64-alpine-linux-musl",
|
|
Arch.armel: "armv5-alpine-linux-musleabi",
|
|
Arch.armhf: "armv6-alpine-linux-musleabihf",
|
|
Arch.armv7: "armv7-alpine-linux-musleabihf",
|
|
Arch.loongarch32: "loongarch32-alpine-linux-musl",
|
|
Arch.loongarchx32: "loongarchx32-alpine-linux-musl",
|
|
Arch.loongarch64: "loongarch64-alpine-linux-musl",
|
|
Arch.mips: "mips-alpine-linux-musl",
|
|
Arch.mips64: "mips64-alpine-linux-musl",
|
|
Arch.mipsel: "mipsel-alpine-linux-musl",
|
|
Arch.mips64el: "mips64el-alpine-linux-musl",
|
|
Arch.ppc: "powerpc-alpine-linux-musl",
|
|
Arch.ppc64: "powerpc64-alpine-linux-musl",
|
|
Arch.ppc64le: "powerpc64le-alpine-linux-musl",
|
|
Arch.riscv32: "riscv32-alpine-linux-musl",
|
|
Arch.riscv64: "riscv64-alpine-linux-musl",
|
|
Arch.s390x: "s390x-alpine-linux-musl",
|
|
Arch.x86: "i586-alpine-linux-musl",
|
|
Arch.x86_64: "x86_64-alpine-linux-musl",
|
|
}
|
|
|
|
if self in mapping:
|
|
return mapping[self]
|
|
|
|
raise ValueError(f"Can not map Alpine architecture '{self}'"
|
|
" to the right hostspec value")
|
|
|
|
|
|
def cpu_emulation_required(self):
|
|
# 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())
|