ホームページ > ウェブフロントエンド > jsチュートリアル > C/C を使用して Node.js モジュールを実装する (1)_node.js

C/C を使用して Node.js モジュールを実装する (1)_node.js

WBOY
リリース: 2016-05-16 16:35:33
オリジナル
1229 人が閲覧しました

昔発生した落とし穴 - Node.js を使用して NBUT のオンライン ジャッジを再構築する際、評価側も含めて再構築する必要がありました。 (いつ完成するかは心配しないでください(/‵Д´)/~ ╧╧

つまり、今私たちがしなければならないことは、実際に C/C を使用して Node.js モジュールを実装することです。

準備

労働者が自分の仕事をうまくやり遂げたいなら、まず~~悪党を演じ~~、自分の道具を研ぐ必要があります。

ノード-gyp

まず、node-gyp モジュールが必要です。

任意のコーナーで、次を実行します:

コードをコピー コードは次のとおりです:

$ npm install node-gyp -g

一連のなんとかの後で、あなたはインストールされます。

パイソン

そうするとPython環境が必要になります。

公式ウェブサイトにアクセスしてご自身で入手してください。


注:node-gyp の GitHub によると、Python のバージョンが 2.5.0 ~ 3.0.0 であることを確認してください。

コンパイル環境

うーん、詳しく書くのが面倒なので、node-gyp にアクセスしてコンパイラの要件を確認してください。そしてよく注ぎます。

はじめに

公式 Web サイトの Hello World の紹介について少しお話しましょう。

ハローワールド

C ファイルを用意してください (たとえば ~~sb.cc~~ hello.cc という名前)。

それでは、段階的に進みましょう。最初にヘッダー ファイルを作成し、名前空間を定義します。

コードをコピー コードは次のとおりです:

#include
#include
名前空間 v8 を使用;

メイン関数

次に、戻り値が Handle である関数を作成します。

コードをコピー コードは次のとおりです:

ハンドル<値> Hello(const Arguments& args)
{
//... 書き込みを待っています
}

それでは、これらのことを簡単に分析してみましょう:

ハンドル

人間としての誠実さを持っていなければなりません、ここから引用することをあらかじめ断っておきます(@fool)。


V8 は、Handle 型を使用して JavaScript オブジェクトをホストします。C の std::sharedpointer と同様に、Handle 型間の割り当てはオブジェクト参照を直接渡しますが、違いは、V8 がインテリジェントな一般的に使用される参照ではなく、独自の GC を使用してオブジェクトのライフサイクルを管理することです。ポインタをカウントしています。

JavaScript の型には、C の対応するカスタム型 (String、Integer、Object、Date、Array など) があり、JavaScript の継承関係に厳密に準拠します。これらの型を C で使用する場合は、ネイティブ スタックとヒープを使用する代わりに、ハンドル管理を使用して GC を使用してライフ サイクルを管理する必要があります。

このいわゆる Value は、V8 エンジンのヘッダー ファイル v8.h のさまざまな継承関係からわかります。これは、実際には JavaScript のさまざまなオブジェクトの基本クラスです。

このことを理解すると、不定型の値を返す Hello 関数を書くという上記の関数宣言の意味が大体理解できると思います。


注: Handle の管理下では、特定の型 (String、Integer など) のみを返すことができます。

引数

これは、この関数に渡されるパラメータです。 Node.js ではパラメーターの数がランダムであることは誰もが知っています。これらのパラメーターが C に渡されると、この Arguments 型のオブジェクトに変換されます。

具体的な使い方については後ほど説明します。ここでは、これが何であるかを理解する必要があります。 (なぜそんなに注意するのですか?公式の Node.js ドキュメントの例は個別に説明されているからです。私は今、最初の Hello World の例について話しているだけです (´థ౪థ)σ

貢献

次に、レンガとタイルを追加し始めました。たった 2 つの簡単な文:

コードをコピー コードは次のとおりです:

ハンドル<値> Hello(const Arguments& args)
{
HandleScope スコープ;
戻り値scope.Close(String::New("world"));
}

この 2 つの文は何を意味しますか?大まかな意味は、Node.js で文字列「world」を返すことです。

ハンドルスコープ

同じ参照がここから来ています。


Handle のライフサイクルは C スマート ポインターのライフサイクルとは異なり、C セマンティクスの範囲 (つまり、{} で囲まれた部分) 内には存在しません。HandleScope を通じて手動で指定する必要があります。 HandleScope オブジェクトはスタック上にのみ配置できます。HandleScope オブジェクトが宣言された後、その後に作成される Handle のライフサイクルは HandleScope オブジェクトが破棄された後、GC によって判断されます。リサイクルされた。

したがって、ライフサイクルを管理する必要がある場合は、このスコープを宣言する必要があります。では、なぜコードがこのようにならないのでしょうか?

コードをコピー コードは次のとおりです:

ハンドル<値> Hello(const Arguments& args)
{
HandleScope スコープ;
戻り文字列::New("world");
}

関数が戻るとスコープは破棄され、スコープが管理するハンドルもリサイクルされるため、この String は無意味になります。

そこで、V8 は魔法のアイデア、HandleScope::Close(Handle Value) 関数を思いつきました。この関数の目的は、このスコープを閉じて、内部のパラメータを前の管理用スコープ、つまりこの関数に入る前のスコープに転送することです。

したがって、前のコードのscope.Close(String::New("world")); があります。

文字列::新規

この String クラスは、Node.js のネイティブ String クラスに対応します。 Value クラスから継承されます。これに似たものとして、

もあります。

•配列
•整数
•ブール値
•オブジェクト
•日付
•番号
•機能
•...

これらの一部は Value から継承され、一部は 2 回継承されます。ここではあまり調査しません。V8 コード (少なくともヘッダー ファイル) を確認するか、このマニュアルを読んでください。

では、この New はどうでしょうか?ここで見ることができます。新しい String オブジェクトを作成するだけです。

この時点で、この main 関数の分析は完了しました。

オブジェクトのエクスポート

Node.js で記述する場合、関数やオブジェクトをどのようにエクスポートするかを確認してみましょう。

コードをコピー コードは次のとおりです:

exports.hello = function() {}

では、これを C でどのように行うのでしょうか?

初期化関数

まず、初期化関数を作成します。

コードをコピー コードは次のとおりです:

void init(ハンドル<オブジェクト> エクスポート)
{
//...お姉さんのことを書くのを待っています! #゚Å゚)⊂彡☆))゚Д゚)・∵
}

これはカメのお尻です!関数名が何であっても構いませんが、渡されるパラメータは Handle である必要があります。これは、次にこの製品で何かをエクスポートすることを意味します。

次に、エクスポートされた内容をここに書き込みます:

コードをコピー コードは次のとおりです:

void init(ハンドル<オブジェクト> エクスポート)
{
エクスポート->Set(String::NewSymbol("hello"),
FunctionTemplate::New(Hello)->GetFunction());
}

一般的な意味は、このエクスポート オブジェクトに hello というフィールドを追加し、対応するものが関数であり、この関数が親愛なる Hello 関数であるということです。

擬似コードでわかりやすく言うと:

コードをコピー コードは次のとおりです:

void init(ハンドル<オブジェクト> エクスポート)
{
exports.Set("hello", function hello);
}

完成しました!

(終わったよお姉ちゃん!黙ってろ(‘д‘⊂彡☆))Д´)

真・エクスポート

これは最後のステップであり、これがエクスポートの入り口であることを最終的に宣言する必要があるため、コードの最後に次の行を追加します。 NODE_MODULE(こんにちは、初期化)

1 セント払いましたか? !これは何ですか?

心配しないでください。この NODE_MODULE はマクロです。つまり、init 初期化関数を使用して、hello にエクスポートされるものをエクスポートします。では、この「こんにちは」はどこから来たのでしょうか?

ファイル名から来ています!はい、そうです、それはファイル名から来ています。事前に宣言する必要はなく、それが使用できないことを心配する必要はありません。つまり、最終的にコンパイルされたバイナリ ファイルの名前が何であっても、ここに hello を入力します。もちろん接尾語。

詳細については、公式ドキュメントを参照してください。

すべての Node アドオンは初期化関数をエクスポートする必要があることに注意してください:

コードをコピー コードは次のとおりです:
void Initialize ( エクスポートの処理);
NODE_MODULE(モジュール名, 初期化)

NODE_MODULE は関数ではないため、後にセミコロンはありません (node.h を参照)。

module_name は、最終バイナリのファイル名 (.node 接尾辞を除く) と一致する必要があります。


コンパイル (๑•́ ₃ •̀๑)

さあ、一緒にコンパイルしましょう!

Makefile に似た新しいアーカイブ ファイル binding.gyp を作成しましょう。

そしてこのコードを中に追加します:


コードをコピー コードは次のとおりです:
{
"ターゲット": [
{
"target_name": "こんにちは",
"ソース": [ "hello.cc" ]
}
]
}

なぜこのように書くのですか? node-gyp の公式ドキュメントを参照してください。

設定

ファイルの準備ができたら、このディレクトリで次のコマンドを実行する必要があります:


コードをコピー コードは次のとおりです:
$node-gypconfigure

すべてが正常であれば、ビルド ディレクトリが生成され、その中に関連ファイル (プラットフォームによっては M$ Visual Studio の vcxproj ファイルなど、おそらく Makefile) が存在するはずです。

ビルド

Makefile が生成されたら、構築とコンパイルを開始します。

$node-gyp build

すべてがコンパイルされたら、本当に完了です。私の言うことが信じられない場合は、build/Release ディレクトリを見てください。以下に hello.node ファイルがありますか?はい、これは後で C が Node.js 用に取り上げるソープです。

ゲイになれ!ノードヽ(✿゚▽゚)ノC

先ほどディレクトリに新しいファイル jianfeizao.js を作成します。


コードをコピー コードは次のとおりです:
var addon = require("./build/Release/hello");
console.log(addon.hello());

見ましたか?見ましたか?出た!出た! Node.jsとCを過激にした結果!この addon.hello() は、以前に C コードで記述した Handle Hello(const Arguments& args) で、これが返す値を出力しました。

寝てください。次のセクションではさらに詳しく説明します

遅くなりましたので、今日はここで書き終えます。Hello world の最も基本的な C 拡張機能は、もう誰でも作成できるようになります。次回はもっと詳しく書く予定ですが、次回はいつになるかはわかりません。

(おいおい、オナホってこんなに無責任なもんだ!(o゚ロ゚)┌┛Σ(ノ´ω`)ノ

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート