2023-04-09 06:58:43 +00:00
|
|
|
---
|
|
|
|
title: C++ + ChakraCore
|
|
|
|
pagination_prev: demos/bigdata/index
|
|
|
|
pagination_next: solutions/input
|
|
|
|
---
|
|
|
|
|
2023-04-27 09:12:19 +00:00
|
|
|
import current from '/version.js';
|
2023-06-05 20:12:53 +00:00
|
|
|
import Tabs from '@theme/Tabs';
|
|
|
|
import TabItem from '@theme/TabItem';
|
2023-05-07 13:58:36 +00:00
|
|
|
import CodeBlock from '@theme/CodeBlock';
|
2023-04-27 09:12:19 +00:00
|
|
|
|
2023-04-09 06:58:43 +00:00
|
|
|
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
|
|
|
|
|
2023-06-05 20:12:53 +00:00
|
|
|
This demo was tested in the following deployments:
|
2023-04-09 06:58:43 +00:00
|
|
|
|
2023-06-05 20:12:53 +00:00
|
|
|
| Architecture | Git Commit | Date |
|
|
|
|
|:-------------|:-----------|:-----------|
|
2023-07-06 07:21:41 +00:00
|
|
|
| `darwin-x64` | `c3ead3f` | 2023-07-05 |
|
|
|
|
| `darwin-arm` | `c3ead3f` | 2023-07-05 |
|
|
|
|
| `linux-x64` | `c3ead3f` | 2023-07-05 |
|
2023-04-09 06:58:43 +00:00
|
|
|
|
|
|
|
:::
|
|
|
|
|
2023-07-06 07:21:41 +00:00
|
|
|
0) Install `icu` and `cmake` dependencies.
|
|
|
|
|
|
|
|
<Tabs groupId="triple">
|
|
|
|
<TabItem value="darwin-x64" label="Intel Mac">
|
|
|
|
|
|
|
|
```bash
|
|
|
|
brew install icu4c cmake
|
|
|
|
```
|
|
|
|
|
|
|
|
</TabItem>
|
|
|
|
<TabItem value="darwin-arm" label="Apple Silicon">
|
2023-06-05 20:12:53 +00:00
|
|
|
|
|
|
|
```bash
|
|
|
|
brew install icu4c cmake
|
|
|
|
```
|
|
|
|
|
2023-07-06 07:21:41 +00:00
|
|
|
</TabItem>
|
|
|
|
<TabItem value="linux-x64" label="Linux">
|
|
|
|
|
|
|
|
On Arch Linux / HoloOS:
|
|
|
|
|
|
|
|
```bash
|
|
|
|
sudo pacman -S cmake clang
|
|
|
|
```
|
|
|
|
|
|
|
|
</TabItem>
|
|
|
|
</Tabs>
|
|
|
|
|
2023-06-05 20:12:53 +00:00
|
|
|
1) Download ChakraCore:
|
2023-04-09 06:58:43 +00:00
|
|
|
|
|
|
|
```bash
|
|
|
|
git clone https://github.com/Microsoft/ChakraCore
|
|
|
|
cd ChakraCore
|
|
|
|
git checkout c3ead3f
|
2023-06-05 20:12:53 +00:00
|
|
|
cd ..
|
|
|
|
```
|
|
|
|
|
|
|
|
2) Build ChakraCore:
|
|
|
|
|
|
|
|
<Tabs groupId="triple">
|
|
|
|
<TabItem value="darwin-x64" label="Intel Mac">
|
|
|
|
|
|
|
|
```bash
|
|
|
|
cd ChakraCore
|
2023-04-09 06:58:43 +00:00
|
|
|
./build.sh --static --icu=/usr/local/opt/icu4c/include --test-build -j=8
|
|
|
|
cd ..
|
|
|
|
```
|
|
|
|
|
2023-07-06 07:21:41 +00:00
|
|
|
:::caution
|
|
|
|
|
|
|
|
When this demo was last tested, the build failed with the message:
|
|
|
|
|
|
|
|
```
|
|
|
|
!!! couldn't find ICU ...
|
|
|
|
```
|
|
|
|
|
|
|
|
This was fixed with a local symlink to the `icu4c` folder before the build step:
|
|
|
|
|
|
|
|
```bash
|
|
|
|
cd ChakraCore
|
|
|
|
mkdir -p usr/local/opt
|
|
|
|
ln -s /opt/homebrew/opt/icu4c usr/local/opt/icu4c
|
|
|
|
cd ..
|
|
|
|
```
|
|
|
|
|
|
|
|
:::
|
|
|
|
|
2023-06-05 20:12:53 +00:00
|
|
|
</TabItem>
|
|
|
|
<TabItem value="darwin-arm" label="Apple Silicon">
|
|
|
|
|
|
|
|
:::info
|
|
|
|
|
|
|
|
When the demo was last tested, ChakraCore JIT was not supported.
|
|
|
|
|
|
|
|
:::
|
|
|
|
|
|
|
|
```bash
|
|
|
|
cd ChakraCore
|
|
|
|
./build.sh --static --icu=/usr/local/opt/icu4c/include --test-build -j=8 --no-jit
|
|
|
|
cd ..
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
:::caution
|
|
|
|
|
2023-07-06 07:21:41 +00:00
|
|
|
When this demo was last tested, the build failed with the message:
|
2023-06-05 20:12:53 +00:00
|
|
|
|
|
|
|
```
|
|
|
|
!!! couldn't find ICU ...
|
|
|
|
```
|
|
|
|
|
|
|
|
This was fixed with a local symlink to the `icu4c` folder before the build step:
|
|
|
|
|
|
|
|
```bash
|
|
|
|
cd ChakraCore
|
|
|
|
mkdir -p usr/local/opt
|
|
|
|
ln -s /opt/homebrew/opt/icu4c usr/local/opt/icu4c
|
|
|
|
cd ..
|
|
|
|
```
|
|
|
|
|
|
|
|
:::
|
|
|
|
|
2023-07-06 07:21:41 +00:00
|
|
|
</TabItem>
|
|
|
|
<TabItem value="linux-x64" label="Linux">
|
|
|
|
|
|
|
|
:::caution
|
|
|
|
|
|
|
|
When the demo was last tested, ChakraCore JIT was not supported.
|
|
|
|
|
|
|
|
:::
|
|
|
|
|
|
|
|
```bash
|
|
|
|
cd ChakraCore
|
|
|
|
./build.sh --static --embed-icu --test-build -j=8 --no-jit
|
|
|
|
cd ..
|
|
|
|
```
|
|
|
|
|
|
|
|
</TabItem>
|
|
|
|
</Tabs>
|
|
|
|
|
2023-06-05 20:12:53 +00:00
|
|
|
3) Download the source file and `Makefile`:
|
2023-04-09 06:58:43 +00:00
|
|
|
|
|
|
|
- [`sheetjs.ch.cpp`](pathname:///chakra/sheetjs.ch.cpp)
|
|
|
|
- [`Makefile`](pathname:///chakra/Makefile)
|
|
|
|
|
|
|
|
```bash
|
2023-06-05 20:12:53 +00:00
|
|
|
curl -LO https://docs.sheetjs.com/chakra/sheetjs.ch.cpp
|
2023-04-09 06:58:43 +00:00
|
|
|
curl -LO https://docs.sheetjs.com/chakra/Makefile
|
|
|
|
```
|
|
|
|
|
2023-06-05 20:12:53 +00:00
|
|
|
4) Build the sample application:
|
2023-04-09 06:58:43 +00:00
|
|
|
|
|
|
|
```bash
|
|
|
|
make
|
|
|
|
```
|
|
|
|
|
|
|
|
This program tries to parse the file specified by the first argument
|
|
|
|
|
2023-06-05 20:12:53 +00:00
|
|
|
:::caution
|
|
|
|
|
|
|
|
When this demo was last tested on macOS, the build failed with the message:
|
|
|
|
|
|
|
|
```
|
|
|
|
clang: error: no such file or directory: '/usr/local/opt/icu4c/lib/libicudata.a'
|
|
|
|
```
|
|
|
|
|
|
|
|
This was fixed by creating a symbolic link:
|
|
|
|
|
|
|
|
```bash
|
|
|
|
cd /usr/local
|
|
|
|
sudo mkdir -p opt
|
|
|
|
cd opt
|
|
|
|
sudo ln -s /opt/homebrew/opt/icu4c
|
|
|
|
```
|
|
|
|
|
|
|
|
:::
|
|
|
|
|
|
|
|
5) Download the standalone script, shim script, and test file:
|
2023-04-09 06:58:43 +00:00
|
|
|
|
|
|
|
<ul>
|
2023-04-27 09:12:19 +00:00
|
|
|
<li><a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`}>xlsx.full.min.js</a></li>
|
|
|
|
<li><a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/shim.min.js`}>shim.min.js</a></li>
|
2023-04-09 06:58:43 +00:00
|
|
|
<li><a href="https://sheetjs.com/pres.numbers">pres.numbers</a></li>
|
|
|
|
</ul>
|
|
|
|
|
2023-05-07 13:58:36 +00:00
|
|
|
<CodeBlock language="bash">{`\
|
2023-04-27 09:12:19 +00:00
|
|
|
curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js
|
|
|
|
curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/shim.min.js
|
|
|
|
curl -LO https://sheetjs.com/pres.numbers`}
|
2023-05-07 13:58:36 +00:00
|
|
|
</CodeBlock>
|
2023-04-09 06:58:43 +00:00
|
|
|
|
2023-06-05 20:12:53 +00:00
|
|
|
6) Run the test program:
|
2023-04-09 06:58:43 +00:00
|
|
|
|
|
|
|
```
|
|
|
|
./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>
|
2023-04-27 09:12:19 +00:00
|
|
|
<li><a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`}>xlsx.full.min.js</a></li>
|
|
|
|
<li><a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/shim.min.js`}>shim.min.js</a></li>
|
2023-04-09 06:58:43 +00:00
|
|
|
<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
|
|
|
|
```
|