Skip to content
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

Apple Silicon/M1 Support #357

Closed
tusing opened this issue Dec 21, 2020 · 60 comments
Closed

Apple Silicon/M1 Support #357

tusing opened this issue Dec 21, 2020 · 60 comments

Comments

@tusing
Copy link

tusing commented Dec 21, 2020

It would be fantastic if we could get a version compiled and optimized for Apple Silicon.

(I believe this would require an upgrade to Electron 11.)

@tusing tusing changed the title Version for Apple Silicon/M1 Macs Apple Silicon/M1 Support Dec 21, 2020
@vladimiry
Copy link
Owner

vladimiry commented Dec 21, 2020

The recent app release is based on Electron v11.1.0. I can't guarantee proper work on Apple Silicon hardware nor on macOS in general since I don't possess sold-by-apple devices. The released app versions go through the e2e/spectron tests executed on Linux/macOS/Windows systems which is the way I used to verify that the app is functioning on the macOS system.

@vladimiry
Copy link
Owner

vladimiry commented Dec 22, 2020

Ideally, I need GitHub Actions to support Apple-Silicon-based environment (which unlikely to happen any time soon), so I could compile the native dependencies and test the basic app functionality on the system close to end-user systems. Although it appears that Xcode 12.2+ is already supported there so I guess things might go well if I just compile arm arch using the recent electron-builder version which supports @electron/universal thing.

@vladimiry
Copy link
Owner

vladimiry commented Jan 18, 2021

This will be wontfix for now since I won't be able to verify things when/if I play around the issue.

@badwulfy
Copy link

badwulfy commented Sep 12, 2021

I know you don't plan to support officially M1, but by curiosity I tried to build an arm64 version of Electronmail on my M1 Macbook and it succeed.
First, I did some edit in package.json to change the architecture to arm64. Then I used the usual way to build the app as said on the readme of the project.
The app work flawlessly and smoothly. I created a gist with the DMG and the diff in package.json is someone is interested : https://gist.github.com/badwulfy/90d6e2596fe7f14019f2330ff007fd85

Then I tried to do the same build procedure on an Intel Mac. The build succeed, but I wasn't able to run on my M1 Mac (crashed immediately). I have not yet investigated further. If someone has an idea, I'm interested.

@vladimiry
Copy link
Owner

@badwulfy thanks for the report. Yes, the process should not be complex but I still tend to avoid adding support for M1 primarily because I'd like to be able to test things at my side at least initially.

Then I tried to do the same build procedure on an Intel Mac. The build succeed, but I wasn't able to run on my M1 Mac (crashed immediately).

There are native dependencies involved that get compiled from code sources during the app package assembling process. That might be the cause.

If your app has native dependency, it can be compiled only on the target platform unless prebuild is not used.

@badwulfy
Copy link

For people interested, I published an M1 build of the version 4.12.8 in the release page on my "fork" (used only to build the app). https://github.com/badwulfy/ElectronMail/releases/tag/v4.12.8

I plan to automate build with github actions when I'll have time.

@vladimiry
Copy link
Owner

I published an M1 build of the version 4.12.8

I'd recommend to wait for #443 resolving in 4.12.9.

@badwulfy
Copy link

I had not seen the issue. I just built the new version 4.12.9 : https://github.com/badwulfy/ElectronMail/releases/tag/v4.12.9
Thanks for pointing it out.

@macbugs
Copy link
Contributor

macbugs commented Mar 21, 2022

I created a gist with the DMG and the diff in package.json if someone is interested

I applied the patch, but the build of current version still fails, as some script is missing...

% npm run electron-builder:dist

> electron-mail@4.12.7 electron-builder:dist
> npm exec --package=ts-node -- ts-node --files --require tsconfig-paths/register ./scripts/electron-builder/run-with-default-evn-vars.ts --arm64 --publish never

node:internal/modules/cjs/loader:936
  throw err;
  ^

Error: Cannot find module './run-with-default-evn-vars.ts'

@ylluminate
Copy link

Anyone having any luck here yet with Apple Silicon build automation?

@ajgraves
Copy link

ajgraves commented May 5, 2022

Came to check on M1/arm64 support for macOS, and subscribing (even though this is closed). Hoping some traction can be made here, as Electron apps running under Rosetta 2 are nowhere near as performant as Electron apps for M1/arm64.

@ylluminate
Copy link

Too true. Electron and Chromium based apps are indeed horrible on Rosetta.

@macbugs
Copy link
Contributor

macbugs commented May 11, 2022

Oh well, same problem here 😉

@ylluminate
Copy link

ylluminate commented Jul 13, 2022

@vladimiry any chance you might be able to look over the situation more closely and offer an updated estimate of where things stand now? (eg, does this help?: https://github.com/electron/universal/releases)

@vladimiry
Copy link
Owner

I'm generally avoiding macOS-specific tasks, primarily because not able to test stuff at my side. But I could pull the trigger on this one if you will be ready to test the build.

@ylluminate
Copy link

More than happy to test anytime you're ready @vladimiry.

@vladimiry vladimiry reopened this Jul 13, 2022
@vladimiry
Copy link
Owner

vladimiry commented Jul 13, 2022

The test build is uploaded here. The file to test is electron-mail-5.0.2-mac-universal.dmg. If possible, run the tests on both M1 and non-M1 laptops.

@ylluminate
Copy link

Thanks so much @vladimiry!

The x64 (electron-mail-5.0.2-mac-x64.dmg) works fine - just as always without any noticeable changes. It does indeed show up as "Intel" mode in Activity Monitor.

When I attempt to run the Universal version (electron-mail-5.0.2-mac-universal.dmg), I receive the following error:

A JavaScript error occurred in the main process
Uncaught Exception:
Error: dlopen(/Applications/ElectronMail.app/Contents/Resources/app.asar.unpacked/node_modules/sodium-native/build/Release/sodium.node, 0x0001): tried: '/Applications/ElectronMail.app/Contents/Resources/app.asar.unpacked/node_modules/sodium-native/build/Release/sodium.node' (mach-o file, but is an incompatible architecture (have (x86_64), need (arm64e)))
at process.func [as dlopen] (node:electron/js2c/asar_bundle:5:1812)
at Module._extensions..node (node:internal/modules/cjs/loader:1203:18)
at Object.func [as .node] (node:electron/js2c/asar_bundle:5:2039)
at Module.load (node:internal/modules/cjs/loader:988:32)
at Module._load (node:internal/modules/cjs/loader:829:12)
at c._load (node:electron/js2c/asar_bundle:5:13343)
at Module.require (node:internal/modules/cjs/loader:1012:19)
at require (node:internal/modules/cjs/helpers:102:18)
at load (/Applications/ElectronMail.app/Contents/Resources/app.asar/node_modules/node-gyp-build/index.js:22:10)
at Object.<anonymous> (/Applications/ElectronMail.app/Contents/Resources/app.asar/node_modules/sodium-native/index.js:1:39)

I do, however, see the app still running as an "Apple" mode app within Activity Monitor, so you do appear to be close.

When in /Applications/ElectronMail.app/Contents/MacOS file shows:

$ file ElectronMail
ElectronMail: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit executable x86_64Mach-O 64-bit executable x86_64] [arm64:Mach-O 64-bit executable arm64Mach-O 64-bit executable arm64]
ElectronMail (for architecture x86_64):	Mach-O 64-bit executable x86_64
ElectronMail (for architecture arm64):	Mach-O 64-bit executable arm64

It appears that other frameworks show similar results via file.

Any additional details I might provide?

@vladimiry
Copy link
Owner

Any additional details I might provide?

If you have a non-M1 laptop, but Intel-based, try electron-mail-5.0.2-mac-universal.dmg on it.

so you do appear to be close

Just asked electron-builder to prepare a "universal" build. Unfortunately, it didn't work out, even though there were no errors during the packaging process:

  > npm exec --package=electron-builder -- electron-builder --universal --publish never
  
    • electron-builder  version=23.3.1 os=20.6.0
    • loaded configuration  file=/Users/runner/work/ElectronMail/ElectronMail/electron-builder.yml
    • rebuilding native dependencies  dependencies=keytar@7.9.0, msgpackr-extract@2.0.2, sodium-native@3.3.0, spellchecker@3.7.0 platform=darwin arch=x64
    • install prebuilt binary  name=keytar version=7.9.0 platform=darwin arch=x64 napi= 
    ⨯ cannot find prebuild-install  
    • packaging       platform=darwin arch=x64 electron=19.0.8 appOutDir=dist/mac-universal--x64
    • downloading     url=https://github.com/electron/electron/releases/download/v19.0.8/electron-v19.0.8-darwin-x64.zip size=82 MB parts=6
    • downloaded      url=https://github.com/electron/electron/releases/download/v19.0.8/electron-v19.0.8-darwin-x64.zip duration=2.287s
    • rebuilding native dependencies  dependencies=keytar@7.9.0, msgpackr-extract@2.0.2, sodium-native@3.3.0, spellchecker@3.7.0 platform=darwin arch=arm64
    • install prebuilt binary  name=keytar version=7.9.0 platform=darwin arch=arm64 napi= 
    ⨯ cannot find prebuild-install  
    • packaging       platform=darwin arch=arm64 electron=19.0.8 appOutDir=dist/mac-universal--arm64
    • downloading     url=https://github.com/electron/electron/releases/download/v19.0.8/electron-v19.0.8-darwin-arm64.zip size=79 MB parts=6
    • downloaded      url=https://github.com/electron/electron/releases/download/v19.0.8/electron-v19.0.8-darwin-arm64.zip duration=1.413s
    • packaging       platform=darwin arch=universal electron=19.0.8 appOutDir=dist/mac-universal

So the only thing I could try for now is disabling mergeASARs flag, so a new build is coming (it's not going to help though I guess).

@ylluminate
Copy link

I did indeed ask for some feedback from someone with an Intel Mac, should hear back soon.

Hmmmmmmm.... It seems perhaps there is something going on with the arm64 vs arm64e ABI situation... Hmmmm.

@vladimiry
Copy link
Owner

Ideally, I need GitHub Actions to support Apple-Silicon-based environment (which unlikely to happen any time soon), so I could compile the native dependencies and test the basic app functionality on the system close to end-user systems.

Besides, I guess it's impossible to properly compile arm64 native modules on non-M1 system (currently using macos-latest GitHub Actions runner). The CI system is yet to support M1 silicon runner (also see actions/runner-images#2187).

@ylluminate
Copy link

Hmm, this is interesting/strange. I'll need to check with another project I work with to see how the CI guys are generating their Apple Silicon binaries on GH Actions runner...

I suppose one option could be to just outline an "Apple Silicon Build Instructions" sections on the front page and I could test that out and we could iterate and refine it to get it working such that any Apple Silicon users that want it could build our own with a clean process (and I could probably get someone to make a MacPorts formula to make it simpler).

@vladimiry
Copy link
Owner

vladimiry commented Jul 13, 2022

I suppose one option could be to just outline an "Apple Silicon Build Instructions" sections on the front page and I could test that out

It should be almost the same process as currently listed in the readme expect for the final/packaging step where you set --arm64 or --universal option (use master branch):

  • pnpm install --frozen-lockfile
  • pnpm run app:dist
  • pnpm run clean:prebuilds && npm exec --package=electron-builder -- electron-builder --arm64 --publish never (also try --universal instead of --arm64 if you want)

If you want to skip building the @ProtonMail stuff (I'd recommend), foremost unpack the proton-clients-artifact file to the project folder. The file listed at the page bottom on the https://github.com/vladimiry/ElectronMail/actions/runs/2514834063 page (prebuilt @ProtonMail clients of the latest release).

You could also skip the pnpm run app:dist step by unpacking the app-artifact-macOS file to the project folder (located on the same above-listed page). So no app/proton building steps but just packaging.

@mafintosh
Copy link

sodium should def work on m1. Are you sure electron-rebuild isn’t rebuilding it? That’s normally what goes wrong for users, instead of using the prebuild

@vladimiry
Copy link
Owner

vladimiry commented Jul 14, 2022

Going to trigger a new build on macos-12 CI system, just in case.

A new build to test is uploaded here.

Are you sure electron-rebuild isn’t rebuilding it?

All the native deps in this project by design get compiled on the packaging stage (triggered by electron-builder => rebuild --verbose keytar@7.9.0 msgpackr-extract@2.0.2 sodium-native@3.3.0 spellchecker@3.7.0 and so on). It's used to work well on x64 arch systems, but now we are trying to ship arm64 build. I explicitly drop the prebuild-install module and existing prebuilds. I understand that it complicates things for developers, but I'm ok to maintain it this way. The issue is that I don't have M1 hardware to test stuff at my side.

@vladimiry
Copy link
Owner

vladimiry commented Jul 14, 2022

Btw, there are other sodium bindings available, including rust-based. So the last resort is replacing "sodium-native" with something else (I'd prefer a native module vs wasm-based solution). But it's successfully used in the project from day one (~5 years), and it's confirmed as working on arm64 arch, so I'd like to keep it here.

@ylluminate
Copy link

A new build to test is uploaded here.

Sorry, another crash report:
https://p153.p0.n0.cdn.getcloudapp.com/items/o0uGJm6n/19ab666b-1cf1-4276-852b-0e36f31d4633.txt

@vladimiry
Copy link
Owner

vladimiry commented Jul 14, 2022

Thanks. It looks the same, Code 4 Symbol missing, related to libsodium.node.

I've just compared sodium.node size of x64/arm64, and it's 999584/318312, which looks suspicious (3x difference). So I think I should get it to the stage when arm64 libsodium.node size looks similar to x64 and only then ask to test the build again.

@mafintosh
Copy link

sodium is already prebuilt for all platforms, all in the installed bundle. I’d strongly suggest just not to rebuild it, you’ll probably only run into trouble.

@vladimiry
Copy link
Owner

vladimiry commented Jul 14, 2022

@mafintosh yep, I know that it's coming with prebuilds, and thanks for the warning. Still going to keep fighting it for a while (it works well on x64 arch after all without troubles). It generally feels better when I know how and can replicate the compiling at my side. It's about better control on things. For example, there were cases when prebuilds of some native deps were shipped in a sort of doubtful state, so I had to improve things a little (like specifying MACOSX_DEPLOYMENT_TARGET and lowering the Linux version to get as many old systems as possible compatible with "glibc" lib).

@mafintosh
Copy link

For sure. We do all of that already 🙂 Are you rebuilding for arm and x64 on the same macbook?

@vladimiry
Copy link
Owner

For sure. We do all of that already

Yep, I know (briefly looked into it before). I didn't mean your lib.

Are you rebuilding for arm and x64 on the same macbook?

I don't have any apple laptops (none of intel/m1 based). So it's just GH CI system, and then I ask guys to test stuff 😓 Yes, this sounds like a terrifying dev experience, so I normally avoid handling the macOS-specific tasks 😄

@mafintosh
Copy link

I had tons of trouble building for arm on GH so we actually do those manually with an macbook mini in our office. The sodium build is downloading the sodium static lib from the official sodium site when building. Maybe it's pulling down the wrong static build? How are you building it for arm?

@vladimiry
Copy link
Owner

vladimiry commented Jul 14, 2022

How are you building it for arm?

Same way for all builds, via electron-builder. It then triggers npm rebuild --verbose keytar@7.9.0 msgpackr-extract@2.0.2 sodium-native@3.3.0 spellchecker@3.7.0 command (weird, but there is no --arch=arm64 arg, maybe this is the issue), which triggers the install package script, which I guess then with a support of node-gyp does the trick. Currently trying some idea. If it doesn't work out, I guess I will be trying to trigger the build like described in https://www.electronjs.org/docs/latest/tutorial/using-native-node-modules So direct node-gyp rebuild call (used this way before for other modules when was testing things, and it worked well).

The sodium build is downloading the sodium static lib from the official sodium site when building.

Yep, I've noticed that node deps/bin.js trigger is specified in binding.gyp.

@mafintosh
Copy link

How does electron-builder signal that it wants to rebuild for arm64 when running on x64?

@vladimiry
Copy link
Owner

vladimiry commented Jul 14, 2022

How does electron-builder signal that it wants to rebuild for arm64 when running on x64?

It has an arg for this purpose and the log says that arm64 build takes place. I've noticed in the log, though, that the npm rebuild --verbose command executed without the --arch=arm64 arg. So, maybe I should explicitly set the npm_config_arch + npm_config_target_arch env vars or patch the electron-builder a little (although, I think it has a working arm64 support as it's widely used and "universal" build support is already there for a while).

@mafintosh
Copy link

Could you try setting the PREBUILD_ARCH=arm64 env var when building for arm64? That is used here https://github.com/sodium-friends/sodium-native/blob/master/deps/bin.js#L29

@vladimiry
Copy link
Owner

vladimiry commented Jul 14, 2022

Ok, I've set PREBUILD_ARCH=arm64 and also npm_config_arch=npm_config_target_arch=arm64 just in case and triggered the CI build (maybe it should have been just npm_config_target_arch, without npm_config_arch). Let's see if it helps.

@ylluminate
Copy link

Just an FYI, it seems that a lot of Chinese users are using the arm64e ABI, which Apple, for some reason, seems to have turned on at large in Asia vs arm64 in the rest of the world (it would seem at least)...

@vladimiry
Copy link
Owner

It appears that I might need to append the CFLAGS env var with -target arm64-apple-macos11 for arm64 build executed on x64 system.

@vladimiry
Copy link
Owner

vladimiry commented Jul 15, 2022

I got the sodium.node file size increased 318312 => 585912 (the size is now similar to the size of the prebuild file version), so this might be it. The build is uploaded here. If the build runs well, I will post then what needed to be done to make the sodium-native/libsodium cross compiling work on GH CI system.

@badwulfy
Copy link

It runs well without issues ! 🎉

The only thing I had to do before being able to run it was the command "xattr -r -d com.apple.quarantine /Applications/ElectronMail.app". Before MacOS said it was "corrupted", but I think it is because your build is not notarised.

@vladimiry
Copy link
Owner

vladimiry commented Jul 15, 2022

Ok, this is what I did to make it work. The issue was about compiling sodium-native/libsodium native dep, the rest of them didn't demonstrate any issues. The sodium-native/deps/bin.js explicitly triggers libsodium compilation without complete cross compiling respecting, if I got it right. So it works if the arch of both build and target systems is the same, but not if those are different (cross compiling case).

  • I first made the GH CI build the native deps using direct node-gyp call, as described in https://www.electronjs.org/docs/latest/tutorial/using-native-node-modules. This way is easier for me when I need to test/debug native deps related things than using some wrappers (there are many of them, not just electron-builder install-app-deps). The https://github.com/vladimiry/ElectronMail/blob/wip/scripts/ci/prepare-native-deps.ts script handles this task.
  • I extended the CFLAGS env var with -target arm64-apple-macos11 -arch arm64 value. I think the -arch arm64 part might be unnecessary here, didn't try to drop it yet. After applying this change, I started getting the following error:
    configure: error: cannot run C compiled programs.
    If you meant to cross compile, use `--host'.
    See `config.log' for more details
    
  • So I added the --host=arm64-apple-darwin arg to the ./configure call via the module patching. Having applied this change, I started facing another error:
    Invalid configuration `arm64-apple-darwin': machine `arm64-apple' not recognized
    configure: error: /bin/sh build-aux/config.sub arm64-apple-darwin failed
    
  • I added the ./autogen.sh -s call before the ./configure call (using the same "module patching" approach). This call updates the libsodium/build-aux/config.sub file (committed to the repo version is quite outdated, ie knows nothing about the arm64 arch). Things finally got compiled without errors.

I had tons of trouble building for arm on GH so we actually do those manually with an macbook mini in our office.

@mafintosh, so with some effort, the cross compiling works for the sodium-native module on GH CI x64-macos image. I guess you might want to consider switching to the GH CI based prebuilds compiling. Aside from other matters (like saving your time via automation), this would enable a reproducible build scenario for prebuild binaries compiling. And if you print result binaries hashsums to the CI output, the module consumers if needed will be able to verify that the binaries got actually compiled at the CI system from the actual sources vs on-premise/manual compilation (manual scenario might potentially include unintentionally/or-unlikely-intentionally injected malicious stuff for example due to the compromised local system, etc). Unfortunately, github/roadmap#528 is still unresolved, so at the moment it's impossible to run proper e2e tests on GH CI for arm64 binaries.

@ylluminate
Copy link

WOWOWOWOW @vladimiry! The difference is night and day. I am now going to be able to use ElectronMail again without grunting and agonizing about needing to do it for 5 minutes before even clicking the icon to start it up!

Smooth as butter now!!!!! ❤️❤️❤️❤️❤️❤️❤️❤️❤️

@vladimiry
Copy link
Owner

vladimiry commented Jul 16, 2022

without grunting and agonizing about needing to do it for 5 minutes before even clicking

I don't believe M1 hardware is so slow in a virt. mode. Anyway, thanks for testing this smooth butter stuff. Closing as resolved then. Next release coming with 2 macos builds.

@ylluminate
Copy link

ylluminate commented Jul 16, 2022

Thank you again. I have a pretty heavy load with a lot of apps open and pushing the limits of max mem config for my system model. There's an enormous speed difference in these burdened configurations. You might be right for lower load systems, but for folks like me this makes all the difference @vladimiry.

@vladimiry
Copy link
Owner

Well, yes, I understand that squeezing more juice from the same hardware always causes a good feeling.

PS I already know what it's like to use slow hardware on a daily basis. But I'm going to refresh this feeling since going to try switching to an ancient but fanless laptop.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants