Reputation: 302
My macOS 14.2.1 (Darwin 23.2.0) is arm64
by default. I set up a bunch of x86_64
versions for different apps (have Rosetta 2 set up as well). For example, cmake and Homebrew. But when I call them with arch -x86_64
prefix, the OS cannot find them:
arch -x86_64 cmake
arch: posix_spawnp: cmake: Bad CPU type in executable
The following thing works though:
arch -x86_64 /usr/local/Homebrew/Cellar/cmake/3.31.4/bin/cmake
The same is with the other apps installed for x86_64.
Even when I call arch -x86_64 zsh
and switch my bash to the x86_64 mode, it can't find the paths. When I call
which cmake
It always shows only one path (arm64), either when I'm on arm64 or x86_64 version of zsh:
/opt/homebrew/bin/cmake
Should I manually add all paths to the x86_64 applications to $PATH
or is there a better way to tell the OS to do this automatically?
Upvotes: -1
Views: 68
Reputation: 23820
This is not how slice selection works (which is what the arch
binary and the underlying posix_spawnp
option do). Slice selection works when you have a fat Mach-O with multiple architectures in the same file.
What you have is just different binaries with the same basename in different paths. When you run arch -x86_64 cmake
and /opt/homebrew/bin/cmake
is the first cmake
in your path, then that is equivalent to invoking arch -x86_64 /opt/homebrew/bin/cmake
, but /opt/homebrew/bin/cmake
only has an arm64 slice, so there is no x86_64
slice to select.
One option would be to manually go through all the files that you have compiled for multiple architectures and use lipo
to merge them into fat binaries, then put those in some location in $PATH
that takes precedence over Homebrew - but I imagine this isn't very maintainable.
Another option would be to manually iterate through all matching binaries in $PATH
, check if they have the desired architecture, and then run them. With zsh, this could e.g. be done with whence -pa
and lipo -archs
:
arm64()
{
bin="$1";
shift;
whence -pa "$bin" | while read -r p; do
if lipo -archs "$p" 2>/dev/null | fgrep -q 'arm64'; then
arch -arm64 "$p" "$@";
break;
fi;
done;
}
x86_64()
{
bin="$1";
shift;
whence -pa "$bin" | while read -r p; do
if lipo -archs "$p" 2>/dev/null | fgrep -q 'x86_64'; then
arch -x86_64 "$p" "$@";
break;
fi;
done;
}
Note that this intentionally does not use the -w
flag with (f)grep, so that arm64e
and x86_64h
also count as matches. I'm sure you could combine those two and engineer them into a wrapper around arch
, but if you wanted to support the full set of i386
/x86_64
/x86_64h
/arm64
/arm64e
and -32
/-64
flags, then there are a whole bunch of edge cases and defaults and preference rules that I'm not keen to dig into right now.
Upvotes: 0