読者です 読者をやめる 読者になる 読者になる

凹みTips

C++、JavaScript、Unity、ガジェット等の Tips について雑多に書いています。

Windows でも Node.js C/C++ アドオンを作ってみる

C++ JavaScript Windows Node.js

はじめに

Linux や Mac で動かしている方が多いと思いますが、Windows でも Node.js を動かすことが出来ます。手順はとても簡単で、インストーラを実行するだけです。

他の PF と比較すると数は減りますが、コンパイルが必要な socket.io などの有名モジュールも使用することが出来ます。更に、C/C++ アドオンを自分で作成して、Win32 API を叩いて他のアプリケーションと連携するなんてことも可能です。Twitter で「メモ帳開いて」というとメモ帳が開かれる、みたいなことも簡単に実現できます。
今回は簡単な例として、メモ帳を起動してみる例を紹介したいと思います。

作成方法

まず空の notepad.cc を作成、そこへ binding.gyp を置きます。

binding.gyp
{
	'targets': [
		{
			'target_name' : 'notepad',
			'sources' : [ 'notepad.cc' ],
		},
	],
}

そしてコンソールから以下のコマンドを実行します。

$ node-gyp configure

これで build フォルダができ、その中にソリューションファイル(binding.sln)ができているのでこれを開きます。node.h へのパスも通っているので補完も効いて編集もしやすいです。なお、Debug でなく Release にすることが必要です。コードは以下になります。

notepad.cc
#include <node.h>
#include <windows.h>

using namespace v8;

Handle<Value> open_notepad(const Arguments& args) {
    HandleScope scope;

    ShellExecute(nullptr, "open", "notepad.exe", nullptr, nullptr, SW_SHOWNORMAL);

    return scope.Close(Undefined());
}

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

NODE_MODULE(notepad, init)

VS でビルドするか、コンソールから

$ node-gyp build

を実行してビルドします。そして以下の JavaScript を書いて実行してみます。

var notepad = require('./build/Release/notepad');
notepad.open();

これでメモ帳が開きます。

(補足 1)インクルード順

node.hwindows.h よりも先に読み込んでいますが、これを逆順にすると「warning C4005: 'AF_IPX' : マクロが再定義されました。」をはじめとする幾つかの警告とエラーが吐き出されます。

これを回避するためには、インクルード順に気をつけるか、上記エントリのように「#define _WINSOCKAPI_」をインクルード前に定義して下さい。

(補足 2)Visual Studio 2010 / 2012 を入れている際の落とし穴

私はこの罠にハマってしまったのですが、2010 -> 2012 と Visual Studio Express をインストールしている際は、以下の様なエラーが発生します。

c:\tmp\node_modules\node-osc\node_modules\osc-min\node_modules\binpack>node "C:\
Program Files\nodejs\node_modules\npm\bin\node-gyp-bin\\..\..\node_modules\node-
gyp\bin\node-gyp.js" rebuild
このソリューション内のプロジェクトを 1 度に 1 つずつビルドします。並行ビルドを有
効にするには、"/m" スイッチを追加してください。
C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\Platforms\x64\Microsoft.Cpp.x
64.Targets(514,5): error MSB8008: 指定したプラットフォーム ツールセット (v110)
はインストールされていないか無効です
。サポートされている PlatformToolset 値が選択されていることを確認してください。
[c:\tmp\node_modules\node-osc\
node_modules\osc-min\node_modules\binpack\build\binpack.vcxproj]
gyp ERR! build error
gyp ERR! stack Error: `C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe
` failed with exit code: 1
gyp ERR! stack     at ChildProcess.onExit (C:\Program Files\nodejs\node_modules\
npm\node_modules\node-gyp\lib\build.js:267:23)
gyp ERR! stack     at ChildProcess.EventEmitter.emit (events.js:98:17)
gyp ERR! stack     at Process.ChildProcess._handle.onexit (child_process.js:789:
12)
gyp ERR! System Windows_NT 6.1.7601
gyp ERR! command "node" "C:\\Program Files\\nodejs\\node_modules\\npm\\node_modu
les\\node-gyp\\bin\\node-gyp.js" "rebuild"
gyp ERR! cwd c:\tmp\node_modules\node-osc\node_modules\osc-min\node_modules\binp
ack
gyp ERR! node -v v0.10.16
gyp ERR! node-gyp -v v0.10.9
gyp ERR! not ok
npm ERR! weird error 1
npm ERR! not ok code 0

これは以下の issue にも書かれているように、node-gyp configure の設定に因ると思われます。

これを解決するためには、「C:\Program Files\nodejs\node_modules\npm\node_modules\node-gyp\lib」(上のエラーで吐き出されている実行した「node-gyp.js」を格納した場所)にある、configure.js を修正することで回避できます。

configure.js:285 行目
if (win) {
  if (hasVC2012Express && hasWin8SDK) {
    defaults.msbuild_toolset = 'v110'
  } else if (hasVCExpress && hasWin71SDK) {
    defaults.msbuild_toolset = 'Windows7.1SDK'
  }
}
変更後
if (win) {
  if (hasVCExpress && hasWin71SDK) {
    defaults.msbuild_toolset = 'Windows7.1SDK'
  } else if (hasVC2012Express && hasWin8SDK) {
    defaults.msbuild_toolset = 'v110'
  }
}

※ 別途 Windows SDK v7.1 を私はインストールしましたが、必要だったかどうかは未検証です。

おわりに

Windows でもこれだけ楽にモジュール開発が可能なら、モジュールが充実すれば色々出来そうで面白そうです。