-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
Build binaries that can load in electron by default. #653
Build binaries that can load in electron by default. #653
Conversation
Attempt to load node.dll first, if its not found then link to the running process under the assumption that it is node/iojs or has statically linked to node. This adds support for electron or any other app that dynamically links to node.
Just for a little extra context, building electron modules the node-gyp way Results in binaries that are dynamically linked to node.dll This changeset allows you to build binaries either normally or through electrons recommended way which will run in electron or node/iojs without requiring recompilation. |
/cc @piscisaureus |
👊 Ping :) For proof, I have integrated this into a couple of working examples, including electron-celt You can see in the binding.gyp the addition of delay loading Here is the actual delay_load_hook.h I am using. |
@piscisaureus @orangemocha Would love some input on this one. |
Does it work? It seems a bit backwards. |
@piscisaureus Yes it works, my electron-celt project should be proof. You can get that binary and try to load it as is, in electron and iojs if desired. I have a couple projects that are using the technique now. I could create a simpler proof of concept also probably. But I'm not adding I'd be happy to do a screen share and walk through with someone if you wanted a deeper dive. |
return NULL; | ||
|
||
m = GetModuleHandle(NULL); | ||
m = GetModuleHandle("node.dll"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if the module is loaded the traditional way (by node.exe or iojs.exe) but there is a node.dll in the path? Will that cause an unintended conflict?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I believe it would cause a conflict and probably fatal or unexpected results. Now that you mention it, I agree that it should be more restrictive than searching for node anywhere in path. Perhaps it must be located in the same dir as the current executable?
psuedo code:
m = GetModuleHandle(NULL)
p = GetModulePath(m)
p = Path.Join(Path.Dirname(p), "node.dll")
n = GetModuleHandle(p)
if(n != NULL) m = n;
return m;
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It sounds like the more robust approach would be to avoid looking for node.dll anywhere if the addon was loaded the 'traditional' way. Is there way that you can reliably tell, other than comparing the current executable name to node.exe
and iojs.exe
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe there isn't.
I can however, get the current executables name first, and if it is "node.exe" or "iojs.exe" then just return that. If not, search for "node.dll" in the same directory as the executable. That seems fairly restrictive and reasonable, no?
m = GetModuleHandle(NULL) // current executable
p = GetModulePath(m)
name = ToLower(Path.Basename(p))
if (name == "node.exe" || name == "iojs.exe") {
return m
} else {
p = Path.Join(Path.Dirname(p), "node.dll")
return GetModuleHandle(p)
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It works by accident - the addon thinks it's been linked with a DLL and we're now cheating on them and giving them exports from an unrelated project. It works by accident, but it would not if e.g. the dll used DLLMain() to do some static initialization.
That's fairly different from the original trick, where we are just helping the addon find exports from the .exe which are expected to come from a .exe.
I could live with it if you created a fairly unique name for the DLL you're linking to (e.g. '$bla.dll' or 'node-addon-interface.dll'. However doing this for node.dll adds spooky action at a distance and creates gotchas for people who genuinely want to link node dynamically.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that I don't maintain node-gyp, and I don't make the final decision here.
@TooTallNate asked for my advice, and my advice is to not land this as-is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think from the perspective of windows and LoadLibrary, a dll and an exe are the same. The fact that someone would compile node into a dll and ship it with their application isn't an accident and isn't really any different, in my opinion. Electron is shipping a dll called node.dll and Microsoft is doing the same in their chakra version, it sounds like. So I don't understand what you're saying is spooky or accidental?
The feature logic is simply "If we are running in node.exe or iojs.exe, use that. If not, try node.dll, otherwise use the current executable, whatever its called." Not too spooky in my opinion.
All this PR is really saying, is that node embedders can ship their own node.dll
and automatically have compatibility with node-gyp built binaries, no extra build tool shenanigans required.
As I understand it, node doesn't want to ship a separate dll, only a single .exe for aesthetic and portability reason. If they shipped a dll this would all go away, but without it we can still use the delay load hook to automatically support the dll form for embedders.
Without this we have multiple one off solutions, like electron-rebuild, nw-gyp and electron-updater-tools. Every other node embedder would have to create another one off solution.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I updated the PR based on feedback from this thread, does this change your opinon?
Let me rephrase my cryptic comment... 😄 In order to support Windows 10 IoT, @munyirik has made some changes to build node as a dll. Those changes haven't been integrated into node yet, but the plan is to do so in the future. Perhaps we can leverage the build-as-dll changes as a generic way for embedders to redistributed node. At least, we should check that these two mechanisms don't cause any conflicts with each other. |
for reference. the changes that orangemocha is talking about are in https://github.com/Microsoft/node/tree/ch0.12-uwp |
@orangemocha @munyirik Question about that, will native addons compiled via node-gyp still be dynamically linked to If however |
@justinmchase our node.dll is standalone so this change can be leveraged in future. |
@zcbenz Maybe you would be willing to give input here too? |
Also @paulcbetts, the author of |
I give this A+ full marks, I believe that this will fix the issues that |
🔔 Friendly ping on this. It's still applicable and would be nice to have integrated. |
I'm 👍 on this, there is already a |
This handles the Windows case certainly. Does it also work across other OS and Arch? |
@rgbkrk This is a windows only issue, as far as I know. |
🔔 Ping! |
Sadly this was never accepted. The problem remains in node-gyp, closing so I don't have to see it in my list anymore. |
@justinmchase over in https://github.com/CodeJockey/node-ninja we're trying a different approach and migrating to ninja for the build system, it would be great to see your patches /cc @hintjens |
@rgbkrk Whoa, I would like to subscribe to this newsletter |
@justinmchase yes, please, bring your patches to |
@rgbkrk Interesting, I'll check it out thanks. |
Attempt to load node.dll first, if its not found then link to the
running process under the assumption that it is node/iojs or has
statically linked to node. This adds support for electron or any
other app that dynamically links to node.
With this PR, node does not need to ship a "node.dll" but if 3rd party apps want to embed node they can build their own node.dll and will have automatic support from node-gyp.