强制WASM增量构建

结论:INI和解释器WASM构建已改为对象、依赖和命令指纹驱动的增量编译,并将所有构建必须增量写入项目规则。
This commit is contained in:
2026-06-08 05:05:17 +08:00
parent caa35820cd
commit 09304115ef
4 changed files with 203 additions and 13 deletions

View File

@@ -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

View File

@@ -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 \

View File

@@ -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 \

View File

@@ -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
}