Node Canvas is not working for me on m1
When I try to run my project I get this error message:
Error: dlopen(.../node_modules/canvas/build/Release/canvas.node, 0x0001): tried: '.../node_modules/canvas/build/Release/canvas.node' (mach-o file, but is an incompatible architecture (have 'arm64', need 'x86_64')), '/usr/local/lib/canvas.node' (no such file), '/usr/lib/canvas.node' (no such file)
Already did:
brew install pkg-config cairo pango libpng jpeg giflib librsvg
xcode-select --install
npm i canvas
With no errors
Not sure how to debug this as there are people with Node Canvas working on m1 laptops, please help.
The most important thing is to make sure your Node executable has been compiled for Apple Silicon, meaning there's a pre-built binary for darwin-arm64. You can see which versions have which binaries here (the following page has the binaries for Node version 16.13.1): https://nodejs.org/download/release/v16.13.1/.
Node v14 has no pre-built binaries for darwin-arm64 (see https://github.com/nodejs/node/issues/36161), because it can't be compiled natively to Apple Silicon.
I use volta (https://volta.sh/) to manage my Node versions, so if you install Node v16 with volta install node#16 and then run npm i canvas, you should get a correctly compiled canvas.node file.
If that fails, go to node_modules/canvas and run npm install --build-from-source, which will compile the C++ addon and output the corect canvas.node.
You can check this by running:
file node_modules/canvas/build/Release/canvas.node
# outputs: node_modules/canvas/build/Release/canvas.node: Mach-O 64-bit bundle arm64
If it says arm64 at the end, then you're good to go. If it still says x86_64, then something went wrong.
I use npm install --build-from-source. It work!
But there are new mistakes
dlopen(.../node_modules/canvas/build/Release/canvas.node, 0x0001): symbol not found in flat namespace '_cairo_fill'
Related
I'm using Rosetta 2 with Homebrew and have sqlite3 installed.
I added these to my ~/.zshrc so that the node compiler can find the brew installs:
export PATH="/usr/local/opt/sqlite/bin:$PATH"
export LDFLAGS="-L/usr/local/opt/sqlite/lib"
export CPPFLAGS="-I/usr/local/opt/sqlite/include"
I'm using installing using npm install sqlite3, building from source with --build-from-source flag, I'm also specifying the homebrew version of sqlite with --sqlite=/usr/local/opt/sqlite/
node-gyp goes to its fallback build node-pre-gyp install --fallback-to-build
After installation, I'm rebuilding it's native dependencies with electron-builder and install-app-deps
It even rebuilds to the platform and arch I'm looking for, darwin and x64. Which is promising.
• electron-builder version=23.0.3
• loaded parent configuration preset=react-cra
• rebuilding native dependencies dependencies=sqlite3#5.0.8 platform=darwin arch=x64
However, when run the app with npm run dev which runs concurrently " cross-env BROWSER=none npm start" "wait-on http://localhost:3000 && electron ."
It still is trying to find the arm64 version of it:
Error: Cannot find module '[..]/node_modules/sqlite3/lib/binding/napi-v6-darwin-unknown-arm64/node_sqlite3.node'
Even though I can confirm, it did build the x64 version because I have one located at:
/napi-v6-darwin-unknown-x64/node_sqlite3.node
Any help to get this working would be greatly appreciated, thanks!
After 4 days of digging, I have finally gotten it to work!!!
For anyone that might stumble on this:
The reason why sqlite3 won't behave is threefold:
When node sqlite3 is installed using npm install sqlite3, it fetches all dependencies and installs it. It then fetches the precompiled binary binding file for the target arch and platform. In my case we would want napi-v6-darwin-unknown-arm64 for ARM64 and darwin for Apple M1. There is no precompiled binary available yet for this Apple ARM64 and even if there is, the next paragraph will detail why it still won't work.
The problem is that it determines the the system's platform and architecture using the binary compiling package node-pre-gyp and this very savior of a Github issue details how node-pre-gyp is not handling ARM architecture detection properly and basically mixing everything up. Because it's not detecting properly, even if we build our own binding with --build-from-source when installing, it still won't work because it is compiling the wrong binding file for the wrong architecture. To make matters worse, if we don't use --build-from-source, it just simply fetches the Intel precompiled binding file. napi-v6-darwin-unknown-x64
Now for some reason, during runtime, it now detects the architecture properly and tries to look for the ARM64 version of the binding file, it won't find it and will throw the feared error 'module not found' for napi-v6-darwin-unknown-arm64. It obviously won't find it and even if it does, it will throw wrong architecture error because we have the Intel version on board napi-v6-darwin-unknown-x64.
So finally after digging at this for 4 days, here's how I got it working:
Uninstall sqlite3: npm uninstall sqlite3
Install a fresh sqlite3, build it from source, specify the target arch and use fallback build with node-pre-gyp just to be safe: npm install sqlite3 --build-from-source --target_arch=arm64 --fallback-to-build
Now the correct binding file is compiled for the correct platform and architecture, on runtime it will find it and will run!
I want to render a chart to use with my discord bot and so far all the tutorials i have seen are using the chartjs-node-canvas module. But it gives errors when installing.
If someone gives me an alternative package to chartjs-node-canvas this is perfectly fine but i would prefer just solving this error and using the existing package.
Since stackoverflow does not allow adding text files (and if i just paste the text it is more than 30000 characters) here is a link to a pastebin with the npm log
pastebin.com/raw/yXrTyq85
I believe the problem lies in the installation of node-canvas which is a dependency for chartjs-node-canvas. After spending a lot of time researching why the library isn't getting installed, I got a lead to the following link: https://github.com/Automattic/node-canvas/wiki#installation-guides
I installed the below-mentioned dependencies on my machine and used a node version of 16.x
This did the work for me.
Here is how I installed the required dependencies:
brew install pkg-config cairo pango libpng jpeg giflib librsvg
After installing these dependencies, you can install the library using npm or yarn.
After updating NPM, my binaries are not getting installed properly. The module itself is getting installed at /usr/local/lib/node_modules, but the binary is not getting installed at /usr/local/bin.
How do I know the path where the binaries are getting installed?
Thanks!
I have a node webkit application that uses the mdns module for publishing a Bonjour service from a Mac (with Mavericks). When I run the server code with node server.js everything works OK, but when running the node webkit application that uses the same server code I get this error:
"Uncaught Error: dlopen(/Users/me/myfolder/node_modules/mdns/build/Release/dns_sd_bindings.node, 1): no suitable image found. Did find:
/Users/me/myfolder/node_modules/mdns/build/Release/dns_sd_bindings.node: mach-o, but wrong architecture", source: /Users/me/myfolder/node_modules/mdns/lib/dns_sd.js (35)
Apparently when you install the mdns module with npm it's built for an x86 architecture and I need it for i386, because node-webkit is built for i386 (I found out about this by reading this thread: http://forums.macrumors.com/showthread.php?t=879780). You can verify it by running this in a terminal:
$ lipo -info /Applications/node-webkit.app/Contents/MacOS/node-webkit
Non-fat file: /Applications/node-webkit.app/Contents/MacOS/node-webkit is architecture: i386
I found this link suggesting a solution: https://github.com/rogerwang/node-webkit/issues/296 for another module (node proxy). The suggested instructions are:
I managed to build a 32-bit version of node-proxy as follows:
I installed nw-gyp
I ran nw-gyp configure --target=0.3.6
I edited the generated file nodeproxy.target.mk in the build directory by replacing -arch x86_64by -arch i386
I ran nw-gyp build
But as I'm not used to building node modules manually, while following the instructions it wasn't clear to me in which folder I should run those steps (I assumed it's in the module folder inside node_modules:
a) when I install nw-gyp I don't get the nw-gyp command to use globally (I guess the -g option is missing in the instructions)
b) using instead gyp configure --target=0.3.6 gives me an error saying that there is no option target
c) I tried skipping the configure step (just to try) and the build command breaks with:
Could not automatically locate src directory. This isa temporary
Chromium feature that will be removed. Use--depth as a workaround.
But when trying to use --depth (of course) it requires an argument, I couldn't find out what to put there.
So... how should I build the mdns module for using it with node webkit? (either the 0.8.6 version or the 0.10.0, I can adapt).
I managed to make it work.
As I had already installed the mdns module, I already had the source code of the module in the folder node_modules/mdns inside my project folder.
So these are the steps I followed to build the mdns module for the i386 architecture:
1) Install nw-gyp by running: npm install -g nw-gyp
2) Enter in the node_modules/mdns folder of your node-webkit project
3) Run nw-gyp configure --target=0.8.6 (this target is the version of the node-webkit you have installed)
4) And finally run nw-gyp build
I got a lot of warnings of deprecated functions, but it was built OK and now my node-webkit application can publish the Bonjour service successfully.
Unfortunately this is not the best solution, though, because the next person that installs the project will have to do the same after the regular npm install... But at least it's something to get it working.
I frequently hear from experienced node developers that checking in node_modules is good practice. But most developers write on Mac/Darwin x64, but deploy on Linux x64.
If a node module happens to be written in C, and I install it on OS X, wouldn't I have to rebuild it on Linux?
The answer is: it depends on the package
Most packages do require reinstall, as node gyp the compiler does not cross compile by default - thanks #tkone.
Some packages like node-sass dynamically download prebuilt binaries for the relevant platform (previously node-sass used to include binaries for all platforms, however this has changed recently).
The now current node-sass 3.4.2 doesn't include the binaries in the originally downloaded npm package (as found in the npm package cache under ~/.npm).
What it does is that its install.js script will download the platform specific binary and store it under vendor/{platform}-{arch}-{process.versions.module}.node. Once installed, the install.js script normally isn't invoked again by npm.
So when you check in node_modules, it will contain the binary only for your initial platform.
For the fun of it I moved away the downloaded binary, which should be the same as someone else checking out your node_modules on a different platform. When then run, node-sass is so smart to detect that the required binary doesn't exist. It exits gracefully, recommending to run npm rebuild node-sass (also hinting that this is usually necessary when you change the node version). This will download the binary for the current platform, and then all is fine.
However, that's totally specific to node-sass, other packages with binaries may behave entirely different.
(See Node.js release versions for an explanation of process.versions.modules aka. NODE_MODULES_VERSION that determines the last number in the binary download URL. The binary name is constructed in function getBinaryName() in ~/.npm/node-sass/{version}/package.tgz/lib/extension.js )