chakra
This commit is contained in:
parent
76543faea9
commit
5b755a1370
232
docz/docs/03-demos/12-engines/07_chakra.md
Normal file
232
docz/docs/03-demos/12-engines/07_chakra.md
Normal file
@ -0,0 +1,232 @@
|
||||
---
|
||||
title: C++ + ChakraCore
|
||||
pagination_prev: demos/bigdata/index
|
||||
pagination_next: solutions/input
|
||||
---
|
||||
|
||||
ChakraCore is an embeddable JS engine written in C++.
|
||||
|
||||
The [Standalone scripts](/docs/getting-started/installation/standalone) can be
|
||||
parsed and evaluated in a ChakraCore context.
|
||||
|
||||
## Integration Details
|
||||
|
||||
_Initialize ChakraCore_
|
||||
|
||||
ChakraCore provides a `global` object through `JsGetGlobalObject`:
|
||||
|
||||
```cpp
|
||||
/* initialize */
|
||||
JsRuntimeHandle runtime;
|
||||
JsContextRef context;
|
||||
size_t cookie = 0;
|
||||
JsCreateRuntime(JsRuntimeAttributeNone, nullptr, &runtime);
|
||||
JsCreateContext(runtime, &context);
|
||||
JsSetCurrentContext(context);
|
||||
|
||||
/* obtain reference to global object */
|
||||
JsValueRef global;
|
||||
JsGetGlobalObject(&global);
|
||||
|
||||
/* DO WORK HERE */
|
||||
|
||||
/* cleanup */
|
||||
JsSetCurrentContext(JS_INVALID_REFERENCE);
|
||||
JsDisposeRuntime(runtime);
|
||||
```
|
||||
|
||||
:::note
|
||||
|
||||
Cleanup and validation code is omitted from the discussion. The integration
|
||||
example shows structured validation and controlled memory usage.
|
||||
|
||||
:::
|
||||
|
||||
_Load SheetJS Scripts_
|
||||
|
||||
The main library can be loaded by reading the script from the file system and
|
||||
evaluating in the ChakraCore context:
|
||||
|
||||
```cpp
|
||||
static char *read_file(const char *filename, size_t *sz) {
|
||||
FILE *f = fopen(filename, "rb");
|
||||
if(!f) return NULL;
|
||||
long fsize; { fseek(f, 0, SEEK_END); fsize = ftell(f); fseek(f, 0, SEEK_SET); }
|
||||
char *buf = (char *)malloc(fsize * sizeof(char));
|
||||
*sz = fread((void *) buf, 1, fsize, f);
|
||||
fclose(f);
|
||||
return buf;
|
||||
}
|
||||
|
||||
#define EVAL_FILE(path) {\
|
||||
JsValueRef filename; \
|
||||
JsValueRef result; \
|
||||
JsCreateString(path, strlen(path), &filename); \
|
||||
size_t len; const char* script = read_file(path, &len);\
|
||||
JsValueRef src;\
|
||||
JsCreateExternalArrayBuffer((void*)script, len, nullptr, nullptr, &src);\
|
||||
JsRun(src, cookie++, filename, JsParseScriptAttributeNone, &result); \
|
||||
}
|
||||
|
||||
// ...
|
||||
/* load library */
|
||||
EVAL_FILE("shim.min.js")
|
||||
EVAL_FILE("xlsx.full.min.js")
|
||||
```
|
||||
|
||||
### Reading Files
|
||||
|
||||
`JsCreateExternalArrayBuffer` can generate an `ArrayBuffer` from a C byte array:
|
||||
|
||||
```cpp
|
||||
/* read file */
|
||||
size_t len; char *buf = read_file(argv[1], &len);
|
||||
|
||||
/* load data into array buffer */
|
||||
JsValueRef ab;
|
||||
JsCreateExternalArrayBuffer((void*)buf, len, nullptr, nullptr, &ab);
|
||||
```
|
||||
|
||||
After pushing the data, it is easiest to store properties on `globalThis`:
|
||||
|
||||
```cpp
|
||||
/* assign to the `buf` global variable */
|
||||
JsValueRef buf_str; JsCreateString("buf", strlen("buf"), &buf_str);
|
||||
JsObjectSetProperty(global, buf_str, ab, true);
|
||||
|
||||
/* call globalThis.wb = XLSX.read(ab) */
|
||||
const char* script_str ="globalThis.wb = XLSX.read(buf);"
|
||||
|
||||
JsValueRef script;
|
||||
JsCreateExternalArrayBuffer((void*)script_str, (size_t)strlen(script_str), nullptr, nullptr, &script);
|
||||
JsRun(script, cookie++, fname, JsParseScriptAttributeNone, &result);
|
||||
```
|
||||
|
||||
## Complete Example
|
||||
|
||||
The "Integration Example" covers a traditional integration in a C application,
|
||||
while the "CLI Test" demonstrates other concepts using the `ch` CLI tool.
|
||||
|
||||
### Integration Example
|
||||
|
||||
:::note
|
||||
|
||||
This demo was last tested on 2023 April 09 against ChakraCore commit `c3ead3f`
|
||||
on a Intel Mac. `gcc -v` printed:
|
||||
|
||||
```
|
||||
Apple clang version 14.0.0 (clang-1400.0.29.202)
|
||||
Target: x86_64-apple-darwin21.6.0
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
0) Build ChakraCore:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/Microsoft/ChakraCore
|
||||
cd ChakraCore
|
||||
git checkout c3ead3f
|
||||
./build.sh --static --icu=/usr/local/opt/icu4c/include --test-build -j=8
|
||||
cd ..
|
||||
```
|
||||
|
||||
1) Download the source file and Makefile:
|
||||
|
||||
- [`sheetjs.ch.cpp`](pathname:///chakra/sheetjs.ch.cpp)
|
||||
- [`Makefile`](pathname:///chakra/Makefile)
|
||||
|
||||
```bash
|
||||
curl -LO https://docs.sheetjs.com/chakra/sheetjs.ch.c
|
||||
curl -LO https://docs.sheetjs.com/chakra/Makefile
|
||||
```
|
||||
|
||||
2) Build the sample application:
|
||||
|
||||
```bash
|
||||
make
|
||||
```
|
||||
|
||||
This program tries to parse the file specified by the first argument
|
||||
|
||||
4) Download the standalone script, shim script, and test file:
|
||||
|
||||
<ul>
|
||||
<li><a href={`https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js`}>xlsx.full.min.js</a></li>
|
||||
<li><a href={`https://cdn.sheetjs.com/xlsx-latest/package/dist/shim.min.js`}>shim.min.js</a></li>
|
||||
<li><a href="https://sheetjs.com/pres.numbers">pres.numbers</a></li>
|
||||
</ul>
|
||||
|
||||
```bash
|
||||
curl -LO https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js
|
||||
curl -LO https://cdn.sheetjs.com/xlsx-latest/package/dist/shim.min.js
|
||||
curl -LO https://sheetjs.com/pres.numbers
|
||||
```
|
||||
|
||||
5) Run the test program:
|
||||
|
||||
```
|
||||
./sheetjs.ch pres.numbers
|
||||
```
|
||||
|
||||
If successful, the program will print the contents of the first sheet as CSV.
|
||||
|
||||
|
||||
### CLI Test
|
||||
|
||||
:::note
|
||||
|
||||
This demo was last tested on 2023 April 09 against `ch` `1.13.0.0-beta`.
|
||||
The command line tool was built against commit `c3ead3f`.
|
||||
|
||||
:::
|
||||
|
||||
Due to limitations of the `ch` standalone binary, this demo will encode a test
|
||||
file as a Base64 string and directly add it to an amalgamated script.
|
||||
|
||||
0) Download and extract the ChakraCore release ZIP. Copy the binary (`bin/ch`)
|
||||
to your project folder.
|
||||
|
||||
1) Download the standalone script, shim, and test file:
|
||||
|
||||
<ul>
|
||||
<li><a href={`https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js`}>xlsx.full.min.js</a></li>
|
||||
<li><a href={`https://cdn.sheetjs.com/xlsx-latest/package/dist/shim.min.js`}>shim.min.js</a></li>
|
||||
<li><a href="https://sheetjs.com/pres.numbers">pres.numbers</a></li>
|
||||
</ul>
|
||||
|
||||
2) Bundle the test file and create `payload.js`:
|
||||
|
||||
```bash
|
||||
node -e "fs.writeFileSync('payload.js', 'var payload = \"' + fs.readFileSync('pres.numbers').toString('base64') + '\";')"
|
||||
```
|
||||
|
||||
3) Create support scripts:
|
||||
|
||||
- `global.js` creates a `global` variable:
|
||||
|
||||
```js title="global.js"
|
||||
var global = (function(){ return this; }).call(null);
|
||||
```
|
||||
|
||||
- `chakra.js` will call `XLSX.read` and `XLSX.utils.sheet_to_csv`:
|
||||
|
||||
```js title="chakra.js"
|
||||
var wb = XLSX.read(payload, {type:'base64'});
|
||||
console.log(XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]));
|
||||
```
|
||||
|
||||
4) Create the amalgamation `xlsx.chakra.js`:
|
||||
|
||||
```bash
|
||||
cat global.js xlsx.full.min.js payload.js chakra.js > xlsx.chakra.js
|
||||
```
|
||||
|
||||
The final script defines `global` before loading the standalone library. Once
|
||||
ready, it will read the bundled test data and print the contents as CSV.
|
||||
|
||||
5) Run the script using the ChakraCore standalone binary:
|
||||
|
||||
```
|
||||
./ch xlsx.chakra.js
|
||||
```
|
@ -126,7 +126,7 @@ Target: x86_64-apple-darwin21.6.0
|
||||
0) Build `libquickjs.a`:
|
||||
|
||||
```bash
|
||||
git clone --depth=1 https://github.com/bellard/quickjs
|
||||
git clone https://github.com/bellard/quickjs
|
||||
cd quickjs
|
||||
git checkout 2788d71
|
||||
make
|
||||
|
@ -57,6 +57,12 @@ only be used when there is no safe way to pass `ArrayBuffer` or `Uint8Array`.
|
||||
|
||||
This list is sorted in alphabetical order.
|
||||
|
||||
### ChakraCore
|
||||
|
||||
ChakraCore is an embeddable JS engine written in C++.
|
||||
|
||||
This demo has been moved [to a dedicated page](/docs/demos/engines/chakra).
|
||||
|
||||
### Duktape
|
||||
|
||||
Duktape is an embeddable JS engine written in C. It has been ported to a number
|
||||
@ -261,82 +267,3 @@ This demo has been moved [to a dedicated page](/docs/demos/engines/quickjs).
|
||||
Rhino is an ES3+ engine in Java.
|
||||
|
||||
This demo has been moved [to a dedicated page](/docs/demos/engines/rhino).
|
||||
|
||||
### ChakraCore
|
||||
|
||||
:::caution
|
||||
|
||||
ChakraCore was an open source JavaScript engine released by Microsoft. It was a
|
||||
fork of the Chakra engine that powered Internet Explorer. When Microsoft Edge
|
||||
switched to become a fork of Chromium, Microsoft stopped providing support.
|
||||
|
||||
:::
|
||||
|
||||
ChakraCore is an embeddable JS engine written in C++. The library and binary
|
||||
distributions include a command-line tool `chakra` for running JS scripts.
|
||||
|
||||
The simplest way to interact with the engine is to pass Base64 strings. The make
|
||||
target builds a very simple payload with the data.
|
||||
|
||||
:::note
|
||||
|
||||
The official release includes the `ch` standalone binary. While applications
|
||||
should link against the official libraries, the standalone tool is useful for
|
||||
verifying functionality.
|
||||
|
||||
:::
|
||||
|
||||
<details><summary><b>Complete Example</b> (click to show)</summary>
|
||||
|
||||
Due to limitations of the standalone binary, this demo will encode a test file
|
||||
as a Base64 string and directly add it to an amalgamated script.
|
||||
|
||||
0) Download and extract the ChakraCore release ZIP. Copy the binary (`bin/ch`)
|
||||
to your project folder.
|
||||
|
||||
1) Download the standalone script, shim, and test file:
|
||||
|
||||
<ul>
|
||||
<li><a href={`https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js`}>xlsx.full.min.js</a></li>
|
||||
<li><a href={`https://cdn.sheetjs.com/xlsx-latest/package/dist/shim.min.js`}>shim.min.js</a></li>
|
||||
<li><a href="https://sheetjs.com/pres.numbers">pres.numbers</a></li>
|
||||
</ul>
|
||||
|
||||
2) Bundle the test file and create `payload.js`:
|
||||
|
||||
```bash
|
||||
node -e "fs.writeFileSync('payload.js', 'var payload = \"' + fs.readFileSync('pres.numbers').toString('base64') + '\";')"
|
||||
```
|
||||
|
||||
3) Create support scripts:
|
||||
|
||||
- `global.js` creates a `global` variable:
|
||||
|
||||
```js title="global.js"
|
||||
var global = (function(){ return this; }).call(null);
|
||||
```
|
||||
|
||||
- `chakra.js` will call `XLSX.read` and `XLSX.utils.sheet_to_csv`:
|
||||
|
||||
```js title="chakra.js"
|
||||
/* sheetjs (C) 2013-present SheetJS -- https://sheetjs.com */
|
||||
var wb = XLSX.read(payload, {type:'base64'});
|
||||
console.log(XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]));
|
||||
```
|
||||
|
||||
4) Create the amalgamation `xlsx.chakra.js`:
|
||||
|
||||
```bash
|
||||
cat global.js xlsx.full.min.js payload.js chakra.js > xlsx.chakra.js
|
||||
```
|
||||
|
||||
The final script defines `global` before loading the standalone library. Once
|
||||
ready, it will read the bundled test data and print the contents as CSV.
|
||||
|
||||
5) Run the script using the ChakraCore standalone binary:
|
||||
|
||||
```
|
||||
./ch xlsx.chakra.js
|
||||
```
|
||||
|
||||
</details>
|
||||
|
@ -142,7 +142,7 @@ const config = {
|
||||
prism: {
|
||||
theme: lightCodeTheme,
|
||||
darkTheme: darkCodeTheme,
|
||||
additionalLanguages: [ "swift", "java", "csharp", "perl", "ruby" ],
|
||||
additionalLanguages: [ "swift", "java", "csharp", "perl", "ruby", "cpp" ],
|
||||
},
|
||||
liveCodeBlock: {
|
||||
playgroundPosition: 'top'
|
||||
|
13
docz/static/chakra/Makefile
Normal file
13
docz/static/chakra/Makefile
Normal file
@ -0,0 +1,13 @@
|
||||
CC=g++
|
||||
CHAKRALIB=ChakraCore/out/Test/lib/libChakraCoreStatic.a
|
||||
ICU4C=/usr/local/opt/icu4c/lib
|
||||
ICULIB=$(ICU4C)/libicudata.a $(ICU4C)/libicuuc.a $(ICU4C)/libicui18n.a
|
||||
|
||||
CFLAGS=-lstdc++ -std=c++11 -IChakraCore/lib/Jsrt
|
||||
|
||||
sheetjs.ch: sheetjs.ch.cpp
|
||||
g++ $< $(CFLAGS) -Wl,-force_load $(CHAKRALIB) $(ICULIB) -framework CoreFoundation -framework Security -lm -ldl -Wno-c++11-compat-deprecated-writable-strings -Wno-deprecated-declarations -Wno-unknown-warning-option -o $@
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm sheetjs.ch
|
89
docz/static/chakra/sheetjs.ch.cpp
Normal file
89
docz/static/chakra/sheetjs.ch.cpp
Normal file
@ -0,0 +1,89 @@
|
||||
/* this sample is based off of the official ChakraCore examples */
|
||||
#include "ChakraCore.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
|
||||
#define FAIL_CHECK(cmd) \
|
||||
do { \
|
||||
JsErrorCode errCode = cmd; \
|
||||
if (errCode != JsNoError) { \
|
||||
printf("Error %d at '%s'\n", errCode, #cmd); \
|
||||
return 1; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
using namespace std;
|
||||
|
||||
static char *read_file(const char *filename, size_t *sz) {
|
||||
FILE *f = fopen(filename, "rb");
|
||||
if(!f) return NULL;
|
||||
long fsize; { fseek(f, 0, SEEK_END); fsize = ftell(f); fseek(f, 0, SEEK_SET); }
|
||||
char *buf = (char *)malloc(fsize * sizeof(char));
|
||||
*sz = fread((void *) buf, 1, fsize, f);
|
||||
fclose(f);
|
||||
return buf;
|
||||
}
|
||||
|
||||
#define EVAL_FILE(path) {\
|
||||
JsValueRef filename; \
|
||||
JsValueRef result; \
|
||||
FAIL_CHECK(JsCreateString(path, strlen(path), &filename)); \
|
||||
size_t len; const char* script = read_file(path, &len);\
|
||||
JsValueRef src;\
|
||||
FAIL_CHECK(JsCreateExternalArrayBuffer((void*)script, len, nullptr, nullptr, &src));\
|
||||
FAIL_CHECK(JsRun(src, cookie++, filename, JsParseScriptAttributeNone, &result)); \
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
JsRuntimeHandle runtime;
|
||||
JsContextRef context;
|
||||
JsValueRef result;
|
||||
size_t cookie = 0;
|
||||
|
||||
FAIL_CHECK(JsCreateRuntime(JsRuntimeAttributeNone, nullptr, &runtime));
|
||||
FAIL_CHECK(JsCreateContext(runtime, &context));
|
||||
FAIL_CHECK(JsSetCurrentContext(context));
|
||||
|
||||
JsValueRef global;
|
||||
FAIL_CHECK(JsGetGlobalObject(&global));
|
||||
|
||||
EVAL_FILE("shim.min.js")
|
||||
|
||||
EVAL_FILE("xlsx.full.min.js")
|
||||
|
||||
JsValueRef buf_str;
|
||||
FAIL_CHECK(JsCreateString("buf", strlen("buf"), &buf_str));
|
||||
|
||||
size_t len; char *buf = read_file(argv[1], &len);
|
||||
JsValueRef ab;
|
||||
FAIL_CHECK(JsCreateExternalArrayBuffer((void*)buf, len, nullptr, nullptr, &ab));
|
||||
FAIL_CHECK(JsObjectSetProperty(global, buf_str, ab, true));
|
||||
|
||||
JsValueRef fname;
|
||||
FAIL_CHECK(JsCreateString("<script>", strlen("<script>"), &fname));
|
||||
|
||||
const char* script_str =
|
||||
"var wb = XLSX.read(buf);"
|
||||
"var ws = wb.Sheets[wb.SheetNames[0]];"
|
||||
"XLSX.utils.sheet_to_csv(ws);";
|
||||
|
||||
JsValueRef script;
|
||||
FAIL_CHECK(JsCreateExternalArrayBuffer((void*)script_str, (size_t)strlen(script_str), nullptr, nullptr, &script));
|
||||
FAIL_CHECK(JsRun(script, cookie++, fname, JsParseScriptAttributeNone, &result));
|
||||
|
||||
free(buf);
|
||||
FAIL_CHECK(JsCopyString(result, nullptr, 0, &len));
|
||||
buf = (char*)malloc(len + 1);
|
||||
FAIL_CHECK(JsCopyString(result, buf, len + 1, nullptr));
|
||||
buf[len] = 0;
|
||||
|
||||
printf("%s\n", buf);
|
||||
free(buf);
|
||||
|
||||
FAIL_CHECK(JsSetCurrentContext(JS_INVALID_REFERENCE));
|
||||
FAIL_CHECK(JsDisposeRuntime(runtime));
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user