node-gyp

Node.jsでは、C++で拡張モジュールを作ることができる。
この拡張モジュールを経由して、LinuxならシステムコールWindowsならWin32APIなどを呼び出すことができる。

GitHub - nodejs/node-gyp: Node.js native addon build tool
Node.jsのネイティブ拡張を作ってみよう 〜NAN, 非同期処理, npm公開まで〜 - Qiita

今回は、node-gypを用いて、簡単な拡張モジュールを作る。

まずは、npm init。

$ pwd
/home/bg1/project/cloud/github.com/Sample/node-gyp/node-gyp/node-gyp/src/native_ext
$ ls
$ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
package name: (native_ext)
version: (1.0.0)
description: node-gyp sample
entry point: (index.js) main.js
test command: start
git repository: -
keywords: -
author: B.G
license: (ISC) MIT
About to write to
/home/bg1/project/cloud/github.com/Sample/node-gyp/node-gyp/node-gyp/src/native_ext/package.json:

{
  "name": "native_ext",
  "version": "1.0.0",
  "description": "node-gyp sample",
  "main": "main.js",
  "scripts": {
    "test": "start"
  },
  "repository": {
    "type": "git",
    "url": "-"
  },
  "keywords": [
    "-"
  ],
  "author": "B.G",
  "license": "MIT"
}


Is this OK? (yes)
$

続いて、node-gypをインストール。

$ npm install node-gyp
npm notice created a lockfile as package-lock.json. You should commit this file.
+ node-gyp@3.8.0
added 97 packages from 67 contributors and audited 183 packages in 6.812s
found 0 vulnerabilities



   ╭───────────────────────────────────────────────────────────────╮
   │                                                               │
   │       New minor version of npm available! 6.4.1 → 6.9.0       │
   │   Changelog: https://github.com/npm/cli/releases/tag/v6.9.0   │
   │               Run npm install -g npm to update!               │
   │                                                               │
   ╰───────────────────────────────────────────────────────────────╯

$

Python2.7(3系は非対応)が必要なのだが、入ってないので入れる。

$ which python
/usr/bin/which: no python in
(/home/bg1/.local/bin:/home/bg1/bin:/home/bg1/.local/bin:/home/bg1/bin:/usr/share/Modules/bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin)
$ sudo yum install python
メタデータの期限切れの最終確認: xx:xx:xx 時間前の 2019年xx月xx日 xx時xx分xx秒 に実施しました。
依存関係が解決しました。
=======================================================================================================
 パッケージ                          アーキテクチャー
                                                     バージョン
    リポジトリ       サイズ
=======================================================================================================
インストール:
 python-unversioned-command          noarch          2.7.15-11.fc29
         updates           13 k
依存関係をインストール中:
 python2                             x86_64          2.7.15-11.fc29
         updates           46 k
 python2-libs                        x86_64          2.7.15-11.fc29
         updates          6.1 M
 compat-openssl10                    x86_64          1:1.0.2o-3.fc29
         fedora           1.1 M
 gdbm                                x86_64          1:1.18-1.fc29
         fedora           116 k
弱い依存関係をインストール中:
 python2-pip                         noarch          18.1-1.fc29
         updates          1.9 M
 python2-setuptools                  noarch          40.8.0-1.fc29
         updates          644 k

トランザクションの概要
=======================================================================================================
インストール  7 パッケージ

ダウンロードサイズの合計: 10 M
インストール済みのサイズ: 41 M
これでよろしいですか? [y/N]: y
パッケージのダウンロード中です:
(1/7): python2-2.7.15-11.fc29.x86_64.rpm
 24 kB/s |  46 kB     00:01
(2/7): python-unversioned-command-2.7.15-11.fc29.noarch.rpm
6.9 kB/s |  13 kB     00:01
(3/7): python2-setuptools-40.8.0-1.fc29.noarch.rpm
156 kB/s | 644 kB     00:04
(4/7): compat-openssl10-1.0.2o-3.fc29.x86_64.rpm
728 kB/s | 1.1 MB     00:01
(5/7): python2-libs-2.7.15-11.fc29.x86_64.rpm
694 kB/s | 6.1 MB     00:09
(6/7): gdbm-1.18-1.fc29.x86_64.rpm
 58 kB/s | 116 kB     00:01
(7/7): python2-pip-18.1-1.fc29.noarch.rpm
228 kB/s | 1.9 MB     00:08
-------------------------------------------------------------------------------------------------------
合計
732 kB/s |  10 MB     00:13
トランザクションの確認を実行中
トランザクションの確認に成功しました。
トランザクションのテストを実行中
トランザクションのテストに成功しました。
トランザクションを実行中
  準備             :
                          1/1
Installed: gdbm-1:1.18-1.fc29.x86_64
  インストール中   : gdbm-1:1.18-1.fc29.x86_64
                     1/7
Installed: gdbm-1:1.18-1.fc29.x86_64
Installed: compat-openssl10-1:1.0.2o-3.fc29.x86_64
  インストール中   : compat-openssl10-1:1.0.2o-3.fc29.x86_64
                     2/7
  scriptletの実行中: compat-openssl10-1:1.0.2o-3.fc29.x86_64
                        2/7
Installed: compat-openssl10-1:1.0.2o-3.fc29.x86_64
Installed: python2-libs-2.7.15-11.fc29.x86_64
  インストール中   : python2-libs-2.7.15-11.fc29.x86_64
                     3/7
Installed: python2-libs-2.7.15-11.fc29.x86_64
Installed: python2-pip-18.1-1.fc29.noarch
  インストール中   : python2-pip-18.1-1.fc29.noarch
                     4/7
Installed: python2-pip-18.1-1.fc29.noarch
Installed: python2-setuptools-40.8.0-1.fc29.noarch
  インストール中   : python2-setuptools-40.8.0-1.fc29.noarch
                     5/7
Installed: python2-setuptools-40.8.0-1.fc29.noarch
Installed: python2-2.7.15-11.fc29.x86_64
  インストール中   : python2-2.7.15-11.fc29.x86_64
                     6/7
Installed: python2-2.7.15-11.fc29.x86_64
Installed: python-unversioned-command-2.7.15-11.fc29.noarch
  インストール中   : python-unversioned-command-2.7.15-11.fc29.noarch
                     7/7
Installed: python-unversioned-command-2.7.15-11.fc29.noarch
  scriptletの実行中: python-unversioned-command-2.7.15-11.fc29.noarch
                        7/7
  検証             : python-unversioned-command-2.7.15-11.fc29.noarch
                          1/7
  検証             : python2-2.7.15-11.fc29.x86_64
                          2/7
  検証             : python2-libs-2.7.15-11.fc29.x86_64
                          3/7
  検証             : python2-pip-18.1-1.fc29.noarch
                          4/7
  検証             : python2-setuptools-40.8.0-1.fc29.noarch
                          5/7
  検証             : compat-openssl10-1:1.0.2o-3.fc29.x86_64
                          6/7
  検証             : gdbm-1:1.18-1.fc29.x86_64
                          7/7

インストール済み:
  python-unversioned-command-2.7.15-11.fc29.noarch
python2-pip-18.1-1.fc29.noarch
  python2-setuptools-40.8.0-1.fc29.noarch
python2-2.7.15-11.fc29.x86_64
  python2-libs-2.7.15-11.fc29.x86_64
compat-openssl10-1:1.0.2o-3.fc29.x86_64
  gdbm-1:1.18-1.fc29.x86_64

完了しました!
$

binding.gypというファイルに、

と書く。
native_ext.ccというのがC++ソースファイル。
native_ext.ccには、

get_abcという自作関数を用意し、args.GetReturnValue().Setで"ABC"をセットすることで、戻り値"ABC"を返してる。
(おまじないということで詳細は後で・・・。)

node-gypコマンドを使って、configureとbuildをする。

$ vi binding.gyp
$ vi native_ext.cc
$ ls
binding.gyp  build  native_ext.cc  node_modules  package-lock.json  package.json
$ ./node_modules/.bin/node-gyp configure
gyp info it worked if it ends with ok
gyp info using node-gyp@3.8.0
gyp info using node@10.15.0 | linux | x64
gyp info spawn /usr/bin/python2
gyp info spawn args [
'/home/bg1/project/cloud/github.com/Sample/node-gyp/node-gyp/node-gyp/src/native_ext/node_modules/node-gyp/gyp/gyp_main.py',
gyp info spawn args   'binding.gyp',
gyp info spawn args   '-f',
gyp info spawn args   'make',
gyp info spawn args   '-I',
gyp info spawn args
'/home/bg1/project/cloud/github.com/Sample/node-gyp/node-gyp/node-gyp/src/native_ext/build/config.gypi',
gyp info spawn args   '-I',
gyp info spawn args
'/home/bg1/project/cloud/github.com/Sample/node-gyp/node-gyp/node-gyp/src/native_ext/node_modules/node-gyp/addon.gypi',
gyp info spawn args   '-I',
gyp info spawn args   '/home/bg1/.node-gyp/10.15.0/include/node/common.gypi',
gyp info spawn args   '-Dlibrary=shared_library',
gyp info spawn args   '-Dvisibility=default',
gyp info spawn args   '-Dnode_root_dir=/home/bg1/.node-gyp/10.15.0',
gyp info spawn args
'-Dnode_gyp_dir=/home/bg1/project/cloud/github.com/Sample/node-gyp/node-gyp/node-gyp/src/native_ext/node_modules/node-gyp',
gyp info spawn args
'-Dnode_lib_file=/home/bg1/.node-gyp/10.15.0/<(target_arch)/node.lib',
gyp info spawn args
'-Dmodule_root_dir=/home/bg1/project/cloud/github.com/Sample/node-gyp/node-gyp/node-gyp/src/native_ext',
gyp info spawn args   '-Dnode_engine=v8',
gyp info spawn args   '--depth=.',
gyp info spawn args   '--no-parallel',
gyp info spawn args   '--generator-output',
gyp info spawn args   'build',
gyp info spawn args   '-Goutput_dir=.' ]
gyp info ok
$ ./node_modules/.bin/node-gyp build
gyp info it worked if it ends with ok
gyp info using node-gyp@3.8.0
gyp info using node@10.15.0 | linux | x64
gyp info spawn make
gyp info spawn args [ 'BUILDTYPE=Release', '-C', 'build' ]
make: ディレクトリ '/home/bg1/project/cloud/github.com/Sample/node-gyp/node-gyp/node-gyp/src/native_ext/build'
に入ります
  CXX(target) Release/obj.target/native_ext/native_ext.o
In file included from ../native_ext.cc:2:
/home/bg1/.node-gyp/10.15.0/include/node/node.h:570:43: 警告: cast
between incompatible function types from ‘void
(*)(v8::Local<v8::Object>)’ to ‘node::addon_register_func’ {aka ‘void
(*)(v8::Local<v8::Object>, v8::Local<v8::Value>, void*)’}
[-Wcast-function-type]
       (node::addon_register_func) (regfunc),                          \
                                           ^
/home/bg1/.node-gyp/10.15.0/include/node/node.h:604:3: 備考: in
expansion of macro ‘NODE_MODULE_X’
   NODE_MODULE_X(modname, regfunc, NULL, 0)  // NOLINT (readability/null_usage)
   ^~~~~~~~~~~~~
../native_ext.cc:24:1: 備考: in expansion of macro ‘NODE_MODULE’
 NODE_MODULE(native_ext, init);
 ^~~~~~~~~~~
  SOLINK_MODULE(target) Release/obj.target/native_ext.node
  COPY Release/native_ext.node
make: ディレクトリ '/home/bg1/project/cloud/github.com/Sample/node-gyp/node-gyp/node-gyp/src/native_ext/build'
から出ます
gyp info ok
$

グローバルインストール( -g)じゃないので、"./node_modules/.bin/node-gyp"の"conigure"と"build"を使って、ビルドまで行う。

$ ls
binding.gyp  build  native_ext.cc  node_modules  package-lock.json  package.json
$ cd build/
$ ls
Makefile  Release  binding.Makefile  config.gypi  native_ext.target.mk
$ cd Release/
$ ls
native_ext.node  obj.target
$ pwd
/home/bg1/project/cloud/github.com/Sample/node-gyp/node-gyp/node-gyp/src/native_ext/build/Release
$

build/Releaseの下の、"native_ext.node"がビルドで生成されたモジュール。
これを、main.jsから参照させる。

このようにnativeExt.get_abc()を呼び出せるので、戻り値の"ABC"をconsole.logで出力。
これでnodeコマンドで呼び出せるが、せっかくなので、package.jsonで、


"scripts"で"start"なら"node ."を実行するようにする。

$ vi package.json
$ npm start

> native_ext@1.0.0 start /home/bg1/project/cloud/github.com/Sample/node-gyp/node-gyp/node-gyp/src/native_ext
> node .

ABC
$

npm startで起動して、取得した"ABC"を出力するようにできた。

Sample/node-gyp/node-gyp/node-gyp/src/native_ext at master · bg1bgst333/Sample · GitHub