twpayne / chezmoi

Manage your dotfiles across multiple diverse machines, securely.

Home Page:https://www.chezmoi.io/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Add `.chezmoi.rustArchTriple` template variable

twpayne opened this issue · comments

Is your feature request related to a problem? Please describe.

I'm always frustrated when I want to download platform-specific binaries built with Rust and have to construct the binary's URL myself.

Typically this includes a Rust architecture string, which requires a lot of template gymnastics, especially because chezmoi's Go-based view of operating systems (runtime.GOOS) and architectures (runtime.GOARCH) do not map well onto Rust's supported operating systems and architectures.

Describe the solution you'd like

As @halostatue said, it would be great if chezmoi had a .chezmoi.rustArchTriple template variable that people could use in their templates.

Describe alternatives you've considered

Constructing Rust arch triples in my own configs.

Additional context

Refs #3735 for .deb and .rpm support.

cc @VorpalBlade as a Rust expert

This might be better as a template function because there are some variations which may require some special handling. Linux has the choice between musl and glibc and Windows has the choice between msvc and mingw (glibc) and mingw (llvm).

Maybe something like rustArchTarget [optional-library-value]. For platforms that don’t have choices, the argument(s) are ignored. For those that do have choices, the default would either be (a) default for GOOS and GOARCH combinations and/or (b) (if possible) overridden for specific builds (e.g., apk/alpine).

I’ve always seen it called the triple, but given that some of them are 4+. parts long, maybe just rustArch or rustArchTarget or rustTarget.

There’s four classes of architectures for Rust:

  1. Tier 1
  2. Tier 2 (hosted)
  3. Tier 2 (not hosted)
  4. Tier 3 (ad hoc, community supported)

Chezmoi only supports a subset of the possible Rust architectures even for the first three.

Tier 1

  • aarch64-unknown-linux-gnu: linux_arm64 (except probably apk) glibc
  • i686-pc-windows-msvc: probablywindows_i386; 32-bit Windows MSVC
  • i686-pc-windows-gnu: windows_i386; 32-bit Windows MinGW
  • i686-unknown-linux-gnu: linux_i386 (except probably apk) 32-bit glibc
  • x86_64-apple-darwin: darwin-amd64
  • x86_64-pc-windows-gnu: maybe windows_amd64
  • x86_64-pc-windows-msvc: probably windows_amd64
  • x86_64-unknown-linux-gnu: linux_amd64 (except probably apk) glibc

Tier 2 (Hosted)

  • aarch64-apple-darwin: darwin-arm64
  • aarch-pc-windows-msvc: windows_arm64
  • aarch64-unknown-linux-musl: linux_arm64.apk
  • loongarch64-unknown-linux-gnu: loong64 except apk glibc
  • powerpc64-unknown-linux-gnu: ppc64 except apk glibc
  • powerpc64le-unknown-linux-gnu: ppc64le except apk glibc
  • riscv64gc-unknown-linux-gnu: riscv64 except apk glibc
  • s390x-unknown-linux-gnu: s390x except apk glibc
  • x86_64-unknown-freebsd: freebsd_amd64
  • x86_64-unknown-linux-musl: linux-amd64-musl

Tier 2 (Not Hosted)

  • aarch64-linux-android: android_arm64
  • arm-unknown-linux-musleabi: linux_arm
  • i686-unknown-freebsd: freebsd_i386
  • i686-unknown-linux-musl: linux_i386 apk

Tier 3

  • arm64ec-pc-windows-msvc: windows_arm maybe?
  • aarch64-unknown-freebsd: freebsd_arm64
  • aarch64-unknown-openbsd: openbsd_arm64
  • armv6-unknown-freebsd: freebsd_arm maybe? (might be armv7-unknown-freebsd)
  • i686-unknown-openbsd: openbsd_i386
  • loongarch64-unknown-linux-musl loong64 apk
  • mips64-unknown-linux-gnuabi64: mips64 probably
  • mips64el-unknown-linux-gnuabi64: mips64le probably
  • powerpc64-unknown-linux-musl: ppc64 apk
  • powerpc64le-unknown-linux-musl: ppc64le apk
  • riscv64gc-unknown-linux-musl: risc apk
  • s390x-unknown-linux-musl: s390x apk
  • x86_64-unknown-openbsd: openbsd_amd64

chezmoi with No Matching Triple

  • armhfp.rpm
  • mips64le_hardfloat
  • linux_armel
  • openbsd_arm

This leaves a number of unsupported or not-clearly-supported Tier 2 targets which might work because Go doesn’t actually use libc unless CGO is used.

Tier 2 Hosted

  • arm-unknown-linux-gnueabi: ARMv6 Linux (kernel 3.2, glibc 2.17)
  • arm-unknown-linux-gnueabihf: ARMv6 Linux, hardfloat (kernel 3.2, glibc 2.17)
  • armv7-unknown-linux-gnueabihf: ARMv7-A Linux, hardfloat (kernel 3.2, glibc 2.17)
  • powerpc-unknown-linux-gnu: PowerPC Linux (kernel 3.2, glibc 2.17)
  • x86_64-unknown-illumos: illumos
  • x86_64-unknown-netbsd: NetBSD/amd64

Tier 2 Not Hosted

  • aarch64-apple-ios: ARM64 iOS
  • aarch64-apple-ios-sim: Apple iOS Simulator on ARM64
  • aarch64-fuchsia: Alias for aarch64-unknown-fuchsia
  • aarch64-unknown-fuchsia: ARM64 Fuchsia
  • aarch64-pc-windows-gnullvm: ARM64 MinGW (Windows 10+), LLVM ABI
  • aarch64-unknown-linux-ohos: ARM64 OpenHarmony
  • arm-linux-androideabi: ARMv6 Android
  • arm-unknown-linux-musleabihf: ARMv6 Linux with musl 1.2.3, hardfloat
  • armv5te-unknown-linux-gnueabi: ARMv5TE Linux (kernel 4.4, glibc 2.23)
  • armv5te-unknown-linux-musleabi: ARMv5TE Linux with musl 1.2.3
  • armv7-linux-androideabi: ARMv7-A Android
  • armv7-unknown-linux-gnueabi: ARMv7-A Linux (kernel 4.15, glibc 2.27)
  • armv7-unknown-linux-musleabi: ARMv7-A Linux with musl 1.2.3
  • armv7-unknown-linux-musleabihf: ARMv7-A Linux with musl 1.2.3, hardfloat
  • armv7-unknown-linux-ohos: ARMv7-A OpenHarmony
  • i586-unknown-linux-gnu: 32-bit Linux w/o SSE (kernel 3.2, glibc 2.17) 2
  • i586-unknown-linux-musl: 32-bit Linux w/o SSE, musl 1.2.3 2
  • i686-linux-android: 32-bit x86 Android 1
  • i686-pc-windows-gnullvm: 32-bit x86 MinGW (Windows 10+), LLVM ABI 1
  • sparc64-unknown-linux-gnu: SPARC Linux (kernel 4.4, glibc 2.23)
  • sparcv9-sun-solaris: SPARC Solaris 11, illumos
  • thumbv7neon-linux-androideabi: Thumb2-mode ARMv7-A Android with NEON
  • thumbv7neon-unknown-linux-gnueabihf: Thumb2-mode ARMv7-A Linux with NEON (kernel 4.4, glibc 2.23)
  • wasm32-unknown-emscripten: WebAssembly via Emscripten
  • wasm32-unknown-unknown: WebAssembly
  • wasm32-wasi: WebAssembly with WASI (undergoing a rename to wasm32-wasip1)
  • wasm32-wasip1: WebAssembly with WASI
  • wasm32-wasip1-threads:
  • x86_64-apple-ios: 64-bit x86 iOS
  • x86_64-fortanix-unknown-sgx: Fortanix ABI for 64-bit Intel SGX
  • x86_64-fuchsia: Alias for x86_64-unknown-fuchsia
  • x86_64-unknown-fuchsia: 64-bit x86 Fuchsia
  • x86_64-linux-android: 64-bit x86 Android
  • x86_64-pc-solaris: 64-bit Solaris 11, illumos
  • x86_64-pc-windows-gnullvm: 64-bit x86 MinGW (Windows 10+), LLVM ABI
  • x86_64-unknown-linux-gnux32: 64-bit Linux (x32 ABI) (kernel 4.15, glibc 2.27)
  • x86_64-unknown-linux-ohos: x86_64 OpenHarmony
  • x86_64-unknown-redox: Redox OS

This list is based on Rust Platform Support and the latest release of chezmoi to see the pre-built versions.

This leaves a number of unsupported or not-clearly-supported Tier 2 targets which might work because Go doesn’t actually use libc unless CGO is used.

I can confirm that I used to use chezmoi and rust on a 32-bit Raspberry Pi. Which I believe was "armv7-unknown-linux-gnueabihf: ARMv7-A Linux, hardfloat (kernel 3.2, glibc 2.17)".

Arm is a bit of a rabbit hole of strange target triplets with hard float vs software float. MIPS has this too (but is becoming less and less relevant). That is not a rust specific problem, I believe you see these over in C/C++-land too. That said, I'm not sure if there are any additional quirks of rust target strings vs GCC / LLVM ones.

Also, musl targets are a bit strange in rust. These are normally statically linked, such that the resulting binary can run anywhere. This can be useful to deal with the mess that is glibc backward compatibility: if you build against a newer glibc it can't run on an older one.

However, you can build dynamically against musl too, and on alpine I believe that is the default.

Windows is another strange case, with two different targets: msvc or gnu (mingw). I'm not an expert on Windows at all, but as I understand it these two toolchains are not compatible (ABI differs, different libc, etc).

In both these cases it means that there could be two different target triplets that might work for your platform. And if your goal is to figure out whst pre-build binary to download from github releases, you would have to check both in case only one of them is provided. For example I only provide static musl builds for paketkoll because of the pain that is glibc backward compatibility. But these will run on a -gnu host too.

Also: Mac might or might not have universal binaries I believe. And Rosetta. But I know nothing about how that works, I haven't owned a mac since the 90s.

macOS has universal binaries, but I do not believe that Rust tools are typically built universal (I don’t think that rustc or crate can do this natively, so there would be some otool or similar shenanigans that would have to happen).

What I was thinking with a rustArch template function is something like this:

  • macOS: rustArch [arm64|amd64] - by default returns the native arch, but can be overridden to the other as appropriate.
  • Windows: rustArch [mscv|mingw] [arm64|amd64|i686] - by default returns the native arch for MSCV, but can be overridden for MinGW and/or arm/x86-64/x86-32 as appropriate.
  • Linux: rustArch [glibc|musl] [arch?] - by default returns the native arch glibc (or musl, maybe) but can be overridden as appropriate. On Alpine (and/or other known musl targets) the default return is musl, not glibc.

We could have a .chezmoi.rustArch that boils down to the default value returned from rustArch, but that doesn’t really allow for alternatives.

Thank you for the deep technical discussion!

Given #3735 (comment), I'll close this issue.