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

Package pre-compiled binaries with node-canvas for downstream consumers #641

Closed
eonarheim opened this issue Oct 13, 2015 · 32 comments
Closed
Labels

Comments

@eonarheim
Copy link

I propose that for major OS's (windows, mac, ubuntu, fedora, etc) node-canvas have a pre-compiled set of binaries for consumers to avoid install/configuration/build woes.

I think this was proposed in an older comment in the issue tracker:
#113 (comment)

I've noticed in the issues list that there are quite a number of people having trouble with running/installing/building node-canvas (23 labeled with the installation label https://github.com/Automattic/node-canvas/labels/Installation). That being said, I think the manual install/build for people actively working on and developing node-canvas directly is okay.

However, for people who want to consume node-canvas in a downstream system this is a tremendous hassle. Currently, I have been trying to use js-imagediff which takes a dependency on node-canvas. Now I have to go through a multi-step install process for node-canvas to get js-imagediff to work. I feel like this breaks the compactness and the "it just works" promise of npm modules.

@eonarheim
Copy link
Author

Additionally on first glance https://github.com/mapbox/node-pre-gyp seems to provide these features for relatively low cost, since node-canvas already uses node-gyp. Even outline stems for automating Linux/OSX builds with TravisCI and Windows builds with Appveyor.

Also node-pre-gyp has a "fallback-to-build" when the appropriate binary cannot be located.

@LinusU
Copy link
Collaborator

LinusU commented Oct 14, 2015

This would be very nice to have. It might not be as straight forward since we probably want to package with binaries of libcairo as well, otherwise you still need to have that installed for stuff to work. I'm not entirely sure how that would work to be honest.

@eonarheim
Copy link
Author

I think you would package all the appropriate binary dependencies with the pre-compiled distribution. In the windows build all of the necessary binaries land in the ./build/Release directory. This is all you need to run node-canvas compactly. By default windows looks in the current directory for dependent assemblies, linux not so much.

image

However, this can be done for linux and mac distributions as well since we are well aware of the libraries that we are linking against in order to build the canvas.node native extension. Copy the shared libraries to the /build/Release directory which can be found with the following command, or have the dependent libraries checked into the repository under a "/deps" folder and copied on a build step.

~/node-canvas/build/Release$ readelf -d canvas.node | grep NEEDED
 0x0000000000000001 (NEEDED)             Shared library: [libcairo.so.2]
 0x0000000000000001 (NEEDED)             Shared library: [libpng12.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libpangocairo-1.0.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libpango-1.0.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libgobject-2.0.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libjpeg.so.8]
 0x0000000000000001 (NEEDED)             Shared library: [libgif.so.4]
 0x0000000000000001 (NEEDED)             Shared library: [libstdc++.so.6] # probably don't need to package these
 0x0000000000000001 (NEEDED)             Shared library: [libm.so.6] #
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6] #

Then the only thing needed would to link the canvas.node binary to look at the origin for shared libraries something like -Wl,-rpath \'-Wl,$$ORIGIN\' so canvas.node could be packaged with it's shared assemblies

/// binding.gyp
...
}, { # 'OS!="win"'
   'ldflags': [
       '-Wl,-rpath \'-Wl,$$ORIGIN\'',
   ],

...

Notice that the linker looks local now first, instead of the shared location which would require an install.

~/node-canvas$ objdump -p build/Release/canvas.node  | grep RPATH
  RPATH                $ORIGIN

~/node-canvas/build/Release$ ldd canvas.node
        linux-vdso.so.1 =>  (0x00007fffe5dc3000)
        libcairo.so.2 => /home/eonarheim/node-canvas/build/Release/./libcairo.so.2 (0x00007f5492e46000)
        libpng12.so.0 => /home/eonarheim/node-canvas/build/Release/./libpng12.so.0 (0x00007f5492c20000)
        libpangocairo-1.0.so.0 => /home/eonarheim/node-canvas/build/Release/./libpangocairo-1.0.so.0 (0x00007f5492a12000)
        libpango-1.0.so.0 => /home/eonarheim/node-canvas/build/Release/./libpango-1.0.so.0 (0x00007f54927c5000)
        libgobject-2.0.so.0 => /home/eonarheim/node-canvas/build/Release/./libgobject-2.0.so.0 (0x00007f5492574000)
        libjpeg.so.8 => /home/eonarheim/node-canvas/build/Release/./libjpeg.so.8 (0x00007f549231e000)
        libgif.so.4 => /home/eonarheim/node-canvas/build/Release/./libgif.so.4 (0x00007f5492115000)

Now with node-pre-gyp you could select the appropriate binary tarbar containing the finished products and dependencies to unpack and drop into /build/Release depending on platform/architecture

///package.json
 "scripts": {
        "install": "node-pre-gyp install --fallback-to-build",
    },
    "binary": {
        "module_name": "your_module",
        "module_path": "./lib/binding/",
        "host": "https://your_module.s3-us-west-1.amazonaws.com"
    }
~/myfork-node-canvas/node-canvas$ make
npm install

> canvas@1.2.9 install /home/eonarheim/myfork-node-canvas/node-canvas
> node-pre-gyp install --fallback-to-build

node-pre-gyp http GET https://github.com/eonarheim/node-canvas/raw/master/dist/c
anvas-v1.2.9-node-v11-linux-x64.tar.gz
node-pre-gyp http 200 https://github.com/eonarheim/node-canvas/raw/master/dist/c
anvas-v1.2.9-node-v11-linux-x64.tar.gz
[canvas] Success: "/home/eonarheim/myfork-node-canvas/node-canvas/build/Release/
canvas.node" is installed via remote

~/myfork-node-canvas/node-canvas$ make test

   canvas: 1.2.9
   cairo: 1.13.1


  ․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․

  37 passing (207ms)

Complete!

I've done a little work on my fork to demonstrate the basic principle in linux, node-canvas builds and tests pass. Right now the tars are in github (a dubious place to host at best 😉) The full implementation would be integrating with TravisCI and AppVeyor to automatically build and put the binaries for all the major systems in a central location.

https://github.com/eonarheim/node-canvas

Thoughts?

@LinusU
Copy link
Collaborator

LinusU commented Oct 15, 2015

Wow, very good work! How does this work with different distributions of Linux? Where did you get the so files from?

We would also need to fix this for OS X.

Nice job! Glad someone is picking this up 👍

@inssein
Copy link
Contributor

inssein commented Oct 19, 2015

@eonarheim was just looking at this today for my fork of node-canvas. I would definitely like to see this get solved.

Where would these build files get hosted? We would probably need an S3 bucket. While it isn't expensive, how does an open source project handle that?

@eonarheim
Copy link
Author

@LinusU I think a best effort approach is best. Target the most popular web server/dev platforms like: ubuntu server, redhat, fedora, windows, OSX etc. I think this is where we would get the most bang for the buck. Once that is done node-pre-gyp has a fall back to build when the requisite binary cannot be located for the platform.

@inssein I agree completely 😄

I think there are a few options available for open source projects to host binary files. Here are a couple I found after quickly searching (by no means an exhaustive list, I'm sure there are others).

I think ideally the TravisCI/AppVeyor build automation for the various platforms and the chosen binary hosting option would be owned by the project maintainers. Also the associated accounts/passwords/api-keys etc.

Thoughts?

@eonarheim
Copy link
Author

@LinusU The needed .so files could be lifted from the build system dynamically using readelf -d canvas.node | grep NEEDED then using those names locate the .so files.

Or the needed .so files could be explicitly identified up front and placed in a "deps" directory and linked to a project local directory like the above. (I used ldd canvas.node on the original distribution to find all of the linked libraries and their shared locations, then copied them locally). There would be some manual maintenance with this option, but less platform fragmentation (you know exactly the versions of the dependencies node-canvas is built and runs best against)
image

@piranna
Copy link
Contributor

piranna commented Jan 3, 2016

This would be very nice to have. It might not be as straight forward since we probably want to package with binaries of libcairo as well, otherwise you still need to have that installed for stuff to work. I'm not entirely sure how that would work to be honest.

I has a pull-request that add support to generate a statically linked version of node-canvas, so Cairo and all its dependencies get bundled inside the final cairo.node library file and there's no need to have installed any dynamic library. It's pending for aproval since last June without any answer...

@piranna
Copy link
Contributor

piranna commented Jan 3, 2016

Also, by doing a statically linked library, all the problems about OSX would disappear, and would make the distribution using node-pre-gyp fairly trivial.

@potmo
Copy link

potmo commented Jun 7, 2016

👍

@chearon
Copy link
Collaborator

chearon commented Jun 11, 2016

I've been thinking about this a lot too, having node-canvas as a dependency in your project can end up being hellish. When a new issue is posted here there's a 75% chance that the problem is in the build system.

Some things to add

  • bintray is free for open source
  • I think node-pre-gyp recommends using GitHub releases for hosting binaries
  • One time I calculated how much S3 would cost for node-canvas, and given that Windows needs around 30MB in binaries it wasn't pennies

@LinusU it would be great to add this to the 2.0 release list

@piranna
Copy link
Contributor

piranna commented Jun 11, 2016

I have been using lately prebuild and prebuild-install and they are really easy to use, and use Github releases by default.

@chearon
Copy link
Collaborator

chearon commented Jun 11, 2016

@piranna good, I'm going to try that... and (to your comment in January) wouldn't a single canvas.node mean you have to recompile dependencies?

@piranna
Copy link
Contributor

piranna commented Jun 11, 2016

wouldn't a single canvas.node mean you have to recompile dependencies?

If they are compiled statically no, since they are included inside the canvas.node file.

I have tried to update my pull-request to latest code from node-canvas, but due the changes on nan2 I'm having some problems (I've not used nan too much).

@anatolly
Copy link

anatolly commented Dec 23, 2016

Do you think is it possible to make a list of compiled builds just to use?
I've spent about 8 hours trying to compile canvas on Windows 8.1 x64 and no success. Thanks for Installation wiki page, it's nice and full. I re-installed VS Express 3 times, tried to install VS SDK, Windows SDK and etc. But every time I have some problem with compiling.
Please help, make and publish 'canvas.node' just for nice using.

@rgbkrk
Copy link

rgbkrk commented Jan 2, 2017

Now that prebuild is quite good and even supports Electron, this is worth re-visiting.

@anatolly
Copy link

anatolly commented Jan 2, 2017

Thanks, rgbkrk.
Please, help. I don't understand what to do exactly.

I've got source of canvas by "git clone https://github.com/Automattic/node-canvas.git"
I've installed "nan" by "npm install nan"

Then "prebuild --download --no-compile" says "No prebuilt binaries found":
prebuild info begin Prebuild version 5.1.2
prebuild info looking for local prebuild @ prebuilds\canvas-v1.6.0-node-v48-win32-x64.tar.gz
prebuild info looking for cached prebuild @ C:\Users\Anatolly\AppData\Roaming\npm-cache_prebuilds\https-github.com-Automattic-node-canvas-releases-download-v1.6.0-canvas-v1.6.0-node-v48-win32-x64.tar.gz
prebuild http request GET https://github.com/Automattic/node-canvas/releases/download/v1.6.0/canvas-v1.6.0-node-v48-win32-x64.tar.gz
prebuild http 404 https://github.com/Automattic/node-canvas/releases/download/v1.6.0/canvas-v1.6.0-node-v48-win32-x64.tar.gz
prebuild WARN install No prebuilt binaries found (target=6.6.0 runtime=node arch=x64 platform=win32)
prebuild info install no-compile specified, not attempting build.

or "prebuild --install --no-compile" raise another error:
..\src\register_font.cc(1): fatal error C1083: Cannot open include file: 'pango/pangocairo.h': No such file or directory [D:\Anatolly\BMS\2\node-canvas\build\binding.sln]
c:\users\anatolly.node-gyp\6.6.0\include\node\v8.h(19): fatal error C1083: Cannot open include file: 'stdint.h': No such file or directory [D:\Anatolly\BMS\2\node-canvas\build\binding.sln]
c:\users\anatolly.node-gyp\6.6.0\include\node\v8.h(19): fatal error C1083: Cannot open include file: 'stdint.h': No such file or directory [D:\Anatolly\BMS\2\node-canvas\build\binding.sln]
..\src\init.cc(9): fatal error C1083: Cannot open include file: 'pango/pango.h': No such file or directory [D:\Anatolly\BMS\2\node-canvas\build\binding.sln]
d:\anatolly\bms\2\node-canvas\src\color.h(12): fatal error C1083: Cannot open include file: 'stdint.h': No such file or directory [D:\Anatolly\BMS\2\node-canvas\build\binding.sln]
c:\users\anatolly.node-gyp\6.6.0\include\node\v8.h(19): fatal error C1083: Cannot open include file: 'stdint.h': No such file or directory [D:\Anatolly\BMS\2\node-canvas\build\binding.sln]
d:\anatolly\bms\2\node-canvas\src\color.h(12): fatal error C1083: Cannot open include file: 'stdint.h': No such file or directory [D:\Anatolly\BMS\2\node-canvas\build\binding.sln]
c:\users\anatolly.node-gyp\6.6.0\include\node\v8.h(19): fatal error C1083: Cannot open include file: 'stdint.h': No such file or directory [D:\Anatolly\BMS\2\node-canvas\build\binding.sln]

Please help how to use prebuild just to download binary of canvas?

@rgbkrk
Copy link

rgbkrk commented Jan 2, 2017

@anatolly You can't use prebuild directly as a user to install canvas, we need canvas to package prebuilt binaries for users. I'm looking into how to do this, if developers want to support it, and where @piranna's PR is at.

@piranna
Copy link
Contributor

piranna commented Jan 2, 2017 via email

@chearon
Copy link
Collaborator

chearon commented Jan 3, 2017

@rgbkrk @piranna is prebuild able to handle the system dependencies Canvas has? How does it build to all 3 operating systems? I made this which has worked great for me and my colleagues. I'll be the first to admit it was very time consuming to get all of the CIs to build/bundle/publish in a way that is immune to changes. So if prebuild can handle the complexities of node-canvas it would definitely be worth looking at

@piranna
Copy link
Contributor

piranna commented Jan 3, 2017

prebuild just only compile the module with the instructions on binding.gyp and upload it to Github releases, it doen't have any other magic behind this, and you'll still need to configure your CI servers. Good thing is, it's designed to automatically generate the builds against all the possible versions of Node.js, so you only need to worry about configure the build matrix only once for each operating system. That's why I said that my static build pull-request would simplify this, because it download and compile automatically all the dependencies and the final product is a fully statically linked module ready to use. This is important for Linux system because you don't have to worry about different versions of the libraries in the different distros, but also on MacOS X and Windows because don't require users to have installed other libraries by hand.

@playground
Copy link

Hi, this sounds like something that I will need for what I'm trying to accomplish, ref here #867
Can someone tell me what I need to get node-canvas to work with Webpack? Thanks.

@pravdomil
Copy link
Contributor

see #942 (comment)

@tettusud
Copy link

I am facing issue using canvas inside electron app.While I run it separately it works fine while launching as part of electron it says Trouble launching DLL. Does any one have a working sample of Node and canvas and electron?

@LinusU
Copy link
Collaborator

LinusU commented Dec 17, 2018

@tettusud native modules compiled for Node.js doesn't usually work in Electron, see this: https://electronjs.org/docs/tutorial/using-native-node-modules

@LinusU
Copy link
Collaborator

LinusU commented Dec 17, 2018

Closing this since we now ship prebuilds for all major platforms 🎉

@LinusU LinusU closed this as completed Dec 17, 2018
@Nantris
Copy link

Nantris commented Jan 29, 2019

we now ship prebuilds for all major platforms

@LinusU, does that include for Electron? It seems not, but it would be really great if prebuilts were available for Electron.

@LinusU
Copy link
Collaborator

LinusU commented Jan 30, 2019

@slapbox I'm open to that. But is there a use case? Doesn't Electron already have a Canvas implementation built in?

@rgbkrk
Copy link

rgbkrk commented Jan 30, 2019

The "renderer" side of electron has canvas built in (since it's chromium) while the "main" process side of electron doesn't have canvas (it's pure node).

Another reason is that without the proper binary, when any library requires canvas applications are forced to build canvas. This is extra painful as an open source project to have to help contributors with something that isn't a necessary dependency yet part of some other package that requires it (even if as an optional dep).

@Nantris
Copy link

Nantris commented Jan 30, 2019

It turned out building was easy, even on Windows, but prebuilts would still be great!

As @rgbkrk, the main process doesn't have window or any of the related functionality available.

@rastographics
Copy link

@slapbox can you give the general steps you took to get canvas to build for electron on Windows? I followed all Readme instructions and still getting build errors on Electron 8.3 and Node 12

I'm using 4 other native modules and they all build without issues. Just stuck on canvas

@Nantris
Copy link

Nantris commented Jun 14, 2020

@rastographics I abandoned this package and changed our method of building binaries, so I'm afraid I can't be of that much help.

Have you tried electron-rebuild --version 8.3.0 --only node-canvas ?

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

No branches or pull requests