Nodejs如何编译独立的node扩展插件(Addons)

Nodejs如何编译独立的node扩展插件(Addons)

如题:如何编译一个独立的,不依赖于linux系统库的的可运行程序。 下面说一下需求: 同一台机器上,会运行多个Node程序,有js项目,有node插件项目,还有混合项目。 js项目对node版本的依赖要轻得多,而插件就不同了,对版本的依赖比较重,甚至是严格, 当系统升级时,对node插件的影响就比较大,甚至于要重新编译。 有没有什么好的解决办法,可以编译一个非常独立的Node,或者另有好的解决方案。 nodejs官网释出的版本,也需要依赖系统库。


感谢shaun的提醒,“node 本身的版本没有问题”,一语中的! 所以,将标题修改为:如何编译独立的node扩展插件(Addons)? 纠正一下问题,官方给出的node Binaries是独立的, 真正的问题在于,编译node的C++插件时,产生了依赖库,这个该如何解决? 是否有方法可以把所有使用到的系统库全部编译进去。 2014.07.29更新


结帖! 感谢 shaun 和 kingapple zhs007 的指点和提醒。 下面做一下小结,方便后来人查看: 编译独立的node扩展插件(Addons),这个问题的实质是编译不依赖于其他库的动态链接库,因为node Addons本质上就是动态链接库。 所以,解决办法是,在编译动态链接库时,所有依赖的库使用静态链接的方式编译进去; 不过有一点需要注意的:用了 GPL 的库就没法静态连接了。(shaun提供) 2014.08.03更新


5 回复

Node.js 如何编译独立的 Node 扩展插件(Addons)

背景介绍

在开发 Node.js 应用时,我们经常需要编写 C++ 扩展插件(Node.js Addons)来提高性能或访问底层功能。然而,这些插件通常依赖于系统库,这使得它们在不同环境下的部署变得复杂。本文将探讨如何编译一个完全独立的 Node.js 扩展插件,以避免依赖系统库带来的问题。

需求说明

在同一台机器上,可能会运行多个 Node.js 应用,包括纯 JavaScript 项目、Node.js 扩展插件项目以及混合项目。JavaScript 项目对 Node.js 版本的依赖性较低,而扩展插件则对版本的依赖性较高,甚至需要特定版本的 Node.js 才能正常工作。当系统升级时,这些扩展插件可能需要重新编译,导致维护成本增加。

解决方案

编译独立的 Node.js 扩展插件的核心在于确保这些插件在编译时不会依赖外部的系统库。具体来说,我们需要将所有依赖项静态链接到插件中。

示例代码

以下是一个简单的 Node.js 扩展插件示例:

// addon.cc
#include <node.h>
#include <v8.h>

using namespace v8;

void Method(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = args.GetIsolate();
  HandleScope scope(isolate);

  args.GetReturnValue().Set(String::NewFromUtf8(isolate, "world").ToLocalChecked());
}

void Initialize(Local<Object> exports) {
  NODE_SET_METHOD(exports, "hello", Method);
}

NODE_MODULE(addon, Initialize)

编译这个插件时,我们需要确保所有依赖项都被静态链接。可以使用 gyp 工具来管理构建过程,并通过指定静态链接选项来实现这一点。

构建脚本
# binding.gyp
{
  "targets": [
    {
      "target_name": "addon",
      "sources": [ "addon.cc" ],
      "cflags!": [ "-fno-exceptions" ],
      "cflags_cc!": [ "-fno-exceptions" ],
      "defines": [ "NAPI_DISABLE_CPP_EXCEPTIONS" ],
      "libraries": [ "-static-libgcc -static-libstdc++" ]
    }
  ]
}

上述配置文件中,libraries 字段用于指定静态链接选项。通过这种方式,编译出的插件将不再依赖外部的系统库。

结论

通过上述方法,我们可以编译出一个完全独立的 Node.js 扩展插件,从而减少对系统库的依赖,简化部署流程。希望这个示例能帮助你更好地理解和应用这一技术。


1、node 本身的版本没有问题,如果这个都有问题,就不要把 node 放到 $PATH,每个版本放到不同的目录 2、项目中不要是用全局的 npm,也就是说用 npm 安装依赖时不要加 -g 参数,这样每个项目都有自己独立的 node_modules 3、为每个项目建立各自的 package.json 文件,在 npm install 的时候带上 --save 参数,就会自动帮你写入依赖的各种版本 4、为每个项目调用不同的 node 版本去执行

这样同时解决了 node 的多版本,和 npm 依赖的版本问题

node除了glibc外,还依赖其他什么库呢? 都静态链接?

要看开源协议,用了 GPL 的库就没法静态连接了

为了编译一个独立的Node.js扩展插件(Addons),我们需要确保该插件在编译时不会依赖于系统的动态库。这可以通过使用静态链接的方式来实现。以下是具体步骤和示例代码:

步骤

  1. 安装必要的工具:确保你的开发环境已经安装了node-gyp和相关的构建工具。

  2. 编写C++代码:编写一个简单的Node.js扩展插件(Addons)。

  3. 配置编译选项:在编译过程中,需要确保所有依赖项都使用静态链接。

示例代码

假设我们要创建一个简单的Node.js扩展插件,名为addon。该插件包含一个函数add,用于执行两个整数的加法。

addon.cc

#include <node.h>
#include <v8.h>

int add(int a, int b) {
    return a + b;
}

void Add(const v8::FunctionCallbackInfo<v8::Value>& args) {
    Isolate* isolate = args.GetIsolate();
    int result = add(args[0]->Int32Value(isolate->GetCurrentContext()).ToChecked(), 
                     args[1]->Int32Value(isolate->GetCurrentContext()).ToChecked());
    args.GetReturnValue().Set(v8::Integer::New(isolate, result));
}

void Initialize(v8::Local<v8::Object> exports) {
    NODE_SET_METHOD(exports, "add", Add);
}

NODE_MODULE(addon, Initialize)

编译

在项目根目录下创建一个binding.gyp文件,配置编译选项以静态链接所有依赖项。

{
  "targets": [
    {
      "target_name": "addon",
      "sources": [ "addon.cc" ],
      "cflags_cc": [ "-fPIC", "-static" ],
      "ldflags": [ "-static-libgcc -static-libstdc++" ]
    }
  ]
}

接下来使用node-gyp来编译这个插件:

npm install node-gyp -g
node-gyp configure build

注意事项

  • 确保所有依赖库(如Boost或其他第三方库)都支持静态链接。
  • 使用静态链接可能会增加最终生成的二进制文件大小。

通过上述步骤,你可以编译一个完全独立的Node.js扩展插件,从而减少对系统库的依赖。

回到顶部