From 09304115ef5eadeab0c86010f257ad91493f2dbb Mon Sep 17 00:00:00 2001 From: wangdequan Date: Mon, 8 Jun 2026 05:05:17 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BC=BA=E5=88=B6WASM=E5=A2=9E=E9=87=8F?= =?UTF-8?q?=E6=9E=84=E5=BB=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 结论:INI和解释器WASM构建已改为对象、依赖和命令指纹驱动的增量编译,并将所有构建必须增量写入项目规则。 --- wasm-port/AGENTS.md | 3 + wasm-port/tools/build_ini_panel.sh | 45 ++++-- wasm-port/tools/build_wasm_core.sh | 29 +++- wasm-port/tools/wasm_incremental_build_lib.sh | 139 ++++++++++++++++++ 4 files changed, 203 insertions(+), 13 deletions(-) create mode 100644 wasm-port/tools/wasm_incremental_build_lib.sh diff --git a/wasm-port/AGENTS.md b/wasm-port/AGENTS.md index f379314..a731254 100644 --- a/wasm-port/AGENTS.md +++ b/wasm-port/AGENTS.md @@ -70,6 +70,9 @@ expanded into a separate implementation of G-code behavior. - GUI. 7. Frontend code must be implemented with web technology, not migrated from native GUI code. +8. All build scripts must be incremental. Native and WASM builds must reuse + object files, dependency files, and command fingerprints, and must not + unconditionally recompile unchanged source files. ## Required Layout diff --git a/wasm-port/tools/build_ini_panel.sh b/wasm-port/tools/build_ini_panel.sh index 0aa8682..b1f4164 100755 --- a/wasm-port/tools/build_ini_panel.sh +++ b/wasm-port/tools/build_ini_panel.sh @@ -3,17 +3,44 @@ set -euo pipefail ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)" OUT_DIR="$ROOT_DIR/runtime/ui/ini-panel" +BUILD_DIR="$ROOT_DIR/build/wasm/ini-panel" +OBJ_DIR="$BUILD_DIR/obj" -emcc \ - -std=c++20 \ +source "$ROOT_DIR/tools/wasm_incremental_build_lib.sh" + +mkdir -p "$OUT_DIR" "$BUILD_DIR" "$OBJ_DIR" + +TARGET="linuxcnc_ini_wasm" +: > "$BUILD_DIR/$TARGET.stdout.log" +: > "$BUILD_DIR/$TARGET.stderr.log" + +COMMON_FLAGS=( + -std=c++20 + -O2 + -I"$ROOT_DIR/runtime/core/shims" + -I"$ROOT_DIR/vendor/linuxcnc/src" + -I"$ROOT_DIR/vendor/linuxcnc/src/rtapi" + -I"$ROOT_DIR/vendor/linuxcnc/src/emc" +) + +SOURCES=( + "$ROOT_DIR/vendor/linuxcnc/src/emc/ini/inifile.cc" + "$ROOT_DIR/runtime/core/linuxcnc_wrap/linuxcnc_ini_wasm.cpp" +) + +OBJECTS=() +for source in "${SOURCES[@]}"; do + obj="$(source_object_path "$source" "$ROOT_DIR" "$OBJ_DIR")" + OBJECTS+=("$obj") + compile_wasm_object "$TARGET" "$source" "$obj" "$BUILD_DIR" "${COMMON_FLAGS[@]}" +done + +link_wasm_module \ + "$TARGET" \ + "$OUT_DIR/linuxcnc_ini.js" \ + "$BUILD_DIR" \ -O2 \ - -I"$ROOT_DIR/runtime/core/shims" \ - -I"$ROOT_DIR/vendor/linuxcnc/src" \ - -I"$ROOT_DIR/vendor/linuxcnc/src/rtapi" \ - -I"$ROOT_DIR/vendor/linuxcnc/src/emc" \ - "$ROOT_DIR/vendor/linuxcnc/src/emc/ini/inifile.cc" \ - "$ROOT_DIR/runtime/core/linuxcnc_wrap/linuxcnc_ini_wasm.cpp" \ - -o "$OUT_DIR/linuxcnc_ini.js" \ + "${OBJECTS[@]}" \ -s MODULARIZE=1 \ -s EXPORT_ES6=1 \ -s ENVIRONMENT=web,node \ diff --git a/wasm-port/tools/build_wasm_core.sh b/wasm-port/tools/build_wasm_core.sh index 3bd39ca..0309f45 100755 --- a/wasm-port/tools/build_wasm_core.sh +++ b/wasm-port/tools/build_wasm_core.sh @@ -7,8 +7,16 @@ WRAP_DIR="$ROOT_DIR/runtime/core/linuxcnc_wrap" SHIM_DIR="$ROOT_DIR/runtime/core/shims" INCLUDE_DIR="$ROOT_DIR/runtime/core/include" OUT_DIR="$ROOT_DIR/build/wasm/core" +BUILD_DIR="$OUT_DIR" +OBJ_DIR="$BUILD_DIR/obj" -mkdir -p "$OUT_DIR" +source "$ROOT_DIR/tools/wasm_incremental_build_lib.sh" + +mkdir -p "$OUT_DIR" "$OBJ_DIR" + +TARGET="linuxcnc_interp_wasm" +: > "$BUILD_DIR/$TARGET.stdout.log" +: > "$BUILD_DIR/$TARGET.stderr.log" COMMON_FLAGS=( -std=c++20 @@ -62,11 +70,24 @@ INTERP_CORE_SOURCES=( "$VENDOR_DIR/src/emc/ini/inifile.cc" ) -emcc \ - "${COMMON_FLAGS[@]}" \ +SOURCES=( "${INTERP_CORE_SOURCES[@]}" \ "$WRAP_DIR/linuxcnc_interp_wasm.cpp" \ - -o "$OUT_DIR/linuxcnc_interp.js" \ +) + +OBJECTS=() +for source in "${SOURCES[@]}"; do + obj="$(source_object_path "$source" "$ROOT_DIR" "$OBJ_DIR")" + OBJECTS+=("$obj") + compile_wasm_object "$TARGET" "$source" "$obj" "$BUILD_DIR" "${COMMON_FLAGS[@]}" +done + +link_wasm_module \ + "$TARGET" \ + "$OUT_DIR/linuxcnc_interp.js" \ + "$BUILD_DIR" \ + -O2 \ + "${OBJECTS[@]}" \ -s MODULARIZE=1 \ -s EXPORT_ES6=1 \ -s ENVIRONMENT=web,node \ diff --git a/wasm-port/tools/wasm_incremental_build_lib.sh b/wasm-port/tools/wasm_incremental_build_lib.sh new file mode 100644 index 0000000..ef1d720 --- /dev/null +++ b/wasm-port/tools/wasm_incremental_build_lib.sh @@ -0,0 +1,139 @@ +#!/usr/bin/env bash + +write_command_file() { + local file="$1" + shift + printf '%q\n' "$@" > "$file" +} + +command_matches() { + local file="$1" + shift + + local tmp + tmp="$(mktemp)" + write_command_file "$tmp" "$@" + if [[ -f "$file" ]] && cmp -s "$tmp" "$file"; then + rm -f "$tmp" + return 0 + fi + rm -f "$tmp" + return 1 +} + +depfile_newer_than() { + local depfile="$1" + local output="$2" + + [[ -f "$depfile" ]] || return 0 + + local deps + deps="$(tr '\\\n' ' ' < "$depfile" | sed -e 's/^[^:]*://')" + local dep + for dep in $deps; do + if [[ -f "$dep" && "$dep" -nt "$output" ]]; then + return 0 + fi + done + return 1 +} + +object_needs_rebuild() { + local obj="$1" + local depfile="$2" + local cmdfile="$3" + shift 3 + + [[ -f "$obj" ]] || return 0 + command_matches "$cmdfile" "$@" || return 0 + depfile_newer_than "$depfile" "$obj" && return 0 + return 1 +} + +link_needs_rebuild() { + local output="$1" + local cmdfile="$2" + shift 2 + + [[ -f "$output" ]] || return 0 + command_matches "$cmdfile" "$@" || return 0 + + local arg + for arg in "$@"; do + if [[ -f "$arg" && "$arg" -nt "$output" ]]; then + return 0 + fi + done + return 1 +} + +source_object_path() { + local source="$1" + local root_dir="$2" + local obj_dir="$3" + local relative="${source#"$root_dir"/}" + + if [[ "$relative" == "$source" ]]; then + relative="$(basename "$source")" + fi + + relative="${relative//\//__}" + printf '%s/%s.o' "$obj_dir" "${relative%.*}" +} + +compile_wasm_object() { + local target="$1" + local source="$2" + local obj="$3" + local build_dir="$4" + shift 4 + + local stdout_log="$build_dir/$target.stdout.log" + local stderr_log="$build_dir/$target.stderr.log" + local depfile="$obj.d" + local cmdfile="$obj.cmd" + local cmd=(emcc "$@" -MMD -MP -MF "$depfile" -c "$source" -o "$obj") + + mkdir -p "$(dirname "$obj")" + if ! object_needs_rebuild "$obj" "$depfile" "$cmdfile" "${cmd[@]}"; then + printf 'up to date: %s\n' "$source" >> "$stdout_log" + return 0 + fi + + printf 'compile: %s\n' "$source" >> "$stdout_log" + if "${cmd[@]}" >> "$stdout_log" 2>> "$stderr_log"; then + write_command_file "$cmdfile" "${cmd[@]}" + return 0 + fi + return 1 +} + +link_wasm_module() { + local target="$1" + local output="$2" + local build_dir="$3" + shift 3 + + local stdout_log="$build_dir/$target.stdout.log" + local stderr_log="$build_dir/$target.stderr.log" + local cmdfile="$build_dir/$(basename "$output").cmd" + local wasm_output="${output%.js}.wasm" + local cmd=(emcc "$@" -o "$output") + + if [[ -f "$output" && ! -f "$wasm_output" ]]; then + printf 'missing paired wasm output: %s\n' "$wasm_output" >> "$stdout_log" + rm -f "$output" + fi + + if ! link_needs_rebuild "$output" "$cmdfile" "${cmd[@]}"; then + printf 'up to date: %s\n' "$output" >> "$stdout_log" + return 0 + fi + + printf 'link: %s\n' "$output" >> "$stdout_log" + if "${cmd[@]}" >> "$stdout_log" 2>> "$stderr_log"; then + write_command_file "$cmdfile" "${cmd[@]}" + return 0 + fi + return 1 +}