Browse Source

fix: export libuv symbols (#24659)

* fix: export libuv symbols

* add test for linux and windows

* mac linker flags

* assuming same foo.so path for macos

* use --whole-archive flag for mac as well

* use force_load for mac

* refactor: use napi c api directly

Co-authored-by: Cheng Zhao <[email protected]>
Teo Koon Peng 4 years ago
parent
commit
14aba3f0de

+ 11 - 1
BUILD.gn

@@ -814,6 +814,9 @@ if (is_mac) {
       "-Wl,-install_name,@rpath/$output_name.framework/$output_name",
       "-rpath",
       "@loader_path/Libraries",
+
+      # Required for exporting all symbols of libuv.
+      "-Wl,-force_load,obj/third_party/electron_node/deps/uv/libuv.a",
     ]
     if (is_component_build) {
       ldflags += [
@@ -1145,7 +1148,14 @@ if (is_mac) {
       ]
     }
     if (is_linux) {
-      ldflags = [ "-pie" ]
+      ldflags = [
+        "-pie",
+
+        # Required for exporting all symbols of libuv.
+        "-Wl,--whole-archive",
+        "obj/third_party/electron_node/deps/uv/libuv.a",
+        "-Wl,--no-whole-archive",
+      ]
 
       if (!is_component_build && is_component_ffmpeg) {
         configs += [ "//build/config/gcc:rpath_for_built_shared_libraries" ]

+ 1 - 0
spec-main/fixtures/module/uv-dlopen.js

@@ -0,0 +1 @@
+require('uv-dlopen');

+ 13 - 0
spec-main/fixtures/native-addon/uv-dlopen/binding.gyp

@@ -0,0 +1,13 @@
+{
+  "targets": [
+    {
+      "target_name": "test_module",
+      "sources": [ "main.cpp" ],
+    },
+    {
+      "target_name": "libfoo",
+      "type": "shared_library",
+      "sources": [ "foo.cpp" ]
+    }
+  ]
+}

+ 2 - 0
spec-main/fixtures/native-addon/uv-dlopen/foo.cpp

@@ -0,0 +1,2 @@
+extern "C"
+void foo() { }

+ 16 - 0
spec-main/fixtures/native-addon/uv-dlopen/index.js

@@ -0,0 +1,16 @@
+const testLoadLibrary = require('./build/Release/test_module');
+
+const lib = (() => {
+  switch (process.platform) {
+    case 'linux':
+      return `${__dirname}/build/Release/foo.so`;
+    case 'darwin':
+      return `${__dirname}/build/Release/foo.dylib`;
+    case 'win32':
+      return `${__dirname}/build/Release/libfoo.dll`;
+    default:
+      throw new Error('unsupported os');
+  }
+})();
+
+testLoadLibrary(lib);

+ 42 - 0
spec-main/fixtures/native-addon/uv-dlopen/main.cpp

@@ -0,0 +1,42 @@
+#include <node_api.h>
+#include <uv.h>
+
+namespace test_module {
+
+napi_value TestLoadLibrary(napi_env env, napi_callback_info info) {
+  size_t argc = 1;
+  napi_value argv;
+  napi_status status;
+  status = napi_get_cb_info(env, info, &argc, &argv, NULL, NULL);
+  if (status != napi_ok) napi_fatal_error(NULL, 0, NULL, 0);
+
+  char lib_path[256];
+  status = napi_get_value_string_utf8(env, argv, lib_path, 256, NULL);
+  if (status != napi_ok) napi_fatal_error(NULL, 0, NULL, 0);
+
+  uv_lib_t lib;
+  auto uv_status = uv_dlopen(lib_path, &lib);
+  if (uv_status == 0) {
+    napi_value result;
+    status = napi_get_boolean(env, true, &result);
+    if (status != napi_ok) napi_fatal_error(NULL, 0, NULL, 0);
+    return result;
+  } else {
+    status = napi_throw_error(env, NULL, uv_dlerror(&lib));
+    if (status != napi_ok) napi_fatal_error(NULL, 0, NULL, 0);
+  }
+}
+
+napi_value Init(napi_env env, napi_value exports) {
+  napi_value method;
+  napi_status status;
+  status = napi_create_function(env, "testLoadLibrary", NAPI_AUTO_LENGTH,
+                                TestLoadLibrary, NULL, &method);
+  if (status != napi_ok)
+    return NULL;
+  return method;
+}
+
+NAPI_MODULE(TestLoadLibrary, Init);
+
+}  // namespace test_module

+ 5 - 0
spec-main/fixtures/native-addon/uv-dlopen/package.json

@@ -0,0 +1,5 @@
+{
+  "name": "uv-dlopen",
+  "version": "0.0.1",
+  "main": "index.js"
+}

+ 21 - 0
spec-main/modules-spec.ts

@@ -44,6 +44,27 @@ describe('modules support', () => {
       });
     });
 
+    const enablePlatforms: NodeJS.Platform[] = [
+      'linux',
+      'darwin',
+      'win32'
+    ];
+    ifdescribe(nativeModulesEnabled && enablePlatforms.includes(process.platform))('module that use uv_dlopen', () => {
+      it('can be required in renderer', async () => {
+        const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true } });
+        w.loadURL('about:blank');
+        await expect(w.webContents.executeJavaScript('{ require(\'uv-dlopen\'); null }')).to.be.fulfilled();
+      });
+
+      ifit(features.isRunAsNodeEnabled())('can be required in node binary', async function () {
+        const child = childProcess.fork(path.join(fixtures, 'module', 'uv-dlopen.js'));
+        await new Promise(resolve => child.once('exit', (exitCode) => {
+          expect(exitCode).to.equal(0);
+          resolve();
+        }));
+      });
+    });
+
     describe('q', () => {
       describe('Q.when', () => {
         it('emits the fullfil callback', (done) => {

+ 1 - 0
spec-main/package.json

@@ -10,6 +10,7 @@
     "echo": "file:fixtures/native-addon/echo",
     "q": "^1.5.1",
     "sinon": "^9.0.1",
+    "uv-dlopen": "./fixtures/native-addon/uv-dlopen/",
     "ws": "^7.2.1"
   },
   "dependencies": {

+ 3 - 0
spec-main/yarn.lock

@@ -268,6 +268,9 @@ uri-js@^4.2.2:
   dependencies:
     punycode "^2.1.0"
 
+uv-dlopen@./fixtures/native-addon/uv-dlopen/:
+  version "0.0.1"
+
 worker-loader@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/worker-loader/-/worker-loader-2.0.0.tgz#45fda3ef76aca815771a89107399ee4119b430ac"