This is a minimal repro to demonstrate an issue with building native addons for Electron that use standard C++ headers and libraries.
It's based on the simplest "hello_world" addon from node-addon-examples with a one-line change to include the C++11 standard include file <regex>
.
On my system (A Mac running macOS Sierra 10.12.2) this addon compiles with no warnings or errors when using node-gyp
to build for node.js v7.1.0.
Rebuilding this addon for electron.js following the instructions in Using Native Node Modules fails with an error indicating the the standard C++ header file <regex>
is not found.
I would expect this addon to compile without warnings or errors when building for electron.
$ git clone git@github.com:antonycourtney/electron-cpp-addon.git
[...]
$ cd electron-cpp-addon
$ npm install
The final command should produce output something like the following:
> hello_world@0.0.0 install /private/tmp/electron-cpp-addon
> node-gyp rebuild
CXX(target) Release/obj.target/hello/hello.o
SOLINK_MODULE(target) Release/hello.node
hello_world@0.0.0 /private/tmp/electron-cpp-addon
├── bindings@1.2.1
└── nan@2.5.0
$
Confirm that this built succesfully:
$ node --version
v7.1.0
$ node hello.js
world
$
( You can also run the commmand node-gyp rebuild
manually from the shell any time after npm install
to recompile the addon for node.)
Following the approach recommended in Using Native Node Modules, attempt to run node-gyp
to rebuild this addon for Electron:
$ HOME=~/.electron-gyp node-gyp rebuild --target=1.4.15 --arch=x64
On my machine, this produces the following output:
gyp info it worked if it ends with ok
gyp info using node-gyp@3.5.0
gyp info using node@7.1.0 | darwin | x64
gyp info spawn /Users/antony/anaconda/bin/python2
gyp info spawn args [ '/usr/local/lib/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 '/private/tmp/electron-cpp-addon/build/config.gypi',
gyp info spawn args '-I',
gyp info spawn args '/usr/local/lib/node_modules/node-gyp/addon.gypi',
gyp info spawn args '-I',
gyp info spawn args '/Users/antony/.electron-gyp/.node-gyp/iojs-1.4.15/common.gypi',
gyp info spawn args '-Dlibrary=shared_library',
gyp info spawn args '-Dvisibility=default',
gyp info spawn args '-Dnode_root_dir=/Users/antony/.electron-gyp/.node-gyp/iojs-1.4.15',
gyp info spawn args '-Dnode_gyp_dir=/usr/local/lib/node_modules/node-gyp',
gyp info spawn args '-Dnode_lib_file=iojs.lib',
gyp info spawn args '-Dmodule_root_dir=/private/tmp/electron-cpp-addon',
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 spawn make
gyp info spawn args [ 'BUILDTYPE=Release', '-C', 'build' ]
CXX(target) Release/obj.target/hello/hello.o
../hello.cc:2:10: fatal error: 'regex' file not found
#include <regex>
^
1 error generated.
make: *** [Release/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 (/usr/local/lib/node_modules/node-gyp/lib/build.js:276:23)
gyp ERR! stack at emitTwo (events.js:106:13)
gyp ERR! stack at ChildProcess.emit (events.js:191:7)
gyp ERR! stack at Process.ChildProcess._handle.onexit (internal/child_process.js:215:12)
gyp ERR! System Darwin 16.3.0
gyp ERR! command "/usr/local/bin/node" "/usr/local/bin/node-gyp" "rebuild" "--target=1.4.15" "--arch=x64"
gyp ERR! cwd /private/tmp/electron-cpp-addon
gyp ERR! node -v v7.1.0
gyp ERR! node-gyp -v v3.5.0
gyp ERR! not ok
$
If we run the node-gyp rebuild
command manually to build for node.js, we see that the common.gypi
file used by node-gyp when building for node (7.1.0 on my system) is ~/.node-gyp/7.1.0/include/node/common.gypi
whereas when we build for electron, we are using ~/.electron-gyp/.node-gyp/iojs-1.4.14/common.gypi
.
digging in to these two files and comparing the differences, we see that around line 387 in node's common.gypi we have:
['clang==1', {
'xcode_settings': {
'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
'CLANG_CXX_LANGUAGE_STANDARD': 'gnu++0x', # -std=gnu++0x
'CLANG_CXX_LIBRARY': 'libc++',
},
}],
The corresponding fragment from electron's version of the same file is almost identical, but missing the CLANG_CXX_LIBRARY
definition:
['clang==1', {
'xcode_settings': {
'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
'CLANG_CXX_LANGUAGE_STANDARD': 'gnu++0x', # -std=gnu++0x
},
}],
We can get this to compile if we add the following fragment to binding.gyp
in this project:
"conditions": [
[ 'OS=="mac"', {
'xcode_settings': {
'CLANG_CXX_LIBRARY': 'libc++'
}
}]]
This should be added as a property of the object in the targets
array, so that the complete binding.gyp
becomes:
{
"targets": [
{
"target_name": "hello",
"sources": [ "hello.cc" ],
"include_dirs": [
"<!(node -e \"require('nan')\")"
],
"conditions": [
[ 'OS=="mac"', {
'xcode_settings': {
'CLANG_CXX_LIBRARY': 'libc++'
}
}]]
}
]
}