Using C and C++ to implement node. js module (1)

  • 2020-03-30 03:59:18
  • OfStack

A long time ago, the Online Judge of NBUT was refactored with node. js, including the benchmark. (as for when to finish it, don't care, (/ � Д ') / ~ � �

Anyway, what we're going to do now is simply to implement the node. js module in C/C++.

The preparatory work

Work to do its job, must first ~~ play rascal ~~ its weapon.

Node - gyp

First you need a node-gyp module.

In any corner, execute:


$ npm install node-gyp -g

  After a series of blahblah, you are installed.

Python

Then you need to have a python environment.

Go to the official website to get one.


Note: according to the GitHub display of node-gyp, make sure your python version is between 2.5.0 and 3.0.0.
 
Compile environment

Well, I'm going to be lazy and move to node-gyp to see what the compiler requires. And well done.

An introduction to

I'll take a look at Hello World.

Hello World

Please prepare a C++ file, such as ~~sb. Cc ~~ hello.cc.

Then we'll go through it step by step, getting the files in and defining the namespace:


#include <node.h>
#include <v8.h>
using namespace v8;

  The main function

Next we write a function that returns Handle< Value> .


Handle<Value> Hello(const Arguments& args)
{
    //.
}

  And then I'm going to go through the rough stuff:

Handle< Value>

Be a person to have integrity, I declare beforehand I from here (@fool) reference.


The Handle type is used to host JavaScript objects in V8. Similar to STD ::sharedpointer in C++, the assignments between the handles pass object references directly.

JavaScript types in C++ have corresponding custom types, such as String, Integer, Object, Date, Array, etc., which strictly comply with the inheritance relationship in JavaScript. When using these types in C++, you must use Handle to manage their lifecycle using GC instead of native stacks and heaps.
 
This so-called Value, which can be seen from the various inheritance relationships in V8 engine's header file v8.h, is actually the base class of various objects in JavaScript.

Now that we've looked at this, we get a sense of what the function declaration above means is that we write a Hello function that returns a value of an indeterminate type.


Note: we can only return certain types, String, Integer, etc. under Handle.
 
The Arguments

This is the argument that's passed in to this function. We all know that in node. js, the number of arguments is messed up. When these Arguments are passed into C++, they become an object of this Arguments type.

We'll talk about that later, but we just need to understand what this is. Is there any doubt about it? Since the examples in the node. js documentation are separate, I'm just going to show you the first Hello World example (& acute; The & # 3109; The & # 3178; The & # 3109;) sigma

The countrys

Then we began to build. Just two simple sentences:


Handle<Value> Hello(const Arguments& args)
{
    HandleScope scope;
    return scope.Close(String::New("world"));
}

  What do these two sentences mean? Returns a string "world" in node. js.

HandleScope

Refer to here.


Handle, unlike the C++ smart pointer, does not live within the scope of C++ semantics (that is, the part surrounded by {}) and needs to be specified manually through the HandleScope. HandleScope can only be allocated on the stack. After the declaration of the HandleScope object, the handles created afterwards are managed by the HandleScope to manage the life cycle. After the destruction of the HandleScope object, the handles managed by the HandleScope will be determined by the GC whether to recycle or not.
 
So, we have to declare this Scope when we need to manage its life cycle. Okay, so why doesn't our code do that?


Handle<Value> Hello(const Arguments& args)
{
    HandleScope scope;
    return String::New("world");
}

  Because when the function returns, the scope is destructed and the handles it manages are recycled, the String becomes meaningless.

So V8 came up with a magic idea: HandleScope::Close(Handle< T> Value) function! The purpose of this function is to close the Scope and pass the arguments inside to the previous Scope management, which is the Scope before entering the function.

Hence our previous code scope.Close(String::New("world")); .

String: : New

This String class corresponds to the native String class in node. js. Inherited from the Value class. Similarly, there are:

  The & # 8226; Array
The & # 8226; The Integer
The & # 8226; Boolean
The & # 8226; The Object
The & # 8226; The Date
The & # 8226; Number
The & # 8226; The Function
The & # 8226; .
 
Some of these things are inherited from Value, some of them are secondary. We won't do much research here, so you can look at the V8 code (or at least the header file) for yourself and study it or look at this manual.

What about this New? You can see it here. I'm just creating a new String object.

At this point, we're done parsing the main function.

Export object

Let's review, how do we export functions or objects if we're writing in node. js?


exports.hello = function() {}

  So, how do we do this in C++?

Initialization function

First, let's write an initialization function:


void init(Handle<Object> exports)
{
    //. Wait to write your sister! # & # 65439; & Aring; The & # 65439;) The & # 8834; 彡 ) being the & # 65439; Д & # 65439;) The & # 65381; ∵ < br / > }

  It's a turtle bottom! It doesn't matter what the name of the function is, but the parameter passed in must be a Handle< Object> , which means we are going to export something on it next.

And then, we'll put the exported thing in here:


void init(Handle<Object> exports)
{
    exports->Set(String::NewSymbol("hello"),
        FunctionTemplate::New(Hello)->GetFunction());
}

  In other words, adding a field called hello to this exports object is a function that is our dear hello function.

Writing in pseudocode is straightforward:


void init(Handle<Object> exports)
{
    exports.Set("hello", function hello);
}

  Done!

It's over with your sister! Shut up, " д " & # 8834; 彡 ) being Д & acute;)

True ・ export

This is the last step, and we're going to say, this is the entry to the export, so we're going to add this line at the end of the code:
NODE_MODULE (hello, init)

  Paid a penny? ! What is this?

Don't worry, this NODE_MODULE is a macro, and what it means is we're going to init this initialization function to export something to hello. So where does this hello come from?

It comes from the filename! Yes, that's right, it comes from the file name. You don't have to declare it in advance, you don't have to worry about not being able to use it, but whatever the name of your final compiled binary is, you put in the word "hello" here, minus the suffix, of course.

See the official documentation.


Note that all Node addons must export an initialization function:


void Initialize (Handle<Object> exports);
NODE_MODULE(module_name, Initialize)

  There is no semi-colon after NODE_MODULE as it's not a function (see node.h).

The module_name needs to match The filename of The final binary (minus The. Node suffix).
 
Compile (& # 3665; The & # 8226; The & # 769; The & # 8323; The & # 8226; The & # 768; The & # 3665;)

Come on, let's compile together!

Let's create a Makefile like archive - binding.gyp.

And add such code inside:


{
  "targets": [
    {
      "target_name": "hello",
      "sources": [ "hello.cc" ]
    }
  ]
}

  Why do you write it that way? You can refer to the official documentation for node-gyp.

configure

After the files are in order, we will execute the command under this directory:


$ node-gyp configure

  If all goes well, a directory of builds should be generated, and then there are related files in it, maybe the vcxproj file of M$Visual Studio, etc., maybe the Makefile, depending on the platform.

The build

Once the Makefile has been generated, we start building and compiling:
$node - gyp build

  Wait until everything is compiled, then you are done! If you want to check the build/Release directory, is there a hello.node file under it? Yes, this is the soap that C++ will pick up for node. js later!

Be gay! The Node � (& # 10047; The & # 65439; � the & # 65439;) ノ c + +

So let's create a new file in that directory called jianfeizao.js:


var addon = require("./build/Release/hello");
console.log(addon.hello());

  See! See! Out! Out! Out! Node.js and C++ are gay! This adon.hello () is what we wrote in our C++ code earlier: Handle< Value> Hello(const Arguments& args), we have now returned the value to the output.

Wash and sleep. Go deeper

It's getting late, so I'm going to stop here today, so far you can make the most basic C++ extension of Hello world. The next one should be a little more in-depth, and I don't know when the next one will be.
  (feed feed, the lu Lord how can be so irresponsible! (o & # 65439; The & # 65435; The & # 65439;) ┌ ┛ Σ (& # 65417; & acute; Omega `) & # 65417;


Related articles: