ChakraCore 中的工作表
ChakraCore 是一个用 C++ 编写的嵌入式 JS 引擎。
¥ChakraCore is an embeddable JS engine written in C++.
SheetJS 是一个用于从电子表格读取和写入数据的 JavaScript 库。
¥SheetJS is a JavaScript library for reading and writing data from spreadsheets.
该演示使用 ChakraCore 和 SheetJS 从电子表格中提取数据并打印 CSV 行。我们将探索如何在 ChakraCore 上下文中加载 SheetJS 并从 C++ 程序处理电子表格。
¥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 spreadsheets from a C++ program.
"集成示例" 部分包括一个完整的命令行工具,用于从文件中读取数据。
¥The "Integration Example" section includes a complete command-line tool for reading data from files.
集成详情
¥Integration Details
初始化 ChakraCore
¥Initialize ChakraCore
ChakraCore 通过 JsGetGlobalObject
提供 global
对象:
¥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);
讨论中省略了清理和验证代码。集成示例显示了结构化验证和受控内存使用。
¥Cleanup and validation code is omitted from the discussion. The integration example shows structured validation and controlled memory usage.
加载 SheetJS 脚本
¥Load SheetJS Scripts
SheetJS 独立脚本 可以在 ChakraCore 上下文中进行解析和评估。
¥SheetJS Standalone scripts can be parsed and evaluated in a ChakraCore context.
可以通过从文件系统读取脚本并在 ChakraCore 上下文中进行评估来加载主库:
¥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
可以从 C 字节数组生成 ArrayBuffer
:
¥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);
推送数据后,最简单的方法是在 globalThis
上存储属性:
¥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
"集成示例" 涵盖了 C 应用中的传统集成,而 "CLI 测试" 使用 ch
CLI 工具演示了其他概念。
¥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
该演示在以下部署中进行了测试:
¥This demo was tested in the following deployments:
架构 | Git 提交 | 日期 |
---|---|---|
darwin-x64 | e26c81f | 2024-12-17 |
darwin-arm | e26c81f | 2025-01-13 |
win11-x64 | e26c81f | 2024-12-19 |
win11-arm | e26c81f | 2025-02-23 |
linux-x64 | e26c81f | 2025-01-09 |
-
安装依赖:
¥Install dependencies:
- X64 Mac
- ARM64 Mac
- Linux
- X64 Windows
- ARM64 Windows
brew install icu4c cmake
brew install icu4c cmake
在 Arch Linux / HoloOS 上:
¥On Arch Linux / HoloOS:
sudo pacman -S cmake clang
安装带有 "使用 C++ 进行桌面开发" 工作流和 "适用于 Windows 的 Git" 单独组件的 Visual Studio 2022。
¥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 "Native Tools Command Prompt".
安装带有 "使用 C++ 进行桌面开发" 工作流和 "适用于 Windows 的 Git" 单独组件的 Visual Studio 2022。
¥Install Visual Studio 2022 with the "Desktop Development with C++" workflow and the "Git for Windows" individual component.
此演示中的命令应在 "ARM64 原生工具命令提示符" 中运行。
¥The commands in this demo should be run in "ARM64 Native Tools Command Prompt".
-
下载脉轮核心:
¥Download ChakraCore:
git clone https://github.com/chakra-core/ChakraCore.git
cd ChakraCore
git checkout e26c81f
cd ..
-
构建 ChakraCore:
¥Build ChakraCore:
- X64 Mac
- ARM64 Mac
- Linux
- X64 Windows
- ARM64 Windows
cd ChakraCore
./build.sh --static --icu=/usr/local/opt/icu4c/include --test-build -j=8 --system-icu --no-jit
cd ..
在某些测试运行中,构建失败并显示以下消息:
¥In some test runs, the build failed with the message:
!!! couldn't find ICU ...
在构建步骤之前,已通过指向 icu4c
文件夹的本地符号链接修复了此问题:
¥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 ..
MacOS 15.1 SDK 和 ChakraCore JIT 存在已知问题。这些问题不会影响针对 MacOS 14.5 的早期测试。当前建议禁用 JIT 并使用系统 ICU 实现。
¥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.
上次测试演示时,不支持 ChakraCore JIT。
¥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 ..
在某些测试运行中,构建失败并显示以下消息:
¥In some test runs, the build failed with the message:
!!! couldn't find ICU ...
在构建步骤之前,已通过指向 icu4c
文件夹的本地符号链接修复了此问题:
¥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 ..
在某些测试运行中,编译失败并出现 operator
错误:
¥In some test runs, compilation failed with operator
errors:
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.2.sdk/usr/include/c++/v1/new:279:66: error: redefinition of 'operator new'
279 | _LIBCPP_NODISCARD_AFTER_CXX17 inline _LIBCPP_HIDE_FROM_ABI void* operator new(std::size_t, void* __p) _NOEXCEPT {
| ^
/tmp/sheetjs-chakra/ChakraCore/lib/Common/Memory/Allocator.h:457:1: note: previous definition is here
457 | operator new(
| ^
ChakraCore/lib/Common/Memory/Allocator.h
头文件必须修复:
¥The ChakraCore/lib/Common/Memory/Allocator.h
header file must be fixed:
diff --git a/lib/Common/Memory/Allocator.h b/lib/Common/Memory/Allocator.h
index 5a3a099bc..e05a7390f 100644
--- a/lib/Common/Memory/Allocator.h
+++ b/lib/Common/Memory/Allocator.h
@@ -452,24 +452,7 @@ void AssertValue(void * mem, T value, uint byteCount)
#ifndef __PLACEMENT_NEW_INLINE
#define __PLACEMENT_NEW_INLINE
-_Ret_notnull_
-NO_EXPORT(inline void *) __cdecl
-operator new(
-DECLSPEC_GUARD_OVERFLOW size_t byteSize,
-_In_ void * previousAllocation) throw()
-{
- return previousAllocation;
-}
-
-
-NO_EXPORT(inline void) __cdecl
-operator delete(
-void * allocationToFree, // Allocation to free
-void * previousAllocation // Previously allocated memory
-) throw()
-{
-
-}
+#include <new>
#endif
上次测试演示时,不支持 ChakraCore JIT。
¥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 ..
正如 ChakraCore 项目 wiki[^1] 中所解释的,该构建接受一些标志:
¥As explained in the ChakraCore project wiki[^1], the build accepts a few flags:
-
/p:Platform=x64
控制架构¥
/p:Platform=x64
controls the architecture -
/p:Configuration=Debug
启用运行时检查¥
/p:Configuration=Debug
enables runtime checks -
/p:RuntimeLib=static_library
确保 MSVC 库是静态链接的¥
/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 ..
在某些测试运行期间,构建失败并显示一条引用 cfguard.h
的消息:
¥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
必须对源文件 lib\Runtime\Base\ThreadContextInfo.cpp
进行修补。高亮的行必须注释:
¥The source file lib\Runtime\Base\ThreadContextInfo.cpp
must be patched. The
highlighted lines must be commented:
#if defined(_UCRT) && _CONTROL_FLOW_GUARD
//# if _MSC_VER >= 1913
//# include <cfguard.h>
//# else
extern "C" void __fastcall _guard_check_icall(_In_ uintptr_t _Target);
//# endif
#endif
构建完成后,应将生成的 DLL 复制到项目文件夹中:
¥After building, the generated DLL should be copied into the project folder:
copy .\ChakraCore\Build\VcBuild\bin\x64_debug\ChakraCore.dll .
正如 ChakraCore 项目 wiki[^1] 中所解释的,该构建接受一些标志:
¥As explained in the ChakraCore project wiki[^1], the build accepts a few flags:
-
/p:Platform=arm64
控制架构¥
/p:Platform=arm64
controls the architecture -
/p:Configuration=Debug
启用运行时检查¥
/p:Configuration=Debug
enables runtime checks -
/p:RuntimeLib=static_library
确保 MSVC 库是静态链接的¥
/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 ..
在某些测试运行期间,构建失败并显示一条引用 LegalizeMD.cpp
的消息:
¥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 [...]
必须对源文件 lib\Backend\arm64\LegalizeMD.cpp
进行修补。必须注释掉高亮的行:
¥The source file lib\Backend\arm64\LegalizeMD.cpp
must be patched. The
highlighted line must be commented:
void LegalizeMD::LegalizeIndirOffset(IR::Instr * instr, IR::IndirOpnd * indirOpnd, LegalForms forms)
{
//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.
构建完成后,应将生成的 DLL 复制到项目文件夹中:
¥After building, the generated DLL should be copied into the project folder:
copy .\ChakraCore\Build\VcBuild\bin\arm64_debug\ChakraCore.dll .
-
下载源文件和
Makefile
:¥Download the source file and
Makefile
:
curl -L -O https://xlsx.nodejs.cn/chakra/sheetjs.ch.cpp
curl -L -O https://xlsx.nodejs.cn/chakra/Makefile
-
构建示例应用:
¥Build the sample application:
- Linux/MacOS
- Windows
make
在某些 macOS 测试运行中,构建失败并显示以下消息:
¥In some macOS test runs, 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:
sudo mkdir -p /usr/local/opt
sudo ln -s /opt/homebrew/opt/icu4c /usr/local/opt
make
- X64 Windows
- ARM64 Windows
cl sheetjs.ch.cpp ChakraCore.lib /I ChakraCore\lib\Jsrt /link /LIBPATH:ChakraCore\Build\VcBuild\bin\x64_debug
cl sheetjs.ch.cpp ChakraCore.lib /I ChakraCore\lib\Jsrt /link /LIBPATH:ChakraCore\Build\VcBuild\bin\arm64_debug
-
下载 SheetJS Standalone 脚本、shim 脚本和测试文件。将所有三个文件移动到项目目录:
¥Download the SheetJS Standalone script, shim script and test file. Move all three files to the project directory:
curl -L -O https://cdn.sheetjs.com/xlsx-0.20.3/package/dist/xlsx.full.min.js
curl -L -O https://cdn.sheetjs.com/xlsx-0.20.3/package/dist/shim.min.js
curl -L -O https://xlsx.nodejs.cn/pres.numbers
-
运行测试程序:
¥Run the test program:
- Linux/MacOS
- Windows
./sheetjs.ch pres.numbers
.\sheetjs.ch.exe pres.numbers
如果成功,程序将以 CSV 格式打印第一张纸的内容。
¥If successful, the program will print the contents of the first sheet as CSV.
CLI 测试
¥CLI Test
此演示最后一次测试是在 2025-01-09,针对 ch
提交 e26c81f
。
¥This demo was last tested on 2025-01-09 against ch
commit e26c81f
.
由于 ch
独立二进制文件的限制,此演示将测试文件编码为 Base64 字符串,并将其直接添加到合并脚本中。
¥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.
-
下载并解压 ChakraCore 版本 ZIP。将二进制文件 (
bin/ch
) 复制到你的项目文件夹。¥Download and extract the ChakraCore release ZIP. Copy the binary (
bin/ch
) to your project folder.
"集成示例" 还构建了 ch
二进制文件!它通常放置在 Linux/macOS 上的 ChakraCore/out/Test/
文件夹中或 x64 Windows 上的 ChakraCore\Build\VcBuild\bin\x64_debug\
文件夹中。
¥The "Integration Example" also builds the ch
binary!
It will typically be placed in the ChakraCore/out/Test/
folder on Linux/macOS
or ChakraCore\Build\VcBuild\bin\x64_debug\
on x64 Windows.
-
下载 SheetJS Standalone 脚本、shim 脚本和测试文件。将所有三个文件移动到项目目录:
¥Download the SheetJS Standalone script, shim script and test file. Move all three files to the project directory:
curl -L -O https://cdn.sheetjs.com/xlsx-0.20.3/package/dist/xlsx.full.min.js
curl -L -O https://cdn.sheetjs.com/xlsx-0.20.3/package/dist/shim.min.js
curl -L -O https://xlsx.nodejs.cn/pres.numbers
-
打包测试文件并创建
payload.js
:¥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
创建global
变量:¥
global.js
creates aglobal
variable:
var global = (function(){ return this; }).call(null);
-
chakra.js
将调用XLSX.read
和XLSX.utils.sheet_to_csv
:¥
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]]));
-
创建合并
xlsx.chakra.js
:¥Create the amalgamation
xlsx.chakra.js
:
cat global.js xlsx.full.min.js payload.js chakra.js > xlsx.chakra.js
最终脚本在加载独立库之前定义了 global
。准备就绪后,它将读取打包的测试数据并将内容打印为 CSV。
¥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.
在 Windows 上,命令应在 WSL 中运行。
¥On Windows, the command should be run in WSL.
-
使用 ChakraCore 独立二进制文件运行脚本:
¥Run the script using the ChakraCore standalone binary:
- Linux/MacOS
- Windows
./ch xlsx.chakra.js
.\ch.exe xlsx.chakra.js
[^1]: 请参阅 ChakraCore 项目 wiki 中的 "构建脉轮核心"
¥See "Building ChakraCore" in the ChakraCore project wiki