docs.sheetjs.com/docz/docs/03-demos/42-engines/02-v8.md

1094 lines
29 KiB
Markdown
Raw Normal View History

2023-05-21 02:11:51 +00:00
---
2023-08-26 23:05:59 +00:00
title: Blazing Fast Data Processing with V8
sidebar_label: C++ + V8
2024-05-29 05:10:39 +00:00
description: Process structured data in C++ or Rust programs. Seamlessly integrate spreadsheets by pairing V8 and SheetJS. Modernize workflows while maintaining Excel compatibility.
2023-05-21 02:11:51 +00:00
pagination_prev: demos/bigdata/index
pagination_next: solutions/input
---
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-21 02:11:51 +00:00
import CodeBlock from '@theme/CodeBlock';
2023-08-26 23:05:59 +00:00
[V8](https://v8.dev/) is an embeddable JavaScript engine written in C++. It
powers Chromium and Chrome, NodeJS and Deno, Adobe UXP and other platforms.
2023-05-21 02:11:51 +00:00
2023-08-26 23:05:59 +00:00
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
data from spreadsheets.
This demo uses V8 and SheetJS to read and write spreadsheets. We'll explore how
to load SheetJS in a V8 context and process spreadsheets and structured data from
C++ and Rust programs.
The ["Complete Example"](#complete-example) creates a C++ command-line tool for
reading spreadsheet files and generating new workbooks. ["Bindings"](#bindings)
covers V8 engine bindings for other programming languages.
2023-05-21 02:11:51 +00:00
## Integration Details
2023-08-26 23:05:59 +00:00
The [SheetJS Standalone scripts](/docs/getting-started/installation/standalone)
can be parsed and evaluated in a V8 context.
2024-05-29 05:10:39 +00:00
:::note pass
This section describes a flow where the script is parsed and evaluated every
time the program is run.
Using V8 snapshots, SheetJS libraries can be parsed and evaluated beforehand.
This greatly improves program startup time.
The ["Snapshots"](#snapshots) section includes a complete example.
:::
2024-01-29 03:29:45 +00:00
### Initialize V8
2023-05-21 02:11:51 +00:00
The official V8 `hello-world` example covers initialization and cleanup. For the
purposes of this demo, the key variables are noted below:
```cpp
v8::Isolate* isolate = v8::Isolate::New(create_params);
v8::Local<v8::Context> context = v8::Context::New(isolate);
```
The following helper function evaluates C strings as JS code:
```cpp
2023-08-26 23:05:59 +00:00
v8::Local<v8::Value> eval_code(v8::Isolate *isolate, v8::Local<v8::Context> context, char* code, size_t sz = -1) {
v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate, code, v8::NewStringType::kNormal, sz).ToLocalChecked();
v8::Local<v8::Script> script = v8::Script::Compile(context, source).ToLocalChecked();
return script->Run(context).ToLocalChecked();
2023-05-21 02:11:51 +00:00
}
```
2024-01-29 03:29:45 +00:00
### Load SheetJS Scripts
2023-05-21 02:11:51 +00:00
The main library can be loaded by reading the scripts from the file system and
evaluating in the V8 context:
```cpp
/* simple wrapper to read the entire script file */
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;
}
// ...
size_t sz; char *file = read_file("xlsx.full.min.js", &sz);
2023-08-26 23:05:59 +00:00
v8::Local<v8::Value> result = eval_code(isolate, context, file, sz);
2023-05-21 02:11:51 +00:00
```
To confirm the library is loaded, `XLSX.version` can be inspected:
```cpp
/* get version string */
v8::Local<v8::Value> result = eval_code(isolate, context, "XLSX.version");
v8::String::Utf8Value vers(isolate, result);
printf("SheetJS library version %s\n", *vers);
```
### Reading Files
V8 supports `ArrayBuffer` natively. Assuming `buf` is a C byte array, with
length `len`, this snippet stores the data as an `ArrayBuffer` in global scope:
```cpp
/* load C char array and save to an ArrayBuffer */
std::unique_ptr<v8::BackingStore> back = v8::ArrayBuffer::NewBackingStore(isolate, len);
memcpy(back->Data(), buf, len);
v8::Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, std::move(back));
v8::Maybe<bool> res = context->Global()->Set(context, v8::String::NewFromUtf8Literal(isolate, "buf"), ab);
/* parse with SheetJS */
v8::Local<v8::Value> result = eval_code(isolate, context, "globalThis.wb = XLSX.read(buf)");
```
`wb` will be a variable in the JS environment that can be inspected using the
various SheetJS API functions.
### Writing Files
The underlying memory from an `ArrayBuffer` can be recovered:
```c
/* write with SheetJS using type: "array" */
v8::Local<v8::Value> result = eval_code(isolate, context, "XLSX.write(wb, {type:'array', bookType:'xlsb'})");
/* pull result back to C++ */
v8::Local<v8::ArrayBuffer> ab = v8::Local<v8::ArrayBuffer>::Cast(result);
size_t sz = ab->ByteLength();
char *buf = ab->Data();
```
The resulting `buf` can be written to file with `fwrite`.
## Complete Example
2023-11-28 07:05:59 +00:00
:::note Tested Deployments
2023-05-21 02:11:51 +00:00
This demo was tested in the following deployments:
2023-10-12 08:39:38 +00:00
| V8 Version | Platform | OS Version | Compiler | Date |
|:--------------|:-------------|:--------------|:-----------------|:-----------|
2024-03-16 16:04:18 +00:00
| `12.4.253` | `darwin-x64` | macOS 14.4 | `clang 15.0.0` | 2024-03-15 |
2024-05-26 07:50:55 +00:00
| `12.7.130` | `darwin-arm` | macOS 14.5 | `clang 15.0.0` | 2024-05-25 |
2024-03-25 04:13:01 +00:00
| `12.5.48` | `win10-x64` | Windows 10 | `CL 19.39.33523` | 2024-03-24 |
2024-03-22 04:45:40 +00:00
| `12.5.48` | `linux-x64` | HoloOS 3.5.17 | `gcc 13.1.1` | 2024-03-21 |
2024-05-26 07:50:55 +00:00
| `12.7.130` | `linux-arm` | Debian 12 | `gcc 12.2.0` | 2024-05-25 |
2023-05-21 02:11:51 +00:00
:::
This program parses a file and prints CSV data from the first worksheet. It also
generates an XLSB file and writes to the filesystem.
2023-08-26 23:05:59 +00:00
:::caution pass
2023-05-21 02:11:51 +00:00
2023-06-03 09:10:50 +00:00
When the demo was last tested, there were errors in the official V8 embed guide.
The correct instructions are included below.
2023-05-21 02:11:51 +00:00
:::
2023-08-26 23:05:59 +00:00
:::caution pass
2023-05-21 02:11:51 +00:00
The build process is long and will test your patience.
:::
### Preparation
2023-08-26 23:05:59 +00:00
<Tabs groupId="os">
<TabItem value="unix" label="Linux/MacOS">
2023-06-05 20:12:53 +00:00
0) Prepare `/usr/local/lib`:
2023-05-21 02:11:51 +00:00
```bash
mkdir -p /usr/local/lib
cd /usr/local/lib
2023-06-05 20:12:53 +00:00
```
2023-12-02 08:39:35 +00:00
:::note pass
2023-06-05 20:12:53 +00:00
2024-05-26 07:50:55 +00:00
If this step throws a permission error, run the following commands:
2023-06-05 20:12:53 +00:00
```bash
sudo mkdir -p /usr/local/lib
sudo chmod 777 /usr/local/lib
```
:::
2023-08-26 23:05:59 +00:00
</TabItem>
<TabItem value="win" label="Windows">
0) Follow the official ["Visual Studio"](https://chromium.googlesource.com/chromium/src/+/master/docs/windows_build_instructions.md#visual-studio)
installation steps.
:::info pass
Using the installer tool, the "Desktop development with C++" workload must be
installed. In the sidebar, verify the following components are checked:
- "C++ ATL for latest ... build tools" (`v143` when last tested)
- "C++ MFC for latest ... build tools" (`v143` when last tested)
In the "Individual components" tab, search for "Windows 11 SDK" and verify that
"Windows 11 SDK (10.0.22621.0)" is checked.
Click "Modify" and allow the installer to finish.
The SDK debugging tools must be installed after the SDK is installed.
1) Using the Search bar, search "Apps & features".
2) When the setting panel opens, scroll down to "Windows Software Development
Kit - Windows 10.0.22621 and click "Modify".
3) In the new window, select "Change" and click "Next"
4) Check "Debugging Tools for Windows" and click "Change"
:::
The following `git` settings should be changed:
```bash
git config --global core.autocrlf false
git config --global core.filemode false
git config --global branch.autosetuprebase always
```
</TabItem>
</Tabs>
2023-06-05 20:12:53 +00:00
1) Download and install `depot_tools`:
2023-08-26 23:05:59 +00:00
<Tabs groupId="os">
<TabItem value="unix" label="Linux/MacOS">
2023-06-05 20:12:53 +00:00
```bash
2023-05-21 02:11:51 +00:00
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
```
2023-12-02 08:39:35 +00:00
:::note pass
2024-05-26 07:50:55 +00:00
If this step throws a permission error, run the following commands and retry:
2023-12-02 08:39:35 +00:00
```bash
sudo mkdir -p /usr/local/lib
sudo chmod 777 /usr/local/lib
```
:::
2023-08-26 23:05:59 +00:00
</TabItem>
<TabItem value="win" label="Windows">
[The bundle](https://storage.googleapis.com/chrome-infra/depot_tools.zip) is a
ZIP file that should be downloaded and extracted.
The demo was last tested on an exFAT-formatted drive (mounted at `E:\`).
After extracting, verify that the `depot_tools` folder is not read-only.
</TabItem>
</Tabs>
2023-05-21 02:11:51 +00:00
2) Add the path to the `PATH` environment variable:
2023-08-26 23:05:59 +00:00
<Tabs groupId="os">
<TabItem value="unix" label="Linux/MacOS">
2023-05-21 02:11:51 +00:00
```bash
export PATH="/usr/local/lib/depot_tools:$PATH"
```
At this point, it is strongly recommended to add the line to a shell startup
script such as `.bashrc` or `.zshrc`
2023-08-26 23:05:59 +00:00
</TabItem>
<TabItem value="win" label="Windows">
:::caution pass
These instructions are for `cmd` use. Do not run in PowerShell!
It is strongly recommended to use the "Developer Command Prompt" from Visual
Studio as it prepares the console to run build tools.
:::
```bash
set DEPOT_TOOLS_WIN_TOOLCHAIN=0
set PATH=E:\depot_tools;%PATH%
```
In addition, the `vs2022_install` variable must be set to the Visual Studio
folder. For example, using the "Community Edition", the assignment should be
```bash
set vs2022_install="C:\Program Files\Microsoft Visual Studio\2022\Community"
```
These environment variables can be persisted in the Control Panel.
</TabItem>
</Tabs>
2023-05-21 02:11:51 +00:00
3) Run `gclient` once to update `depot_tools`:
2023-08-26 23:05:59 +00:00
<Tabs groupId="os">
<TabItem value="unix" label="Linux/MacOS">
2023-05-21 02:11:51 +00:00
```bash
gclient
```
2023-08-26 23:05:59 +00:00
</TabItem>
<TabItem value="win" label="Windows">
```bash
gclient
```
:::caution pass
`gclient` may throw errors related to `git` and permissions issues:
```
fatal: detected dubious ownership in repository at 'E:/depot_tools'
'E:/depot_tools' is on a file system that doesnot record ownership
To add an exception for this directory, call:
git config --global --add safe.directory E:/depot_tools
```
These issues are related to the exFAT file system. They were resolved by running
the recommended commands and re-running `gclient`.
:::
:::caution pass
There were errors pertaining to `gitconfig`:
```
error: could not write config file E:/depot_tools/bootstrap-2@3_8_10_chromium_26_bin/git/etc/gitconfig: File exists
```
This can happen if the `depot_tools` folder is read-only. The workaround is to
unset the read-only flag for the `E:\depot_tools` folder.
:::
</TabItem>
</Tabs>
2023-05-21 02:11:51 +00:00
### Clone V8
4) Create a base directory:
2023-08-26 23:05:59 +00:00
<Tabs groupId="os">
<TabItem value="unix" label="Linux/MacOS">
2023-05-21 02:11:51 +00:00
```bash
mkdir -p ~/dev/v8
cd ~/dev/v8
fetch v8
cd v8
```
Note that the actual repo will be placed in `~/dev/v8/v8`.
2023-08-26 23:05:59 +00:00
</TabItem>
<TabItem value="win" label="Windows">
```bash
cd E:\
mkdir v8
cd v8
fetch v8
cd v8
```
:::caution pass
On exFAT, every cloned repo elicited the same `git` permissions error. `fetch`
will fail with a clear remedy message such as
```
git config --global --add safe.directory E:/v8/v8
```
Run the command then run `gclient sync`, repeating each time the command fails.
:::
:::caution pass
There were occasional `git` conflict errors:
```
v8/tools/clang (ERROR)
----------------------------------------
[0:00:01] Started.
...
error: Your local changes to the following files would be overwritten by checkout:
plugins/FindBadRawPtrPatterns.cpp
...
Please commit your changes or stash them before you switch branches.
Aborting
error: could not detach HEAD
----------------------------------------
Error: 28> Unrecognized error, please merge or rebase manually.
28> cd E:\v8\v8\tools\clang && git rebase --onto 65ceb79efbc9d1dec9b1a0f4bc0b8d010b9d7a66 refs/remotes/origin/main
```
The recommended fix is to delete the referenced folder and re-run `gclient sync`
:::
</TabItem>
</Tabs>
2024-05-26 07:50:55 +00:00
5) Checkout the desired version. The following command pulls `12.7.130`:
2023-08-26 23:05:59 +00:00
```bash
2024-05-26 07:50:55 +00:00
git checkout tags/12.7.130 -b sample
2023-08-26 23:05:59 +00:00
```
:::caution pass
The official documentation recommends:
2023-05-21 02:11:51 +00:00
```bash
2024-05-26 07:50:55 +00:00
git checkout refs/tags/12.7.130 -b sample -t
2023-05-21 02:11:51 +00:00
```
2023-08-26 23:05:59 +00:00
This command failed in local testing:
```
2024-05-26 07:50:55 +00:00
E:\v8\v8>git checkout refs/tags/12.7.130 -b sample -t
fatal: cannot set up tracking information; starting point 'refs/tags/12.7.130' is not a branch
2023-08-26 23:05:59 +00:00
```
:::
2023-05-21 02:11:51 +00:00
### Build V8
6) Build the static library.
2023-06-05 20:12:53 +00:00
<Tabs groupId="triple">
2023-09-27 04:43:00 +00:00
<TabItem value="darwin-x64" label="Intel Mac">
2023-06-05 20:12:53 +00:00
2023-05-21 02:11:51 +00:00
```bash
tools/dev/v8gen.py x64.release.sample
ninja -C out.gn/x64.release.sample v8_monolith
```
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
```bash
tools/dev/v8gen.py arm64.release.sample
ninja -C out.gn/arm64.release.sample v8_monolith
2023-09-27 04:43:00 +00:00
```
</TabItem>
<TabItem value="linux-x64" label="Linux x64">
```bash
tools/dev/v8gen.py x64.release.sample
ninja -C out.gn/x64.release.sample v8_monolith
```
2023-11-28 07:05:59 +00:00
:::note pass
2023-10-12 08:39:38 +00:00
2023-11-28 07:05:59 +00:00
In some Linux x64 tests using GCC 12, there were build errors that stemmed from
warnings. The error messages included the tag `-Werror`:
2023-10-12 08:39:38 +00:00
```
../../src/compiler/turboshaft/wasm-gc-type-reducer.cc:212:18: error: 'back_insert_iterator' may not intend to support class template argument deduction [-Werror,-Wctad-maybe-unsupported]
212 | std::back_insert_iterator(snapshots), [this](Block* pred) {
| ^
../../build/linux/debian_bullseye_amd64-sysroot/usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/stl_iterator.h:596:11: note: add a deduction guide to suppress this warning
596 | class back_insert_iterator
| ^
1 error generated.
```
2024-01-29 03:29:45 +00:00
This was resolved by manually editing `out.gn/x64.release.sample/args.gn`. The
option `treat_warnings_as_errors` should be set to `false`:
2023-10-12 08:39:38 +00:00
```ninja title="out.gn/x64.release.sample/args.gn (add to file)"
treat_warnings_as_errors = false
```
:::
2023-09-27 04:43:00 +00:00
</TabItem>
<TabItem value="linux-arm" label="Linux ARM">
```bash
tools/dev/v8gen.py arm64.release.sample
```
2023-12-02 08:39:35 +00:00
Append the following lines to `out.gn/arm64.release.sample/args.gn`:
2023-09-27 04:43:00 +00:00
```text title="out.gn/arm64.release.sample/args.gn (add to file)"
is_clang = false
2023-12-02 08:39:35 +00:00
treat_warnings_as_errors = false
2023-09-27 04:43:00 +00:00
```
Run the build:
```bash
ninja -C out.gn/arm64.release.sample v8_monolith
2023-06-05 20:12:53 +00:00
```
2024-05-26 07:50:55 +00:00
:::caution pass
When this demo was last tested, an assertion failed:
```
../../src/base/small-vector.h: In instantiation of class v8::base::SmallVector<std::pair<const v8::internal::compiler::turboshaft::PhiOp*, const v8::internal::compiler::turboshaft::OpIndex>, 16>:
../../src/compiler/turboshaft/loop-unrolling-reducer.h:577:11: required from here
../../src/base/macros.h:215:55: error: static assertion failed: T should be trivially copyable
215 | static_assert(::v8::base::is_trivially_copyable<T>::value, \
| ^~~~~
../../src/base/small-vector.h:25:3: note: in expansion of macro ASSERT_TRIVIALLY_COPYABLE
25 | ASSERT_TRIVIALLY_COPYABLE(T);
| ^~~~~~~~~~~~~~~~~~~~~~~~~
```
The build passed after disabling the assertions:
```cpp title="src/base/small-vector.h (edit highlighted lines)"
class SmallVector {
// Currently only support trivially copyable and trivially destructible data
// types, as it uses memcpy to copy elements and never calls destructors.
// highlight-start
//ASSERT_TRIVIALLY_COPYABLE(T);
//static_assert(std::is_trivially_destructible<T>::value);
// highlight-end
public:
static constexpr size_t kInlineSize = kSize;
```
:::
2023-08-26 23:05:59 +00:00
</TabItem>
<TabItem value="win10-x64" label="Windows">
```bash
python3 tools\dev\v8gen.py -vv x64.release.sample
ninja -C out.gn\x64.release.sample v8_monolith
```
:::caution pass
In local testing, the build sometimes failed with a `dbghelp.dll` error:
```
Exception: dbghelp.dll not found in "C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\dbghelp.dll"
```
This issue was fixed by removing and reinstalling "Debugging Tools for Windows"
from the Control Panel as described in step 0.
:::
:::caution pass
In local testing, the `ninja` build failed with C++ deprecation errors:
```c++
2023-10-29 03:22:50 +00:00
../..\src/wasm/wasm-code-manager.h(670,28): error: 'atomic_load<v8::base::OwnedVector<const unsigned char>>' is deprecated: warning STL4029: std::atomic_*() overloads for shared_ptr are deprecated in C++20. The shared_ptr specialization of std::atomic provides superior functionality. You can define _SILENCE_CXX20_OLD_SHARED_PTR_ATOMIC_SUPPORT_DEPRECATION_WARNING or _SILENCE_ALL_CXX20_DEPRECATION_WARNINGS to suppress this warning. [-Werror,-Wdeprecated-declarations]
670 | auto wire_bytes = std::atomic_load(&wire_bytes_);
2023-08-26 23:05:59 +00:00
| ^
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.37.32822\include\memory(3794,1): note: 'atomic_load<v8::base::OwnedVector<const unsigned char>>' has been explicitly marked deprecated here
3794 | _CXX20_DEPRECATE_OLD_SHARED_PTR_ATOMIC_SUPPORT _NODISCARD shared_ptr<_Ty> atomic_load(
| ^
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.37.32822\include\yvals_core.h(1317,7): note: expanded from macro '_CXX20_DEPRECATE_OLD_SHARED_PTR_ATOMIC_SUPPORT'
1317 | [[deprecated("warning STL4029: " \
| ^
2 errors generated.
```
The workaround is to append a line to `out.gn\x64.release.sample\args.gn`:
```text title="out.gn\x64.release.sample\args.gn (add to end)"
treat_warnings_as_errors = false
```
2023-10-29 03:22:50 +00:00
After adding the line, run the `ninja` command again:
```bash
ninja -C out.gn\x64.release.sample v8_monolith
```
2023-08-26 23:05:59 +00:00
:::
2023-06-05 20:12:53 +00:00
</TabItem>
</Tabs>
2023-05-21 02:11:51 +00:00
7) Ensure the sample `hello-world` compiles and runs:
2023-06-05 20:12:53 +00:00
<Tabs groupId="triple">
2023-09-27 04:43:00 +00:00
<TabItem value="darwin-x64" label="Intel Mac">
2023-06-05 20:12:53 +00:00
2023-05-21 02:11:51 +00:00
```bash
g++ -I. -Iinclude samples/hello-world.cc -o hello_world -fno-rtti -lv8_monolith \
2024-03-16 16:04:18 +00:00
-ldl -Lout.gn/x64.release.sample/obj/ -pthread \
2023-05-21 02:11:51 +00:00
-std=c++17 -DV8_COMPRESS_POINTERS=1 -DV8_ENABLE_SANDBOX
./hello_world
```
2024-03-16 16:04:18 +00:00
:::info pass
In older V8 versions, the flags `-lv8_libbase -lv8_libplatform` were required.
Linking against `libv8_libbase` or `libv8_libplatform` in V8 version `12.4.253`
elicited linker errors:
```
ld: multiple errors: unknown file type in '/Users/test/dev/v8/v8/out.gn/x64.release.sample/obj/libv8_libplatform.a'; unknown file type in '/Users/test/dev/v8/v8/out.gn/x64.release.sample/obj/libv8_libbase.a'
```
:::
2023-06-05 20:12:53 +00:00
</TabItem>
2023-09-27 04:43:00 +00:00
<TabItem value="darwin-arm" label="ARM64 Mac">
```bash
g++ -I. -Iinclude samples/hello-world.cc -o hello_world -fno-rtti -lv8_monolith \
2024-05-26 07:50:55 +00:00
-ldl -Lout.gn/arm64.release.sample/obj/ -pthread \
2023-09-27 04:43:00 +00:00
-std=c++17 -DV8_COMPRESS_POINTERS=1 -DV8_ENABLE_SANDBOX
./hello_world
```
2024-05-26 07:50:55 +00:00
:::info pass
In older V8 versions, the flags `-lv8_libbase -lv8_libplatform` were required.
Linking against `libv8_libbase` or `libv8_libplatform` in V8 version `12.4.253`
elicited linker errors:
```
ld: multiple errors: unknown file type in '/Users/test/dev/v8/v8/out.gn/x64.release.sample/obj/libv8_libplatform.a'; unknown file type in '/Users/test/dev/v8/v8/out.gn/x64.release.sample/obj/libv8_libbase.a'
```
:::
2023-09-27 04:43:00 +00:00
</TabItem>
<TabItem value="linux-x64" label="Linux x64">
```bash
g++ -I. -Iinclude samples/hello-world.cc -o hello_world -fno-rtti -lv8_monolith \
-lv8_libbase -lv8_libplatform -ldl -Lout.gn/x64.release.sample/obj/ -pthread \
-std=c++17 -DV8_COMPRESS_POINTERS=1 -DV8_ENABLE_SANDBOX
./hello_world
```
</TabItem>
<TabItem value="linux-arm" label="Linux ARM">
2023-06-05 20:12:53 +00:00
```bash
g++ -I. -Iinclude samples/hello-world.cc -o hello_world -fno-rtti -lv8_monolith \
-lv8_libbase -lv8_libplatform -ldl -Lout.gn/arm64.release.sample/obj/ -pthread \
-std=c++17 -DV8_COMPRESS_POINTERS=1 -DV8_ENABLE_SANDBOX
./hello_world
2023-08-26 23:05:59 +00:00
```
</TabItem>
<TabItem value="win10-x64" label="Windows">
```bash
cl /I. /Iinclude samples/hello-world.cc /GR- v8_monolith.lib Advapi32.lib Winmm.lib Dbghelp.lib /std:c++17 /DV8_COMPRESS_POINTERS=1 /DV8_ENABLE_SANDBOX /link /out:hello_world.exe /LIBPATH:out.gn\x64.release.sample\obj\
.\hello_world.exe
2023-06-05 20:12:53 +00:00
```
</TabItem>
</Tabs>
2023-05-21 02:11:51 +00:00
### Prepare Project
8) Make a new project folder:
2023-08-26 23:05:59 +00:00
<Tabs groupId="os">
<TabItem value="unix" label="Linux/MacOS">
2023-05-21 02:11:51 +00:00
```bash
cd ~/dev
2023-08-26 23:05:59 +00:00
mkdir -p sheetjs-v8
cd sheetjs-v8
```
</TabItem>
<TabItem value="win" label="Windows">
```bash
cd E:\
2023-05-21 02:11:51 +00:00
mkdir sheetjs-v8
cd sheetjs-v8
```
2023-08-26 23:05:59 +00:00
</TabItem>
</Tabs>
2023-05-21 02:11:51 +00:00
9) Copy the sample source:
2023-08-26 23:05:59 +00:00
<Tabs groupId="os">
<TabItem value="unix" label="Linux/MacOS">
2023-05-21 02:11:51 +00:00
```bash
cp ~/dev/v8/v8/samples/hello-world.cc .
```
10) Create symbolic links to the `include` headers and `obj` library folders:
2023-06-05 20:12:53 +00:00
<Tabs groupId="triple">
2023-09-27 04:43:00 +00:00
<TabItem value="darwin-x64" label="Intel Mac">
```bash
ln -s ~/dev/v8/v8/include
ln -s ~/dev/v8/v8/out.gn/x64.release.sample/obj
```
</TabItem>
<TabItem value="darwin-arm" label="ARM64 Mac">
```bash
ln -s ~/dev/v8/v8/include
ln -s ~/dev/v8/v8/out.gn/arm64.release.sample/obj
```
</TabItem>
<TabItem value="linux-x64" label="Linux x64">
2023-06-05 20:12:53 +00:00
2023-05-21 02:11:51 +00:00
```bash
ln -s ~/dev/v8/v8/include
ln -s ~/dev/v8/v8/out.gn/x64.release.sample/obj
```
2023-06-05 20:12:53 +00:00
</TabItem>
2023-09-27 04:43:00 +00:00
<TabItem value="linux-arm" label="Linux ARM">
2023-06-05 20:12:53 +00:00
```bash
ln -s ~/dev/v8/v8/include
ln -s ~/dev/v8/v8/out.gn/arm64.release.sample/obj
```
</TabItem>
</Tabs>
2023-08-26 23:05:59 +00:00
</TabItem>
<TabItem value="win" label="Windows">
```bash
copy E:\v8\v8\samples\hello-world.cc .\
```
10) Observe that exFAT does not support symbolic links and move on to step 11.
</TabItem>
</Tabs>
2023-05-21 02:11:51 +00:00
11) Build and run the `hello-world` example from this folder:
2023-08-26 23:05:59 +00:00
<Tabs groupId="os">
<TabItem value="unix" label="Linux/MacOS">
2023-05-21 02:11:51 +00:00
```bash
g++ -I. -Iinclude hello-world.cc -o hello_world -fno-rtti -lv8_monolith \
-lv8_libbase -lv8_libplatform -ldl -Lobj/ -pthread -std=c++17 \
-DV8_COMPRESS_POINTERS=1 -DV8_ENABLE_SANDBOX
./hello_world
```
2024-03-16 16:04:18 +00:00
:::caution pass
In some V8 versions, the command failed in the linker stage:
```
ld: multiple errors: unknown file type in '/Users/test/dev/v8/v8/out.gn/x64.release.sample/obj/libv8_libplatform.a'; unknown file type in '/Users/test/dev/v8/v8/out.gn/x64.release.sample/obj/libv8_libbase.a'
```
The build succeeds after removing `libv8_libbase` and `libv8_libplatform`:
```bash
g++ -I. -Iinclude hello-world.cc -o hello_world -fno-rtti -lv8_monolith \
-ldl -Lobj/ -pthread -std=c++17 \
-DV8_COMPRESS_POINTERS=1 -DV8_ENABLE_SANDBOX
./hello_world
```
:::
2023-08-26 23:05:59 +00:00
</TabItem>
<TabItem value="win" label="Windows">
```bash
cl /MT /I..\v8\v8\ /I..\v8\v8\include hello-world.cc /GR- v8_monolith.lib Advapi32.lib Winmm.lib Dbghelp.lib /std:c++17 /DV8_COMPRESS_POINTERS=1 /DV8_ENABLE_SANDBOX /link /out:hello_world.exe /LIBPATH:..\v8\v8\out.gn\x64.release.sample\obj\
.\hello_world.exe
```
</TabItem>
</Tabs>
2023-05-21 02:11:51 +00:00
### Add SheetJS
2023-09-22 06:32:55 +00:00
12) Download the SheetJS Standalone script and test file. Save both files in
the project directory:
2023-05-21 02:11:51 +00:00
<ul>
<li><a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`}>xlsx.full.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-05-21 02:11:51 +00:00
</ul>
<CodeBlock language="bash">{`\
curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js
2024-04-26 04:16:13 +00:00
curl -LO https://docs.sheetjs.com/pres.numbers`}
2023-05-21 02:11:51 +00:00
</CodeBlock>
13) Download [`sheetjs.v8.cc`](pathname:///v8/sheetjs.v8.cc):
```bash
curl -LO https://docs.sheetjs.com/v8/sheetjs.v8.cc
```
14) Compile standalone `sheetjs.v8` binary
2023-08-26 23:05:59 +00:00
<Tabs groupId="os">
<TabItem value="unix" label="Linux/MacOS">
2023-05-21 02:11:51 +00:00
```bash
g++ -I. -Iinclude sheetjs.v8.cc -o sheetjs.v8 -fno-rtti -lv8_monolith \
-lv8_libbase -lv8_libplatform -ldl -Lobj/ -pthread -std=c++17 \
-DV8_COMPRESS_POINTERS=1 -DV8_ENABLE_SANDBOX
```
2024-03-16 16:04:18 +00:00
:::caution pass
In some V8 versions, the command failed in the linker stage:
```
ld: multiple errors: unknown file type in '/Users/test/dev/v8/v8/out.gn/x64.release.sample/obj/libv8_libplatform.a'; unknown file type in '/Users/test/dev/v8/v8/out.gn/x64.release.sample/obj/libv8_libbase.a'
```
The build succeeds after removing `libv8_libbase` and `libv8_libplatform`:
```bash
g++ -I. -Iinclude sheetjs.v8.cc -o sheetjs.v8 -fno-rtti -lv8_monolith \
-ldl -Lobj/ -pthread -std=c++17 \
-DV8_COMPRESS_POINTERS=1 -DV8_ENABLE_SANDBOX
```
:::
2023-08-26 23:05:59 +00:00
</TabItem>
<TabItem value="win" label="Windows">
```bash
cl /MT /I..\v8\v8\ /I..\v8\v8\include sheetjs.v8.cc /GR- v8_monolith.lib Advapi32.lib Winmm.lib Dbghelp.lib /std:c++17 /DV8_COMPRESS_POINTERS=1 /DV8_ENABLE_SANDBOX /link /out:sheetjs.v8.exe /LIBPATH:..\v8\v8\out.gn\x64.release.sample\obj\
```
</TabItem>
</Tabs>
2023-05-21 02:11:51 +00:00
15) Run the demo:
2023-08-26 23:05:59 +00:00
<Tabs groupId="os">
<TabItem value="unix" label="Linux/MacOS">
2023-05-21 02:11:51 +00:00
```bash
./sheetjs.v8 pres.numbers
```
2023-08-26 23:05:59 +00:00
</TabItem>
<TabItem value="win" label="Windows">
```bash
2023-09-05 18:04:23 +00:00
.\sheetjs.v8.exe pres.numbers
2023-08-26 23:05:59 +00:00
```
</TabItem>
</Tabs>
2023-05-21 02:11:51 +00:00
If the program succeeded, the CSV contents will be printed to console and the
file `sheetjsw.xlsb` will be created. That file can be opened with Excel.
2023-05-22 08:06:09 +00:00
## Bindings
2023-05-26 22:50:23 +00:00
Bindings exist for many languages. As these bindings require "native" code, they
may not work on every platform.
2023-05-22 08:06:09 +00:00
### Rust
The `v8` crate provides binary builds and straightforward bindings. The Rust
code is similar to the C++ code.
Pulling data from an `ArrayBuffer` back into Rust involves an unsafe operation:
```rust
/* assuming JS code returns an ArrayBuffer, copy result to a Vec<u8> */
fn eval_code_ab(scope: &mut v8::HandleScope, code: &str) -> Vec<u8> {
2024-05-29 05:10:39 +00:00
let source = v8::String::new(scope, code).unwrap();
2023-05-22 08:06:09 +00:00
let script = v8::Script::compile(scope, source, None).unwrap();
let result: v8::Local<v8::ArrayBuffer> = script.run(scope).unwrap().try_into().unwrap();
/* In C++, `Data` returns a pointer. Collecting data into Vec<u8> is unsafe */
unsafe { return std::slice::from_raw_parts_mut(
result.data().unwrap().cast::<u8>().as_ptr(),
result.byte_length()
).to_vec(); }
}
```
2023-11-28 07:05:59 +00:00
:::note Tested Deployments
2023-05-22 08:06:09 +00:00
2023-05-25 01:36:15 +00:00
This demo was last tested in the following deployments:
| Architecture | V8 Crate | Date |
|:-------------|:---------|:-----------|
2024-05-29 05:10:39 +00:00
| `darwin-x64` | `0.92.0` | 2024-05-28 |
2024-05-26 07:50:55 +00:00
| `darwin-arm` | `0.92.0` | 2024-05-25 |
2024-03-25 04:13:01 +00:00
| `win10-x64` | `0.89.0` | 2024-03-24 |
2024-04-26 04:16:13 +00:00
| `linux-x64` | `0.91.0` | 2024-04-25 |
2024-05-26 07:50:55 +00:00
| `linux-arm` | `0.92.0` | 2024-05-25 |
2023-05-25 01:36:15 +00:00
2023-05-22 08:06:09 +00:00
:::
1) Create a new project:
```bash
cargo new sheetjs-rustyv8
cd sheetjs-rustyv8
cargo run
```
2) Add the `v8` crate:
```bash
cargo add v8
cargo run
```
2024-04-26 04:16:13 +00:00
3) Download the SheetJS Standalone script and test file. Save both files in the
project directory:
2023-09-22 06:32:55 +00:00
<ul>
<li><a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`}>xlsx.full.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-09-22 06:32:55 +00:00
</ul>
2023-05-22 08:06:09 +00:00
<CodeBlock language="bash">{`\
2024-04-26 04:16:13 +00:00
curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js
curl -LO https://docs.sheetjs.com/pres.numbers`}
2023-05-22 08:06:09 +00:00
</CodeBlock>
4) Download [`main.rs`](pathname:///v8/main.rs) and replace `src/main.rs`:
```bash
curl -L -o src/main.rs https://docs.sheetjs.com/v8/main.rs
```
2024-04-26 04:16:13 +00:00
5) Build and run the app:
2023-05-22 08:06:09 +00:00
```bash
cargo run pres.numbers
```
If the program succeeded, the CSV contents will be printed to console and the
file `sheetjsw.xlsb` will be created. That file can be opened with Excel.
2024-05-29 05:10:39 +00:00
## Snapshots
At a high level, V8 snapshots are raw dumps of the V8 engine state. It is much
more efficient for programs to load snapshots than to evaluate code.
### Snapshot Demo
There are two parts to this demo:
A) The [`snapshot`](pathname:///cli/snapshot.rs) command creates a snapshot with
the [SheetJS standalone script](/docs/getting-started/installation/standalone)
and [supplementary NUMBERS script](/docs/api/write-options#writing-options). It
will dump the snapshot to `snapshot.bin`
B) The [`sheet2csv`](pathname:///cli/sheet2csv.rs) tool embeds `snapshot.bin`.
The tool will parse a specified file, print CSV contents of a named worksheet,
and export the workbook to NUMBERS.
:::note Tested Deployments
This demo was last tested in the following deployments:
| Architecture | V8 Version | Crate | Date |
|:-------------|:--------------|:---------|:-----------|
| `darwin-x64` | `12.6.228.3` | `0.92.0` | 2024-05-28 |
| `darwin-arm` | `12.6.228.3` | `0.92.0` | 2024-05-23 |
| `win10-x64` | `12.3.219.9` | `0.88.0` | 2024-03-24 |
| `win11-x64` | `12.6.228.3` | `0.92.0` | 2024-05-23 |
| `linux-x64` | `12.3.219.9` | `0.88.0` | 2024-03-18 |
| `linux-arm` | `12.6.228.3` | `0.92.0` | 2024-05-26 |
:::
0) Make a new folder for the project:
```bash
mkdir sheetjs2csv
cd sheetjs2csv
```
1) Download the following scripts:
- [`Cargo.toml`](pathname:///cli/Cargo.toml)
- [`snapshot.rs`](pathname:///cli/snapshot.rs)
- [`sheet2csv.rs`](pathname:///cli/sheet2csv.rs)
```bash
curl -o Cargo.toml https://docs.sheetjs.com/cli/Cargo.toml
curl -o snapshot.rs https://docs.sheetjs.com/cli/snapshot.rs
curl -o sheet2csv.rs https://docs.sheetjs.com/cli/sheet2csv.rs
```
2) Download the SheetJS Standalone script and NUMBERS supplementary script. Move
both scripts to the project directory:
<ul>
<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/xlsx.zahl.js`}>xlsx.zahl.js</a></li>
</ul>
<CodeBlock language="bash">{`\
curl -o xlsx.full.min.js https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js
curl -o xlsx.zahl.js https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.zahl.js`}
</CodeBlock>
3) Build the V8 snapshot:
```bash
cargo build --bin snapshot
cargo run --bin snapshot
```
:::caution pass
In some tests, the Linux AArch64 build failed with an error:
```
error[E0080]: evaluation of constant value failed
|
1715 | assert!(size_of::<TypeId>() == size_of::<u64>());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: size_of::<TypeId>() == size_of::<u64>()'
```
Versions `0.75.1`, `0.82.0`, and `0.92.0` are known to work.
:::
4) Build `sheet2csv` (`sheet2csv.exe` in Windows):
```bash
cargo build --release --bin sheet2csv
```
5) Download the test file https://docs.sheetjs.com/pres.numbers:
```bash
curl -o pres.numbers https://docs.sheetjs.com/pres.numbers
```
6) Test the application:
<Tabs groupId="os">
<TabItem value="unix" label="Linux/MacOS">
```bash
mv target/release/sheet2csv .
./sheet2csv pres.numbers
```
</TabItem>
<TabItem value="win" label="Windows">
```bash
mv target/release/sheet2csv.exe .
.\sheet2csv.exe pres.numbers
```
</TabItem>
</Tabs>