9.9 KiB
title | pagination_prev | pagination_next |
---|---|---|
C++ + ChakraCore | demos/bigdata/index | solutions/input |
import current from '/version.js'; import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; import CodeBlock from '@theme/CodeBlock';
ChakraCore is an embeddable JS engine written in C++.
The Standalone scripts can be parsed and evaluated in a ChakraCore context.
Integration Details
Initialize ChakraCore
ChakraCore provides a global
object through JsGetGlobalObject
:
/* 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:
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:
/* 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
:
/* 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 tested in the following deployments:
Architecture | Git Commit | Date |
---|---|---|
darwin-x64 |
c3ead3f |
2023-08-26 |
darwin-arm |
c3ead3f |
2023-08-26 |
win10-x64 |
c3ead3f |
2023-08-26 |
linux-x64 |
c3ead3f |
2023-07-05 |
:::
- Install dependencies:
brew install icu4c cmake
brew install icu4c cmake
On Arch Linux / HoloOS:
sudo pacman -S cmake clang
Install Visual Studio 2022 with the "Desktop Development with C++" workflow. All commands in this demo should be run in a Developer Command Prompt.
- Download ChakraCore:
git clone https://github.com/Microsoft/ChakraCore.git
cd ChakraCore
git checkout c3ead3f
cd ..
- Build ChakraCore:
cd ChakraCore
./build.sh --static --icu=/usr/local/opt/icu4c/include --test-build -j=8
cd ..
:::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:
cd ChakraCore
mkdir -p usr/local/opt
ln -s /opt/homebrew/opt/icu4c usr/local/opt/icu4c
cd ..
:::
:::info
When the demo was last tested, ChakraCore JIT was not supported.
:::
cd ChakraCore
./build.sh --static --icu=/usr/local/opt/icu4c/include --test-build -j=8 --no-jit
cd ..
:::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:
cd ChakraCore
mkdir -p usr/local/opt
ln -s /opt/homebrew/opt/icu4c usr/local/opt/icu4c
cd ..
:::
:::caution
When the demo was last tested, ChakraCore JIT was not supported.
:::
cd ChakraCore
./build.sh --static --embed-icu --test-build -j=8 --no-jit
cd ..
:::info pass
As explained in the ChakraCore project wiki1, the build accepts a few flags:
/p:Platform=x64
controls the architecture/p:Configuration=Debug
enables runtime checks/p:RuntimeLib=static_library
ensures MSVC libraries are statically linked
:::
cd ChakraCore
msbuild /m /p:Platform=x64 /p:Configuration=Debug /p:RuntimeLib=static_library Build\Chakra.Core.sln
cd ..
After building, the generated DLL should be copied into the project folder:
copy .\ChakraCore\Build\VcBuild\bin\x64_debug\ChakraCore.dll .
- Download the source file and
Makefile
:
curl -L -O https://docs.sheetjs.com/chakra/sheetjs.ch.cpp
curl -L -O https://docs.sheetjs.com/chakra/Makefile
- Build the sample application:
make
:::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:
cd /usr/local
sudo mkdir -p opt
cd opt
sudo ln -s /opt/homebrew/opt/icu4c
:::
cl sheetjs.ch.cpp ChakraCore.lib /I ChakraCore\lib\Jsrt /link /LIBPATH:ChakraCore\Build\VcBuild\bin\x64_debug
- Download the standalone script, shim script, and test file:
- xlsx.full.min.js
- shim.min.js
- pres.numbers
{\ curl -L -O https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js curl -L -O https://cdn.sheetjs.com/xlsx-${current}/package/dist/shim.min.js curl -L -O https://sheetjs.com/pres.numbers
}
- Run the test program:
./sheetjs.ch pres.numbers
.\sheetjs.ch.exe 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-08-26 against ch
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.
- Download and extract the ChakraCore release ZIP. Copy the binary (
bin/ch
) to your project folder.
:::note pass
The "Integration Example" also builds the ch
binary!
It will typically be placed in the ChakraCore/out/Test/
folder.
:::
- Download the standalone script, shim, and test file:
- xlsx.full.min.js
- shim.min.js
- pres.numbers
{\ curl -L -O https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js curl -L -O https://cdn.sheetjs.com/xlsx-${current}/package/dist/shim.min.js curl -L -O https://sheetjs.com/pres.numbers
}
- Bundle the test file and create
payload.js
:
node -e "fs.writeFileSync('payload.js', 'var payload = \"' + fs.readFileSync('pres.numbers').toString('base64') + '\";')"
- Create support scripts:
global.js
creates aglobal
variable:
var global = (function(){ return this; }).call(null);
chakra.js
will callXLSX.read
andXLSX.utils.sheet_to_csv
:
var wb = XLSX.read(payload, {type:'base64'});
console.log(XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]));
- Create the amalgamation
xlsx.chakra.js
:
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.
- Run the script using the ChakraCore standalone binary:
./ch xlsx.chakra.js
-
See "Building ChakraCore" in the ChakraCore project wiki ↩︎