-
Notifications
You must be signed in to change notification settings - Fork 77
run.sh: force MacOs to run the executable natively when on Apple Silicon #79
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
run.sh: force MacOs to run the executable natively when on Apple Silicon #79
Conversation
# CPUs for Apple Silicon are in the format "Apple M.." | ||
cpu_type="$(sysctl -n machdep.cpu.brand_string)" | ||
case "${cpu_type}" in | ||
Apple*) | ||
is_apple_silicon=1 | ||
;; | ||
esac |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My understanding is that on Intel Macs this would be something like Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
.
I don't have an Intel Mac to test this but I've reached out to a mate with one to check the output as a sanity check
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe uname -m
would work? Is there a world where this matches on Linux?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The uname
shipped with MacOS is also a universal binary so it falls into the same pitfalls where it'll just run it via Rosetta and return x86_64.
Could run it via arch
and ARCHPREFERENCES
like the main executable but I'm not actually sure if the arch
command shipped on Intel Macs behaves the same without throwing a fit. Will have someone who has an Intel Mac check this.
Is there a world where this matches on Linux?
My understanding is that machdep
is an Apple only namespace, plus this is in the *Darwin*)
branch so linux wouldn't reach here.
|
||
exec "$executable_path" "$@" | ||
if [ -n "${is_apple_silicon}" ]; then | ||
export ARCHPREFERENCE="arm64,x86_64" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From man arch
:
ENVIRONMENT The environment variable ARCHPREFERENCE can be used to provide architecture order preferences. It is checked before looking for the corresponding property list file. ... ARCHPREFERENCE Values i386,x86_64,x86_64h,arm64,arm64e A specifier that matches any name.
This tells arch to prefer arm64
and only fallback to x86_64
if arm64
is not suitable for this executable.
This works as expected regardless of whether the executable is universal, arm64 or solely x86_64.
assets/nix/run.sh
Outdated
# the executable is universal, supporting both x86_64 and arm64, MacOs will still run it as x86_64 | ||
# if the parent process is running as x86. | ||
# arch also strips the DYLD_INSERT_LIBRARIES env var so we have to pass that in manually | ||
arch -e DYLD_INSERT_LIBRARIES=$DYLD_INSERT_LIBRARIES "$executable_path" "$@" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wasn't able to find concrete docs on DYLD_INSERT_LIBRARIES
being stripped here but my guess it's done so that you don't try to run an arm64 process with a x86_64 preload so the setting has to be explicit.
Without this the env var is null
in the main exec and the dylib doesn't get loaded at all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't $DYLD_INSERT_LIBRARIES
be in quotes, or is there no chance of it having a space? Also I couldn't find docs on the -e switch from a quick search, is this macos-only?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, fixed: d4b21af
And yeah looks like -e
is macOS only - the macOS arch
version seems to have a bunch of other functionality. Here's the full dump of the man page.
From man arch
:
-e envname=value Assigns the given value to the named environment
variable in the environment that will be passed
to the command to be run. Any existing
environment variable with the same name will be
replaced.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it should be fine, but I have no way of testing it so multiple people will have to test this on Linux and MacOS before it can be merged.
# CPUs for Apple Silicon are in the format "Apple M.." | ||
cpu_type="$(sysctl -n machdep.cpu.brand_string)" | ||
case "${cpu_type}" in | ||
Apple*) | ||
is_apple_silicon=1 | ||
;; | ||
esac |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe uname -m
would work? Is there a world where this matches on Linux?
assets/nix/run.sh
Outdated
# the executable is universal, supporting both x86_64 and arm64, MacOs will still run it as x86_64 | ||
# if the parent process is running as x86. | ||
# arch also strips the DYLD_INSERT_LIBRARIES env var so we have to pass that in manually | ||
arch -e DYLD_INSERT_LIBRARIES=$DYLD_INSERT_LIBRARIES "$executable_path" "$@" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't $DYLD_INSERT_LIBRARIES
be in quotes, or is there no chance of it having a space? Also I couldn't find docs on the -e switch from a quick search, is this macos-only?
eb008b9 updates to calling arch via Tested with a small Without exec |
This is a fix for #78 which updates
run.sh
to usearch
instead ofexec
when on Apple Silicon to allow the executable to run natively when the run script is invoked from a process running on Rosetta.I've tested the script itself somewhat thoroughly with a custom exec and custom dylib for injection to confirm that both the executable is ran natively and there's no impact to environment variables. This was done with x86_64, arm64, and universal versions of the exec as well as laughing the script directly from a terminal running natively & via Rosetta and having another process run the script via exec'ing
sh
. In all cases the executable and dylib were loaded natively as arm64.e.g. running a small x86_64
summon
executable via Rosetta that just usesexecvp
to run the script.Also tested practically with doorstop and BepInEx 5 running Silksong through Steam - the game launches natively with BepInEx loading all expected plugins meaning doorstop was successful.
The main thing I'm not sure about if any special handling is needed for the
Special case: program is launched via Steam
case - I've been laughing the game via Steam with launch options but I don't think it applied here, not sure if that might be only for Linux?