背景

Rust で node の native modules を書くの、Rustを書いてみたいからっていう理由だけで試してみたい。 https://t.co/vek4YFjW5e https://t.co/uqpd95C4QQ— Yosuke FURUKAWA (@yosuke_furukawa) 2015, 12月 24

 

なんて、ツイートをたまたま見かけ、

原理的にちょっとまえのRustだとdleopn時に呼び出す関数を指定できなかったから直接.nodeファイルはRustが吐けないはずなんだけど、その辺りどうなってるのだろうか / “dherman/wc-demo · GitHub” https://t.co/pdAqgRMFbW— kjunichi (@kjunichi) 2015, 12月 24

なぜ原理的に無理そうなのか

    • http://abrakatabura.hatenablog.com/entry/2015/12/14/214922

 

    https://users.rust-lang.org/t/library-onload-initialization/3079/2

やってみた

Rustがある時から、「attribute((constructor))」をサポートしたのかもと思い、調べるも見当たらず。

wc-demoのコードをたどり、依存モジュールのリポジトリのpackage.jsonをたどるも
node-ffiすら見当たらず、これは俺が知らない未知のテクノロジーを使って解決したのか!

と、期待を膨らませて実際に動かしてみた。

rustのアップデート

1.5以上とwc-demoに書いてあるので、

curl -sSf https://static.rust-lang.org/rustup.sh | sh

OSXではPkgも用意されているので、そこらへんはお好みで。

wc-demoをクローンして試す

$ nodebrew ls
v0.10.35
v0.12.0
v4.2.1
v5.1.1
v5.2.0
v5.3.0

current: v5.3.0

$ npm install
npm WARN prefer global node-gyp@3.0.3 should be installed with -g

> wc-demo@0.0.0 postinstall /Users/kjw_junichi/work/rust/neon/wc-demo
> neon build

  ACTION binding_gyp_wc_demo_target_generate Release/obj.target/wc_demo/geni/binding.cc
  ACTION binding_gyp_wc_demo_target_cargo ../target/release/libwc_demo.a
Unable to update file:///Users/kjw_junichi/work/rust/neon/wc-demo

Caused by:
  Could not find `Cargo.toml` in `/Users/kjunichi/work/rust/neon/neon`
make: *** [../target/release/libwc_demo.a] Error 101
gyp ERR! build error 
gyp ERR! stack Error: `make` failed with exit code: 2
gyp ERR! stack     at ChildProcess.onExit (/Users/kjunichi/work/rust/neon/wc-demo/node_modules/node-gyp/lib/build.js:270:23)
gyp ERR! stack     at emitTwo (events.js:87:13)
gyp ERR! stack     at ChildProcess.emit (events.js:172:7)
gyp ERR! stack     at Process.ChildProcess._handle.onexit (internal/child_process.js:200:12)
gyp ERR! System Darwin 15.2.0
gyp ERR! command "/Users/kjunichi/.nodebrew/node/v5.3.0/bin/node" "/Users/kjunichi/work/rust/neon/wc-demo/node_modules/.bin/node-gyp" "rebuild"
gyp ERR! cwd /Users/kjunichi/work/rust/neon/wc-demo
gyp ERR! node -v v5.3.0
gyp ERR! node-gyp -v v3.0.3
gyp ERR! not ok 

npm ERR! Darwin 15.2.0
npm ERR! argv "/Users/kjunichi/.nodebrew/node/v5.3.0/bin/node" "/Users/kjunichi/.nodebrew/current/bin/npm" "install"
npm ERR! node v5.3.0
npm ERR! npm  v3.3.12
npm ERR! code ELIFECYCLE
npm ERR! wc-demo@0.0.0 postinstall: `neon build`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the wc-demo@0.0.0 postinstall script 'neon build'.
npm ERR! Make sure you have the latest version of node.js and npm installed.
npm ERR! If you do, this is most likely a problem with the wc-demo package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR!     neon build
npm ERR! You can get their info via:
npm ERR!     npm owner ls wc-demo
npm ERR! There is likely additional logging output above.

npm ERR! Please include the following file with any support request:
npm ERR!     /Users/kjunichi/work/rust/neon/wc-demo/npm-debug.log

動かすには

cd ..
git clone https://github.com/dherman/neon.git
npm install -g neon-cli
cd wc-demo
cargo update
npm install
$ node -e 'require("./")'
node -e 'require("./")'
3092 [280ms, 914μs, 751ns]
3092 [40ms, 930μs, 825ns]

動きました!

$ cat binding.gyp
# THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT.

{
    "target_defaults": {
        "default_configuration": "Release"
    },

    "targets": [{
        "target_name": "wc_demo",

        "variables": {
            "rust_inputs": ["src/lib.rs"],
            "static_lib": "target/release/<(STATIC_LIB_PREFIX)wc_demo<(STATIC_LIB_SUFFIX)",
            "shared_lib": "target/release/<(SHARED_LIB_PREFIX)wc_demo<(SHARED_LIB_SUFFIX)"
        },

        "sources": ["<(INTERMEDIATE_DIR)/binding.cc"],

        "include_dirs": ["<!(neon include-path)"],

        "libraries": ["../<(shared_lib)"],

        "actions": [{
            "action_name": "cargo",
            "inputs": ["<@(rust_inputs)"],
            "outputs": ["../<(static_lib)"],
            "action": ["cargo", "rustc", "--release", "--", "--crate-type", "staticlib"]
        }, {
            "action_name": "shared_lib",
            "inputs": ["<(static_lib)"],
            "outputs": ["../<(shared_lib)"],
            # FIXME: OSX-specific
            "action": ["gcc", "-dynamiclib", "-Wl,-undefined,dynamic_lookup", "-Wl,-force_load,<(static_lib)", "-o", "<(shared_lib)"]
        }, {
            "action_name": "generate",
            "inputs": [],
            "outputs": ["<(INTERMEDIATE_DIR)/binding.cc"],
            "action": ["neon", "generate", "<(INTERMEDIATE_DIR)/binding.cc"]
        }]
    }]

}

ということで、biding.ccをエントリポイントにして、その先がRustで記述されたモジュールとなっているようです。

関連

    • Rustでコマンドラインアプリでキーが押されたかの判定しつつ、別の処理も進めるには

 

    • RustでWebカメラの映像をコマンドプロンプトに出すコマンドを作った

 

    • RustでGoのライブラリを使うときのCargoのbuild.rsの書き方

 

    • Surface Goのカメラ映像をRustでコマンドプロンプトに表示した

 

    Rustで共有ライブラリを作る際に必要だったCのconst char*をRustの&strにする方法
广告
将在 10 秒后关闭
bannerAds