nodejsv12跨平台(Windows&linux&mac)编译c++插件addon

470 阅读1分钟

nodejsv12跨平台(Windows&linux&mac)编译c++插件addon

环境:

OS : deepin 20.1

nodejs : 12.13.0

node-gyp : 6.1.0

compile : gcc 8.3.0

Python : 2.7


OS : windows 10 1909

nodejs : 14.15.4

node-gyp : 7.0.0

GCC :Visual Studio 2019

Python : 3.8

1. 安装nodejs

略过

2.安装node-gyp

参考www.npmjs.com/package/nod…

Linux下:

前提:

  • python (推荐 v2.7)
  • make
  • C/C++编译工具,例如GCC
# 安装
npm install -g node-gyp

建立软连接(这里假设nodejs安装路径为/app/software/)

sudo ln -s /app/software/nodejs/bin/node-gyp /usr/local/bin/ 

查看node-gyp的版本

node-gyp -v

3.编写测试代码

node_addon_cpp_demo
+--- addon.cc
+--- binding.gyp
+--- compile.bat
+--- compile.sh
+--- readme.md
+--- run_test.bat
+--- run_test.sh
+--- test.js
+--- thirdlib
|   +--- CMakeLists.txt
|   +--- compile.bat
|   +--- compile.sh
|   +--- myadd.cc
|   +--- myadd.h

3.1 编写第三方动态库代码myadd.c

源文件

// myadd.h

#if defined(_WIN32)
#define DLL_EXPORT __declspec(dllexport) ///< define DLL_EXPORT windows
#else
#define DLL_EXPORT __attribute__((visibility("default"))) ///< define DLL_EXPORT unix 
#endif

int DLL_EXPORT myAdd(int x, int y);
// myadd.cc

#include "myadd.h"

int myAdd(int x, int y)
{
	return x + y;
}

编译可以使用cmake、make或Visual Studio

cmake_minimum_required(VERSION 2.8)

project(myadd)

message(STATUS "operation system is ${CMAKE_SYSTEM}")

# 设置头文件路径
include_directories(.)

# 设置依赖文件路径
# link_directories(.)

# 源文件列表
file(GLOB_RECURSE SOURCE_CPP myadd.cc) 

# 生成库文件
add_library( ${PROJECT_NAME} SHARED ${SOURCE_CPP})

3.2 编写 addon.cc

// addon.cc

// node v12.13.0

#include <node.h>

#include "myadd.h"

#include <iostream>
using namespace std;

namespace demo {

using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::NewStringType;
using v8::Object;
using v8::String;
using v8::Value;

using v8::Number;

void helloMethod(const FunctionCallbackInfo<Value> &args) {
  Isolate *isolate = args.GetIsolate();
  
  args.GetReturnValue().Set(
      String::NewFromUtf8(isolate, "hello world", NewStringType::kNormal)
          .ToLocalChecked());
}

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

  int x = args[0].As<Number>()->Value();
  int y = args[1].As<Number>()->Value();

  double value = myAdd(x, y);
  cout << "C++ output : " << x << "+" << y << "=" << value << endl;

  args.GetReturnValue().Set(Number::New(isolate, value));
}

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

NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)

} // namespace demo

注意1:

所有的 Node.js 插件必须导出一个如下模式的初始化函数:

void Initialize(Local<Object> exports);
NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)

NODE_MODULE 后面没有分号,因为它不是一个函数(详见 node.h)。

module_name 必须匹配最终的二进制文件名(不包括 .node 后缀)。

在 hello.cc 示例中,初始化函数是 Init,插件模块名是 addon。

使用 node-gyp 构建插件时,使用宏 NODE_GYP_MODULE_NAME 作为 NODE_MODULE() 的第一个参数将确保会将最终二进制文件的名称传给 NODE_MODULE()。

3.3 编写构建文件binding.gyp

支持windows、linux、mac

{
  'targets': [
    {
      'target_name': 'addon',
      'sources': [ 'addon.cc' ],
	  'include_dirs':[ 'thirdlib' ],
      'libraries':[ '-lmyadd' ],
      'conditions': [
          ['OS=="win"',{
              'library_dirs':[ '<(module_root_dir)/thirdlib/bin_win/Debug' ]
          }],
          ['OS=="linux"',{              'library_dirs':[ '<(module_root_dir)/thirdlib/bin_unix' ]
          }],
          ['OS=="mac"',{ # not test              'library_dirs':[ '<(module_root_dir)/thirdlib/bin_unix' ]
          }]
      ]
    }
  ]
}

3.4 编译.node模块

node-gyp configure --debug build

--debug参数表示生成debug文件

3.5 编写 test.js

//test.js

var addon = require('./build/Debug/addon.node');

console.log('JS output : ',addon.hello()); // hello world

console.log('JS output : ', addon.add(3, 6)); // 3+6=9

require的路径需要和3.4中编译出来的路径一致

3.6 运行

windows

set path=%~dp0/thirdlib/bin_win/Debug;%path%

node test.js

linux

export LD_LIBRARY_PATH=`pwd`/thirdlib/bin_unix:$LD_LIBRARY_PATH

node test.js

3.6 结果

$ node test.js 
JS output :  hello world
C++ output : 3+6=9
JS output :  9