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
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