Cross compile with Node.js C++ Addons to ARM

Set ENV

  1. export HOST=arm-linux-gnueabihf
  2. export CPP="${HOST}-gcc -E"
  3. export STRIP="${HOST}-strip"
  4. export OBJCOPY="${HOST}-objcopy"
  5. export AR="${HOST}-ar"
  6. export RANLIB="${HOST}-ranlib"
  7. export LD="${HOST}-ld"
  8. export OBJDUMP="${HOST}-objdump"
  9. export CC="${HOST}-gcc"
  10. export CXX="${HOST}-g++"
  11. export NM="${HOST}-nm"
  12. export AS="${HOST}-as"
  13. export LD="$CXX"
  14. export LINK="$CXX"
  15. export GYP_DEFINES="armv7=0"

Build

  1. node-gyp --arch arm configure build

Test

  1. root@imx6ul7d:~# node hello.js      
  2. world

TIP 0

  1. {
  2.   "targets": [
  3.     {
  4.       "target_name": "addon",
  5.       "sources": [ "test_api.cc" ],
  6. 	  "include_dirs" : ["sdk/inc"],
  7. 	  "link_settings": {"libraries": [ "-L/mnt/hgfs/tmp0511/sdk/lib"] },
  8. 	  "libraries": [ "-lpos", "-lpthread", "-lrt", "-lpng", "-liconv", "-lfreetype", "-lz" ],
  9.     }
  10.   ]
  11. }

TIP 1

  1. using v8::FunctionCallbackInfo;
  2. using v8::Isolate;
  3. using v8::Local;
  4. using v8::Object;
  5. using v8::String;
  6. using v8::Value;
  7. using v8::Number;
  8. using v8::Exception;
  9.  
  10. void js_Exchange(const FunctionCallbackInfo<Value>& args) {
  11.   Isolate* isolate = args.GetIsolate();
  12.  
  13.   int slot = args[0]->NumberValue();
  14.  
  15.   String::Utf8Value param1(args[1]->ToString());  
  16.   char *szApdu = *param1;  
  17.  
  18.   uint8_t apdu[300] = "\0";
  19.   MyAHex((uint8_t *)szApdu, apdu, strlen(szApdu));
  20.  
  21.   uint8_t rpdu[300] = "\0";
  22.   uint32_t rpdu_len = 0;
  23.   char szResult[300] = "\0";
  24.  
  25.   int ret = Exchange(slot, apdu, strlen(szApdu) / 2, rpdu, &rpdu_len);
  26.   if(0 == ret) {
  27.     MyHexA(rpdu, (uint8_t *)szResult, rpdu_len);
  28.     args.GetReturnValue().Set(String::NewFromUtf8(isolate, szResult));
  29.   } else {
  30.     args.GetReturnValue().Set(String::NewFromUtf8(isolate, ""));
  31.   }
  32. }

Node.js C++ Addons

Install node-gyp

  1. npm install -g node-gyp

Prepare SourceCode

  1. [root@localhost test_nodejs]# ls
  2. binding.gyp  hello.cc  hello.js

hello.cc

  1. #include <node.h>
  2.  
  3. namespace demo {
  4.  
  5. using v8::FunctionCallbackInfo;
  6. using v8::Isolate;
  7. using v8::Local;
  8. using v8::Object;
  9. using v8::String;
  10. using v8::Value;
  11.  
  12. void Method(const FunctionCallbackInfo<Value>& args) {
  13.   Isolate* isolate = args.GetIsolate();
  14.   args.GetReturnValue().Set(String::NewFromUtf8(isolate, "world"));
  15. }
  16.  
  17. void init(Local<Object> exports) {
  18.   NODE_SET_METHOD(exports, "hello", Method);
  19. }
  20.  
  21. NODE_MODULE(NODE_GYP_MODULE_NAME, init)
  22.  
  23. }  // namespace demo

hello.js

  1. // hello.js
  2. const addon = require('./build/Release/addon');
  3.  
  4. console.log(addon.hello());
  5. // Prints: 'world'

binding.gyp

  1. {
  2.   "targets": [
  3.     {
  4.       "target_name": "addon",
  5.       "sources": [ "hello.cc" ]
  6.     }
  7.   ]
  8. }

Compile & Test

  1. [root@localhost test_nodejs]# node-gyp configure
  2. gyp info it worked if it ends with ok
  3. gyp info using node-gyp@3.6.2
  4. gyp info using node@8.11.1 | linux | x64
  5. gyp info spawn /usr/bin/python2
  6. gyp info spawn args [ '/usr/local/node-v8.11.1-linux-x64/lib/node_modules/node-gyp/gyp/gyp_main.py',
  7. gyp info spawn args   'binding.gyp',
  8. gyp info spawn args   '-f',
  9. gyp info spawn args   'make',
  10. gyp info spawn args   '-I',
  11. gyp info spawn args   '/mnt/hgfs/linux_tmp/test_nodejs/build/config.gypi',
  12. gyp info spawn args   '-I',
  13. gyp info spawn args   '/usr/local/node-v8.11.1-linux-x64/lib/node_modules/node-gyp/addon.gypi',
  14. gyp info spawn args   '-I',
  15. gyp info spawn args   '/root/.node-gyp/8.11.1/include/node/common.gypi',
  16. gyp info spawn args   '-Dlibrary=shared_library',
  17. gyp info spawn args   '-Dvisibility=default',
  18. gyp info spawn args   '-Dnode_root_dir=/root/.node-gyp/8.11.1',
  19. gyp info spawn args   '-Dnode_gyp_dir=/usr/local/node-v8.11.1-linux-x64/lib/node_modules/node-gyp',
  20. gyp info spawn args   '-Dnode_lib_file=/root/.node-gyp/8.11.1/<(target_arch)/node.lib',
  21. gyp info spawn args   '-Dmodule_root_dir=/mnt/hgfs/linux_tmp/test_nodejs',
  22. gyp info spawn args   '-Dnode_engine=v8',
  23. gyp info spawn args   '--depth=.',
  24. gyp info spawn args   '--no-parallel',
  25. gyp info spawn args   '--generator-output',
  26. gyp info spawn args   'build',
  27. gyp info spawn args   '-Goutput_dir=.' ]
  28. gyp info ok 
  29. [root@localhost test_nodejs]# 
  30. [root@localhost test_nodejs]# ls
  31. binding.gyp  build  hello.cc  hello.js
  32. [root@localhost test_nodejs]# ls build/
  33. addon.target.mk  binding.Makefile  config.gypi  Makefile
  34.  
  35. [root@localhost test_nodejs]# node-gyp build
  36. gyp info it worked if it ends with ok
  37. gyp info using node-gyp@3.6.2
  38. gyp info using node@8.11.1 | linux | x64
  39. gyp info spawn make
  40. gyp info spawn args [ 'BUILDTYPE=Release', '-C', 'build' ]
  41. make: Entering directory `/mnt/hgfs/linux_tmp/test_nodejs/build'
  42.   CXX(target) Release/obj.target/addon/hello.o
  43.   SOLINK_MODULE(target) Release/obj.target/addon.node
  44.   COPY Release/addon.node
  45. make: Leaving directory `/mnt/hgfs/linux_tmp/test_nodejs/build'
  46. gyp info ok 
  47.  
  48. [root@localhost test_nodejs]# ls build/
  49. addon.target.mk  binding.Makefile  config.gypi  Makefile  Release
  50. [root@localhost test_nodejs]# ls build/Release/
  51. addon.node  obj.target
  52.  
  53. [root@localhost test_nodejs]# node hello.js
  54. world