+-
专题:让C++给node做技术加持(二)-NodeJs调用C++方法

欢迎来到我的专题文章:《让C++给node做技术加持》系列。更多内容,持续更新中,欢迎关注。

目录:
专题:让C++给node做技术加持(一)环境搭建,项目运行


...

NodeJs调用C++方法

前面的章节,我们已经搭建好了整个打包的运行环境,接下来,让我们抛开官网的demo,自己写一些简单的C++代码供NodeJs调用。

先来创建一个空目录

mkdir demo && cd demo

创建两个文件。Calc.h, Calc.cc

说明:这里的.h文件是C++的头文件,.cc是c++的主要逻辑代码文件

我们需要定义两个方法,一个做两个数的相加,返回结果,还有一个是传入一个字符串,返回一个新的字符串。

//定义calc.h头文件 #pragma once //#pragma once是一个比较常用的C/C++预处理指令,只要在头文件的最开始加入这条预处理指令,就能够保证头文件只被编译一次。 #include <string> class Calc{ public: static double add(int a, int b); static std::string reverse(std::string arr); }; //这里使用到了C++类的概念,有些ES6基础的基本都能看明白,定义了一个Calc的类,并定义了两个可供外界访问的 //静态方法

再来看下Calc.cc文件

#include "Calc.h" //引入刚定义好的头文件 #include <string> using namespace std; //要想用string 需要引入std全名空间 double Calc::add(int a,int b){ return a + b; } string Calc::reverse(string str) { return str + "-> 畅哥聊技术 ^_^"; } //这里实现了刚才头文件里面方法。调用静态方法我们在ES6中是直接通过类名.静态方法,C++中些许的差异, //通过类名::静态方法名,像php

方法的实现也很简单。

接下来我们开始编译了。

说明:这样的C++代码是不能直接被我们的V8调用,我们需要对C++进行加工处理下。

...

重点来了!!!

//1、先将.cc文件编译成 .o 文件 我们采用g++命令 g++ -c Calc.cc


... 生成了Calc.o文件

生成了.o文件后,我们还不能直接用它,我们需要做二次编译

ar -crv libCalc.a Calc.o //libCalc.a将是我们最终要的文件


... 最终的.a文件生成了

接着,我们要开始创建我们node-gyp的配置文件了,binding.gyp

{ "targets": [ { "target_name": "test", "sources": [ "test.cc" ], "libraries":["../libCalc.a"] } ] } //参数libraries 指向了我们刚打包出来的.a文件。

接下来我们开始创建我们的v8测试文件了,test.cc

#include <node.h> #include "./Calc.h" //引入刚才我们创建好的.h头文件 #include <string> using namespace std; namespace MyDemo { //引入v8相关类型,用于与C++交互 using v8::Exception; using v8::FunctionCallbackInfo; using v8::Isolate; using v8::Local; using v8::NewStringType; using v8::Number; using v8::Object; using v8::String; using v8::Value; void Add(const FunctionCallbackInfo<Value>& args) { Isolate* isolate = args.GetIsolate(); //引入了头文件后,我们就可以调用里面的方法了。 //args是用来接收我们从node传过来的参数。下面是取number类型的数据。 double value = Calc::add(args[0].As<Number>()->Value(),args[1].As<Number>()->Value()); //isolate是一个node与C++链接的管道 指针对象 Local<Number> num = Number::New(isolate, value); //最后将计算后的结果num返回给node端。 args.GetReturnValue().Set(num); } void Reverse(const FunctionCallbackInfo<Value>& args) { Isolate* isolate = args.GetIsolate(); //通过接收args接收node传过来的参数,并转成v8类型的字符串。 String::Utf8Value param1(args[0]->ToString()); //得到的param1对象是一个指针对象,它指向的是一个内存地址, //所以我们在调用Calc::reverse的方法的时候需要将param1指针解引用拿到对应的字符串值 // *param1 就是解引用,拿到具体的字符串。 string str = Calc::reverse(*param1); Local<String> val = String::NewFromUtf8(isolate,str.c_str()); // Calc::reverse(*param1);返回的是一个C++ 的 string类型的数据。我们还不能直接返回 //具体的问题,我们上一个章节已经做过说明了。需要经过 str.c_str()处理下。 args.GetReturnValue().Set(val); //最后将结果返回给node端 } void Init(Local<Object> exports) { //向nodejs导出两个方法、 NODE_SET_METHOD(exports,"add", Add); NODE_SET_METHOD(exports,"reverse",Reverse); } NODE_MODULE(addon, Init) }

接下来我们看下编译过程:


... 成功编译

最后来调用下吧。创建index.js

... 成功调用了C++的方法

到这里,我们已经成功调用了C++编写的方法了。

总结

记住一些打包的步骤,然后最好有一些C++的基础,有些概念可能比较难懂,比如指针,指针的解引用等操作。

我开始写demo的时候,也是遇到了各种坑。好在最终都一一填完了。

这里是 畅哥聊技术 《让C++给node做技术加持》专题系列文章,更多内容,持续更新中,欢迎关注。

下期,我继续带大家入坑,看C++如果在electron开发中给我们预留的坑吧。

全文完。