I've written a cross-platform nodejs native module in C using cmake, musl, plus a few abstractions and carefully placed #ifdefs.
It is built into a module using cmake-js and I have 3 build servers: Windows
, Mac
and Linux
doing the buliding so I have 3 native modules that work fine on all the platforms.
We have an internal NPM repository that I could go ahead and publish to so that other teams within the company can simply npm install module
to get my module.
The thing is, it's kind of messy that the client would need to pick a module based on the platform they're on (i.e. I would deploy all 3 modules from each of the build servers) so I would rather deploy a single module by somehow merging together the 3 platform specific modules.
Is this possible and how do I structure the internals of such a module?*
Does, for example, bindings figure out the platform and find the appropriate .node
file?
*I don't want to include the code and have the client compile it as that puts a pretty large burden on the client (they would be expecting to be able to write a simple script using Javascript, for example, and use my module - it would be a shock that they need to set up C build chains, worry about the platform their script is running on etc, etc, etc).
The most simple solution that comes to my mind - if you packed your code into modules for different platforms then you've got package like:
fancy-module-linux
fancy-module-windows
fancy-module-mac
You can also provide a common module let's say fancy-module
.
In a most basic scenario:
fancy-module
is an empty module with just a README
You provide custom install
script in the package.json
{
...
"scripts": {
"install": "node ./install_platform_dep.js"
}
}
Then when installing fancy-module
the install_platform_dep.js
script will be executed. Inside install_platform_dep.js
you place:
// For Windows...
if(process.platform === 'win32') {
// Trigger Windows module installation
exec('npm install fancy-module-windows', (err, stdout, stderr) => {
// Some error handling...
}
} else if ... // Process other OS'es
You don't have to even publish anything separately! Alternatively you can just put everything into fancy-module
:
package.json
README.md
src
|- Windows
| # Here you've got just copied contents of `fancy-module-windows`
|- Linux
| # This folder have same contents as `fancy-module-linux`
\- Mac
# Same
And do exec('npm install ./src/Windows' /* ... */)
And you get one nice single multiplatform bundle.
There's no other way to achieve multiplatform module than doing what I described.
Anyway it's rather ugly to provide installer-like module just to install stuff but afik that's the most straightforward option.
Many packages (built around Electron and paltform dependent stuff) on npm are just installers to install other packages, so it's a good way to go.
Edit:
For os detection you can use modules like: is-linux
or is-windows
etc. and not worry about process.platform
Read more about is-linux
Read more about is-windows
Read more about process.paltform
Read more about install hook in package.json
Edit #2:
Alternatively you can use already made package node-pre-gyp
as described here:
Cross platform addon using node-pre-gyp
This package does in reality something to the described approach.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With