Files
smart_wasm/scripts/build.ps1
2026-06-16 12:56:26 +08:00

439 lines
14 KiB
PowerShell
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# build.ps1 - 智能 WASM 构建脚本
param(
[switch]$Clean,
[switch]$Serve,
[switch]$Test,
[string]$BuildType = "Release"
)
Write-Host "=========================================" -ForegroundColor Cyan
Write-Host " 智能 JSON-WASM 项目构建系统 " -ForegroundColor Cyan
Write-Host "=========================================" -ForegroundColor Cyan
Write-Host ""
# 1. 设置环境变量
$emsdkCandidates = @()
if ($env:EMSDK) {
$emsdkCandidates += $env:EMSDK
}
$emsdkCandidates += "E:\emsdk"
$emsdkCandidates += (Join-Path (Split-Path $PSScriptRoot -Parent) "..\emsdk")
$emsdkCandidates += (Join-Path (Split-Path $PSScriptRoot -Parent) "emsdk")
$emccCommand = Get-Command emcc -ErrorAction SilentlyContinue
if ($emccCommand -and $emccCommand.Source) {
$emccSourceDir = Split-Path $emccCommand.Source -Parent
if (Test-Path (Join-Path $emccSourceDir "emcc.ps1")) {
$emsdkCandidates += (Split-Path (Split-Path $emccSourceDir -Parent) -Parent)
}
}
$EmsdkPath = $null
foreach ($candidate in $emsdkCandidates | Select-Object -Unique) {
if (-not [string]::IsNullOrWhiteSpace($candidate)) {
try {
if (Test-Path $candidate) {
$resolvedCandidate = [System.IO.Path]::GetFullPath($candidate)
if (Test-Path (Join-Path $resolvedCandidate "upstream\emscripten\emcc.ps1")) {
$EmsdkPath = $resolvedCandidate
break
}
}
} catch {
continue
}
}
}
if (-not $EmsdkPath) {
Write-Host "[错误] 未找到 Emscripten" -ForegroundColor Red
Write-Host "请设置 EMSDK 环境变量,或确认 emsdk 已安装。" -ForegroundColor Yellow
exit 1
}
# 设置 PATH
$env:PATH = "$EmsdkPath\upstream\emscripten;$env:PATH"
Write-Host "[✓] 设置 Emscripten 环境: $EmsdkPath" -ForegroundColor Green
# 2. 清理旧构建
if ($Clean) {
Write-Host "[ ] 清理构建文件..." -ForegroundColor Cyan
Remove-Item -Path "build", "public/wasm" -Recurse -Force -ErrorAction SilentlyContinue
Write-Host "[✓] 清理完成" -ForegroundColor Green
}
# 3. 创建目录
New-Item -Path "build", "public/wasm" -ItemType Directory -Force | Out-Null
# 4. 编译 WASM
Write-Host "[ ] 编译智能 WASM 模块..." -ForegroundColor Cyan
$startTime = Get-Date
# 编译命令 - 使用当前真实业务模块源码
$compileResult = emcc `
src/api/KinematicsWebAPI.Core.cpp `
src/api/KinematicsWebAPI.RobotCommands.cpp `
src/api/KinematicsWebAPI.SpcCommands.cpp `
src/api/KinematicsWebAPI.FourBarCommands.cpp `
src/api/KinematicsWebAPI.QuadrupedCommands.cpp `
src/main.cpp `
src/Robot.cpp `
src/spc_core.cpp `
src/QuadrupedRobotSimulation/RobotConfig.cpp `
src/QuadrupedRobotSimulation/BaseClass.cpp `
src/QuadrupedRobotSimulation/KinematicsSimulation.cpp `
src/QuadrupedRobotSimulation/CompleteJsonExporter.cpp `
src/QuadrupedRobotSimulation/KinematicsReverse.cpp `
src/QuadrupedRobotSimulation/KinematicsHelper.cpp `
src/QuadrupedRobotSimulation/SharedGeometry.cpp `
src/FourBarMechanism/CrankSliderMechanism.cpp `
src/FourBarMechanism/CrankRockingBlockMechanism_Forward.cpp `
src/FourBarMechanism/CrankRockingBlockMechanism_Inverse.cpp `
src/FourBarMechanism/FourBarMechanism.cpp `
src/FourBarMechanism/SliderCrankMechanism.cpp `
src/RobotManager.cpp `
src/utils.cpp `
src/math_utils.cpp `
src/smart_json_wrapper.cpp `
third_party/kdl_parser/src/kdl_parser.cpp `
third_party/kdl_parser/src/joint.cpp `
third_party/kdl_parser/src/link.cpp `
third_party/kdl_parser/src/model.cpp `
third_party/kdl_parser/src/pose.cpp `
third_party/kdl_parser/src/tinystr.cpp `
third_party/kdl_parser/src/tinyxml.cpp `
third_party/kdl_parser/src/tinyxml2.cpp `
third_party/kdl_parser/src/tinyxmlerror.cpp `
third_party/kdl_parser/src/tinyxmlparser.cpp `
third_party/kdl_parser/src/twist.cpp `
third_party/kdl_parser/src/world.cpp `
-I./include `
-I./third_party `
-I./third_party/kdl_parser/include `
-I./third_party/orocos_kdl/install_wasm/include `
-I./third_party/eigen3 `
-L./third_party/orocos_kdl/install_wasm/lib `
-lorocos-kdl `
-std=c++17 `
-s WASM=1 `
-s EXPORTED_FUNCTIONS='["_init_func","_func","_smart_process_json","_smart_get_function_list","_smart_get_function_info","_smart_test_match","_smart_get_version","_smart_free_string","_malloc","_free","_add","_subtract","_multiply","_divide","_fibonacci","_create_buffer","_destroy_buffer","_compute_sum","_get_greeting","_main"]' `
-s EXPORTED_RUNTIME_METHODS='["UTF8ToString","stringToUTF8","lengthBytesUTF8","ccall","cwrap","HEAPU8","HEAP8","HEAPF32","HEAPF64"]' `
-s MODULARIZE=1 `
-s EXPORT_NAME='createSmartMathModule' `
-s ALLOW_MEMORY_GROWTH=1 `
-s ENVIRONMENT='web,node,worker' `
-s ASSERTIONS=1 `
-s DISABLE_EXCEPTION_CATCHING=0 `
-s INITIAL_MEMORY=67108864 `
-s MAXIMUM_MEMORY=268435456 `
-s STACK_SIZE=5242880 `
-s USE_PTHREADS=0 `
-O3 `
-Wno-deprecated-literal-operator `
-Wno-deprecated-declarations `
-o public/wasm/smart_math.js 2>&1
$endTime = Get-Date
$duration = ($endTime - $startTime).TotalSeconds
if ($LASTEXITCODE -ne 0) {
Write-Host "[✗] 编译失败" -ForegroundColor Red
Write-Host $compileResult -ForegroundColor Red
exit 1
}
Write-Host "[✓] 编译完成" -ForegroundColor Green
# 5. 检查生成的文件
$jsFile = Get-Item "public/wasm/smart_math.js" -ErrorAction SilentlyContinue
$wasmFile = Get-Item "public/wasm/smart_math.wasm" -ErrorAction SilentlyContinue
if (-not $jsFile -or -not $wasmFile) {
Write-Host "[✗] 未找到生成文件" -ForegroundColor Red
exit 1
}
$jsSize = $jsFile.Length / 1KB
$wasmSize = $wasmFile.Length / 1KB
# 6. 显示构建结果
Write-Host ""
Write-Host "构建成功" -ForegroundColor Green
Write-Host ("=" * 50) -ForegroundColor DarkGray
Write-Host "生成文件:" -ForegroundColor White
Write-Host " - smart_math.js ($($jsSize.ToString('F1')) KB)" -ForegroundColor Gray
Write-Host " - smart_math.wasm ($($wasmSize.ToString('F1')) KB)" -ForegroundColor Gray
Write-Host ""
Write-Host "功能特性:" -ForegroundColor White
Write-Host " - 机器人正逆解业务接口 (func/init_func)" -ForegroundColor Gray
Write-Host " - SPC / 四足机器人 / 连杆机构业务接口" -ForegroundColor Gray
Write-Host " - 智能 JSON 数学测试接口" -ForegroundColor Gray
Write-Host " - Node / Web 双环境加载" -ForegroundColor Gray
Write-Host " - 与 Emscripten 内存管理兼容" -ForegroundColor Gray
Write-Host " - 批量回归测试可直接调用" -ForegroundColor Gray
Write-Host ""
Write-Host "输出目录: $((Get-Location).Path)\public\wasm" -ForegroundColor Gray
Write-Host "编译耗时: $($duration.ToString('F2'))" -ForegroundColor Gray
Write-Host ""
# 7. 生成 JavaScript 包装器(可选)
Write-Host "[ ] 生成 JavaScript 包装器..." -ForegroundColor Cyan
$jsWrapper = @'
// Smart WASM JSON API JavaScript 包装器
class SmartWasmAPI {
constructor() {
this.module = null;
this.initialized = false;
}
allocString(value) {
const size = this.module.lengthBytesUTF8(value) + 1;
const ptr = this.module._malloc(size);
this.module.stringToUTF8(value, ptr, size);
return ptr;
}
async initialize() {
if (this.initialized) return;
// 加载 WASM 模块
this.module = await createSmartMathModule();
this.initialized = true;
console.log('Smart WASM API 初始化完成');
return this;
}
async initializeBusinessApi() {
if (!this.initialized) {
await this.initialize();
}
let responsePtr = null;
try {
responsePtr = this.module._init_func();
const responseStr = this.module.UTF8ToString(responsePtr);
return JSON.parse(responseStr);
} finally {
if (responsePtr) {
this.module._smart_free_string(responsePtr);
}
}
}
async processBusinessRequest(jsonRequest) {
if (!this.initialized) {
await this.initialize();
}
let requestPtr = null;
let responsePtr = null;
try {
requestPtr = this.allocString(JSON.stringify(jsonRequest));
responsePtr = this.module._func(requestPtr);
const responseStr = this.module.UTF8ToString(responsePtr);
return JSON.parse(responseStr);
} catch (error) {
console.error('处理业务 JSON 请求时出错:', error);
throw error;
} finally {
if (requestPtr) {
this.module._free(requestPtr);
}
if (responsePtr) {
this.module._smart_free_string(responsePtr);
}
}
}
// 处理 JSON 请求
async processJsonRequest(jsonRequest) {
if (!this.initialized) {
await this.initialize();
}
let requestPtr = null;
let responsePtr = null;
try {
// 将 JSON 字符串转换为 WASM 内存中的字符串
requestPtr = this.allocString(JSON.stringify(jsonRequest));
// 调用 WASM 函数
responsePtr = this.module._smart_process_json(requestPtr);
// 将结果转换回 JavaScript 字符串
const responseStr = this.module.UTF8ToString(responsePtr);
// 解析 JSON 结果
return JSON.parse(responseStr);
} catch (error) {
console.error('处理 JSON 请求时出错:', error);
throw error;
} finally {
// 释放内存
if (requestPtr) {
this.module._free(requestPtr);
}
if (responsePtr) {
this.module._smart_free_string(responsePtr);
}
}
}
// 获取函数列表
async getFunctionList() {
if (!this.initialized) {
await this.initialize();
}
let responsePtr = null;
try {
responsePtr = this.module._smart_get_function_list();
const responseStr = this.module.UTF8ToString(responsePtr);
return JSON.parse(responseStr);
} catch (error) {
console.error('获取函数列表时出错:', error);
throw error;
} finally {
if (responsePtr) {
this.module._smart_free_string(responsePtr);
}
}
}
// 调用特定函数
async callFunction(funcName, params = {}) {
const request = {
req_cmd: funcName,
...params
};
return await this.processJsonRequest(request);
}
// 测试智能匹配
async testSmartMatch(jsonRequest) {
if (!this.initialized) {
await this.initialize();
}
let requestPtr = null;
let responsePtr = null;
try {
requestPtr = this.allocString(JSON.stringify(jsonRequest));
responsePtr = this.module._smart_test_match(requestPtr);
const responseStr = this.module.UTF8ToString(responsePtr);
return JSON.parse(responseStr);
} catch (error) {
console.error('测试智能匹配时出错:', error);
throw error;
} finally {
if (requestPtr) {
this.module._free(requestPtr);
}
if (responsePtr) {
this.module._smart_free_string(responsePtr);
}
}
}
// 获取版本信息
async getVersion() {
if (!this.initialized) {
await this.initialize();
}
let responsePtr = null;
try {
responsePtr = this.module._smart_get_version();
const responseStr = this.module.UTF8ToString(responsePtr);
return JSON.parse(responseStr);
} catch (error) {
console.error('获取版本信息时出错:', error);
throw error;
} finally {
if (responsePtr) {
this.module._smart_free_string(responsePtr);
}
}
}
// 直接调用数学函数(绕过 JSON 处理)
callMathFunction(name, ...args) {
if (!this.initialized) {
throw new Error('WASM 模块未初始化');
}
switch (name.toLowerCase()) {
case 'add':
return this.module._add(args[0] || 0, args[1] || 0);
case 'subtract':
return this.module._subtract(args[0] || 0, args[1] || 0);
case 'multiply':
return this.module._multiply(args[0] || 0, args[1] || 0);
case 'divide':
return this.module._divide(args[0] || 0, args[1] || 1);
case 'fibonacci':
return this.module._fibonacci(args[0] || 0);
default:
throw new Error('未知的数学函数: ' + name);
}
}
}
// 创建全局实例
if (typeof window !== 'undefined') {
window.SmartWasmAPI = SmartWasmAPI;
}
export default SmartWasmAPI;
'@
$jsWrapper | Out-File -FilePath "public/wasm/smart_api_wrapper.js" -Encoding UTF8
Write-Host "[✓] 生成 JavaScript 包装器" -ForegroundColor Green
# 8. 本地测试(可选)
if ($Test) {
Write-Host "[ ] 运行本地测试..." -ForegroundColor Cyan
try {
node --version 2>&1 | Out-Null
if ($LASTEXITCODE -eq 0) {
Write-Host "[ ] 执行 WASM 回归测试..." -ForegroundColor Cyan
node scripts/run_wasm_tests.js
}
} catch {
Write-Host "[!] 本地测试跳过(需要 Node.js" -ForegroundColor Yellow
}
}
# 9. 启动开发服务器(可选)
if ($Serve) {
Write-Host "[ ] 启动开发服务器..." -ForegroundColor Cyan
Write-Host " 访问: http://localhost:8080/smart_test.html" -ForegroundColor Yellow
Write-Host " 按 Ctrl+C 停止服务器" -ForegroundColor Yellow
Write-Host ""
Set-Location "public"
python -m http.server 8080
}
Write-Host ""
Write-Host "使用提示:" -ForegroundColor White
Write-Host " - 在 VS Code 中按 F5 启动调试" -ForegroundColor Gray
Write-Host " - 使用 Ctrl+Shift+B 快速构建" -ForegroundColor Gray
Write-Host " - 查看 public/wasm/smart_api_wrapper.js 了解 JavaScript API 使用" -ForegroundColor Gray
Write-Host " - 运行 npm run serve 启动开发服务器" -ForegroundColor Gray
Write-Host ""