Skip to content
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

Fix fs-native-extensions build #868

Open
gmaclennan opened this issue Nov 27, 2024 · 2 comments
Open

Fix fs-native-extensions build #868

gmaclennan opened this issue Nov 27, 2024 · 2 comments

Comments

@gmaclennan
Copy link
Member

Building newer versions of native modules, and building them for x64, results in runtime errors of symbols not being found. There appear to be errors with the build process that is not correctly linking to nodejs-mobile headers. This is limiting the functionality of sparse files, but also the ability to update our native modules, and the ability to run on x86 architecture.

@gmaclennan gmaclennan converted this from a draft issue Nov 27, 2024
@gmaclennan
Copy link
Member Author

We are currently using [email protected]. This builds successfully for nodejs-mobile, however when requiring it throws the error below. We have not been noticing this because it is conditionally required, but the consequences seem to be that files will not be created in sparse mode.

11-27 16:42:09.144  2548  2617 E nodejs  : node:internal/modules/cjs/loader:1340
11-27 16:42:09.144  2548  2617 E nodejs  :   return process.dlopen(module, path.toNamespacedPath(filename));
11-27 16:42:09.144  2548  2617 E nodejs  :                  ^
11-27 16:42:09.144  2548  2617 E nodejs  :
11-27 16:42:09.144  2548  2617 E nodejs  : Error: dlopen failed: cannot locate symbol "fs_ext__try_lock" referenced by "/data/data/com.andrewchou.nodejsmobileexpoexample/files/nodejs-project/node_modules/fs-native-extensions/build/Release/fs_ext.node"...
11-27 16:42:09.144  2548  2617 E nodejs  :     at Module._extensions..node (node:internal/modules/cjs/loader:1340:18)
11-27 16:42:09.144  2548  2617 E nodejs  :     at Module.load (node:internal/modules/cjs/loader:1119:32)
11-27 16:42:09.144  2548  2617 E nodejs  :     at Module._load (node:internal/modules/cjs/loader:960:12)
11-27 16:42:09.144  2548  2617 E nodejs  :     at Module.require (node:internal/modules/cjs/loader:1143:19)
11-27 16:42:09.144  2548  2617 E nodejs  :     at require (node:internal/modules/cjs/helpers:121:18)
11-27 16:42:09.144  2548  2617 E nodejs  :     at load (/data/data/com.andrewchou.nodejsmobileexpoexample/files/nodejs-project/node_modules/node-gyp-build/node-gyp-build.js:22:10)
11-27 16:42:09.144  2548  2617 E nodejs  :     at Object.<anonymous> (/data/data/com.andrewchou.nodejsmobileexpoexample/files/nodejs-project/node_modules/fs-native-extensions/binding.js:1:43)
11-27 16:42:09.144  2548  2617 E nodejs  :     at Module._compile (node:internal/modules/cjs/loader:1256:14)
11-27 16:42:09.144  2548  2617 E nodejs  :     at Module._extensions..js (node:internal/modules/cjs/loader:1310:10)
11-27 16:42:09.144  2548  2617 E nodejs  :     at Module.load (node:internal/modules/cjs/loader:1119:32) {
11-27 16:42:09.144  2548  2617 E nodejs  :   code: 'ERR_DLOPEN_FAILED'
11-27 16:42:09.144  2548  2617 E nodejs  : }
11-27 16:42:09.144  2548  2617 E nodejs  :
11-27 16:42:09.144  2548  2617 E nodejs  : Node.js v18.17.1

More recent versions of fs-native-extensions do not build with nodejs-mobile-react-native or with prebuild-for-nodejs-mobile because they are not detected as native modules, and they do not expose any build command as an npm script. Instead they do prebuilds in CI using bare-make. bare-make does not do anything Bare specific, it seems to be a wrapper around CMake, that calls it with the correct arguments.

The actual build process is defined in the module's CMakeLists.txt which uses the module cmake-napi to configure the builds for Node. cmake-napi downloads node headers and also skips creating node builds for android.

What I have tried is forking fs-native-extensions and patching cmake-napi to download the nodejs-mobile headers and to build node outputs for android. This does successfully build, however actually using the build results in this error:

11-27 15:46:08.602  2116  2186 E nodejs  : node:internal/modules/cjs/loader:1340
11-27 15:46:08.602  2116  2186 E nodejs  :   return process.dlopen(module, path.toNamespacedPath(filename));
11-27 15:46:08.602  2116  2186 E nodejs  :                  ^
11-27 15:46:08.602  2116  2186 E nodejs  :
11-27 15:46:08.602  2116  2186 E nodejs  : Error: dlopen failed: cannot locate symbol "napi_get_cb_info" referenced by "/data/data/com.andrewchou.nodejsmobileexpoexample/files/nodejs-project/node_modules/fs-native-extensions/prebuilds/android-arm64/fs-native-extensions.node"...
11-27 15:46:08.602  2116  2186 E nodejs  :     at Module._extensions..node (node:internal/modules/cjs/loader:1340:18)
11-27 15:46:08.602  2116  2186 E nodejs  :     at Module.load (node:internal/modules/cjs/loader:1119:32)
11-27 15:46:08.602  2116  2186 E nodejs  :     at Module._load (node:internal/modules/cjs/loader:960:12)
11-27 15:46:08.602  2116  2186 E nodejs  :     at Module.require (node:internal/modules/cjs/loader:1143:19)
11-27 15:46:08.602  2116  2186 E nodejs  :     at require (node:internal/modules/cjs/helpers:121:18)
11-27 15:46:08.602  2116  2186 E nodejs  :     at load (/data/data/com.andrewchou.nodejsmobileexpoexample/files/nodejs-project/node_modules/node-gyp-build/node-gyp-build.js:22:10)
11-27 15:46:08.602  2116  2186 E nodejs  :     at Object.<anonymous> (/data/data/com.andrewchou.nodejsmobileexpoexample/files/nodejs-project/node_modules/fs-native-extensions/binding.js:1:43)
11-27 15:46:08.602  2116  2186 E nodejs  :     at Module._compile (node:internal/modules/cjs/loader:1256:14)
11-27 15:46:08.602  2116  2186 E nodejs  :     at Module._extensions..js (node:internal/modules/cjs/loader:1310:10)
11-27 15:46:08.602  2116  2186 E nodejs  :     at Module.load (node:internal/modules/cjs/loader:1119:32) {
11-27 15:46:08.602  2116  2186 E nodejs  :   code: 'ERR_DLOPEN_FAILED'
11-27 15:46:08.602  2116  2186 E nodejs  : }
11-27 15:46:08.602  2116  2186 E nodejs  :
11-27 15:46:08.602  2116  2186 E nodejs  : Node.js v18.17.1

What I have investigated so far:

I have checked that the symbol napi_get_cb_info actually exists in libnode.so that is in the APK I am running that results in the errors above:

❯ nm -D android/app/build/outputs/apk/debug/app-debug/lib/arm64-v8a/libnode.so | grep napi_get_cb_info
0000000001504acc T napi_get_cb_info

So it seems like the symbol is included in the node binary that we have in the APK.

I have also checked the reference to the symbol in the built file (fs-native-extensions.node):

❯ nm -g prebuilds/android-arm64/fs-native-extensions.node
                 U __cxa_atexit
                 U __cxa_finalize
                 U __register_atfork
                 U __stack_chk_fail
                 U free
000000000000576c T fs_ext__sparse
                 U fs_ext__swap
                 U fs_ext__trim
000000000000574c T fs_ext__try_downgrade_lock
                 U fs_ext__try_lock
000000000000575c T fs_ext__try_upgrade_lock
                 U fs_ext__unlock
0000000000005754 T fs_ext__wait_for_downgrade_lock
                 U fs_ext__wait_for_lock
0000000000005764 T fs_ext__wait_for_upgrade_lock
0000000000004990 T fs_ext_napi_sparse
0000000000004c2c T fs_ext_napi_swap
00000000000046c8 T fs_ext_napi_trim
0000000000004078 T fs_ext_napi_try_downgrade_lock
0000000000003c50 T fs_ext_napi_try_lock
0000000000004318 T fs_ext_napi_try_upgrade_lock
00000000000045b8 T fs_ext_napi_unlock
0000000000004188 T fs_ext_napi_wait_for_downgrade_lock
0000000000003d84 T fs_ext_napi_wait_for_lock
0000000000004428 T fs_ext_napi_wait_for_upgrade_lock
000000000000568c T fs_ext_sparse
00000000000056ec T fs_ext_swap
0000000000005624 T fs_ext_trim
0000000000005510 T fs_ext_try_downgrade_lock
0000000000005470 T fs_ext_try_lock
0000000000005598 T fs_ext_try_upgrade_lock
0000000000005620 T fs_ext_unlock
0000000000005540 T fs_ext_wait_for_downgrade_lock
00000000000054a0 T fs_ext_wait_for_lock
00000000000055c8 T fs_ext_wait_for_upgrade_lock
                 U malloc
                 U napi_close_handle_scope
                 U napi_create_error
                 U napi_create_function
                 U napi_create_reference
                 U napi_create_string_utf8
                 U napi_create_uint32
                 U napi_delete_reference
                 U napi_fatal_exception
                 U napi_get_and_clear_last_exception
                 U napi_get_buffer_info
                 U napi_get_cb_info
                 U napi_get_null
                 U napi_get_reference_value
                 U napi_get_uv_event_loop
                 U napi_get_value_string_utf8
                 U napi_get_value_uint32
                 U napi_make_callback
                 U napi_open_handle_scope
0000000000004f88 T napi_register_module_v1
                 U napi_set_named_property
                 U napi_throw_error
0000000000004f80 T node_api_module_get_api_version_v1
                 U uv_err_name
                 U uv_get_osfhandle
                 U uv_queue_work
                 U uv_strerror

I am unclear what the U and T mean here. The output for the build fs-native-extensions.node that does actually work (the prebuild that ships with the package, for darwin arm64) is:

❯ nm -g node_modules/fs-native-extensions/prebuilds/darwin-arm64/fs-native-extensions.node
                 U ___error
                 U ___stack_chk_fail
                 U ___stack_chk_guard
                 U _calloc
                 U _fcntl
                 U _flock
                 U _free
0000000000002ae0 T _fs_ext__sparse
0000000000002d0c T _fs_ext__swap
0000000000002bc4 T _fs_ext__trim
0000000000002ac0 T _fs_ext__try_downgrade_lock
0000000000002ae8 T _fs_ext__try_lock
0000000000002ad0 T _fs_ext__try_upgrade_lock
0000000000002b80 T _fs_ext__unlock
0000000000002ac8 T _fs_ext__wait_for_downgrade_lock
0000000000002b34 T _fs_ext__wait_for_lock
0000000000002ad8 T _fs_ext__wait_for_upgrade_lock
0000000000001d0c T _fs_ext_napi_sparse
0000000000001fb8 T _fs_ext_napi_swap
0000000000001a34 T _fs_ext_napi_trim
00000000000013a8 T _fs_ext_napi_try_downgrade_lock
0000000000000f6c T _fs_ext_napi_try_lock
0000000000001660 T _fs_ext_napi_try_upgrade_lock
0000000000001918 T _fs_ext_napi_unlock
00000000000014c4 T _fs_ext_napi_wait_for_downgrade_lock
00000000000010ac T _fs_ext_napi_wait_for_lock
000000000000177c T _fs_ext_napi_wait_for_upgrade_lock
0000000000002a00 T _fs_ext_sparse
0000000000002a60 T _fs_ext_swap
0000000000002998 T _fs_ext_trim
0000000000002884 T _fs_ext_try_downgrade_lock
00000000000027e4 T _fs_ext_try_lock
000000000000290c T _fs_ext_try_upgrade_lock
0000000000002994 T _fs_ext_unlock
00000000000028b4 T _fs_ext_wait_for_downgrade_lock
0000000000002814 T _fs_ext_wait_for_lock
000000000000293c T _fs_ext_wait_for_upgrade_lock
                 U _fstat
                 U _malloc
                 U _napi_close_handle_scope
                 U _napi_create_error
                 U _napi_create_function
                 U _napi_create_reference
                 U _napi_create_string_utf8
                 U _napi_create_uint32
                 U _napi_delete_reference
                 U _napi_fatal_exception
                 U _napi_get_and_clear_last_exception
                 U _napi_get_buffer_info
                 U _napi_get_cb_info
                 U _napi_get_null
                 U _napi_get_reference_value
                 U _napi_get_uv_event_loop
                 U _napi_get_value_string_utf8
                 U _napi_get_value_uint32
                 U _napi_make_callback
                 U _napi_open_handle_scope
0000000000002324 T _napi_register_module_v1
                 U _napi_set_named_property
                 U _napi_throw_error
000000000000231c T _node_api_module_get_api_version_v1
                 U _pwrite
                 U _renameatx_np
                 U _uv_err_name
                 U _uv_get_osfhandle
                 U _uv_queue_work
                 U _uv_strerror
                 U _uv_translate_sys_error
                 U dyld_stub_binder

The difference seems to be the prefix of symbols with _, which I have no idea what or why this is.

I'm unsure where to go next. It could be that there is an issue with the header files that are distributed with nodejs-mobile releases, or the build of nodejs-mobile itself, or it could be an issue with how linking is configured during the build process.

@EvanHahn
Copy link
Contributor

I looked into this and don't have an answer—yet, I hope.

I investigated whether the issue was ABI incompatibility, which I don't think is the case, because it looks like napi_get_cb_info is defined in all versions of N-API.

I'll do some more digging later.

I am unclear what the U and T mean here.

U means that the symbol is undefined, which is expected for dynamic linking like this. T is short for "text section symbol"—effectively, the symbol was found.

The difference seems to be the prefix of symbols with _, which I have no idea what or why this is.

I believe this is just how different compilers mangle symbols in the object file, so I don't the underscore matters.

@achou11 achou11 moved this to In Progress in CoMapeo Refactor Nov 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: In Progress
Development

No branches or pull requests

2 participants