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

凹みTips

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

Mac OS X で node-gyp するのに -std=c++0x つけようとしてハマったけど解決した

node.js C++

はじめに

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 で生じる現象のようです。

解決方法

環境変数を設定しておく
$ export CXXFLAGS="-std=c++0x"
$ node-gyp build

これでやれば環境変数書き換わりますが、取り敢えずは通ります。

ビルド時に環境変数を設定
$ node-gyp build CXXFLAGS="-std=c++0x"

これでも動きます。

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