Search code examples
c++dockerbuildnode-gypnode-addon-api

How to build node-addon-api insulated from OS?


I have backend server with nodejs and deployed on heroku.

Problem is that I need to use some fortran-based program with dll file (both 64-bit and 32-bit exists, and used 64-bit).

To handle them all, I wrote some C++ code(node-addon-api).

C++ with node-gyp builds to .node file, and it worked in my local environment.

However, it failed on heroku with following errors.

Error: /app/refprop/refpropNapi.node: invalid ELF header

And I found some explanation about ELF header error. After some searching, I found answer below and it seems precisely fits to my case.

This happens when you build on one architecture and then attempt to use the same built addon on a different architecture (or platform in some cases.

My development environment for node-addon-api was Windows 10, 64 bit. My assumption is heroku uses Linux OS, and that is why compiled node file do not work.

In conclusion, I have 3 questions.

  1. Would compiling C++ and dll on Docker (I don't know how to build in Docker in detail) would create node that can be executed on heroku?

  2. Would it be NECESSARY to dockerize both backend and node-addon-api to ensure they run in same OS?

  3. It seems that deploying using docker makes IaaS much easier, which makes me to escape PaaS (heroku), but I don't have any experience. Will it be a way to escape from heroku? (I don't want to work with server more, because I have enough work by now...)


Solution

  • Short answer:
    The compiled .node must match the specific architecture it's being deployed to. Compiling in a docker image and then deploying that docker image is one way to do this, but it adds complexity, specifically around the extra steps setting up, using, and managing docker. There are less complex ways to do this for node using heroku's build scripts. https://devcenter.heroku.com/changelog-items/1557 and https://devcenter.heroku.com/articles/nodejs-support#customizing-the-build-process

    Long Answer:
    Here's more detail about what what a Heroku 'dyno' is, which runs a Heroku app, as background. https://stackoverflow.com/a/21463495 and https://devcenter.heroku.com/articles/how-heroku-works#building-applications

    The stacks they use for new apps are listed at https://devcenter.heroku.com/categories/stacks

    Currently this is:

    _________________________________________________________________
    |Stack Version       | Base Technology | Supported through      |
    |Heroku-18 (default) | Ubuntu 18.04    | April 2023             |
    |Heroku-16           | Ubuntu 16.04    | April 2021 Learn more  |
    |Container           | Docker          | Developer-maintained*  |
    _________________________________________________________________
    

    The stacks have node buildpacks described at https://github.com/heroku/heroku-buildpack-nodejs that build the node app you add to heroku.

    You can customize the build process as described at https://devcenter.heroku.com/articles/nodejs-support#customizing-the-build-process and https://devcenter.heroku.com/changelog-items/1557 That means you can add a build script that will run each time your application is added to heroku.

    "scripts": {
      "start": "node index.js",
      "build": "build steps here to compile your dll on heroku using node-gyp or npm build or npm install"
    }
    

    or you can use heroku-prebuild or heroku-postbuild scripts.

    "scripts": {
      "heroku-prebuild": "echo This runs before Heroku installs your dependencies.",
      "heroku-postbuild": "echo This runs afterwards."
    }
    

    https://nodejs.org/api/addons.html#addons_building describes in more detail how to build C++ addons.

    Disclaimer: I am not a Heroku employee nor have I used Heroku recently, so I am only going by what is described in the publicly available documentation.


    With that explanation in mind as to what you might want to use instead of docker, here are the answers to your listed questions:

    1. Would compiling C++ and dll on Docker (I don't know how to build in Docker in detail) would create node that can be executed on heroku?

    Yes. Heroku supports docker containers directly or you can compile on an docker image that matches what Heroku uses (e.g. Ubuntu 18.04) and use that compiled code.

    1. Would it be NECESSARY to dockerize both backend and node-addon-api to ensure they run in same OS?

    Both the backend and node-addon-api would need to run in the same docker image if you are using a docker container. If you only compile on docker, the compiled c++ would need to match what OS node is eventually run on.

    1. It seems that deploying using docker makes IaaS much easier, which makes me to escape PaaS (heroku), but I don't have any experience. Will it be a way to escape from heroku? (I don't want to work with server more, because I have enough work by now...)

    Yes. There are other providers that provide docker container services that can run node servers. There are also other cloud providers with virtual images that can run node servers without the need to dockerize as well.