question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Native support for Apple Silicon (M1 / arm64 architecture)

See original GitHub issue

What would you like?

The native support of Apple Silicon by distributing an arm64 macos binary, without having to use Rosetta 2 at all.

Solution 1: by distributing two distinct binaries according to the macos architecture (x64 or arm64) Solution 2: by distributing an Universal macOS Binary

This is not a duplicate of https://github.com/cypress-io/cypress/issues/4478 because I am focusing only on Apple Silicon binaries, not ARM Linux binaries in general. This is however a duplicate of https://github.com/cypress-io/cypress/issues/18724 which was closed, but since my request and my proposed solutions are a bit different, I prefer to open a new issue.

Why is this needed?

@baversjo wrote a very good summary in https://github.com/cypress-io/cypress/issues/4478:

Running cypress on an ARM-based M1 mac is pretty slow under rosetta 2. Considering apple no longer seem to selling new intel macs as of q4 2021, I think it’s a pretty important feature to add?

On top of that, I think the workaround explained here https://cypress.io/blog/2021/01/20/running-cypress-on-the-apple-m1-silicon-arm-architecture-using-rosetta-2/ provides a very poor developer experience, having to maintain two different Nodejs installs with Rosetta.

Proposed solutions

My proposed solution relies on the ability of electron-packager, and thus electron-builder to be able to build macos arm64 binaries on an x64 host, therefore not having to deploy custom CircleCI arm runners, as explained here: https://github.com/electron-userland/electron-builder/issues/5689

Solution 1: two distinct binaries: x64 and arm64

electron-builder.json becomes:

{
  [...]
  "mac": {
    "target": {
      "target": "zip",
      "arch": [
        "x64",
        "arm64"
      ]
    },
    [...]
  },
  [...]
}

I tested: instead of creating one zip file (build/build/Cypress-9.4.0-mac.zip), it creates two (build/build/Cypress-9.4.0-mac.zip and build/build/Cypress-9.4.0-arm64-mac.zip). And as you can see, the binaries are built against the correct architecture:

# Executed on an Intel macbook
➜  cypress git:(develop) ✗ yarn binary-build --platform darwin --version $(node ./scripts/get-next-version.js)
# [...]

➜  cypress git:(develop) ✗ lipo -archs build/build/mac/Cypress.app/Contents/MacOS/Cypress
x86_64
➜  cypress git:(develop) ✗ lipo -archs build/build/mac-arm64/Cypress.app/Contents/MacOS/Cypress 
arm64

Then, I suppose we just would have to upload the two zip files, and modify the various mechanisms in place that detect the current arch to download the correct file. At first sight, the only “tricky” part would be having to patch the arch lib used in cli/lib/tasks/download.js (because of https://github.com/feross/arch/issues/19)

Disclamer: I was not able to test the full build process and thus to test the final binaries on both platforms because I am working on a Macbook behind a corporate proxy, so this is very difficult to install all the correct dev dependencies. Also, I am not a contributor yet so I have a very limited knowledge of the project architecture, so maybe I am missing something.

Solution 2: one universal app

In this case electron-builder.json becomes:

{
  [...]
  "mac": {
    "target": {
      "target": "zip",
      "arch": "universal"
    },
    [...]
  },
  [...]
}

And electron-builder builds the app twice, for each arch, and should bundle the two binaries into the same app. Unfortunately, the “merge” phase failed with this error on my side:

  • packaging       platform=darwin arch=universal electron=15.3.4 appOutDir=/var/folders/1v/csfvz7q15w10lvp83zzlp72w0000gp/T/cypress-build/darwin/build/mac-universal
  ⨯ Command failed with a non-zero return code (1):
lipo /private/var/folders/1v/csfvz7q15w10lvp83zzlp72w0000gp/T/electron-universal-YpnsKo/Tmp.app/Contents/Resources/app/node_modules/@cypress/get-windows-proxy/node_modules/registry-js/build/Release/registry.node /private/var/folders/1v/csfvz7q15w10lvp83zzlp72w0000gp/T/cypress-build/darwin/build/mac-universal--arm64/Cypress.app/Contents/Resources/app/node_modules/@cypress/get-windows-proxy/node_modules/registry-js/build/Release/registry.node -create -output /private/var/folders/1v/csfvz7q15w10lvp83zzlp72w0000gp/T/electron-universal-YpnsKo/Tmp.app/Contents/Resources/app/node_modules/@cypress/get-windows-proxy/node_modules/registry-js/build/Release/registry.node

fatal error: /Library/Developer/CommandLineTools/usr/bin/lipo: /private/var/folders/1v/csfvz7q15w10lvp83zzlp72w0000gp/T/electron-universal-YpnsKo/Tmp.app/Contents/Resources/app/node_modules/@cypress/get-windows-proxy/node_modules/registry-js/build/Release/registry.node and /private/var/folders/1v/csfvz7q15w10lvp83zzlp72w0000gp/T/cypress-build/darwin/build/mac-universal--arm64/Cypress.app/Contents/Resources/app/node_modules/@cypress/get-windows-proxy/node_modules/registry-js/build/Release/registry.node have the same architectures (x86_64) and can't be in the same fat output file  failedTask=build stackTrace=Error: Command failed with a non-zero return code (1):
lipo /private/var/folders/1v/csfvz7q15w10lvp83zzlp72w0000gp/T/electron-universal-YpnsKo/Tmp.app/Contents/Resources/app/node_modules/@cypress/get-windows-proxy/node_modules/registry-js/build/Release/registry.node /private/var/folders/1v/csfvz7q15w10lvp83zzlp72w0000gp/T/cypress-build/darwin/build/mac-universal--arm64/Cypress.app/Contents/Resources/app/node_modules/@cypress/get-windows-proxy/node_modules/registry-js/build/Release/registry.node -create -output /private/var/folders/1v/csfvz7q15w10lvp83zzlp72w0000gp/T/electron-universal-YpnsKo/Tmp.app/Contents/Resources/app/node_modules/@cypress/get-windows-proxy/node_modules/registry-js/build/Release/registry.node

I didn’t have time to debug further.

Which solution should we choose?

I am not a Mac developer so I don’t know what is the best practice here. However, I was not able to test but if I understand well, the merged binary size should double in solution 2. This is why I think solution 1 is preferable in my opinion. And since all the arch detection/distribution is already in place in the project, it should not be difficult to implement.

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Reactions:61
  • Comments:22 (4 by maintainers)

github_iconTop GitHub Comments

45reactions
xegercommented, Apr 8, 2022

Just a comment that the workaround (using Rosetta2 + multiple node installs) is an intractable mess.

  • The Cypress launcher frequently crashes with IPC issues
  • Startup time is atrocious
  • The amd64 browser gets slower constantly, and consumes more memory, until I need to restart after 15 minutes

Please do not let perfect become the enemy of good – give us a native ARM option even if you cannot test it adequately! Even if the default is AMD64 I need to perform some special step to install the ARM binary, I am happy to do that.

The developer experience with Cypress under the status quo is simply not sustainable – my developers will lose even more confidence in this tool if I force them to deal with crashes, memory leaks and slowness in addition to all of Cypress’ flakey test issues.

24reactions
edikdeislingcommented, May 26, 2022

Been waiting for this feature too. For now, my workaround is(thx for @thomvaill):

  1. Clone Cypress repo

  2. git checkout tags/v9.5.4

  3. yarn

  4. Change electron-builder.json image

  5. yarn binary-build --platform darwin --version 9.5.4

  6. mkdir -p ~/Library/Caches/Cypress/9.5.4

  7. cp -R build/build/mac-arm64/* ~/Library/Caches/Cypress/9.5.4

After that I have Cypress that works well

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to make an M1-only (native-only) app? - Apple Developer
I found the answer: there was a User-Defined value for VALID_ARCHS which was set to x86_64. I added arm64 to this, and I'm...
Read more >
Addressing Architectural Differences in Your macOS Code
Fix problems that stem from architectural differences between Apple silicon and Intel-based Mac computers.
Read more >
Porting Your macOS Apps to Apple Silicon
Port your existing macOS app to Apple silicon by creating a universal binary and modifying your code to handle architectural differences.
Read more >
Building a Universal macOS Binary - Apple Developer
A universal binary runs natively on both Apple silicon and Intel-based Mac computers, because it contains executable code for both architectures. Turn all...
Read more >
Mac computers with Apple silicon
MacBook Pro (13-inch, M1, 2020). On Mac computers with Apple silicon, About This Mac shows an item labeled Chip, followed by the name...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found