はじめに
node-waf はオワコンと聞いて node-gyp を使おうと思ったのですが、Mac で相当ハマったのでメモします。
問題点
公式 の HelloWorld を C++11 風に書いてモジュール作れるかなぁ、と試してみました。が、-std=c++0x オプションを binding.gyp に書き込んでも、Mac 上では下記のようにビルド時にエラーしてしまいます。
hello.cc
#include <node.h> #include <v8.h> using namespace v8; void init(Handle<Object> target) { target->Set( String::NewSymbol("hello"), FunctionTemplate::New([](const Arguments& args)->Handle<Value> { HandleScope scope; return scope.Close(String::New("world")); })->GetFunction() ); } NODE_MODULE(hello, init)
binding.gyp
{ 'targets': [ { 'target_name' : 'hello', 'sources' : [ 'hello.cc' ], 'cflags' : [ '-std=c++0x' ], }, ], }
実行&エラー
$ node-gyp build gyp info it worked if it ends with ok gyp info using node-gyp@0.7.1 gyp info using node@0.9.2 | darwin | x64 gyp info spawn make gyp info spawn args [ 'BUILDTYPE=Debug', '-C', 'build' ] CXX(target) Debug/obj.target/hello/hello.o ../hello.cc:9:25: error: expected expression FunctionTemplate::New([](const Arguments& args)->Handle<Value> { ^ 1 error generated. make: *** [Debug/obj.target/hello/hello.o] Error 1 gyp ERR! build error gyp ERR! stack Error: `make` failed with exit code: 2 gyp ERR! stack at ChildProcess.onExit (/Users/hecomi/.nave/installed/0.9.2/lib/node_modules/node-gyp/lib/build.js:236:23) gyp ERR! stack at ChildProcess.EventEmitter.emit (events.js:91:17) gyp ERR! stack at Process._handle.onexit (child_process.js:687:12) gyp ERR! stack at process.startup.processMakeCallback.process._makeCallback (node.js:248:20) gyp ERR! System Darwin 12.0.0 gyp ERR! command "node" "/Users/hecomi/.nave/installed/0.9.2/bin/node-gyp" "build" gyp ERR! cwd /Users/hecomi/Dropbox/Program/javascript/node.js/gyp gyp ERR! node -v v0.9.2 gyp ERR! node-gyp -v v0.7.1 gyp ERR! not ok
Makefile(build/hello.target.mk)を覗いてみるとどこにも -std=c++0x などという文字はおわしませんでした…。が、Ubuntu で同じようにやると通ります。Mac で生じる現象のようです。
解決方法
binding.gyp を以下のように書き換える
{ 'targets': [ { 'target_name' : 'hello', 'sources' : [ 'helloworld.cc' ], 'xcode_settings': { 'OTHER_CFLAGS': [ '-std=c++0x', ], }, } ], }
これでOKです。モジュール配布したときにわざわざ打ち込んでもらう手間も省くことができます。
見つけた手順メモ
以下のファイルに OS 毎の設定が書き込まれてるっぽい、ということを見つけました(nave を使って Node.js を管理していますので、環境によって場所は異なると思います)。
~/.nave/installed/0.9.2/lib/node_modules/node-gyp/legacy/common.gypi
そして以下の様な Mac 用の設定を発見。
(前略) ['OS=="mac"', { 'defines': ['_DARWIN_USE_64_BIT_INODE=1'], 'xcode_settings': { 'ALWAYS_SEARCH_USER_PATHS': 'NO', 'GCC_CW_ASM_SYNTAX': 'NO', # No -fasm-blocks 'GCC_DYNAMIC_NO_PIC': 'NO', # No -mdynamic-no-pic # (Equivalent to -fPIC) 'GCC_ENABLE_CPP_EXCEPTIONS': 'NO', # -fno-exceptions 'GCC_ENABLE_CPP_RTTI': 'NO', # -fno-rtti 'GCC_ENABLE_PASCAL_STRINGS': 'NO', # No -mpascal-strings 'GCC_THREADSAFE_STATICS': 'NO', # -fno-threadsafe-statics 'GCC_VERSION': '4.2', 'GCC_WARN_ABOUT_MISSING_NEWLINE': 'YES', # -Wnewline-eof 'PREBINDING': 'NO', # No -Wl,-prebind 'MACOSX_DEPLOYMENT_TARGET': '10.5', # -mmacosx-version-min=10.5 'USE_HEADERMAP': 'NO', 'OTHER_CFLAGS': [ '-fno-strict-aliasing', ], 'WARNING_CFLAGS': [ '-Wall', '-Wendif-labels', '-W', '-Wno-unused-parameter', ], (以下略)
xcode で開発してなくても xcode_settings が Mac では適用されるみたいです。ということで、ここを参考にして書いたらうまく行った、という感じです。
普通の gyp でも
node-gyp だけでなく、通常の gyp でも同様な問題が起こります。が、同じように設定して実行すれば OK です。format オプション付けないと xcode 用になってしまうので注意。
(同様に binding.gyp を書き換え) $ gyp --depth=. binding.gyp --format=make $ make
おわりに
色々とアドバイスを下さった友人に感謝感謝です m(_ _)m