Description
Context/Setup
- MacOS 14
- An ARM/M1/2 MacOS environment.
- Rosetta installed.
- Puppet-bolt installed via
brew install --cask puppetlabs/puppet/puppet-bolt
, the suggested install method.- An important note: for whatever reason, puppet labs does not provide a bolt installer for
arm64
, and only provides anx86_64
installer:https://downloads.puppet.com/mac/puppet-tools/12/x86_64/puppet-bolt-3.27.4-1.osx12.dmg
at the time of this writing. This means thatbolt
will run via Rosetta in x86 emulation mode.
- An important note: for whatever reason, puppet labs does not provide a bolt installer for
- A puppet-bolt project which ncludes this module in its dependencies.
- A puppet manifest which invokes this module to install any toolchain/target.
- No pre-existing rustup/rust/cargo installation or materials anywhere on the system (
rustup self uninstall
followed byrm -rf ~/.rustup ~/.cargo
should reset things to this state, albeit somewhat destructively).
To reproduce
- Using bolt, apply a manifest that uses this module. For example (given your user name as
$USER
):
> bolt apply --target localhost --run-as root --execute 'rustup { "$USER": toolchains => ["nightly-aarch64-apple-darwin"], targets => ["aarch64-apple-darwin"] }'
- Check the file type of cargo with
file $(which cargo)
.
Expected behavior:
cargo
and rustc
report file types matching the host architecture. For an ARM mac that would look like
> file $(which cargo)
/Users/$USER/.cargo/bin/cargo: Mach-O 64-bit executable arm64
> file $(which rustc)
/Users/$USER/.cargo/bin/rustc: Mach-O 64-bit executable arm64
Observed behavior
> file $(which cargo)
file $(which cargo)
/Users/$USER/.cargo/bin/cargo: Mach-O 64-bit executable x86_64
> file $(which rustc)
/Users/$USER/.cargo/bin/rustc: Mach-O 64-bit executable x86_64
Why this matters
So what happens if cargo
is a non-native architecture?
- That does not affect
cargo
's build behavior. It andrustc
will still compile/cross-compile Rust code normally according to the targets configured inrustup
and will produce binaries of the selected architecture. - Medium severity:
cargo
andrustc
will run unusually slowly on MacOS due to the presence of binary emulation translating the x86_64 binaries into arm64 code. - High severity: programs launched by
cargo
and their subprograms will prefer to launch x86 programs on MacOS. In other words, ifcargo run
or some Cargo plugin runs a universal binary on the system (like, saysudo
), that subprogram will run in x86 mode. Even if spawned subprograms do not support x86 execution (in which case cargo will spawn them as arm64), those programs' spawned subprocesses will still run preferring x86 execution.
That last one can cause problems. I encountered one such issue where the cargo flamegraph
plugin supplied by flamegraph-rs
runs its inner dtrace
process as x86, causing dtrace
to fail when it traced arm64 processes. The bug report for that issue is here, and I blogged about the discovery process of this issue here.
Given that rustup/cargo
installations can persist untouched for long periods of time, and given that the main compiler suite still works, I think it's likely that incorrect-architecture installations of cargo/rustc by this module persist without users' knowledge in many cases, silently causing slowdowns and occasionally causing louder issues like the above.
Suggested resolution
When this module bootstraps cargo
with the rustup
resource, or when it installs a per-toolchain cargo
via the rustup::toolchain
resource, it should allow user specification of the architecture to those resources.
The new architecture =>
or toolchain_architecture =>
parameter that users can specify should, if unspecified, default to the invoking machine's native architecture via the "architecture" fact.
When this module invokes subprograms internally, they should be wrapped in the arch command to force the architecture as requested by the user.
This behavior need only be present on MacOS, as other platforms do not do multiarch/binfmt translation in the same way (and the issue is much more common on MacOS than on free operating systems due to the frequently limited availability of source builds, as is the case with puppet-bolt
in this case: only an x86_64 binary installable is provided, and build steps for creating a correct executable are not readily available).