Hello
I'm writing a module that has both JS and native addon part. The native part is only for windows and on other platform is not needed at all (Based on some windows dll). How could I handle this scenario? Module installation as usual dependency, The JS part available for all users on any OS, but only on windows build the native part?
Two ways:
binding.gyp https://gyp.gsrc.io/docs/InputFormatReference.md#Conditionals.gyp file so npm doesn't trigger on it)@refack Thnx. But could you give an example of using the conditionals?
According to my tests, in conditional you cannot stop the build process on specific OS. You could only remove/change the sources of Windows for linux/darwin. But even a project without any sources (binding.gyp with only targets and one target with only "target_name" field), will start the node-gyp build process, and a .node file will be created. So adding the module as a dependency in a project, Will result that the node-gyp build requirements must be installed in OSes other than Windows.
About the second way you mentioned, is it OK to write an script that will check the platform, then if it is Windows, create a binding.gyp file in module root, so when npm start the installation, it detect the binding.gyp and build? For this scenario, isn't the "preinstall" script better than "prepare"?
How about dividing the module into two separated module. JS and native? then add the native module as optionalDependency of JS module, and then add an os in native module package.json target specific OS?
@refack Thnx. But could you give an example of using the conditionals?
According to my tests, in conditional you cannot stop the build process on specific OS. You could only remove/change the sources of Windows for linux/darwin. But even a project without any sources (binding.gyp with only targets and one target with only "target_name" field), will start the node-gyp build process, and a .node file will be created. So adding the module as a dependency in a project, Will result that the node-gyp build requirements must be installed in OSes other than Windows.
Yes I assume you are right, if that's an unwanted consequence, then take option (2) or (3)
About the second way you mentioned, is it OK to write an script that will check the platform, then if it is Windows, create a binding.gyp file in module root, so when npm start the installation, it detect the binding.gyp and build? For this scenario, isn't the "preinstall" script better than "prepare"?
Sounds fine, but it's all in the details, when is node-gyp actually triggered. I would go "full-on" and trigger node-gyp from within the hook using a different named/located .gyp file that is invisible to npm.
How about dividing the module into two separated module. JS and native? then add the native module as optionalDependency of JS module, and then add an os in native module package.json target specific OS?
That actually sounds the simplest.
@refack Thanks again. I'm working on the situation and soon will send a comment to the issue with final solution I've decided to use with some extra info and then will close the issue.
@alirdn Happy to help. Good luck!
I'd be happy to hear how it turns out...
Closing, seems to have been answered.
@alirdn How did you end up solving this?
@mika-fischer Oh! I thought that I sent a reply to this topic.
Well after some research, finally found below paragraph in npm-scripts, that give me an idea for the best solution.
DEFAULT VALUES
npm will default some script values based on package contents.
"install": "node-gyp rebuild":
If there is a binding.gyp file in the root of your package and you haven't defined your own install or preinstall scripts, npm will default the install command to compile using node-gyp.
So, for a proper build scenario, you should add a custom script as install script, that will decide to build or not? After some tests, I've found the best solution. Actually, best for my requirements that are:
node-pre-gyp great package (The script should run after the dependencies are install. Because I need the node-pre-gyp)npm install process if build failed (Not like optionalDependency. So I decided to use cross-spawn package.)My final solution steps are:
{
...
"dependencies": {
...
"node-pre-gyp": "^0.6.34",
"cross-spawn": "^5.1.0",
...
}
...
}
package.json{
...
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"native_build": "node-gyp rebuild",
"install": "node install.js"
}
...
}
install.js file in module rootconst os = require('os');
var spawn = require('cross-spawn');
if (os.platform() === 'win32') {
spawn.sync('npm', ['run', 'native_build'], {
input: 'win32 detected. Build native module.',
stdio: 'inherit'
});
}
binding.gyp file in module rootUsing this solution, now my package only build native part on Windows, also will use node-pre-gyp for install from binary (Well, above install.js file content just call the node-gyp rebuild, not node-pre-gyp), and finally by inheriting the stdio, any problem during the build, will cause an exit to the whole install process. So it will guarantee proper install of native part on Windows.
@refack I found gyp can support platform_special_source_file, but that seems not work in node-gyp, I add aspecial_win.cc,special_mac.mm in sources and compile it in mac, all the two file will add to compile and will throw a error like duplicate symbol xxx
Most helpful comment
@mika-fischer Oh! I thought that I sent a reply to this topic.
Well after some research, finally found below paragraph in npm-scripts, that give me an idea for the best solution.
So, for a proper build scenario, you should add a custom script as
installscript, that will decide to build or not? After some tests, I've found the best solution. Actually, best for my requirements that are:node-pre-gypgreat package (The script should run after the dependencies are install. Because I need thenode-pre-gyp)npm installprocess if build failed (Not like optionalDependency. So I decided to usecross-spawnpackage.)My final solution steps are:
1. Add needed dependencies in `package.json
2. Add scripts in
package.json3. Create
install.jsfile in module root4. Create
binding.gypfile in module rootUsing this solution, now my package only build native part on Windows, also will use
node-pre-gypfor install from binary (Well, aboveinstall.jsfile content just call thenode-gyp rebuild, notnode-pre-gyp), and finally by inheriting the stdio, any problem during the build, will cause an exit to the whole install process. So it will guarantee proper install of native part on Windows.