2023-04-09 06:58:43 +00:00
---
2023-11-04 05:05:26 +00:00
title: Sheets in ChakraCore
sidebar_label: C++ + ChakraCore
description: Process structured data in C++ programs. Seamlessly integrate spreadsheets into your program by pairing ChakraCore and SheetJS. Handle the most complex files without breaking a sweat.
2023-04-09 06:58:43 +00:00
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++.
2023-11-04 05:05:26 +00:00
[SheetJS ](https://sheetjs.com ) is a JavaScript library for reading and writing
data from spreadsheets.
2024-01-23 09:26:06 +00:00
This demo uses ChakraCore and SheetJS to pull data from a spreadsheet and print
CSV rows. We'll explore how to load SheetJS in a ChakraCore context and process
2023-11-04 05:05:26 +00:00
spreadsheets from a C++ program.
The ["Integration Example" ](#integration-example ) section includes a complete
command-line tool for reading data from files.
2023-04-09 06:58:43 +00:00
## Integration Details
2023-11-04 05:05:26 +00:00
### Initialize ChakraCore
2023-04-09 06:58:43 +00:00
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);
```
2023-09-24 03:59:48 +00:00
:::note pass
2023-04-09 06:58:43 +00:00
Cleanup and validation code is omitted from the discussion. The integration
example shows structured validation and controlled memory usage.
:::
2023-11-04 05:05:26 +00:00
### Load SheetJS Scripts
[SheetJS Standalone scripts ](/docs/getting-started/installation/standalone ) can
be parsed and evaluated in a ChakraCore context.
2023-04-09 06:58:43 +00:00
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
2023-11-04 05:05:26 +00:00
:::note Tested Deployments
2023-04-09 06:58:43 +00:00
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 |
|:-------------|:-----------|:-----------|
2024-12-18 05:47:18 +00:00
| `darwin-x64` | `e26c81f` | 2024-12-17 |
2024-05-24 08:24:50 +00:00
| `darwin-arm` | `3a7b120` | 2024-05-23 |
2024-12-21 03:32:22 +00:00
| `win11-x64` | `e26c81f` | 2024-12-19 |
2024-07-15 01:55:09 +00:00
| `win11-arm` | `13358c6` | 2024-07-14 |
2024-04-26 04:16:13 +00:00
| `linux-x64` | `1f6e17c` | 2024-04-25 |
2023-04-09 06:58:43 +00:00
:::
2023-08-26 23:05:59 +00:00
0) Install dependencies:
2023-07-06 07:21:41 +00:00
< Tabs groupId = "triple" >
2024-12-21 03:32:22 +00:00
< TabItem value = "darwin-x64" label = "X64 Mac" >
2023-07-06 07:21:41 +00:00
```bash
brew install icu4c cmake
```
< / TabItem >
2023-09-27 04:43:00 +00:00
< TabItem value = "darwin-arm" label = "ARM64 Mac" >
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
```
2023-08-26 23:05:59 +00:00
< / TabItem >
2024-12-21 03:32:22 +00:00
< TabItem value = "win11-x64" label = "X64 Windows" >
2023-08-26 23:05:59 +00:00
2024-03-12 06:47:52 +00:00
Install Visual Studio 2022 with the "Desktop Development with C++" workflow and
the "Git for Windows" individual component.
2024-07-15 01:55:09 +00:00
The commands in this demo should be run in "Native Tools Command Prompt".
< / TabItem >
< TabItem value = "win11-arm" label = "ARM64 Windows" >
Install Visual Studio 2022 with the "Desktop Development with C++" workflow and
the "Git for Windows" individual component.
The commands in this demo should be run in "ARM64 Native Tools Command Prompt".
2023-08-26 23:05:59 +00:00
2023-07-06 07:21:41 +00:00
< / TabItem >
< / Tabs >
2023-06-05 20:12:53 +00:00
1) Download ChakraCore:
2023-04-09 06:58:43 +00:00
```bash
2023-11-04 05:05:26 +00:00
git clone https://github.com/chakra-core/ChakraCore.git
2023-04-09 06:58:43 +00:00
cd ChakraCore
2024-12-18 05:47:18 +00:00
git checkout e26c81f
2023-06-05 20:12:53 +00:00
cd ..
```
2) Build ChakraCore:
< Tabs groupId = "triple" >
2024-12-21 03:32:22 +00:00
< TabItem value = "darwin-x64" label = "X64 Mac" >
2023-06-05 20:12:53 +00:00
```bash
cd ChakraCore
2024-12-18 05:47:18 +00:00
./build.sh --static --icu=/usr/local/opt/icu4c/include --test-build -j=8 --system-icu --no-jit
2023-04-09 06:58:43 +00:00
cd ..
```
2024-03-16 16:04:18 +00:00
:::note pass
2023-07-06 07:21:41 +00:00
2024-03-16 16:04:18 +00:00
In some test runs, the build failed with the message:
2023-07-06 07:21:41 +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 ..
```
2024-12-18 05:47:18 +00:00
:::
:::danger pass
There are known issues with MacOS 15.1 SDK and ChakraCore JIT. These issues did
not affect earlier tests against MacOS 14.5. The current recommendation is to
disable JIT and use the system ICU implementation.
2023-07-06 07:21:41 +00:00
:::
2023-06-05 20:12:53 +00:00
< / TabItem >
2023-09-27 04:43:00 +00:00
< TabItem value = "darwin-arm" label = "ARM64 Mac" >
2023-06-05 20:12:53 +00:00
2023-09-19 19:08:29 +00:00
:::info pass
2023-06-05 20:12:53 +00:00
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 ..
```
2024-03-16 16:04:18 +00:00
:::note pass
2023-06-05 20:12:53 +00:00
2024-03-16 16:04:18 +00:00
In some test runs, 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" >
2023-09-24 03:59:48 +00:00
:::caution pass
2023-07-06 07:21:41 +00:00
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 ..
2023-08-26 23:05:59 +00:00
```
< / TabItem >
2024-12-21 03:32:22 +00:00
< TabItem value = "win11-x64" label = "X64 Windows" >
2023-08-26 23:05:59 +00:00
:::info pass
As explained in the ChakraCore project wiki[^1], 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 ..
```
2024-03-12 06:47:52 +00:00
:::caution pass
During some test runs, the build failed with a message referencing `cfguard.h` :
```
44>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\cfguard.h(44,1): error C2220: the following warning is treated as an error
(compiling source file 'ThreadContextInfo.cpp')
44>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\cfguard.h(44,1): warning C4005: '_GUARD_CHECK_ICALL': macro redefinition
```
The source file `lib\Runtime\Base\ThreadContextInfo.cpp` must be patched. The
highlighted lines must be commented:
```cpp title="lib\Runtime\Base\ThreadContextInfo.cpp (comment highlighted lines)"
#if defined(_UCRT) && _CONTROL_FLOW_GUARD
// highlight-start
//# if _MSC_VER >= 1913
//# include < cfguard.h >
//# else
// highlight-end
extern "C" void __fastcall _guard_check_icall(_In_ uintptr_t _Target);
// highlight-next-line
//# endif
#endif
```
:::
2023-08-26 23:05:59 +00:00
After building, the generated DLL should be copied into the project folder:
```
copy .\ChakraCore\Build\VcBuild\bin\x64_debug\ChakraCore.dll .
2024-07-15 01:55:09 +00:00
```
< / TabItem >
< TabItem value = "win11-arm" label = "ARM64 Windows" >
:::info pass
As explained in the ChakraCore project wiki[^1], the build accepts a few flags:
- `/p:Platform=arm64` 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=arm64 /p:Configuration=Debug /p:RuntimeLib=static_library Build\Chakra.Core.sln
cd ..
```
:::caution pass
During some test runs, the build failed with a message referencing `LegalizeMD.cpp` :
```
...\ChakraCore\lib\Backend\arm64\LegalizeMD.cpp(323,16): warning C1489: 'fPostRegAlloc': local variable is initialized but not referenced [...]
```
The source file `lib\Backend\arm64\LegalizeMD.cpp` must be patched. The
highlighted line must be commented:
```cpp title="lib\Backend\arm64\LegalizeMD.cpp (comment highlighted line)"
void LegalizeMD::LegalizeIndirOffset(IR::Instr * instr, IR::IndirOpnd * indirOpnd, LegalForms forms)
{
// highlight-next-line
//const bool fPostRegAlloc = instr->m_func->ShouldLegalizePostRegAlloc();
// For LEA, we have special handling of indiropnds
auto correctSize = [](IR::Instr* instr, IR::IndirOpnd* indirOpnd)#if defined(_UCRT) & & _CONTROL_FLOW_GUARD
```
After commenting the line, run the command again.
:::
After building, the generated DLL should be copied into the project folder:
```
copy .\ChakraCore\Build\VcBuild\bin\arm64_debug\ChakraCore.dll .
2023-07-06 07:21:41 +00:00
```
< / 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-08-26 23:05:59 +00:00
curl -L -O https://docs.sheetjs.com/chakra/sheetjs.ch.cpp
curl -L -O https://docs.sheetjs.com/chakra/Makefile
2023-04-09 06:58:43 +00:00
```
2023-06-05 20:12:53 +00:00
4) Build the sample application:
2023-04-09 06:58:43 +00:00
2023-08-26 23:05:59 +00:00
< Tabs groupId = "os" >
< TabItem value = "unix" label = "Linux/MacOS" >
2023-04-09 06:58:43 +00:00
```bash
make
```
2023-09-24 03:59:48 +00:00
:::caution pass
2023-06-05 20:12:53 +00:00
2024-03-16 16:04:18 +00:00
In some macOS test runs, the build failed with the message:
2023-06-05 20:12:53 +00:00
```
clang: error: no such file or directory: '/usr/local/opt/icu4c/lib/libicudata.a'
```
This was fixed by creating a symbolic link:
```bash
2023-10-20 09:35:44 +00:00
sudo mkdir -p /usr/local/opt
sudo ln -s /opt/homebrew/opt/icu4c /usr/local/opt
make
2023-06-05 20:12:53 +00:00
```
:::
2023-08-26 23:05:59 +00:00
< / TabItem >
< TabItem value = "win" label = "Windows" >
2024-07-15 01:55:09 +00:00
< Tabs groupId = "triple" >
2024-12-21 03:32:22 +00:00
< TabItem value = "win11-x64" label = "X64 Windows" >
2024-07-15 01:55:09 +00:00
2023-08-26 23:05:59 +00:00
```
cl sheetjs.ch.cpp ChakraCore.lib /I ChakraCore\lib\Jsrt /link /LIBPATH:ChakraCore\Build\VcBuild\bin\x64_debug
```
2024-07-15 01:55:09 +00:00
< / TabItem >
< TabItem value = "win11-arm" label = "ARM64 Windows" >
```
cl sheetjs.ch.cpp ChakraCore.lib /I ChakraCore\lib\Jsrt /link /LIBPATH:ChakraCore\Build\VcBuild\bin\arm64_debug
```
< / TabItem >
< / Tabs >
2023-08-26 23:05:59 +00:00
< / TabItem >
< / Tabs >
2023-09-22 06:32:55 +00:00
5) Download the SheetJS Standalone script, shim script and test file. Move all
three files to the project directory:
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 >
2024-04-26 04:16:13 +00:00
< li > < a href = "https://docs.sheetjs.com/pres.numbers" > pres.numbers< / a > < / li >
2023-04-09 06:58:43 +00:00
< / ul >
2023-05-07 13:58:36 +00:00
< CodeBlock language = "bash" > {`\
2023-08-26 23:05:59 +00:00
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
2024-04-26 04:16:13 +00:00
curl -L -O https://docs.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
2023-08-26 23:05:59 +00:00
< Tabs groupId = "os" >
< TabItem value = "unix" label = "Linux/MacOS" >
2023-08-20 20:39:35 +00:00
```bash
2023-04-09 06:58:43 +00:00
./sheetjs.ch pres.numbers
```
2023-08-26 23:05:59 +00:00
< / TabItem >
< TabItem value = "win" label = "Windows" >
```
.\sheetjs.ch.exe pres.numbers
```
< / TabItem >
< / Tabs >
2023-04-09 06:58:43 +00:00
If successful, the program will print the contents of the first sheet as CSV.
### CLI Test
2023-11-04 05:05:26 +00:00
:::note Tested Deployments
2023-04-09 06:58:43 +00:00
2024-12-18 05:47:18 +00:00
This demo was last tested on 2024-12-17 against `ch` commit `e26c81f` .
2023-04-09 06:58:43 +00:00
:::
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.
2023-10-29 03:22:50 +00:00
:::tip pass
2023-08-26 23:05:59 +00:00
The ["Integration Example" ](#integration-example ) also builds the `ch` binary!
2023-10-29 03:22:50 +00:00
It will typically be placed in the `ChakraCore/out/Test/` folder on Linux/macOS
or `ChakraCore\Build\VcBuild\bin\x64_debug\` on x64 Windows.
2023-08-26 23:05:59 +00:00
:::
2023-09-22 06:32:55 +00:00
1) Download the SheetJS Standalone script, shim script and test file. Move all
three files to the project directory:
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 >
2024-04-26 04:16:13 +00:00
< li > < a href = "https://docs.sheetjs.com/pres.numbers" > pres.numbers< / a > < / li >
2023-04-09 06:58:43 +00:00
< / ul >
2023-08-26 23:05:59 +00:00
< CodeBlock language = "bash" > {`\
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
2024-04-26 04:16:13 +00:00
curl -L -O https://docs.sheetjs.com/pres.numbers`}
2023-08-26 23:05:59 +00:00
< / CodeBlock >
2023-04-09 06:58:43 +00:00
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.
2024-07-15 01:55:09 +00:00
:::note pass
On Windows, the command should be run in WSL.
:::
2023-04-09 06:58:43 +00:00
5) Run the script using the ChakraCore standalone binary:
2024-07-15 01:55:09 +00:00
< Tabs groupId = "os" >
< TabItem value = "unix" label = "Linux/MacOS" >
2023-08-20 20:39:35 +00:00
```bash
2023-04-09 06:58:43 +00:00
./ch xlsx.chakra.js
```
2023-08-26 23:05:59 +00:00
2024-07-15 01:55:09 +00:00
< / TabItem >
< TabItem value = "win" label = "Windows" >
```bash
.\ch.exe xlsx.chakra.js
```
< / TabItem >
< / Tabs >
2023-08-26 23:05:59 +00:00
[^1]: See ["Building ChakraCore" ](https://github.com/chakra-core/ChakraCore/wiki/Building-ChakraCore#deployment ) in the ChakraCore project wiki