prebuild / prebuildify

Create and package prebuilds for native modules
MIT License
198 stars 37 forks source link

The specified module could not be found #36

Closed gniezen closed 4 years ago

gniezen commented 4 years ago

I'm attempting to upgrade my app from Electron v3 to v7. macOS and Linux works fine, but I'm getting the following errors on Windows:

32-bit:

Uncaught Error: The specified module could not be found.
\\?\C:\Program Files\Tidepool Uploader\resources\app.asar.unpacked\node_modules\lzo-decompress\prebuilds\win32-ia32\electron.napi.node

64-bit:

Uncaught Error: The specified module could not be found.
\\?\C:\Program Files\Tidepool Uploader\resources\app.asar.unpacked\node_modules\lzo-decompress\prebuilds\win32-x64\electron.napi.node

I've found some threads relating to that error appearing when some .dll's cannot be found. I'm still using the same .dll's that worked under Electron v3, so I thought it may be due to https://electronjs.org/docs/tutorial/using-native-node-modules#a-note-about-win_delay_load_hook, but my understanding is that win_delay_load_hook is handled by node-gyp-build?

The module's source code can be found here: https://github.com/tidepool-org/lzo-decompress/tree/update-deps

Notes:

vweevers commented 4 years ago

Does it work if you don't package electron? I would guess asar is the issue because if it was a win_delay_load_hook issue you'd see slightly different error messages.

gniezen commented 4 years ago

Yes, if I just require the module in the Node CLI, it works without any issues:

C:\Users\Tidepool Test\sandbox>yarn add lzo-decompress
yarn add v1.19.1
info No lockfile found.
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
success Saved 3 new dependencies.
info Direct dependencies
+- lzo-decompress@0.1.12
info All dependencies
+- lzo-decompress@0.1.12
+- napi-macros@2.0.0
+- node-gyp-build@4.2.0
Done in 3.57s.

C:\Users\Tidepool Test\sandbox>node
Welcome to Node.js v12.8.1.
Type ".help" for more information.
> const lzo = require('lzo-decompress')
undefined
> lzo.decompress(new Uint16Array('asdf'), 4)
Thrown:
Error: Failed to decompress
vweevers commented 4 years ago

in the Node CLI

What about electron? E.g. via electron my-test.js.

gniezen commented 4 years ago

Same problem:

Uncaught Error: The specified module could not be found.
\\?\C:\Users\Tidepool Test\uploader\app\node_modules\lzo-decompress\prebuilds\win32-ia32\electron.napi.node
vweevers commented 4 years ago

OK, so you're probably right about win_delay_load_hook. Sorry, had to rule out asar 😃

vweevers commented 4 years ago

This line in the electron docs confuses me:

As such, on Electron 4.x and higher, 'win_delay_load_hook': 'true' is required to load native modules.

Because setting that was never necessary in leveldown (either with electron v4, or the current v7, which we continuously test over there).

gniezen commented 4 years ago

Yeah, I think it defaults to true, so that line is just to make sure that you don't manually set it to false (for whatever reason).

vweevers commented 4 years ago

I remember that leveldown had issues with electron v3 and we ended up requiring a minimum of electron v4, and it was related to the delayed load hook mess. Lemme see if I can find it in GH history.

vweevers commented 4 years ago

Sadly I can't find or remember the full details, but we were unable to make a prebuild that worked in both v3 and v4 (https://github.com/Level/leveldown/issues/602#issuecomment-478058612). We then decided to drop v3 and use a runtime-agnostic prebuild, i.e. node.napi.node (which also works in Electron) rather than electron-napi.node.

If you want to keep supporting Electron v3, a possible solution is to create two prebuilds for electron, one for v3, and one for v4 and up.

gniezen commented 4 years ago

So by using prebuildify -t 8.14.0 --napi --strip you're only targeting Node v8.14.0 and it only produces a node.napi.node? Does that also build for 32-bit Windows?

Why Node v8 specifically?

vweevers commented 4 years ago

Does that also build for 32-bit Windows?

We dropped 32-bit because it's rare.

Why Node v8 specifically?

N-API is forward compatible, but not necessarily backward compatible. By building against node 8, we ensure that the prebuilds work on node 8 and any future version. Whether you need this, depends on which N-API functions you're using. Some folks just build against latest node.

gniezen commented 4 years ago

YES! It's finally working! :tada: Using prebuildify -t 8.14.0 --arch=ia32 --napi --strip and prebuildify -t 8.14.0 --napi --strip I was able to make builds for both 32-bit and 64-bit Windows, and it's working fine with Electron v7.

Maybe this could be clarified in the README?

vweevers commented 4 years ago

Nice, congratulations!

Maybe this could be clarified in the README?

In what form? It's difficult to write up an approach that works for everyone. Perhaps as a FAQ, or a list of caveats?

mafintosh commented 4 years ago

I'm wondering how hard it would be to infer the lowest n-api version needed using a bit of statical analysis. I.e. list all n-api function used, map against the node version it was added (available in the node docs) and build against that one.

gniezen commented 4 years ago

I was thinking maybe just another footnote in the options table, next to the --napi flag. As in, "***** Using prebuildify --napi will only support Electron v3 if not targeting a specific Electron or Node version. Use prebuildify -t 8.14.0 --napi to produce a runtime-agnostic prebuild that works in both Node v8 (and higher) and Electron v4 (and higher)."

Breaking the footnotes into a FAQ/Caveats section could also work.

vweevers commented 4 years ago

@mafintosh For linux that's probably doable, wrapping existing tools. But cross-platform? A simple regex-based solution (find napi_xx) is probably easier than proper cross-platform statistical analysis. With some convention-based logic on top (e.g. if you have napi-macros in your dependencies we include all of its functions, which is easier than parsing includes and macros).

vweevers commented 4 years ago

@mafintosh First step: napi-functions.

vweevers commented 4 years ago

Closing because the original issue is resolved. A PR would be welcome to add docs.