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