Permalink
Fetching contributors…
Cannot retrieve contributors at this time
212 lines (172 sloc) 6.44 KB

This document focuses on jxcore's new public interface located under (src/public). We want this interface to be very easy to use and embedabble on any platform.
If you need to reach all the core features, you may want to check src/public/jx.cc to see how we have actually implemented this interface. So you can add your custom methods.

In order to embed jxcore into an application, you should first compile it as a library.

Posix ./configure --static-library --prefix=/targetFolder --engine-mozilla (for V8 remove --engine-mozilla) ./make install

Windows vcbuild.bat --shared-library --engine-mozilla (for V8 remove --engine-mozilla)

Additional useful parameters

--dest-cpu=ia32   ->  32 bit  (ia32, arm, armv7s, arm64, x86_64)
--dest-os=ios     ->   (ios, android, or leave empty for your current platform)

In the end you will have all the binaries and include files. The new public interface only expects jx.h and jx_result.h files in addition to the libraries under the bin or Release folder. You can find the headers files under src/public

The sample below demonstrates a basic usage of the interface

#include <stdlib.h>
#include <string.h>
#include <sstream>

#if defined(_MSC_VER)
// Sleep time for Windows is 1 ms while it's 1 ns for POSIX
// Beware using this for your app. This is just to give a
// basic idea on usage
#include <windows.h>
#else
#include <unistd.h>
#define Sleep(x) usleep(x)
#endif

#include "jx.h"

#define flush_console(...)        \
  do {                            \
    fprintf(stdout, __VA_ARGS__); \
    fflush(stdout);               \
    } while (0)

void ConvertResult(JXValue *result, std::string &to_result) {
  switch (result->type_) {
  case RT_Null:
    to_result = "null";
    break;
  case RT_Undefined:
    to_result = "undefined";
    break;
  case RT_Boolean:
    to_result = JX_GetBoolean(result) ? "true" : "false";
    break;
  case RT_Int32: {
    std::stringstream ss;
    ss << JX_GetInt32(result);
    to_result = ss.str();
  } break;
  case RT_Double: {
    std::stringstream ss;
    ss << JX_GetDouble(result);
    to_result = ss.str();
  } break;
  case RT_Buffer: {
    to_result = JX_GetString(result);
  } break;
  case RT_Object: {
    to_result = JX_GetString(result);
  } break;
  case RT_String: {
    to_result = JX_GetString(result);
  } break;
  case RT_Error: {
    to_result = JX_GetString(result);
  } break;
  default:
    to_result = "null";
    return;
  }
}

void callback(JXResult *results, int argc) {
  // do nothing
}

void sampleMethod(JXResult *results, int argc) {
  flush_console("sampleMethod Called;\n");

  std::stringstream ss_result;
  for (int i = 0; i < argc; i++) {
    std::string str_result;
    ConvertResult(&results[i], str_result);
    ss_result << i << " : ";
    ss_result << str_result << "\n";
  }

  flush_console("%s", ss_result.str().c_str());

  // return an Array back to JS Land
  const char *str = "[1, 2, 3]";

  // results[argc] corresponds to return value
  JX_SetJSON(&results[argc], str, strlen(str));
}

int main(int argc, char **args) {
  char *path = args[0];
  // Call JX_Initialize only once per app

  JX_Initialize(args[0], callback);
  // Creates a new engine for the current thread
  // It's our first engine instance hence it will be the
  // parent engine for all the other engine instances.
  // If you need to destroy this engine instance, you should
  // destroy everything else first. For the sake of this sample
  // we have our first instance sitting on the main thread
  // and it will be destroyed when the app exists.
  JX_InitializeNewEngine();

  char *contents = "console.log('hello world');";

  // define the entry file contents
  JX_DefineMainFile(contents);

  // define native -named- method
  // we will be reaching to this method from the javascript side like this;
  // process.natives.sampleMethod( ... )
  JX_DefineExtension("sampleMethod", sampleMethod);

  JX_StartEngine();

  // loop for possible IO
  // or JX_Loop() without usleep / while
  while (JX_LoopOnce() != 0) Sleep(1);

  JXValue result;
  JX_Evaluate(
    "var arr = process.natives.sampleMethod('String Parameter', {foo:1}); \n"
    "console.log('result: ', arr, 'length:', arr.length ); \n"
    "setTimeout(function() { \n"
    "  console.log('end!'); \n"
    "}, 100);",
    "myscript", &result);

  JX_Free(&result);
  // loop for possible IO
  // or JX_Loop() without usleep / while
  while (JX_LoopOnce() != 0) Sleep(1);

  JX_StopEngine();
}

Expected output should be;

hello world
sampleMethod Called;
0 : String Parameter
1 : {"foo":1}
result:  [ 1, 2, 3 ] length: 3
end!

####*NIX In order to compile the source codes above (lets say you saved it into sample.cpp)

OSX :

g++ sample.cpp -stdlib=libstdc++ -lstdc++ -std=c++11 -O3 -I/targetFolder/include/node/public \
    /targetFolder/bin/libcares.a	/targetFolder/bin/libjx.a /targetFolder/bin/libsqlite3.a \
    /targetFolder/bin/libchrome_zlib.a /targetFolder/bin/libmozjs.a  /targetFolder/bin/libuv.a \
    /targetFolder/bin/libhttp_parser.a	/targetFolder/bin/libopenssl.a \
    -Wno-c++11-compat-deprecated-writable-strings -Wl -framework CoreServices -o sample

Linux:

g++ sample.cpp -lstdc++ -std=c++11 -pthread -O3 -Wno-write-strings -I/targetFolder/include/node/public \
    -fno-rtti /targetFolder/bin/libjx.a /targetFolder/bin/libsqlite3.a \
    /targetFolder/bin/libchrome_zlib.a /targetFolder/bin/libmozjs.a  /targetFolder/bin/libuv.a \
    /targetFolder/bin/libhttp_parser.a	/targetFolder/bin/libopenssl.a  \
    -ldl /targetFolder/bin/libcares.a \
    -o sample

Scripts above assumes you've compiled JXcore static libraries for x64 architecture. In case you did that for 32 bit, you should add -m32 argument.

Besides the architecture, if you have compiled JXcore with V8 engine, you should replace libmozjs.a above to libv8_base.a and also add libv8_nosnapshot.a

####Sample Windows App: Available here

Additional Notes for Windows GUI / UWP Metro applications: If there is no standard output is available, JXcore pushes console.log/error/warning into either attached debugger or application's temporary folder.

That's all you need to do to embed JXcore!

JXcore native interface - API Documentation

Advanced sample: managing multiple instances