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

Mac M1 Arm, and architecture override #2743

Closed
bartoszhernas opened this issue Feb 14, 2022 · 21 comments · Fixed by #2777
Closed

Mac M1 Arm, and architecture override #2743

bartoszhernas opened this issue Feb 14, 2022 · 21 comments · Fixed by #2777
Labels
OS: Mac OS pull request wanted This is a great way to contribute! Help us out :-D

Comments

@bartoszhernas
Copy link

bartoszhernas commented Feb 14, 2022

Hi,

I have used NVM just when the M1 processors came out. Back then the NVM was returning 404 on binary download and then compiling node by itself. This was not ideal (built binaries would be better) but still ok.

Fast forward to now, rest of my team got the M1 macbooks, they followed my steps of nvm and node installation. We are still on v14, because v15 is not supported by some of our packages, and v16 is not working with Realm.

Imagine my surprise when their environment does not work. We pinpointed the issue to them having x86 node binaries, instead of arm64 ones (as me and our M1 CI has had for months now).

After day of searching for the issue, and not understanding why even the 15.3 which is officially supported arm version of node is not properly installing.

Only then I have found out the culrpit: NVM is overriding architecture for any Node version below 16.

I would vote to remove this as this is hidden, unintended side-effect and changes previous behaviour. In my opinion if I want to install 15.3 and you cannot find binaries, it's better to compile it on device instead of returning me a wrong binary (Intel one).

@ljharb
Copy link
Member

ljharb commented Feb 14, 2022

node itself doesn’t support arm below v16, except with Rosetta, afaik. If this is incorrect, the exact version logic can be tweaked.

I’m not sure why compiling it would be better than using a Rosetta binary?

@bartoszhernas
Copy link
Author

bartoszhernas commented Feb 14, 2022

node itself doesn’t support arm below v16, except with Rosetta, afaik. If this is incorrect, the exact version logic can be tweaked.

From what we have seen node14 and up support arm, or at least works out of the box. Early versions of node14 had some issues with memory while running node in chromium (electron) and were crashing hard, but that was fixed in minor version and compiled binary is native arm one and works great.
node 15.x supported: nodejs/build#2474 (comment)
node 14.x supported: nodejs/build#2474 (comment)

The problem for us is that we are running Electron application with Realm database. Electron supports arm64 out of the box. Realm requires native binaries that are the same arch as Electron.

While installing Node14 from source, or Node15 as well, the binary that comes out is arm64 binary:

> file /Users/bartoszhernas/.nvm/versions/node/v16.14.0/bin/node
/Users/bartoszhernas/.nvm/versions/node/v16.14.0/bin/node: Mach-O 64-bit executable arm64

If you try to install the same version from binary, because of NVM overriding the arch variable, the x86_64 version is being installed. Sounds good, it should work with Rosetta, and that being partially true, most of things do work ok.

In out case however, the Electron was starting, and then our main app was throwing error that Realm requires arm64 binaries, and got x86_64 instead. I believe it was due to node, and hence npm/yarn to install wrong binaries for Realm.

Error:
dlopen(/Users/tomaszwlodarczyk/Tomasz/Work/FYM/app/main/node_modules/realm/build/Release/realm.node, 0x0001): tried:
/Users/tomaszwlodarczyk/Tomasz/Work/FYM/app/main/node_modules/realm/build/Release/realm.n
ode' (mach-o file, but is an incompatible architecture (have '×86_64', need 'arm64e')),
/sr/local/lib/realm.node' (no such file), /sr/lib/realm.node' (no such file)

The problem then sums up to: some tooling takes the arch of the system, and some other tooling takes the arch of the node process and mess occurs. Seems that compiled version of node 14.x and 15.x do support M1 ARM

@njzydark
Copy link

njzydark commented Mar 1, 2022

This installation behavior did change on version 0.39.1, so if you need to compile from source, you can use this installation command, here I'll use lts/erbium as an example:

nvm install -s lts/erbium

@bartoszhernas
Copy link
Author

Yes, we switched to use -s flag for now, but the behaviour in my opinion is just wrong, and it should not override the architecture for nodes below 14.x as these versions have ARM support merged there, even though the binaries are not provided.

@ljharb
Copy link
Member

ljharb commented Mar 1, 2022

I have recently learned that node ^14.17 (not all node 14s, and not node 15) can be compiled in a non-rosetta M1 env, even though binaries are provided only for 16+.

nvm should thus not alter the architecture for ^14.17 either.

@ljharb ljharb added the pull request wanted This is a great way to contribute! Help us out :-D label Mar 1, 2022
@bartoszhernas
Copy link
Author

As previously mentioned, all the node starting from 14.x and up do support M1 already, that's my whole point :)

@ljharb
Copy link
Member

ljharb commented Mar 1, 2022

@bartoszhernas the node release team claims that only node 14.17+ in the 14 line actually supports it.

@bartoszhernas
Copy link
Author

Ahh, ok :)

@louis030195
Copy link

So what's the appropriate way to install it on Mac m1? The readme script and instructions still install intel version (node 16)

@fyun89
Copy link

fyun89 commented Jun 25, 2022

Is there a command that could instruct nvm to install arm version of Node V16.xx? I currently have the machine set up to use Rosetta compiled version.
Something like
nvm install 16.13.0 -arch arm

@ljharb
Copy link
Member

ljharb commented Jun 25, 2022

@fyun89 i believe if you're in a non-Rosetta terminal it should Just Work for node 16+ - make sure you're on the latest version of nvm.

@o0101
Copy link

o0101 commented Aug 11, 2022

I would love an -arch flag.

Basically I am in arm64 zsh, I set arch to x86, but my node (via nvm) is still an arm binary, so process.arch is arm64 for node. I would love to just:

nvm use --arch x86_64

And it just switches my current default lts v16.16.0 to the x86 binary. I would LOVE this.

Maybe I can go spelunk in my nvm script to try to add this myself...

edit I couldn't even find the script that nvm runs from (which nvm just returns a literal bash script not the file path)...so I ended up using Rosetta

@ljharb
Copy link
Member

ljharb commented Aug 11, 2022

@crisdosyago it’s an OS limitation, so I’m not sure how nvm would be able to accomplish that.

@o0101
Copy link

o0101 commented Aug 11, 2022

@ljharb my model was it was as simple as:

nvm-internal-stuff.sh:

  # nvm magic ...
  # set arch
  arch -$(get_arch_arg)
  # check arch
  arch=$(uname -m)
  # get correct binary for arch
  wget -SOJl https://secret-nvm-binary-stash.example.nvm/node-$version-$platform-$arch.tar.gz
  # celebrate more nvm magic...

But I don't know anything about this 🙂 ¯\_(ツ)_/¯

@ljharb
Copy link
Member

ljharb commented Aug 11, 2022

I believe that won't allow the binary to compile (if needed) nor to run. Certainly if there's a way for nvm to make this easier, I'm all for it, but I think M1 owners just have to "know" to switch to Rosetta for non-M1-compatible versions of any application.

@o0101
Copy link

o0101 commented Aug 11, 2022

So in my rosetta zsh in ~/.nvm/versions/node just now I:

cris@-MacBook bin % ./node -p process.arch
x64
cris@-MacBook bin % arch
i386
cris@-MacBook bin % cd ../../v16.16.0/bin
cris@-MacBook bin % ./node -p process.arch
arm64

(because I had installed v16 when in regular shell, and install v18 when in rosetta), then in non rosetta zsh i:

cris@-MacBook node % cd v16.16.0
cris@-MacBook v16.16.0 % cd bin
cris@-MacBook bin % arch
arm64
cris@-MacBook bin % ./node -p process.arch
arm64
cris@-MacBook bin % cd ../../v18.7.0/bin
cris@-MacBook bin % ./node -p process.arch
x64

To me, I don't know anything about this, but it looks like both binaries (arm and x64) both run in both shells (rosetta and normal), and I just thought, maybe there's some way to say:

cris@-MacBook ~ % nvm use v16.16.0-arm64
Now using that other guy
cris@-MacBook ~ % node -p process.arch
arm64
cris@-MacBook ~ % nvm use v16.16.0-x64
Now using that guy
cris@-MacBook ~ % node -p process.arch
x64

¯\_(ツ)_/¯

Like I said, I don't know, but it seems cool 🙂

@ljharb ljharb closed this as completed in c6269e0 Oct 8, 2022
@RyanDriscoll
Copy link

thanks for addressing this issue! sharing what I did to get node v14.17.5 working on m1 without rosetta:

  1. updated nvm to the most recent version
  2. nvm install v14.17.5 failed with an error saying I have python 3.10 and need 3.9 or lower
  3. installed pyenv (nvm for python)
  4. installed python 3.9 (I think I set 3.9 as my global python version for it to work)
  5. nvm install v14.17.5 (check that the download says arm) took a while and had a bunch of bizarre logs but it worked 🤷

examples of log warnings:

In file included from /Users/ryan/.nvm/.cache/src/node-v14.17.5/files/out/Release/obj/gen/torque-output-root/torque-generated/exported-macros-assembler-tq.cc:22:
In file included from /Users/ryan/.nvm/.cache/src/node-v14.17.5/files/out/Release/obj/gen/torque-output-root/torque-generated/exported-macros-assembler-tq.h:4:
In file included from ../deps/v8/src/compiler/code-assembler.h:17:
In file included from ../deps/v8/src/codegen/code-factory.h:8:
In file included from ../deps/v8/src/codegen/callable.h:8:
In file included from ../deps/v8/src/codegen/interface-descriptors.h:12:
../deps/v8/src/codegen/tnode.h:352:9: warning: definition of implicit copy constructor for 'TNode<v8::internal::Smi>' is deprecated because it has a user-provided copy assignment operator [-Wdeprecated-copy-with-user-provided-copy]
  TNode operator=(TNode other) {
        ^
../deps/v8/src/compiler/code-assembler.h:528:12: note: in implicit copy constructor for 'v8::internal::TNode<v8::internal::Smi>' first required here
    return SmiConstant(static_cast<int>(value));
c++ -o /Users/ryan/.nvm/.cache/src/node-v14.17.5/files/out/Release/obj.target/cctest/test/cctest/test_url.o ../test/cctest/test_url.cc '-DV8_DEPRECATION_WARNINGS' '-DV8_IMMINENT_DEPRECATION_WARNINGS' '-D_DARWIN_USE_64_BIT_INODE=1' '-DOPENSSL_NO_PINSHARED' '-DOPENSSL_THREADS' '-DNODE_ARCH="arm64"' '-DNODE_WANT_INTERNALS=1' '-DHAVE_OPENSSL=1' '-DHAVE_INSPECTOR=1' '-D__POSIX__' '-DNODE_USE_V8_PLATFORM=1' '-DNODE_HAVE_I18N_SUPPORT=1' '-DNODE_PLATFORM="darwin"' '-DUCONFIG_NO_SERVICE=1' '-DU_ENABLE_DYLOAD=0' '-DU_STATIC_IMPLEMENTATION=1' '-DU_HAVE_STD_STRING=1' '-DUCONFIG_NO_BREAK_ITERATION=0' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DNGHTTP2_STATICLIB' -I../src -I../tools/msvs/genfiles -I../deps/v8/include -I../deps/cares/include -I../deps/uv/include -I../deps/uvwasi/include -I../test/cctest -I../deps/histogram/src -I../deps/icu-small/source/i18n -I../deps/icu-small/source/common -I../deps/zlib -I../deps/llhttp/include -I../deps/cares/src/lib -I../deps/nghttp2/lib/includes -I../deps/brotli/c/include -I../deps/openssl/openssl/include  -O3 -gdwarf-2 -mmacosx-version-min=10.13 -arch arm64 -Wall -Wendif-labels -W -Wno-unused-parameter -Werror=undefined-inline -Wall -Wendif-labels -W -Wno-unused-parameter -std=gnu++1y -stdlib=libc++ -fno-rtti -fno-exceptions -fno-strict-aliasing -MMD -MF /Users/ryan/.nvm/.cache/src/node-v14.17.5/files/out/Release/.deps//Users/ryan/.nvm/.cache/src/node-v14.17.5/files/out/Release/obj.target/cctest/test/cctest/test_url.o.d.raw   -c

@HelloAlberuni
Copy link

Here is the solution I've found https://devzilla.io/using-nodejs-14-with-mac-silicon-m1

@nick-verida
Copy link

Here is the solution I've found https://devzilla.io/using-nodejs-14-with-mac-silicon-m1

No, this installs the x86 version (which for node14 is the default). Even if you don't change the arch (ie, do NOT run arch -x86_64 zsh) it still installs the x86 version.

AFAIK there is still no easy way to install an arm64 version of node14

@micabaptista
Copy link

I was using a system with x64 architecture, but when I installed Node 18 using NVM (Node Version Manager), it mistakenly installed the arm64 version. This mismatch could potentially cause issues.

To resolve this, I opted for a manual approach since NVM couldn't provide the x64 version of Node 18 that I needed. I visited the Node.js distribution page at https://nodejs.org/dist/v18.19.0 and manually downloaded the appropriate version. After downloading, I copied the contents into the '~/.nvm/versions/node' directory and renamed the folder to 'v18.19.0' to align with the naming convention. This allowed me to continue using NVM as my default tool for switching between Node versions.

@stefan2718
Copy link

For anyone following this issue, there is a good answer for how to do this in another issue: #2350 (comment)

# first run this to switch architectures
arch -x86_64 zsh
# then install
nvm install v14.21.3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
OS: Mac OS pull request wanted This is a great way to contribute! Help us out :-D
Projects
None yet
Development

Successfully merging a pull request may close this issue.