hermes-windows-x64

This commit is contained in:
SheetJS 2023-09-28 13:13:57 -04:00
parent 06e7413d36
commit 2c60a9483f
3 changed files with 304 additions and 3 deletions

@ -135,6 +135,30 @@ static char *read_file(const char *filename, size_t *sz) {
size_t sz; char *xlsx_full_min_js = read_file("xlsx.full.min.js", &sz);
```
:::caution pass
For Windows applications, the string must be null-terminated:
```cpp
/* Hermes-Windows requires the null terminator */
static char *read_file_null(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) + 1; fseek(f, 0, SEEK_SET); }
char *buf = (char *)malloc(fsize * sizeof(char));
*sz = fread((void *) buf, 1, fsize, f);
buf[fsize - 1] = 0;
fclose(f);
return buf;
}
// ...
/* read SheetJS library from filesystem */
size_t sz; char *xlsx_full_min_js = read_file_null("xlsx.full.min.js", &sz);
```
:::
_Hermes Wrapper_
Hermes does not provide a friendly way to prepare JavaScript code stored in a
@ -343,13 +367,20 @@ This demo was tested in the following deployments:
| `linux-x64` | `49e1930` | 2023-09-22 |
| `linux-arm` | `70af78b` | 2023-08-27 |
The main Hermes source tree does not have Windows support. The `hermes-windows`
fork, which powers React Native for Windows, does have built-in support[^5]
| Architecture | Git Commit | Date |
|:-------------|:-----------|:-----------|
| `win10-x64` | `c7a4a82` | 2023-09-27 |
:::
0) Install [dependencies](https://hermesengine.dev/docs/building-and-running/#dependencies)
<details><summary><b>Installation Notes</b> (click to show)</summary>
The official guidance[^5] has been verified in macOS and HoloOS (Linux).
The official guidance[^6] has been verified in macOS and HoloOS (Linux).
On macOS:
@ -424,6 +455,158 @@ curl -LO https://sheetjs.com/pres.numbers`}
If successful, the program will print the library version number and the
contents of the first sheet as CSV rows.
### Windows Example
0) Install dependencies.
<details><summary><b>Installation Notes</b> (click to show)</summary>
CMake and Visual Studio with "Desktop development with C++" workload must be
installed. In addition, the following Spectre-mitigated libs must be added:
- MSVC C++ Spectre-mitigated libs (Latest)
- C++ ATL for latest build tools with Spectre Mitigations
- C++ MFC for latest build tools with Spectre Mitigations
The easiest way to install is to select "Individual components" and search for
"spectre latest" (no quotation marks). Pick each option for the relevant CPU.
</details>
1) Set up `depot_tools`.
[`depot_tools.zip`](https://storage.googleapis.com/chrome-infra/depot_tools.zip)
must be downloaded and extracted to `c:\src\depot_tools\`.
:::note pass
This ZIP has a number of hidden files and folders (including `.git`) which
should be extracted along with the normal files.
:::
Add the path `c:\src\depot_tools\` to the User `PATH` environment variable
<details><summary><b>Environment Variable Setup</b> (click to show)</summary>
Type `env` in the search bar and select "Edit the system environment variables".
In the new window, click the "Environment Variables..." button.
In the new window, look for the "User variables" section. Select "Path" in the
list and click "Edit".
In the new window, click "New" and type `c:\src\depot_tools` and press Enter.
Select the row and repeatedly click "Move Up" until it is the first entry.
Click "OK" in each window (3 windows) and restart your computer.
</details>
2) Delete `c:\src\depot_tools\ninja` if it exists, then download the
[official Windows release](https://github.com/ninja-build/ninja/releases/download/v1.11.1/ninja-win.zip)
and move the `ninja.exe` into `c:\src\depot_tools`. If a `ninja.exe` exists in
the folder, replace the existing program.
3) Make a project directory:
```bash
mkdir sheetjs-hermes
cd sheetjs-hermes
```
4) Clone the `hermes-windows` repo:
```bash
git clone https://github.com/microsoft/hermes-windows
cd hermes-windows
git checkout c7a4a82
cd ..
```
:::note pass
If there are errors related to SSL or certificates or `CApath`, temporarily
disable SSL in Git:
```bash
git config --global http.sslVerify false
git clone https://github.com/microsoft/hermes-windows
git config --global http.sslVerify true
```
:::
5) Build the library:
```bash
cd hermes-windows
.\.ado\scripts\cibuild.ps1 -AppPlatform win32 -Platform x64 -ToolsPlatform x64
cd ..
```
:::note pass
The script may fail with the message:
> cannot be loaded because running scripts is disabled on this system
In a "Run as Administrator" powershell window, run the following command:
```
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned
```
:::
6) Copy every generated `.lib` and `.dll` file into the main folder:
```powershell
dir -r -Path .\hermes-windows\workspace\build\win32-x64-debug\ -Filter "*.dll" | Copy-Item -Destination .\
dir -r -Path .\hermes-windows\workspace\build\win32-x64-debug\ -Filter "*.lib" | Copy-Item -Destination .\
```
7) Download [`sheetjs-hermes.cpp`](pathname:///hermes/sheetjs-hermesw.cpp):
```bash
curl -LO https://docs.sheetjs.com/hermes/sheetjs-hermesw.cpp
```
8) Build the application:
```powershell
cl /MDd sheetjs-hermesw.cpp DbgHelp.lib *.lib /I hermes-windows\API /I hermes-windows\include /I hermes-windows\public\ /I hermes-windows\API\jsi
```
:::caution pass
If `cl` is not found, run the command in the "Native Tools Command Prompt"
:::
9) Download the SheetJS Standalone script and the test file. Save both files in
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://sheetjs.com/pres.numbers">pres.numbers</a></li>
</ul>
<CodeBlock language="bash">{`\
curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js
curl -LO https://sheetjs.com/pres.numbers`}
</CodeBlock>
10) Run the application:
```bash
.\sheetjs-hermesw.exe pres.numbers
```
If successful, the program will print the library version number and the
contents of the first sheet as CSV rows.
### CLI Test
:::note
@ -493,4 +676,5 @@ If successful, the script will print CSV data from the test file.
[^2]: See ["Workbook Object"](/docs/csf/book)
[^3]: See ["Workbook Object"](/docs/csf/book)
[^4]: See [`sheet_to_csv` in "Utilities"](/docs/api/utilities/csv#csv-output)
[^5]: See ["Dependencies" in "Building and Running"](https://hermesengine.dev/docs/building-and-running/#dependencies) in the Hermes Documentation
[^5]: See [`microsoft/hermes-windows`](https://github.com/microsoft/hermes-windows) on GitHub
[^6]: See ["Dependencies" in "Building and Running"](https://hermesengine.dev/docs/building-and-running/#dependencies) in the Hermes Documentation

@ -55,7 +55,7 @@ only be used when there is no safe way to pass `ArrayBuffer` or `Uint8Array`.
**Byte Conventions**
Java has no native concept of unsigned bytes. Values in a `byte[]` are clamped
Java has no native concept of unsigned bytes. Values in a `byte[]` are limited
to the range `-128 .. 127`. They need to be fixed within the JS engine.
Some engines support typed arrays. The `Uint8Array` constructor will fix values:

@ -0,0 +1,117 @@
/* sheetjs-hermesw.cpp Copyright (c) SheetJS LLC. */
#include <iostream>
#include "hermes/hermes.h"
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;
}
/* Hermes-Windows requires the null terminator */
static char *read_file_null(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) + 1; fseek(f, 0, SEEK_SET); }
char *buf = (char *)malloc(fsize * sizeof(char));
*sz = fread((void *) buf, 1, fsize, f);
buf[fsize - 1] = 0;
fclose(f);
return buf;
}
/* Unfortunately the library provides no C-friendly Buffer classes */
class CBuffer : public facebook::jsi::Buffer {
public:
CBuffer(const uint8_t *data, size_t size) : buf(data), sz(size) {}
size_t size() const override { return sz; }
const uint8_t *data() const override { return buf; }
private:
const uint8_t *buf;
size_t sz;
};
/* ArrayBuffer constructor expects MutableBuffer*/
class CMutableBuffer : public facebook::jsi::MutableBuffer {
public:
CMutableBuffer(uint8_t *data, size_t size) : buf(data), sz(size) {}
size_t size() const override { return sz; }
uint8_t *data() override { return buf; }
private:
uint8_t *buf;
size_t sz;
};
int main(int argc, char **argv) {
std::unique_ptr<facebook::jsi::Runtime> rt(facebook::hermes::makeHermesRuntime());
/* setup */
try {
auto src = std::make_shared<facebook::jsi::StringBuffer>(
"var global = (function(){ return this; }).call(null);"
"var console = { log: function(x) { print(x); } };"
);
auto js = rt->prepareJavaScript(src, std::string("<eval>"));
rt->evaluatePreparedJavaScript(js);
} catch (const facebook::jsi::JSIException &e) {
std::cerr << "JavaScript terminated via uncaught exception: " << e.what() << '\n';
return 1;
}
/* load SheetJS library */
try {
size_t sz; char *xlsx_full_min_js = read_file_null("xlsx.full.min.js", &sz);
auto src = std::make_shared<CBuffer>(CBuffer((uint8_t *)xlsx_full_min_js, sz));
auto js = rt->prepareJavaScript(src, std::string("xlsx.full.min.js"));
rt->evaluatePreparedJavaScript(js);
} catch (const facebook::jsi::JSIException &e) {
std::cerr << "JavaScript terminated via uncaught exception: " << e.what() << '\n';
return 1;
}
/* print library version */
try {
auto src = std::make_shared<facebook::jsi::StringBuffer>(
"console.log('SheetJS Library Version: ' + XLSX.version)"
);
auto js = rt->prepareJavaScript(src, std::string("<eval>"));
rt->evaluatePreparedJavaScript(js);
} catch (const facebook::jsi::JSIException &e) {
std::cerr << "JavaScript terminated via uncaught exception: " << e.what() << '\n';
return 1;
}
try {
/* load payload as ArrayBuffer */
size_t sz; char *data = read_file(argv[1], &sz);
auto payload = std::make_shared<CMutableBuffer>(CMutableBuffer((uint8_t *)data, sz));
auto ab = facebook::jsi::ArrayBuffer(*rt, payload);
/* define stub function to read and convert first sheet to CSV */
auto src = std::make_shared<facebook::jsi::StringBuffer>(
"(function(buf) {"
"var wb = XLSX.read(buf);"
"return XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]);"
"})"
);
auto js = rt->prepareJavaScript(src, std::string("<eval>"));
auto func = rt->evaluatePreparedJavaScript(js);
/* call stub function and capture result */
auto csv = func.asObject(*rt).asFunction(*rt).call(*rt, ab);
/* interpret as utf8 and print to stdout */
std::string str = csv.getString(*rt).utf8(*rt);
std::cout << str << std::endl;
} catch (const facebook::jsi::JSIException &e) {
std::cerr << "JavaScript terminated via uncaught exception: " << e.what() << std::endl;
return 1;
}
return 0;
}