Compare commits
132 Commits
f9ac38251b
...
4e246738ac
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4e246738ac | ||
|
|
92562db29f | ||
|
|
de5f28f7ee | ||
|
|
82f222ba44 | ||
|
|
cdc30dda7e | ||
|
|
1d96aa8a55 | ||
|
|
25cb6885bf | ||
|
|
ccd51ff373 | ||
|
|
10bf0a5897 | ||
|
|
ced3e5de0e | ||
|
|
7ba3a22441 | ||
|
|
5aa328b413 | ||
|
|
586c28656d | ||
|
|
6efb77b8e4 | ||
|
|
ebb29f8cb6 | ||
|
|
8544872198 | ||
|
|
e320d6d420 | ||
|
|
ba2d680500 | ||
|
|
9af3443d95 | ||
|
|
4adcd82b74 | ||
|
|
66ea34a76d | ||
|
|
5bc568eaa9 | ||
|
|
23a4679c28 | ||
|
|
3c05202097 | ||
|
|
ba0d973f4f | ||
|
|
f69e10bedf | ||
|
|
a8f6a9d907 | ||
|
|
0850954ca8 | ||
|
|
6bd1c6a429 | ||
|
|
e928b32e69 | ||
|
|
36763c6bcd | ||
|
|
03080afe24 | ||
|
|
120a294f62 | ||
|
|
a3daa829fc | ||
|
|
71c61fca84 | ||
|
|
ff2980569c | ||
|
|
695186ddfc | ||
|
|
8394042d18 | ||
|
|
7e18c6cd40 | ||
|
|
09e2259669 | ||
|
|
867bf09c5d | ||
|
|
d35766e387 | ||
|
|
9c73577ade | ||
|
|
55149b0a0a | ||
|
|
6a886be52d | ||
|
|
acbf5b4686 | ||
|
|
77c6674905 | ||
|
|
eb91ced792 | ||
|
|
1b60bc2b2e | ||
|
|
37879f2a67 | ||
|
|
a7cd889b3a | ||
|
|
4887b2f64e | ||
|
|
cb315ce1cd | ||
|
|
9a4e0e3712 | ||
|
|
98755528e4 | ||
|
|
504b9b6d23 | ||
|
|
284afa1c64 | ||
|
|
428fc46f4e | ||
|
|
d5c6b7555a | ||
|
|
b773946c45 | ||
|
|
7a2a80ea71 | ||
|
|
41db47f440 | ||
|
|
27ac0bfb25 | ||
|
|
cd71eff8a5 | ||
|
|
eb1d31bfee | ||
|
|
2892f2ca9d | ||
|
|
a301965452 | ||
|
|
0737d5ea65 | ||
|
|
3a478ca335 | ||
|
|
a144576e90 | ||
|
|
60745adeef | ||
|
|
6506d23dc2 | ||
|
|
440a61be32 | ||
|
|
9b9e942dd6 | ||
|
|
3c72356c92 | ||
|
|
a89c107676 | ||
|
|
035b25862a | ||
|
|
167703b87a | ||
|
|
b600d6a516 | ||
|
|
0a2d37fae8 | ||
|
|
111cb5f9b9 | ||
|
|
218ac523b8 | ||
|
|
abaebe7940 | ||
|
|
77e92b0116 | ||
|
|
cf3154b043 | ||
|
|
9da6ffcd6a | ||
|
|
c71d2964ee | ||
|
|
c1a130f5fb | ||
|
|
baf8429736 | ||
|
|
2e2fb34cc3 | ||
|
|
810bd92ddc | ||
|
|
6d99ca67a9 | ||
|
|
6a2f63c894 | ||
|
|
bc80d74d1f | ||
|
|
71676ac1be | ||
|
|
89af73298e | ||
|
|
dc5cdeacc2 | ||
|
|
b170ccd95a | ||
|
|
29197b25cc | ||
|
|
5ce3c18103 | ||
|
|
79077fa695 | ||
|
|
f64db24060 | ||
|
|
fb2b5c4920 | ||
|
|
9c52e426f7 | ||
|
|
d80405ccb3 | ||
|
|
a48c02f5cc | ||
|
|
f56468b664 | ||
|
|
ba2d576f8b | ||
|
|
7f45abe93c | ||
|
|
ae7de73a7c | ||
|
|
7471444781 | ||
|
|
f36e2a96c4 | ||
|
|
aaa6dce99a | ||
|
|
b89d6311ff | ||
|
|
a12c0166b5 | ||
|
|
9fd23192dd | ||
|
|
a46910b6c0 | ||
|
|
0b387db8ca | ||
|
|
22c1c311ff | ||
|
|
3079656cfb | ||
|
|
7502684780 | ||
|
|
340966b6f7 | ||
|
|
1f314b7e9e | ||
|
|
1bfb7426d4 | ||
|
|
abd96dfdde | ||
|
|
7b171c605b | ||
|
|
cb22ecd8ef | ||
|
|
a0f6228908 | ||
|
|
8fe468ba3c | ||
|
|
b3b1117ec9 | ||
|
|
4eb694164f | ||
|
|
59b8e2a832 |
@@ -8,8 +8,8 @@ cd "$(dirname "$0")"
|
||||
# src/emc/rs274ngc/gcodemodule.cc, interp_namedparams.cc, interp_o_word.cc,
|
||||
# and the py*.cc module bindings; tooldata/native-backend blockers come from
|
||||
# src/emc/tooldata/tooldata_mmap.cc and tooldata_db.cc; native filesystem
|
||||
# blockers come from LinuxCNC RS274 sources such as interp_o_word.cc and
|
||||
# interp_write.cc.
|
||||
# coverage comes from LinuxCNC RS274 sources such as interp_o_word.cc
|
||||
# directory traversal and rs274ngc_pre.cc parameter-file replacement.
|
||||
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
|
||||
manifest=${1:-linuxcnc-rs274-wasm-source-files.txt}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ cd "$(dirname "$0")"
|
||||
# rs274/tooldata sources directly or link wasm-safe shims whose source basis is
|
||||
# checked against LinuxCNC source comments before building.
|
||||
usage() {
|
||||
echo "usage: $0 --mode tooldata-link|tooldata-common-link|interp-base-link|python-plugin-link|rs274ngc-pre-object" >&2
|
||||
echo "usage: $0 --mode tooldata-link|tooldata-common-link|interp-base-link|python-plugin-link|python-plugin-inittab-link|rs274ngc-pre-object" >&2
|
||||
}
|
||||
|
||||
mode=
|
||||
@@ -33,7 +33,7 @@ while [[ "$#" -gt 0 ]]; do
|
||||
esac
|
||||
done
|
||||
case "$mode" in
|
||||
tooldata-link|tooldata-common-link|interp-base-link|python-plugin-link|rs274ngc-pre-object)
|
||||
tooldata-link|tooldata-common-link|interp-base-link|python-plugin-link|python-plugin-inittab-link|rs274ngc-pre-object)
|
||||
;;
|
||||
"")
|
||||
usage
|
||||
@@ -114,14 +114,21 @@ case "$mode" in
|
||||
)
|
||||
target_name=interp_base_probe
|
||||
;;
|
||||
python-plugin-link)
|
||||
python-plugin-link|python-plugin-inittab-link)
|
||||
python_plugin_shim=$(./list-linuxcnc-wasm-safe-shims.sh python_plugin.cc)
|
||||
grep -F 'LinuxCNC source basis: src/emc/pythonplugin/python_plugin.cc and' core/wasm_shims/pythonplugin/python_plugin_probe_main.cc >/dev/null
|
||||
if [[ "$mode" == "python-plugin-link" ]]; then
|
||||
probe_source=core/wasm_shims/pythonplugin/python_plugin_probe_main.cc
|
||||
target_name=python_plugin_probe
|
||||
grep -F 'LinuxCNC source basis: src/emc/pythonplugin/python_plugin.cc and' "$probe_source" >/dev/null
|
||||
else
|
||||
probe_source=core/wasm_shims/pythonplugin/python_plugin_inittab_probe_main.cc
|
||||
target_name=python_plugin_inittab_probe
|
||||
grep -F 'LinuxCNC source basis: src/emc/pythonplugin/python_plugin.cc' "$probe_source" >/dev/null
|
||||
fi
|
||||
sources+=(
|
||||
"$python_plugin_shim"
|
||||
core/wasm_shims/pythonplugin/python_plugin_probe_main.cc
|
||||
"$probe_source"
|
||||
)
|
||||
target_name=python_plugin_probe
|
||||
;;
|
||||
rs274ngc-pre-object)
|
||||
rs274ngc_pre_source=$(LINUXCNC_ROOT="$linuxcnc_root" ./list-linuxcnc-source-files.sh src/emc/rs274ngc/rs274ngc_pre.cc)
|
||||
|
||||
@@ -26,6 +26,17 @@ fi
|
||||
|
||||
preflight_cache_dir=build/wasm-preflight-cache
|
||||
LINUXCNC_ROOT="$linuxcnc_root" ./check-linuxcnc-inputs-cached.sh --cache-dir "$preflight_cache_dir" "$manifest"
|
||||
./check-linuxcnc-rs274-source-map.sh
|
||||
./check-linuxcnc-kinematics-source-map.sh
|
||||
./check-linuxcnc-opfs-source-map.sh
|
||||
./check-linuxcnc-switchkins-remap-source-map.sh
|
||||
./check-linuxcnc-wasm-smoke-source-map.sh
|
||||
./check-linuxcnc-build-source-map.sh
|
||||
./check-linuxcnc-browser-app-source-map.sh
|
||||
./check-linuxcnc-workstreams-source-map.sh
|
||||
./check-linuxcnc-tooldata-source-map.sh
|
||||
./check-linuxcnc-wasm-shims-source-map.sh
|
||||
./check-linuxcnc-wasm-blockers-source-map.sh
|
||||
LINUXCNC_ROOT="$linuxcnc_root" ./check-linuxcnc-switchkins-remap-table-cached.sh --cache-dir "$preflight_cache_dir" linuxcnc-kinematics-source-files.txt
|
||||
manifest=$(cd "$(dirname "$manifest")" && pwd)/$(basename "$manifest")
|
||||
linuxcnc_root=$(cd "$linuxcnc_root" && pwd)
|
||||
|
||||
130
check-linuxcnc-browser-app-source-map.sh
Executable file
130
check-linuxcnc-browser-app-source-map.sh
Executable file
@@ -0,0 +1,130 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# LinuxCNC source basis: this guard ties the browser app entry point to
|
||||
# LinuxCNC RS274 parameter-file defaults, rs274ngc_pre.cc restore/save/read
|
||||
# file semantics, and the existing OPFS-backed wasm-core bridge. It validates
|
||||
# app integration policy only; it does not add CNC behavior or expand smoke
|
||||
# parsing, or interpret G-code.
|
||||
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
|
||||
linuxcnc_root=$(cd "$linuxcnc_root" && pwd)
|
||||
|
||||
grep -F '#define RS274NGC_PARAMETER_FILE_NAME_DEFAULT "rs274ngc.var"' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/interp_internal.hh" >/dev/null
|
||||
grep -F '#define RS274NGC_PARAMETER_FILE_BACKUP_SUFFIX ".bak"' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/interp_internal.hh" >/dev/null
|
||||
grep -F 'int Interp::restore_parameters(const char *filename)' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'int Interp::save_parameters(const char *filename,' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'std::string tempfile = std::string(filename) + ".new";' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F '+ RS274NGC_PARAMETER_FILE_BACKUP_SUFFIX;' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'unlink(bakfile.c_str());' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'if(link(filename, bakfile.c_str()) < 0)' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'if(rename(tempfile.c_str(), filename) < 0)' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'read_text(command, _setup.file_pointer, _setup.linetext,' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
|
||||
grep -F 'LinuxCNC browser app source map' docs/linuxcnc-browser-app-source-map.md >/dev/null
|
||||
grep -F 'must not add CNC behavior' docs/linuxcnc-browser-app-source-map.md >/dev/null
|
||||
grep -F 'must not expand the temporary smoke parser' docs/linuxcnc-browser-app-source-map.md >/dev/null
|
||||
grep -F '`RS274NGC_PARAMETER_FILE_NAME_DEFAULT` as `rs274ngc.var`' \
|
||||
docs/linuxcnc-browser-app-source-map.md >/dev/null
|
||||
grep -F '`parseFileWithParameterFile(programPath, parameterPath, "linuxcnc", ...)`' \
|
||||
docs/linuxcnc-browser-app-source-map.md >/dev/null
|
||||
grep -F 'orders parameter saves as backup unlink' \
|
||||
docs/linuxcnc-browser-app-source-map.md >/dev/null
|
||||
|
||||
grep -F '<script type="module" src="/src/app.js"></script>' web/index.html >/dev/null
|
||||
grep -F '<option value="linuxcnc-rs274">LINUXCNC</option>' web/index.html >/dev/null
|
||||
if [[ "$(grep -Fc '<option value=' web/index.html)" -ne 1 ]]; then
|
||||
echo "browser app backend selector must expose only the LinuxCNC RS274 backend" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
grep -F 'import { createWasmSimulator } from "./wasm-core.js";' web/src/app.js >/dev/null
|
||||
grep -F 'const programPath = "programs/current.ngc";' web/src/app.js >/dev/null
|
||||
grep -F 'const linuxCncParameterFileName = "rs274ngc.var";' web/src/app.js >/dev/null
|
||||
grep -F 'const parameterPath = `parameters/${linuxCncParameterFileName}`;' web/src/app.js >/dev/null
|
||||
grep -F 'const linuxCncBackend = "linuxcnc-rs274";' web/src/app.js >/dev/null
|
||||
grep -F 'const opfsOptions = { required: true, mountPoint: "/cnc", workspacePath: "cnc-simulator" };' \
|
||||
web/src/app.js >/dev/null
|
||||
grep -F 'simulatorPromise = createWasmSimulator({' web/src/app.js >/dev/null
|
||||
grep -F 'opfs: opfsOptions,' web/src/app.js >/dev/null
|
||||
grep -F 'OPFS workspace is required for browser program parsing' web/src/app.js >/dev/null
|
||||
grep -F 'await simulator.fs.opfs.writeFile(programPath, elements.input.value);' web/src/app.js >/dev/null
|
||||
grep -F 'const events = await simulator.parseFileWithParameterFile(programPath, parameterPath, "linuxcnc", parseOptions);' \
|
||||
web/src/app.js >/dev/null
|
||||
grep -F 'elements.backendSelect.value = linuxCncBackend;' web/src/app.js >/dev/null
|
||||
grep -F 'globalThis.__cncSimulatorForTest = simulatorPromise;' web/src/app.js >/dev/null
|
||||
|
||||
grep -F 'app frame did not persist current program into OPFS' \
|
||||
web/test-browser-wasm-smoke-app-sections.js >/dev/null
|
||||
grep -F 'app frame did not persist LinuxCNC parameter state into OPFS' \
|
||||
web/test-browser-wasm-smoke-app-sections.js >/dev/null
|
||||
grep -F 'app frame did not persist LinuxCNC parameter backup into OPFS' \
|
||||
web/test-browser-wasm-smoke-app-sections.js >/dev/null
|
||||
grep -F 'app frame did not clean up LinuxCNC temporary parameter file in OPFS' \
|
||||
web/test-browser-wasm-smoke-app-sections.js >/dev/null
|
||||
grep -F 'OPFS PROGRAM RESTORED' web/test-browser-wasm-smoke-app-sections.js >/dev/null
|
||||
grep -F 'app frame did not reload LinuxCNC parameter state from OPFS after reload' \
|
||||
web/test-browser-wasm-smoke-app-sections.js >/dev/null
|
||||
grep -F 'runSection("browser app opfs save"' test-web-wasm-browser-smoke.sh >/dev/null
|
||||
grep -F 'runSection("browser app opfs restore"' test-web-wasm-browser-smoke.sh >/dev/null
|
||||
|
||||
if grep -R -n -E 'localStorage|sessionStorage|indexedDB|showOpenFilePicker|showSaveFilePicker|showDirectoryPicker|webkitRequestFileSystem|FileReader' web/src; then
|
||||
echo "browser app/wasm code must not add filesystem persistence outside OPFS" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
python3 - <<'PY'
|
||||
from pathlib import Path
|
||||
|
||||
source_map = Path("docs/linuxcnc-browser-app-source-map.md").read_text(encoding="utf-8")
|
||||
for entry in [
|
||||
"web/index.html",
|
||||
"web/src/app.js",
|
||||
"web/test-browser-wasm-smoke-app-sections.js",
|
||||
]:
|
||||
if f"| `{entry}` |" not in source_map:
|
||||
raise SystemExit(f"docs/linuxcnc-browser-app-source-map.md missing app entry: {entry}")
|
||||
|
||||
for phrase in [
|
||||
"must not add CNC behavior",
|
||||
"must not expand the temporary smoke parser",
|
||||
"existing `createWasmSimulator()` OPFS API",
|
||||
"programs/current.ngc",
|
||||
"parameters/rs274ngc.var",
|
||||
"visible backend selector must stay limited",
|
||||
"./check-linuxcnc-browser-app-source-map.sh",
|
||||
"does not interpret G-code",
|
||||
]:
|
||||
if phrase not in source_map:
|
||||
raise SystemExit(f"docs/linuxcnc-browser-app-source-map.md missing boundary phrase: {phrase}")
|
||||
|
||||
for entry in [
|
||||
"test-native.sh",
|
||||
"test-linuxcnc-source-link.sh",
|
||||
"build-wasm.sh",
|
||||
]:
|
||||
text = Path(entry).read_text(encoding="utf-8")
|
||||
if "./check-linuxcnc-browser-app-source-map.sh" not in text:
|
||||
raise SystemExit(f"{entry} must run ./check-linuxcnc-browser-app-source-map.sh")
|
||||
|
||||
app = Path("web/src/app.js").read_text(encoding="utf-8")
|
||||
if "parse(" in app.replace("parseProgram", ""):
|
||||
raise SystemExit("browser app should route program execution through parseFileWithParameterFile, not direct parse")
|
||||
if app.count("elements.backendSelect.value = linuxCncBackend;") != 2:
|
||||
raise SystemExit("browser app backend selector must only be forced to the LinuxCNC backend")
|
||||
if "backendSelect.value" in app.replace("elements.backendSelect.value = linuxCncBackend;", ""):
|
||||
raise SystemExit("browser app must not read the backend selector as a dynamic backend source")
|
||||
if 'backend: linuxCncBackend' not in app:
|
||||
raise SystemExit("browser app parse options must force the LinuxCNC backend")
|
||||
PY
|
||||
202
check-linuxcnc-build-source-map.sh
Executable file
202
check-linuxcnc-build-source-map.sh
Executable file
@@ -0,0 +1,202 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# LinuxCNC source basis: this guard ties native/source-link/WASM build entry
|
||||
# points to LinuxCNC Submakefile source ownership, source manifests, persistent
|
||||
# build signatures, and source-backed WASM artifact ordering. It validates
|
||||
# build policy only; it does not add CNC behavior, expand smoke parsing, or
|
||||
# interpret G-code.
|
||||
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
|
||||
linuxcnc_root=$(cd "$linuxcnc_root" && pwd)
|
||||
|
||||
grep -F 'LIBRS274SRCS := $(addprefix emc/rs274ngc/,' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/Submakefile" >/dev/null
|
||||
grep -F 'rs274ngc_pre.cc \' "$linuxcnc_root/src/emc/rs274ngc/Submakefile" >/dev/null
|
||||
grep -F '../lib/libtooldata.so.0' "$linuxcnc_root/src/emc/rs274ngc/Submakefile" >/dev/null
|
||||
grep -F 'LIBTOOLDATA_SRCS += emc/tooldata/tooldata_common.cc' \
|
||||
"$linuxcnc_root/src/emc/tooldata/Submakefile" >/dev/null
|
||||
grep -F 'LIBTOOLDATA_SRCS += emc/tooldata/tooldata_mmap.cc' \
|
||||
"$linuxcnc_root/src/emc/tooldata/Submakefile" >/dev/null
|
||||
grep -F 'LIBTOOLDATA_SRCS += emc/tooldata/tooldata_db.cc' \
|
||||
"$linuxcnc_root/src/emc/tooldata/Submakefile" >/dev/null
|
||||
grep -F 'LIBLCNCINISRCS := emc/ini/inifile.cc' \
|
||||
"$linuxcnc_root/src/emc/ini/Submakefile" >/dev/null
|
||||
grep -F 'LIBPPSRCS := $(addprefix emc/pythonplugin/,' \
|
||||
"$linuxcnc_root/src/emc/pythonplugin/Submakefile" >/dev/null
|
||||
grep -F 'GENSERKINSSRCS := emc/kinematics/ugenserkins.c' \
|
||||
"$linuxcnc_root/src/emc/kinematics/Submakefile" >/dev/null
|
||||
grep -F 'extern int kinematicsInverse(const struct EmcPose * world,' \
|
||||
"$linuxcnc_root/src/emc/kinematics/kinematics.h" >/dev/null
|
||||
|
||||
grep -F 'LinuxCNC build source map' docs/linuxcnc-build-source-map.md >/dev/null
|
||||
grep -F 'must not add CNC' docs/linuxcnc-build-source-map.md >/dev/null
|
||||
grep -F 'must not expand the temporary smoke parser' docs/linuxcnc-build-source-map.md >/dev/null
|
||||
grep -F '`src/emc/rs274ngc/Submakefile` defines `LIBRS274SRCS`' \
|
||||
docs/linuxcnc-build-source-map.md >/dev/null
|
||||
grep -F '`src/emc/tooldata/Submakefile` defines the LinuxCNC tooldata' \
|
||||
docs/linuxcnc-build-source-map.md >/dev/null
|
||||
grep -F 'Default WASM manifest partition must remain 26 wasm-safe `core` sources and' \
|
||||
docs/linuxcnc-build-source-map.md >/dev/null
|
||||
grep -F '`build-wasm.sh` must configure with `CNC_SIM_ENABLE_SMOKE_BACKEND=OFF`' \
|
||||
docs/linuxcnc-build-source-map.md >/dev/null
|
||||
grep -F '`test-native.sh`, `test-linuxcnc-source-link.sh`, and `build-wasm.sh` must' \
|
||||
docs/linuxcnc-build-source-map.md >/dev/null
|
||||
|
||||
grep -F 'LinuxCNC source basis: the wasm build preflights and compiles the' build-wasm.sh >/dev/null
|
||||
source_map_guards=(
|
||||
'./check-linuxcnc-rs274-source-map.sh'
|
||||
'./check-linuxcnc-kinematics-source-map.sh'
|
||||
'./check-linuxcnc-opfs-source-map.sh'
|
||||
'./check-linuxcnc-switchkins-remap-source-map.sh'
|
||||
'./check-linuxcnc-wasm-smoke-source-map.sh'
|
||||
'./check-linuxcnc-build-source-map.sh'
|
||||
'./check-linuxcnc-browser-app-source-map.sh'
|
||||
'./check-linuxcnc-workstreams-source-map.sh'
|
||||
'./check-linuxcnc-tooldata-source-map.sh'
|
||||
'./check-linuxcnc-wasm-shims-source-map.sh'
|
||||
'./check-linuxcnc-wasm-blockers-source-map.sh'
|
||||
)
|
||||
for guarded_entry in test-native.sh test-linuxcnc-source-link.sh build-wasm.sh; do
|
||||
for source_map_guard in "${source_map_guards[@]}"; do
|
||||
grep -F "$source_map_guard" "$guarded_entry" >/dev/null
|
||||
done
|
||||
done
|
||||
grep -F 'manifest_core_count=$(count_nonempty_lines "$manifest_core_output")' build-wasm.sh >/dev/null
|
||||
grep -F 'manifest_blocked_count=$(count_nonempty_lines "$manifest_blocked_output")' build-wasm.sh >/dev/null
|
||||
grep -F 'manifest_core_count" -ne 26 || "$manifest_blocked_count" -ne 9' build-wasm.sh >/dev/null
|
||||
grep -F 'run_parallel_wasm_probe "LinuxCNC wasm tooldata shim link probe" ./test-linuxcnc-wasm-tooldata-link.sh' build-wasm.sh >/dev/null
|
||||
grep -F 'run_parallel_wasm_probe "LinuxCNC wasm rs274ngc_pre object probe" ./test-linuxcnc-wasm-rs274ngc-pre-object.sh' build-wasm.sh >/dev/null
|
||||
grep -F 'wait_parallel_wasm_probes' build-wasm.sh >/dev/null
|
||||
grep -F 'for required_tool in cmake emcmake emcc node; do' build-wasm.sh >/dev/null
|
||||
grep -F 'CONFIGURE_RULE_VERSION=2' build-wasm.sh >/dev/null
|
||||
grep -F -- '-DCNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE=ON' build-wasm.sh >/dev/null
|
||||
grep -F -- '-DCNC_SIM_ENABLE_SMOKE_BACKEND=OFF' build-wasm.sh >/dev/null
|
||||
grep -F 'cmake --build build/wasm --target cnc_sim_wasm_runtime_probe cnc_sim_wasm --parallel "$build_jobs"' build-wasm.sh >/dev/null
|
||||
grep -F 'cmp -s build/wasm/cnc_sim.js web/public/cnc_sim.js' build-wasm.sh >/dev/null
|
||||
grep -F 'cmp -s build/wasm/cnc_sim.wasm web/public/cnc_sim.wasm' build-wasm.sh >/dev/null
|
||||
grep -F './test-web-wasm-node-smoke.sh' build-wasm.sh >/dev/null
|
||||
grep -F './test-web-wasm-browser-smoke.sh' build-wasm.sh >/dev/null
|
||||
|
||||
grep -F 'LinuxCNC source basis: this source-link test compiles the manifest-selected' \
|
||||
test-linuxcnc-source-link.sh >/dev/null
|
||||
grep -F 'BUILD_RULE_VERSION=1' test-linuxcnc-source-link.sh >/dev/null
|
||||
grep -F 'make --output-sync=target -j"$build_jobs" -f "$source_link_makefile"' \
|
||||
test-linuxcnc-source-link.sh >/dev/null
|
||||
grep -F 'LinuxCNC source basis: this syntax probe checks the native RS274 manifest' \
|
||||
test-linuxcnc-source-syntax.sh >/dev/null
|
||||
grep -F 'LinuxCNC source basis: the wasm syntax probe compiles the' \
|
||||
test-linuxcnc-wasm-source-syntax.sh >/dev/null
|
||||
grep -F "printf 'CONFIGURE_RULE_VERSION=1\n'" \
|
||||
test-linuxcnc-wasm-cmake-safe-probe.sh >/dev/null
|
||||
grep -F 'cmake --build "$build_dir" --target linuxcnc_rs274_wasm_safe_probe cnc_sim_wasm_runtime_probe --parallel "$build_jobs"' \
|
||||
test-linuxcnc-wasm-cmake-safe-probe.sh >/dev/null
|
||||
|
||||
if grep -F 'printf '\''BUILD_JOBS=%s\n'\'' "$build_jobs"' build-wasm.sh >/dev/null; then
|
||||
echo "build-wasm configure signature must not depend on CNC_SIM_BUILD_JOBS" >&2
|
||||
exit 1
|
||||
fi
|
||||
for hot_signature_script in \
|
||||
build-linuxcnc-wasm-link-probe.sh \
|
||||
build-linuxcnc-wasm-probe-objects.sh \
|
||||
build-linuxcnc-wasm-standalone-probe.sh \
|
||||
build-linuxcnc-native-bridge-objects.sh \
|
||||
test-linuxcnc-api-native.sh \
|
||||
test-linuxcnc-bridge-native.sh \
|
||||
test-linuxcnc-rs274-native.sh \
|
||||
test-linuxcnc-source-link.sh \
|
||||
test-linuxcnc-source-objects.sh \
|
||||
test-linuxcnc-source-syntax.sh \
|
||||
test-native.sh; do
|
||||
if grep -F "sha256sum $hot_signature_script" "$hot_signature_script" >/dev/null; then
|
||||
echo "$hot_signature_script hot object signature must use BUILD_RULE_VERSION instead of the whole script hash" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
python3 - <<'PY'
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
|
||||
source_map = Path("docs/linuxcnc-build-source-map.md").read_text(encoding="utf-8")
|
||||
wasm_manifest = Path("linuxcnc-rs274-wasm-source-files.txt")
|
||||
core_count = len(subprocess.check_output(
|
||||
["./list-linuxcnc-wasm-manifest-sources.sh", str(wasm_manifest), "core"],
|
||||
text=True,
|
||||
).splitlines())
|
||||
blocked_count = len(subprocess.check_output(
|
||||
["./list-linuxcnc-wasm-manifest-sources.sh", str(wasm_manifest), "blocked"],
|
||||
text=True,
|
||||
).splitlines())
|
||||
if core_count != 26 or blocked_count != 9:
|
||||
raise SystemExit(f"unexpected default WASM manifest partition: core={core_count} blocked={blocked_count}")
|
||||
|
||||
for entry in [
|
||||
"test-native.sh",
|
||||
"test-linuxcnc-source-link.sh",
|
||||
"test-linuxcnc-source-syntax.sh",
|
||||
"test-linuxcnc-wasm-cmake-safe-probe.sh",
|
||||
"build-wasm.sh",
|
||||
]:
|
||||
if f"| `{entry}` |" not in source_map:
|
||||
raise SystemExit(f"docs/linuxcnc-build-source-map.md missing build entry: {entry}")
|
||||
|
||||
for phrase in [
|
||||
"must not add CNC",
|
||||
"must not expand the temporary smoke parser",
|
||||
"CNC_SIM_BUILD_JOBS",
|
||||
"BUILD_RULE_VERSION",
|
||||
"CONFIGURE_RULE_VERSION",
|
||||
"CNC_SIM_ENABLE_SMOKE_BACKEND=OFF",
|
||||
"Node smoke before browser smoke",
|
||||
"does not interpret",
|
||||
"G-code",
|
||||
]:
|
||||
if phrase not in source_map:
|
||||
raise SystemExit(f"docs/linuxcnc-build-source-map.md missing boundary phrase: {phrase}")
|
||||
|
||||
build_wasm = Path("build-wasm.sh").read_text(encoding="utf-8").splitlines()
|
||||
positions = {}
|
||||
for index, line in enumerate(build_wasm, start=1):
|
||||
if 'run_parallel_wasm_probe "LinuxCNC wasm tooldata shim link probe"' in line:
|
||||
positions["parallel_start"] = index
|
||||
if "wait_parallel_wasm_probes" in line and "parallel_start" in positions and "wait" not in positions:
|
||||
positions["wait"] = index
|
||||
if "LinuxCNC wasm rs274ngc_pre link blocker scan" in line:
|
||||
positions["pre_link"] = index
|
||||
if "for required_tool in cmake emcmake emcc node; do" in line:
|
||||
positions["tools"] = index
|
||||
if "emcmake cmake -S core -B build/wasm" in line:
|
||||
positions["configure"] = index
|
||||
if "cmake --build build/wasm --target cnc_sim_wasm_runtime_probe cnc_sim_wasm" in line:
|
||||
positions["build"] = index
|
||||
if "cp build/wasm/cnc_sim.js web/public/cnc_sim.js" in line:
|
||||
positions["cp_js"] = index
|
||||
if "cp build/wasm/cnc_sim.wasm web/public/cnc_sim.wasm" in line:
|
||||
positions["cp_wasm"] = index
|
||||
if "cmp -s build/wasm/cnc_sim.js web/public/cnc_sim.js" in line:
|
||||
positions["cmp_js"] = index
|
||||
if "cmp -s build/wasm/cnc_sim.wasm web/public/cnc_sim.wasm" in line:
|
||||
positions["cmp_wasm"] = index
|
||||
if "./test-web-wasm-node-smoke.sh" in line:
|
||||
positions["node"] = index
|
||||
if "./test-web-wasm-browser-smoke.sh" in line:
|
||||
positions["browser"] = index
|
||||
|
||||
required = [
|
||||
"parallel_start", "wait", "pre_link", "tools", "configure", "build",
|
||||
"cp_js", "cp_wasm", "cmp_js", "cmp_wasm", "node", "browser",
|
||||
]
|
||||
missing = [name for name in required if name not in positions]
|
||||
if missing:
|
||||
raise SystemExit(f"build-wasm.sh missing ordered build anchors: {', '.join(missing)}")
|
||||
if not (positions["parallel_start"] < positions["wait"] < positions["pre_link"]):
|
||||
raise SystemExit("build-wasm.sh must wait for parallel probes before rs274ngc_pre link checks")
|
||||
if not (positions["tools"] < positions["configure"] < positions["build"]):
|
||||
raise SystemExit("build-wasm.sh must check tools, then configure, then build")
|
||||
if not (positions["cp_js"] < positions["cmp_js"] < positions["node"] < positions["browser"]):
|
||||
raise SystemExit("build-wasm.js artifact JS copy/compare or smoke ordering changed")
|
||||
if not (positions["cp_wasm"] < positions["cmp_wasm"] < positions["node"] < positions["browser"]):
|
||||
raise SystemExit("build-wasm.wasm artifact copy/compare or smoke ordering changed")
|
||||
PY
|
||||
97
check-linuxcnc-kinematics-source-map.sh
Executable file
97
check-linuxcnc-kinematics-source-map.sh
Executable file
@@ -0,0 +1,97 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# LinuxCNC source basis: this guard keeps the kinematics source map aligned
|
||||
# with linuxcnc-kinematics-source-files.txt, which enumerates LinuxCNC
|
||||
# kinematics, posemath, switchkins INI/HAL/remap/tooldata/assets, and adjacent
|
||||
# build metadata. It validates source coverage documentation only; it does not
|
||||
# add CNC behavior, expand smoke parsing, or interpret G-code.
|
||||
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
|
||||
linuxcnc_root=$(cd "$linuxcnc_root" && pwd)
|
||||
|
||||
grep -F 'GENSERKINSSRCS := emc/kinematics/ugenserkins.c' \
|
||||
"$linuxcnc_root/src/emc/kinematics/Submakefile" >/dev/null
|
||||
grep -F 'extern int kinematicsInverse(const struct EmcPose * world,' \
|
||||
"$linuxcnc_root/src/emc/kinematics/kinematics.h" >/dev/null
|
||||
grep -F 'extern int kinematicsSwitch(int switchkins_type);' \
|
||||
"$linuxcnc_root/src/emc/kinematics/kinematics.h" >/dev/null
|
||||
grep -F 'motion.switchkins-type' \
|
||||
"$linuxcnc_root/configs/sim/axis/vismach/5axis/bridgemill/5axis.ini" >/dev/null
|
||||
grep -F '#<kinstype>' \
|
||||
"$linuxcnc_root/configs/sim/axis/vismach/5axis/bridgemill/remap_subs/428remap.ngc" >/dev/null
|
||||
|
||||
python3 - <<'PY'
|
||||
from pathlib import Path
|
||||
import re
|
||||
|
||||
manifest = Path("linuxcnc-kinematics-source-files.txt").read_text(encoding="utf-8").splitlines()
|
||||
source_map = Path("docs/linuxcnc-kinematics-source-map.md").read_text(encoding="utf-8")
|
||||
|
||||
expected_groups = [
|
||||
"core",
|
||||
"config",
|
||||
"remap",
|
||||
"component",
|
||||
"generated",
|
||||
"header",
|
||||
"metadata",
|
||||
"asset",
|
||||
"tooldata",
|
||||
]
|
||||
counts = {group: 0 for group in expected_groups}
|
||||
for line in manifest:
|
||||
if not line or line.startswith("#"):
|
||||
continue
|
||||
group = line.split(":", 1)[0]
|
||||
if group not in counts:
|
||||
raise SystemExit(f"unexpected kinematics manifest group in source map guard: {group}")
|
||||
counts[group] += 1
|
||||
|
||||
for group, count in counts.items():
|
||||
pattern = rf"\| `{re.escape(group)}` \| {count} \|"
|
||||
if not re.search(pattern, source_map):
|
||||
raise SystemExit(
|
||||
f"docs/linuxcnc-kinematics-source-map.md {group} count no longer matches linuxcnc-kinematics-source-files.txt"
|
||||
)
|
||||
|
||||
for group in expected_groups:
|
||||
if f"`{group}`" not in source_map:
|
||||
raise SystemExit(
|
||||
f"docs/linuxcnc-kinematics-source-map.md is missing kinematics manifest group {group}"
|
||||
)
|
||||
|
||||
required_phrases = [
|
||||
"LinuxCNC Source Anchors",
|
||||
"must not add CNC behavior",
|
||||
"must not",
|
||||
"expand the temporary smoke parser",
|
||||
"`src/emc/kinematics/Submakefile`",
|
||||
"`src/emc/kinematics/kinematics.h`",
|
||||
"motion.switchkins-type",
|
||||
"`#<kinstype>` remap assignment",
|
||||
"not browser API surface",
|
||||
"OPFS-only",
|
||||
"derive M428/M429/M430 cases from",
|
||||
"RTCP and five-axis coverage",
|
||||
"./check-linuxcnc-kinematics-source-map.sh",
|
||||
"./check-linuxcnc-inputs.sh linuxcnc-kinematics-source-files.txt --require-kinematics-complete",
|
||||
"./check-linuxcnc-switchkins-remap-table.sh linuxcnc-kinematics-source-files.txt",
|
||||
"does not interpret G-code",
|
||||
]
|
||||
for phrase in required_phrases:
|
||||
if phrase not in source_map:
|
||||
raise SystemExit(
|
||||
f"docs/linuxcnc-kinematics-source-map.md is missing source-coverage boundary phrase: {phrase}"
|
||||
)
|
||||
|
||||
for entry in [
|
||||
"test-native.sh",
|
||||
"test-linuxcnc-source-link.sh",
|
||||
"build-wasm.sh",
|
||||
]:
|
||||
text = Path(entry).read_text(encoding="utf-8")
|
||||
if "./check-linuxcnc-kinematics-source-map.sh" not in text:
|
||||
raise SystemExit(f"{entry} must run ./check-linuxcnc-kinematics-source-map.sh")
|
||||
PY
|
||||
182
check-linuxcnc-opfs-source-map.sh
Executable file
182
check-linuxcnc-opfs-source-map.sh
Executable file
@@ -0,0 +1,182 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# LinuxCNC source basis: this guard ties browser OPFS parameter persistence to
|
||||
# interp_internal.hh defaults and rs274ngc_pre.cc restore_parameters() /
|
||||
# save_parameters() file semantics. It validates bridge policy only; it does not
|
||||
# add CNC behavior, expand smoke parsing, or interpret G-code.
|
||||
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
|
||||
linuxcnc_root=$(cd "$linuxcnc_root" && pwd)
|
||||
|
||||
grep -F '#define RS274NGC_PARAMETER_FILE_NAME_DEFAULT "rs274ngc.var"' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/interp_internal.hh" >/dev/null
|
||||
grep -F '#define RS274NGC_PARAMETER_FILE_BACKUP_SUFFIX ".bak"' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/interp_internal.hh" >/dev/null
|
||||
grep -F 'int Interp::restore_parameters(const char *filename)' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'int Interp::open(const char *filename)' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F '_setup.file_pointer = fopen(filename, "r");' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'read_text(command, _setup.file_pointer, _setup.linetext,' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'int Interp::save_parameters(const char *filename,' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'std::string tempfile = std::string(filename) + ".new";' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F '+ RS274NGC_PARAMETER_FILE_BACKUP_SUFFIX;' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'unlink(bakfile.c_str());' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'if(link(filename, bakfile.c_str()) < 0)' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'if(rename(tempfile.c_str(), filename) < 0)' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
|
||||
grep -F 'RS274NGC_PARAMETER_FILE_NAME_DEFAULT` as `rs274ngc.var`' \
|
||||
docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F 'RS274NGC_PARAMETER_FILE_BACKUP_SUFFIX` as `.bak`' \
|
||||
docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F '`Interp::restore_parameters()` for parameter-file reads' \
|
||||
docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F '`Interp::open()` by opening' \
|
||||
docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F '`fopen(filename, "r")`, then `Interp::_read()`' \
|
||||
docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F '`read_text()`' docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F '`Interp::save_parameters()` for `filename + ".new"`' \
|
||||
docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F 'unlinks `filename + ".bak"`, links the' \
|
||||
docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F 'must not add independent filesystem behavior or expand the temporary smoke parser' \
|
||||
docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F 'parseFileWithParameterFile()' docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F 'OPFS Coverage' docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F '| `web/src/wasm-core.js` |' docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F '| `web/src/wasm-core.d.ts` |' docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F '| `web/src/app.js` |' docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F '| `web/test-browser-wasm-smoke-opfs-basic-sections.js` |' docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F '| `web/test-browser-wasm-smoke-opfs-parameter-sections.js` |' docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F '| `web/test-browser-wasm-smoke-opfs-workspace-sections.js` |' docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F '| `web/test-browser-wasm-smoke-opfs-mirror-sections.js` |' docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F '| `web/test-browser-wasm-smoke-opfs-directory-sections.js` |' docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F '| `web/test-browser-wasm-smoke-opfs-policy-sections.js` |' docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F '| `web/test-browser-wasm-smoke-app-sections.js` |' docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
|
||||
grep -F 'const LINUXCNC_DEFAULT_PARAMETER_FILE = "rs274ngc.var";' web/src/wasm-core.js >/dev/null
|
||||
grep -F 'async parseFile(path, dialect = "linuxcnc", options = {})' web/src/wasm-core.js >/dev/null
|
||||
grep -F 'OPFS workspace is not available for program file parsing' web/src/wasm-core.js >/dev/null
|
||||
grep -F 'const program = new TextDecoder().decode(await opfs.readFile(path));' web/src/wasm-core.js >/dev/null
|
||||
grep -F 'async parseFileWithParameterFile(path, parameterPath, dialect = "linuxcnc", options = {})' \
|
||||
web/src/wasm-core.js >/dev/null
|
||||
grep -F 'OPFS workspace is not available for program and parameter file parsing' web/src/wasm-core.js >/dev/null
|
||||
grep -F '`${LINUXCNC_DEFAULT_PARAMETER_FILE}.new`' web/src/wasm-core.js >/dev/null
|
||||
grep -F '`${LINUXCNC_DEFAULT_PARAMETER_FILE}.bak`' web/src/wasm-core.js >/dev/null
|
||||
grep -F 'LinuxCNC source basis: rs274ngc_pre.cc restore_parameters() reads the' web/src/wasm-core.js >/dev/null
|
||||
grep -F 'before replacing the main file and managing filename + ".bak".' web/src/wasm-core.js >/dev/null
|
||||
grep -F 'app frame did not clean up LinuxCNC temporary parameter file in OPFS' \
|
||||
web/test-browser-wasm-smoke-app-sections.js >/dev/null
|
||||
grep -F 'OPFS cannot be disabled in browser contexts with OPFS support' web/src/wasm-core.js >/dev/null
|
||||
grep -F 'OPFS path must stay inside the CNC workspace' web/src/wasm-core.js >/dev/null
|
||||
grep -F 'OPFS mount point must stay inside the Emscripten filesystem' web/src/wasm-core.js >/dev/null
|
||||
grep -F 'async persistDirectory(path)' web/src/wasm-core.js >/dev/null
|
||||
grep -F 'async readDirectory(path)' web/src/wasm-core.js >/dev/null
|
||||
grep -F 'export type WasmOpfsWorkspace = {' web/src/wasm-core.d.ts >/dev/null
|
||||
grep -F 'readDirectory(path: string): Promise<string[]>;' web/src/wasm-core.d.ts >/dev/null
|
||||
grep -F 'persistDirectory(path: string): Promise<string[]>;' web/src/wasm-core.d.ts >/dev/null
|
||||
grep -F 'loadParameterFile(path: string): Promise<Uint8Array | null>;' web/src/wasm-core.d.ts >/dev/null
|
||||
grep -F 'persistParameterFile(path: string): Promise<Uint8Array>;' web/src/wasm-core.d.ts >/dev/null
|
||||
grep -F 'opfs?: false | {' web/src/wasm-core.d.ts >/dev/null
|
||||
grep -F 'mountPoint?: string;' web/src/wasm-core.d.ts >/dev/null
|
||||
grep -F 'workspacePath?: string;' web/src/wasm-core.d.ts >/dev/null
|
||||
grep -F 'const events = await simulator.parseFileWithParameterFile(programPath, parameterPath, "linuxcnc", parseOptions);' \
|
||||
web/src/app.js >/dev/null
|
||||
grep -F 'OPFS workspace is required for browser program parsing' web/src/app.js >/dev/null
|
||||
grep -F 'runBrowserOpfsBasicSections(context, simulator)' \
|
||||
web/test-browser-wasm-smoke-opfs-workspace-sections.js >/dev/null
|
||||
grep -F 'runBrowserOpfsParameterSections(context, simulator)' \
|
||||
web/test-browser-wasm-smoke-opfs-workspace-sections.js >/dev/null
|
||||
grep -F 'runBrowserOpfsMirrorSections(context, simulator)' \
|
||||
web/test-browser-wasm-smoke-opfs-workspace-sections.js >/dev/null
|
||||
grep -F 'runBrowserOpfsDirectorySections(context, simulator)' \
|
||||
web/test-browser-wasm-smoke-opfs-workspace-sections.js >/dev/null
|
||||
grep -F 'runBrowserOpfsPolicySections(context)' web/test-browser-wasm-smoke-sections.js >/dev/null
|
||||
grep -F 'runSection("opfs directory persist and load"' \
|
||||
web/test-browser-wasm-smoke-opfs-directory-sections.js >/dev/null
|
||||
grep -F 'runSection("opfs metadata queries avoid wasm mirror pollution"' \
|
||||
web/test-browser-wasm-smoke-opfs-directory-sections.js >/dev/null
|
||||
grep -F 'runSection("opfs copy and move mirror files"' \
|
||||
web/test-browser-wasm-smoke-opfs-mirror-sections.js >/dev/null
|
||||
grep -F 'runSection("browser opfs policy"' \
|
||||
web/test-browser-wasm-smoke-opfs-policy-sections.js >/dev/null
|
||||
grep -F 'runSection("opfs parameter restore in new instance"' test-web-wasm-browser-smoke.sh >/dev/null
|
||||
grep -F 'runSection("opfs invalid parameter restore failures"' test-web-wasm-browser-smoke.sh >/dev/null
|
||||
grep -F 'runSection("opfs stale parameter state cleanup"' test-web-wasm-browser-smoke.sh >/dev/null
|
||||
grep -F 'runSection("opfs program parse and restore"' test-web-wasm-browser-smoke.sh >/dev/null
|
||||
grep -F 'runSection("browser app opfs restore"' test-web-wasm-browser-smoke.sh >/dev/null
|
||||
|
||||
if grep -R -n -E 'localStorage|sessionStorage|indexedDB|showOpenFilePicker|showSaveFilePicker|showDirectoryPicker|webkitRequestFileSystem|FileReader' web/src; then
|
||||
echo "browser app/wasm code must not add filesystem persistence outside OPFS" >&2
|
||||
exit 1
|
||||
fi
|
||||
if grep -n -E 'localStorage|sessionStorage|indexedDB|showOpenFilePicker|showSaveFilePicker|showDirectoryPicker|webkitRequestFileSystem|FileReader' \
|
||||
web/test-browser-wasm-smoke-*.js \
|
||||
web/test-browser-wasm-smoke.html \
|
||||
test-web-wasm-browser-smoke.sh; then
|
||||
echo "browser OPFS smoke harness must not add filesystem persistence outside OPFS" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
python3 - <<'PY'
|
||||
from pathlib import Path
|
||||
|
||||
source_map = Path("docs/linuxcnc-opfs-source-map.md").read_text(encoding="utf-8")
|
||||
coverage_entries = [
|
||||
"web/src/wasm-core.js",
|
||||
"web/src/wasm-core.d.ts",
|
||||
"web/src/app.js",
|
||||
"web/test-browser-wasm-smoke-opfs-basic-sections.js",
|
||||
"web/test-browser-wasm-smoke-opfs-parameter-sections.js",
|
||||
"web/test-browser-wasm-smoke-opfs-workspace-sections.js",
|
||||
"web/test-browser-wasm-smoke-opfs-mirror-sections.js",
|
||||
"web/test-browser-wasm-smoke-opfs-directory-sections.js",
|
||||
"web/test-browser-wasm-smoke-opfs-policy-sections.js",
|
||||
"web/test-browser-wasm-smoke-app-sections.js",
|
||||
]
|
||||
for entry in coverage_entries:
|
||||
if f"| `{entry}` |" not in source_map:
|
||||
raise SystemExit(f"docs/linuxcnc-opfs-source-map.md missing OPFS coverage entry: {entry}")
|
||||
|
||||
required_phrases = [
|
||||
"programs/current.ngc",
|
||||
"parameters/rs274ngc.var",
|
||||
'fopen(filename, "r")',
|
||||
"LinuxCNC `read_text()`",
|
||||
"program reads and parameter restore/save bridge files under the OPFS workspace",
|
||||
"`.new`, `.bak`, failure, and stale-state semantics",
|
||||
'unlinks `filename + ".bak"`',
|
||||
"OPFS/WASM mirror persistence",
|
||||
"OPFS directory persistence and WASM mirror refresh",
|
||||
"OPFS workspace and mount policy",
|
||||
"Browser OPFS smoke harness files must also stay free of Local Storage",
|
||||
"they may only verify OPFS-backed browser persistence",
|
||||
"OPFS-backed workspace, directory, parameter-file, and mount/workspace option types",
|
||||
"app-level OPFS program, parameter, backup, and reload behavior",
|
||||
"./check-linuxcnc-opfs-source-map.sh",
|
||||
"does not interpret G-code",
|
||||
]
|
||||
for phrase in required_phrases:
|
||||
if phrase not in source_map:
|
||||
raise SystemExit(f"docs/linuxcnc-opfs-source-map.md missing OPFS coverage phrase: {phrase}")
|
||||
|
||||
for entry in [
|
||||
"test-native.sh",
|
||||
"test-linuxcnc-source-link.sh",
|
||||
"build-wasm.sh",
|
||||
]:
|
||||
text = Path(entry).read_text(encoding="utf-8")
|
||||
if "./check-linuxcnc-opfs-source-map.sh" not in text:
|
||||
raise SystemExit(f"{entry} must run ./check-linuxcnc-opfs-source-map.sh")
|
||||
PY
|
||||
102
check-linuxcnc-rs274-source-map.sh
Executable file
102
check-linuxcnc-rs274-source-map.sh
Executable file
@@ -0,0 +1,102 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# LinuxCNC source basis: this guard keeps the local source map aligned with the
|
||||
# LinuxCNC-root relative rs274 manifests that drive native and WASM source-link
|
||||
# probes. It validates documentation/manifest drift only; it does not add CNC
|
||||
# behavior, expand smoke parsing, or interpret G-code.
|
||||
python3 - <<'PY'
|
||||
from pathlib import Path
|
||||
|
||||
source_map = Path("docs/linuxcnc-rs274-source-map.md").read_text(encoding="utf-8")
|
||||
native_manifest = Path("linuxcnc-rs274-source-files.txt").read_text(encoding="utf-8").splitlines()
|
||||
wasm_manifest = Path("linuxcnc-rs274-wasm-source-files.txt").read_text(encoding="utf-8").splitlines()
|
||||
|
||||
expected = {
|
||||
"### Interpreter core": [
|
||||
Path(line.split(":", 2)[1]).name
|
||||
for line in native_manifest
|
||||
if line.startswith("core:")
|
||||
],
|
||||
"### Python binding modules": [
|
||||
Path(line.split(":", 2)[1]).name
|
||||
for line in native_manifest
|
||||
if line.startswith("binding:")
|
||||
],
|
||||
"### WASM-safe source core": [
|
||||
line.split(":", 2)[1]
|
||||
for line in wasm_manifest
|
||||
if line.startswith("core:")
|
||||
],
|
||||
"### WASM-blocked sources": [
|
||||
line.split(":", 2)[1]
|
||||
for line in wasm_manifest
|
||||
if line.startswith("blocked:")
|
||||
],
|
||||
"### WASM-tracked headers": [
|
||||
line.split(":", 2)[1]
|
||||
for line in wasm_manifest
|
||||
if line.startswith("header:")
|
||||
],
|
||||
"### WASM-blocked headers": [
|
||||
line.split(":", 2)[1]
|
||||
for line in wasm_manifest
|
||||
if line.startswith("blocked-header:")
|
||||
],
|
||||
"### WASM metadata sources": [
|
||||
line.split(":", 2)[1]
|
||||
for line in wasm_manifest
|
||||
if line.startswith("metadata:")
|
||||
],
|
||||
}
|
||||
|
||||
actual = {section: [] for section in expected}
|
||||
active_section = None
|
||||
for line in source_map.splitlines():
|
||||
if line in expected:
|
||||
active_section = line
|
||||
continue
|
||||
if active_section and line.startswith("### "):
|
||||
active_section = None
|
||||
if active_section and line.startswith("- `"):
|
||||
actual[active_section].append(line.split("`", 2)[1])
|
||||
|
||||
labels = {
|
||||
"### Interpreter core": "interpreter core",
|
||||
"### Python binding modules": "Python binding module",
|
||||
"### WASM-safe source core": "WASM-safe source core",
|
||||
"### WASM-blocked sources": "WASM-blocked source",
|
||||
"### WASM-tracked headers": "WASM-tracked header",
|
||||
"### WASM-blocked headers": "WASM-blocked header",
|
||||
"### WASM metadata sources": "WASM metadata source",
|
||||
}
|
||||
for section, expected_entries in expected.items():
|
||||
if actual[section] != expected_entries:
|
||||
raise SystemExit(
|
||||
f"docs/linuxcnc-rs274-source-map.md {labels[section]} list no longer matches source manifest"
|
||||
)
|
||||
|
||||
for phrase in [
|
||||
"must not add CNC behavior",
|
||||
"must not expand the temporary smoke parser",
|
||||
"source coverage only",
|
||||
"must not become browser API fields",
|
||||
"temporary smoke parser fallback behavior",
|
||||
"Browser-hostile dependencies must remain tracked blockers",
|
||||
"./check-linuxcnc-rs274-source-map.sh",
|
||||
"does not interpret G-code",
|
||||
]:
|
||||
if phrase not in source_map:
|
||||
raise SystemExit(f"docs/linuxcnc-rs274-source-map.md missing boundary phrase: {phrase}")
|
||||
|
||||
for entry in [
|
||||
"test-native.sh",
|
||||
"test-linuxcnc-source-link.sh",
|
||||
"build-wasm.sh",
|
||||
]:
|
||||
text = Path(entry).read_text(encoding="utf-8")
|
||||
if "./check-linuxcnc-rs274-source-map.sh" not in text:
|
||||
raise SystemExit(f"{entry} must run ./check-linuxcnc-rs274-source-map.sh")
|
||||
PY
|
||||
107
check-linuxcnc-switchkins-remap-source-map.sh
Executable file
107
check-linuxcnc-switchkins-remap-source-map.sh
Executable file
@@ -0,0 +1,107 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# LinuxCNC source basis: this guard ties generated switchkins/remap aliases and
|
||||
# config cases to LinuxCNC configs/sim INI REMAP entries, remap_subs
|
||||
# #<kinstype> assignments, and halcmd loadusr parsing sources. It validates
|
||||
# generator/table policy only; it does not add CNC behavior, expand smoke
|
||||
# parsing, or interpret G-code.
|
||||
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
|
||||
linuxcnc_root=$(cd "$linuxcnc_root" && pwd)
|
||||
|
||||
grep -F 'LinuxCNC source basis: generated switchkins/remap tables are extracted from' \
|
||||
generate-linuxcnc-switchkins-remap-table.sh >/dev/null
|
||||
grep -F 'src/hal/utils/halcmd_commands.cc do_loadusr_cmd()' \
|
||||
generate-linuxcnc-switchkins-remap-table.sh >/dev/null
|
||||
grep -F 'getopt("+wWin:")' generate-linuxcnc-switchkins-remap-table.sh >/dev/null
|
||||
grep -F 'src/hal/utils/halcmd_completion.c lists the common -W/-Wn/-w/-iw forms' \
|
||||
generate-linuxcnc-switchkins-remap-table.sh >/dev/null
|
||||
grep -F 'LinuxCNC TOOL_TABLE source is not listed as tooldata' \
|
||||
generate-linuxcnc-switchkins-remap-table.sh >/dev/null
|
||||
|
||||
grep -F 'LinuxCNC source basis: switchkins/remap table validation derives M428/M429/M430' \
|
||||
check-linuxcnc-switchkins-remap-table.sh >/dev/null
|
||||
grep -F 'validate_tool_table_source_coverage_only' \
|
||||
check-linuxcnc-switchkins-remap-table.sh >/dev/null
|
||||
grep -F 'exposes TOOL_TABLE through switchkins API/web bridge' \
|
||||
check-linuxcnc-switchkins-remap-table.sh >/dev/null
|
||||
|
||||
grep -F 'int do_loadusr_cmd(const char *args[])' "$linuxcnc_root/src/hal/utils/halcmd_commands.cc" >/dev/null
|
||||
grep -F 'getopt(argc,' "$linuxcnc_root/src/hal/utils/halcmd_commands.cc" >/dev/null
|
||||
grep -F '"+wWin:"' "$linuxcnc_root/src/hal/utils/halcmd_commands.cc" >/dev/null
|
||||
grep -F -- '-Wn' "$linuxcnc_root/src/hal/utils/halcmd_completion.c" >/dev/null
|
||||
|
||||
python3 - "$linuxcnc_root" <<'PY'
|
||||
from pathlib import Path
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
|
||||
linuxcnc_root = Path(sys.argv[1])
|
||||
source_map = Path("docs/linuxcnc-switchkins-remap-source-map.md").read_text(encoding="utf-8")
|
||||
table = Path("core/src/linuxcnc_switchkins_remap_table.inc").read_text(encoding="utf-8")
|
||||
cpp_cases = Path("core/tests/linuxcnc_switchkins_remap_config_cases.inc").read_text(encoding="utf-8")
|
||||
json_cases = json.loads(Path("web/public/linuxcnc_switchkins_remap_config_cases.json").read_text(encoding="utf-8"))
|
||||
|
||||
counts = {
|
||||
"core/src/linuxcnc_switchkins_remap_table.inc": len(re.findall(r'^\s*\{"', table, re.M)),
|
||||
"core/tests/linuxcnc_switchkins_remap_config_cases.inc": len(re.findall(r'^\s*\{"', cpp_cases, re.M)),
|
||||
"web/public/linuxcnc_switchkins_remap_config_cases.json": len(json_cases),
|
||||
}
|
||||
for path, count in counts.items():
|
||||
if f"| `{path}` | {count} |" not in source_map:
|
||||
raise SystemExit(f"docs/linuxcnc-switchkins-remap-source-map.md count mismatch for {path}")
|
||||
|
||||
remap_sources = [
|
||||
path
|
||||
for path in (linuxcnc_root / "configs/sim").rglob("*remap.ngc")
|
||||
if path.name in {"428remap.ngc", "429remap.ngc", "430remap.ngc"}
|
||||
]
|
||||
remap_ini_re = re.compile(r"REMAP\s*=\s*M(428|429|430)(?:\D|$)", re.I)
|
||||
remap_inis = [
|
||||
path
|
||||
for path in (linuxcnc_root / "configs/sim").rglob("*.ini")
|
||||
if remap_ini_re.search(path.read_text(encoding="utf-8", errors="ignore"))
|
||||
]
|
||||
if f"| LinuxCNC M428/M429/M430 remap sources | {len(remap_sources)} |" not in source_map:
|
||||
raise SystemExit("docs/linuxcnc-switchkins-remap-source-map.md remap source count mismatch")
|
||||
if f"| LinuxCNC switchkins REMAP INI sources | {len(remap_inis)} |" not in source_map:
|
||||
raise SystemExit("docs/linuxcnc-switchkins-remap-source-map.md REMAP INI source count mismatch")
|
||||
|
||||
required_phrases = [
|
||||
"must not add CNC behavior",
|
||||
"must not expand the temporary smoke parser",
|
||||
"`#<kinstype>` assignments",
|
||||
"[EMCIO] TOOL_TABLE` entries are source coverage only",
|
||||
"must not become generated switchkins aliases",
|
||||
"./check-linuxcnc-switchkins-remap-source-map.sh",
|
||||
"./check-linuxcnc-switchkins-remap-table.sh linuxcnc-kinematics-source-files.txt",
|
||||
"does not interpret G-code",
|
||||
]
|
||||
for phrase in required_phrases:
|
||||
if phrase not in source_map:
|
||||
raise SystemExit(
|
||||
f"docs/linuxcnc-switchkins-remap-source-map.md is missing boundary phrase: {phrase}"
|
||||
)
|
||||
|
||||
for entry in [
|
||||
"test-native.sh",
|
||||
"test-linuxcnc-source-link.sh",
|
||||
"build-wasm.sh",
|
||||
]:
|
||||
text = Path(entry).read_text(encoding="utf-8")
|
||||
if "./check-linuxcnc-switchkins-remap-source-map.sh" not in text:
|
||||
raise SystemExit(f"{entry} must run ./check-linuxcnc-switchkins-remap-source-map.sh")
|
||||
|
||||
case_fields = {case["field"] for case in json_cases}
|
||||
source_only_field_re = re.compile(r"asset|metadata|tool|tooldata|tool_table|TOOL_TABLE", re.I)
|
||||
bad_fields = [field for field in case_fields if source_only_field_re.search(field)]
|
||||
if bad_fields:
|
||||
raise SystemExit(f"generated switchkins config cases expose source-only fields: {bad_fields}")
|
||||
api_surface_re = re.compile(r'\b(?:asset|metadata|toolData|tooldata|toolTable|tooltable|tool_table|TOOL_TABLE)\b')
|
||||
for api_path in ["web/src/wasm-core.js", "web/src/index.ts", "core/include/cnc_sim_api.h"]:
|
||||
if api_surface_re.search(Path(api_path).read_text(encoding="utf-8")):
|
||||
raise SystemExit(f"{api_path} exposes source-only switchkins inputs through API surface")
|
||||
PY
|
||||
@@ -381,6 +381,7 @@ validate_generator_cli_contract() {
|
||||
local cli_manifest_without_remap
|
||||
local cli_manifest_without_tooldata
|
||||
local cli_output_root_log
|
||||
local cli_output_file_log
|
||||
local cli_output_whitespace_log
|
||||
cli_dir=$(mktemp -d "${TMPDIR:-/tmp}/linuxcnc_switchkins_remap_cli.XXXXXX")
|
||||
trap 'rm -rf "$cli_dir"' EXIT
|
||||
@@ -411,6 +412,7 @@ validate_generator_cli_contract() {
|
||||
cli_manifest_without_remap="$cli_dir/bridgemill-manifest-without-remap.txt"
|
||||
cli_manifest_without_tooldata="$cli_dir/bridgemill-manifest-without-tooldata.txt"
|
||||
cli_output_root_log="$cli_dir/output-root.log"
|
||||
cli_output_file_log="$cli_dir/output-file.log"
|
||||
cli_output_whitespace_log="$cli_dir/output-whitespace.log"
|
||||
|
||||
if ! awk -F: -v manifest="$manifest_file" '
|
||||
@@ -769,6 +771,18 @@ validate_generator_cli_contract() {
|
||||
sed -n '1,20p' "$cli_output_root_log" >&2
|
||||
exit 1
|
||||
fi
|
||||
printf 'not a directory\n' >"$cli_dir/output-file"
|
||||
if LINUXCNC_ROOT="$linuxcnc_root" ./generate-linuxcnc-switchkins-remap-table.sh \
|
||||
--all-output-dir "$cli_dir/output-file" "$cli_manifest" >"$cli_output_file_log" 2>&1; then
|
||||
echo "switchkins remap generator accepted a file as output directory" >&2
|
||||
exit 1
|
||||
fi
|
||||
if ! grep -F "switchkins remap output path is not a directory: $cli_dir/output-file" \
|
||||
"$cli_output_file_log" >/dev/null; then
|
||||
echo "switchkins remap generator did not report file output paths clearly" >&2
|
||||
sed -n '1,20p' "$cli_output_file_log" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
LINUXCNC_ROOT="$linuxcnc_root" ./generate-linuxcnc-switchkins-remap-table.sh --all-output-dir "$cli_dir/out" "$cli_manifest"
|
||||
LINUXCNC_ROOT="$linuxcnc_root" ./generate-linuxcnc-switchkins-remap-table.sh "$cli_manifest" \
|
||||
|
||||
333
check-linuxcnc-tooldata-source-map.sh
Executable file
333
check-linuxcnc-tooldata-source-map.sh
Executable file
@@ -0,0 +1,333 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# LinuxCNC source basis: this guard ties LinuxCNC tooldata/Submakefile,
|
||||
# src/emc/tooldata sources, native/WASM manifests, and wasm-safe tooldata shims
|
||||
# to the tooldata source map. It validates source coverage only; it does not
|
||||
# add CNC behavior, expand smoke parsing, or interpret G-code.
|
||||
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
|
||||
linuxcnc_root=$(cd "$linuxcnc_root" && pwd)
|
||||
|
||||
grep -F 'LIBTOOLDATA_SRCS += emc/tooldata/tooldata_nml.cc' \
|
||||
"$linuxcnc_root/src/emc/tooldata/Submakefile" >/dev/null
|
||||
grep -F 'LIBTOOLDATA_SRCS += emc/tooldata/tooldata_mmap.cc' \
|
||||
"$linuxcnc_root/src/emc/tooldata/Submakefile" >/dev/null
|
||||
grep -F 'LIBTOOLDATA_SRCS += emc/tooldata/tooldata_common.cc' \
|
||||
"$linuxcnc_root/src/emc/tooldata/Submakefile" >/dev/null
|
||||
grep -F 'LIBTOOLDATA_SRCS += emc/tooldata/tooldata_db.cc' \
|
||||
"$linuxcnc_root/src/emc/tooldata/Submakefile" >/dev/null
|
||||
grep -F 'TOOL_MMAP_READ_SRCS = emc/tooldata/tool_mmap_read.cc' \
|
||||
"$linuxcnc_root/src/emc/tooldata/Submakefile" >/dev/null
|
||||
grep -F 'TOOL_WATCH_SRCS = emc/tooldata/tool_watch.cc' \
|
||||
"$linuxcnc_root/src/emc/tooldata/Submakefile" >/dev/null
|
||||
grep -F 'int main (int argc,char**argv)' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tool_mmap_read.cc" >/dev/null
|
||||
grep -F 'if (tool_mmap_user())' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tool_mmap_read.cc" >/dev/null
|
||||
grep -F 'idx_last = tooldata_last_index_get();' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tool_mmap_read.cc" >/dev/null
|
||||
grep -F 'if (tooldata_get(&tdata,idx) != IDX_OK)' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tool_mmap_read.cc" >/dev/null
|
||||
grep -F 'RCS_STAT_CHANNEL *stat = 0;' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tool_watch.cc" >/dev/null
|
||||
grep -F 'stat = new RCS_STAT_CHANNEL(emcFormat, "emcStatus", "xemc", nmlfile);' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tool_watch.cc" >/dev/null
|
||||
grep -F 'EMC_STAT *emcStatus = static_cast<EMC_STAT*>(stat->get_address());' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tool_watch.cc" >/dev/null
|
||||
grep -F 'emcStatus->io.tool.pocketPrepped' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tool_watch.cc" >/dev/null
|
||||
grep -F '#define TOOL_MMAP_FILENAME ".tool.mmap"' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'bool tool_mmap_is_random_toolchanger(void)' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'ans = hptr->is_random_toolchanger;' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'int tool_mmap_creator(EMC_TOOL_STAT const * ptr,int random_toolchanger)' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'static int inited=0;' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'if (inited) {' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'inited = 1;' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'hptr->is_random_toolchanger = random_toolchanger;' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'hptr->last_index = 0;' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'int tool_mmap_user()' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'fprintf(stderr,"tool_mmap_user(): tool mmap not available\n");' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'return(-1);' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'void tool_mmap_close()' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'if (!tool_mmap_base) { return; }' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'int tooldata_last_index_get(void)' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'tool_mmap_mutex_give(); return -1;' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'int tooldata_find_index_for_tool(int toolno)' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'if (toolno == -1) {tool_mmap_mutex_give(); return -1;}' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'if (!hptr->is_random_toolchanger && toolno == 0)' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'int tool_nml_register(CANON_TOOL_TABLE *tblptr)' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_nml.cc" >/dev/null
|
||||
grep -F 'int tooldata_db_init(char progname_plus_args[]' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_db.cc" >/dev/null
|
||||
grep -F '#define MAX_DB_PROGRAM_ARGS 10' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_db.cc" >/dev/null
|
||||
grep -F 'char* token = strtok_r(progname_plus_args, " ", &saveptr);' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_db.cc" >/dev/null
|
||||
grep -F 'if (child_argc >= MAX_DB_PROGRAM_ARGS)' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_db.cc" >/dev/null
|
||||
grep -F 'if (access(child_argv[0],X_OK))' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_db.cc" >/dev/null
|
||||
grep -F 'int tooldata_db_getall() {' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_db.cc" >/dev/null
|
||||
grep -F 'if (!db_live) {return -1;}' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_db.cc" >/dev/null
|
||||
grep -F 'int tooldata_db_notify(tool_notify_t ntype,' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_db.cc" >/dev/null
|
||||
grep -F 'if (!db_live) return 0;' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_db.cc" >/dev/null
|
||||
grep -F 'int tooldata_read_entry(const char *input_line)' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_common.cc" >/dev/null
|
||||
|
||||
grep -F 'LinuxCNC tooldata source map' docs/linuxcnc-tooldata-source-map.md >/dev/null
|
||||
grep -F 'must not add CNC behavior' docs/linuxcnc-tooldata-source-map.md >/dev/null
|
||||
grep -F 'must not expand the temporary smoke parser' docs/linuxcnc-tooldata-source-map.md >/dev/null
|
||||
grep -F '`src/emc/tooldata/Submakefile` selects `tooldata_mmap.cc`' \
|
||||
docs/linuxcnc-tooldata-source-map.md >/dev/null
|
||||
grep -F 'Tool table files referenced by switchkins INI files are source coverage only' \
|
||||
docs/linuxcnc-tooldata-source-map.md >/dev/null
|
||||
grep -F '`src/emc/tooldata/tool_mmap_read.cc` is the mmap tool table reader utility' \
|
||||
docs/linuxcnc-tooldata-source-map.md >/dev/null
|
||||
grep -F '`tool_mmap_user()`, `tooldata_last_index_get()`, and `tooldata_get()`' \
|
||||
docs/linuxcnc-tooldata-source-map.md >/dev/null
|
||||
grep -F "single-creator process boundary from" docs/linuxcnc-tooldata-source-map.md >/dev/null
|
||||
grep -F "including after" docs/linuxcnc-tooldata-source-map.md >/dev/null
|
||||
grep -F '`src/emc/tooldata/tool_watch.cc` is the NML/mmap tool table watcher utility' \
|
||||
docs/linuxcnc-tooldata-source-map.md >/dev/null
|
||||
grep -F '`EMC_STAT::io.tool` fields through `RCS_STAT_CHANNEL`' \
|
||||
docs/linuxcnc-tooldata-source-map.md >/dev/null
|
||||
|
||||
grep -F 'tooldata:src/emc/tooldata/tooldata_common.cc:shared tool table parser/format logic' \
|
||||
linuxcnc-rs274-source-files.txt >/dev/null
|
||||
grep -F 'tooldata:src/emc/tooldata/tooldata_mmap.cc:native mmap implementation; replace for wasm' \
|
||||
linuxcnc-rs274-source-files.txt >/dev/null
|
||||
grep -F 'tooldata:src/emc/tooldata/tooldata_db.cc:external database integration; exclude from wasm core' \
|
||||
linuxcnc-rs274-source-files.txt >/dev/null
|
||||
grep -F 'tooldata:src/emc/tooldata/tooldata_nml.cc:NML tool table backend selected by LinuxCNC TOOL_NML_FLAG' \
|
||||
linuxcnc-rs274-source-files.txt >/dev/null
|
||||
grep -F 'header:src/emc/tooldata/tooldata.hh:LinuxCNC tooldata declarations used by RS274 and wasm-safe tooldata shims' \
|
||||
linuxcnc-rs274-source-files.txt >/dev/null
|
||||
grep -F 'metadata:src/emc/tooldata/Submakefile:LinuxCNC tooldata build metadata defining mmap and NML backend source selection' \
|
||||
linuxcnc-rs274-source-files.txt >/dev/null
|
||||
grep -F 'core:src/emc/tooldata/tooldata_common.cc:shared tool table parser/format logic linked with wasm-safe mmap backend' \
|
||||
linuxcnc-rs274-wasm-source-files.txt >/dev/null
|
||||
grep -F 'blocked:src/emc/tooldata/tooldata_mmap.cc:native mmap implementation' \
|
||||
linuxcnc-rs274-wasm-source-files.txt >/dev/null
|
||||
grep -F 'metadata:src/emc/tooldata/tooldata_db.cc:source basis for wasm-safe tooldata runtime export shim' \
|
||||
linuxcnc-rs274-wasm-source-files.txt >/dev/null
|
||||
grep -F 'metadata:src/emc/tooldata/tooldata_nml.cc:source basis for wasm-safe tooldata runtime NML export shim' \
|
||||
linuxcnc-rs274-wasm-source-files.txt >/dev/null
|
||||
|
||||
grep -F 'LinuxCNC source basis: src/emc/tooldata/tooldata_mmap.cc provides these' \
|
||||
core/wasm_shims/tooldata/tooldata_mmap_backend.cc >/dev/null
|
||||
grep -F 'bool mmap_created = false;' \
|
||||
core/wasm_shims/tooldata/tooldata_mmap_backend.cc >/dev/null
|
||||
grep -F 'bool mmap_random_toolchanger = false;' \
|
||||
core/wasm_shims/tooldata/tooldata_mmap_backend.cc >/dev/null
|
||||
grep -F 'bool mmap_creator_called = false;' \
|
||||
core/wasm_shims/tooldata/tooldata_mmap_backend.cc >/dev/null
|
||||
grep -F 'int tool_mmap_creator(EMC_TOOL_STAT const *ptr, int random_toolchanger)' \
|
||||
core/wasm_shims/tooldata/tooldata_mmap_backend.cc >/dev/null
|
||||
grep -F 'Error: tool_mmap_creator already called BYE' \
|
||||
core/wasm_shims/tooldata/tooldata_mmap_backend.cc >/dev/null
|
||||
grep -F 'mmap_created = true;' \
|
||||
core/wasm_shims/tooldata/tooldata_mmap_backend.cc >/dev/null
|
||||
grep -F 'mmap_random_toolchanger = random_toolchanger;' \
|
||||
core/wasm_shims/tooldata/tooldata_mmap_backend.cc >/dev/null
|
||||
grep -F 'last_index = 0;' \
|
||||
core/wasm_shims/tooldata/tooldata_mmap_backend.cc >/dev/null
|
||||
grep -F 'int tool_mmap_user(void)' \
|
||||
core/wasm_shims/tooldata/tooldata_mmap_backend.cc >/dev/null
|
||||
grep -F 'tool_mmap_user(): tool mmap not available' \
|
||||
core/wasm_shims/tooldata/tooldata_mmap_backend.cc >/dev/null
|
||||
grep -F 'void tool_mmap_close(void)' \
|
||||
core/wasm_shims/tooldata/tooldata_mmap_backend.cc >/dev/null
|
||||
grep -F 'mmap_created = false;' \
|
||||
core/wasm_shims/tooldata/tooldata_mmap_backend.cc >/dev/null
|
||||
grep -F 'bool tool_mmap_is_random_toolchanger(void)' \
|
||||
core/wasm_shims/tooldata/tooldata_mmap_backend.cc >/dev/null
|
||||
grep -F 'return mmap_random_toolchanger;' \
|
||||
core/wasm_shims/tooldata/tooldata_mmap_backend.cc >/dev/null
|
||||
grep -F 'int tooldata_last_index_get(void)' \
|
||||
core/wasm_shims/tooldata/tooldata_mmap_backend.cc >/dev/null
|
||||
grep -F 'return -1;' \
|
||||
core/wasm_shims/tooldata/tooldata_mmap_backend.cc >/dev/null
|
||||
grep -F 'LinuxCNC source basis: src/emc/tooldata/tooldata_nml.cc and tooldata_db.cc' \
|
||||
core/wasm_shims/tooldata/tooldata_runtime_stubs.cc >/dev/null
|
||||
grep -F 'constexpr int MAX_DB_PROGRAM_ARGS = 10;' \
|
||||
core/wasm_shims/tooldata/tooldata_runtime_stubs.cc >/dev/null
|
||||
grep -F 'strtok_r(progname_plus_args, " ", &saveptr)' \
|
||||
core/wasm_shims/tooldata/tooldata_runtime_stubs.cc >/dev/null
|
||||
grep -F 'argc exceeds MAX_DB_PROGRAM_ARGS=%d' \
|
||||
core/wasm_shims/tooldata/tooldata_runtime_stubs.cc >/dev/null
|
||||
grep -F 'access(program, X_OK) != 0' \
|
||||
core/wasm_shims/tooldata/tooldata_runtime_stubs.cc >/dev/null
|
||||
grep -F 'returns 0 when' core/wasm_shims/tooldata/tooldata_runtime_stubs.cc >/dev/null
|
||||
grep -F 'LinuxCNC source basis: src/emc/tooldata/tooldata_common.cc provides' \
|
||||
core/wasm_shims/tooldata/tooldata_common_probe_main.cc >/dev/null
|
||||
grep -F 'LinuxCNC source basis: src/emc/tooldata/tooldata_mmap.cc, tooldata_nml.cc,' \
|
||||
core/wasm_shims/tooldata/tooldata_probe_main.cc >/dev/null
|
||||
grep -F 'tooldata_db_notify() returns 0 without side effects while db_live is' \
|
||||
core/wasm_shims/tooldata/tooldata_probe_main.cc >/dev/null
|
||||
grep -F 'tooldata_db_init(missing_db_program_with_arg.data(), 1) != -1' \
|
||||
core/wasm_shims/tooldata/tooldata_probe_main.cc >/dev/null
|
||||
grep -F 'missing_db_program_with_arg[separator] != 0' \
|
||||
core/wasm_shims/tooldata/tooldata_probe_main.cc >/dev/null
|
||||
grep -F 'tooldata_db_init(too_many_db_args, 1) != -1' \
|
||||
core/wasm_shims/tooldata/tooldata_probe_main.cc >/dev/null
|
||||
grep -F 'tooldata_db_init(non_db_program, 1) != -1' \
|
||||
core/wasm_shims/tooldata/tooldata_probe_main.cc >/dev/null
|
||||
grep -F 'tool_mmap_creator(nullptr, 1);' \
|
||||
core/wasm_shims/tooldata/tooldata_probe_main.cc >/dev/null
|
||||
grep -F 'WEXITSTATUS(recreate_status) == 0' \
|
||||
core/wasm_shims/tooldata/tooldata_probe_main.cc >/dev/null
|
||||
grep -F 'core/wasm_shims/tooldata/tooldata_mmap_backend.cc' docs/linuxcnc-wasm-shims-source-map.md >/dev/null
|
||||
grep -F 'core/wasm_shims/tooldata/tooldata_runtime_stubs.cc' docs/linuxcnc-wasm-shims-source-map.md >/dev/null
|
||||
|
||||
grep -F 'LinuxCNC source basis: this link probe runs the wasm-safe tooldata shim' \
|
||||
test-linuxcnc-wasm-tooldata-link.sh >/dev/null
|
||||
grep -F 'LinuxCNC source basis: this link probe runs tooldata_common through the' \
|
||||
test-linuxcnc-wasm-tooldata-common-link.sh >/dev/null
|
||||
grep -F 'LinuxCNC source basis: this symbol probe compares the wasm mmap backend shim' \
|
||||
test-linuxcnc-wasm-tooldata-mmap-symbols.sh >/dev/null
|
||||
grep -F 'LinuxCNC source basis: this probe compares wasm-safe tooldata runtime stubs' \
|
||||
test-linuxcnc-wasm-tooldata-runtime-symbols.sh >/dev/null
|
||||
grep -F '!!!!db_init: argc exceeds MAX_DB_PROGRAM_ARGS=10' \
|
||||
test-linuxcnc-wasm-tooldata-link.sh >/dev/null
|
||||
grep -F 'not executable' test-linuxcnc-wasm-tooldata-link.sh >/dev/null
|
||||
grep -F 'Error: tool_mmap_creator already called BYE' \
|
||||
test-linuxcnc-wasm-tooldata-link.sh >/dev/null
|
||||
grep -F 'run_parallel_wasm_probe "LinuxCNC wasm tooldata shim link probe" ./test-linuxcnc-wasm-tooldata-link.sh' \
|
||||
build-wasm.sh >/dev/null
|
||||
grep -F 'run_parallel_wasm_probe "LinuxCNC wasm tooldata_common link probe" ./test-linuxcnc-wasm-tooldata-common-link.sh' \
|
||||
build-wasm.sh >/dev/null
|
||||
grep -F 'run_parallel_wasm_probe "LinuxCNC wasm tooldata_mmap symbol probe" ./test-linuxcnc-wasm-tooldata-mmap-symbols.sh' \
|
||||
build-wasm.sh >/dev/null
|
||||
grep -F 'run_parallel_wasm_probe "LinuxCNC wasm tooldata runtime symbol probe" ./test-linuxcnc-wasm-tooldata-runtime-symbols.sh' \
|
||||
build-wasm.sh >/dev/null
|
||||
|
||||
python3 - <<'PY'
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
|
||||
doc = Path("docs/linuxcnc-tooldata-source-map.md").read_text(encoding="utf-8")
|
||||
build_wasm_lines = Path("build-wasm.sh").read_text(encoding="utf-8").splitlines()
|
||||
native_tooldata = subprocess.check_output(
|
||||
["./list-linuxcnc-source-manifest-sources.sh", "linuxcnc-rs274-source-files.txt", "tooldata"],
|
||||
text=True,
|
||||
).splitlines()
|
||||
expected_native = [
|
||||
"src/emc/tooldata/tooldata_common.cc",
|
||||
"src/emc/tooldata/tooldata_mmap.cc",
|
||||
"src/emc/tooldata/tooldata_db.cc",
|
||||
"src/emc/tooldata/tooldata_nml.cc",
|
||||
"src/emc/tooldata/tool_mmap_read.cc",
|
||||
"src/emc/tooldata/tool_watch.cc",
|
||||
]
|
||||
for source in expected_native:
|
||||
if source not in native_tooldata:
|
||||
raise SystemExit(f"native RS274 manifest missing LinuxCNC tooldata source: {source}")
|
||||
|
||||
kin_tooldata = subprocess.check_output(
|
||||
["./list-linuxcnc-kinematics-manifest-sources.sh", "linuxcnc-kinematics-source-files.txt", "tooldata"],
|
||||
text=True,
|
||||
).splitlines()
|
||||
if len([source for source in kin_tooldata if source.endswith(".tbl")]) != 10:
|
||||
raise SystemExit("kinematics manifest must track exactly 10 LinuxCNC TOOL_TABLE sources")
|
||||
|
||||
positions = {}
|
||||
for index, line in enumerate(build_wasm_lines, start=1):
|
||||
if 'run_parallel_wasm_probe "LinuxCNC wasm tooldata shim link probe"' in line:
|
||||
positions["tooldata_link"] = index
|
||||
if 'run_parallel_wasm_probe "LinuxCNC wasm tooldata_common link probe"' in line:
|
||||
positions["tooldata_common"] = index
|
||||
if 'run_parallel_wasm_probe "LinuxCNC wasm tooldata_mmap symbol probe"' in line:
|
||||
positions["tooldata_mmap"] = index
|
||||
if 'run_parallel_wasm_probe "LinuxCNC wasm tooldata runtime symbol probe"' in line:
|
||||
positions["tooldata_runtime"] = index
|
||||
if "cp build/wasm/cnc_sim.js web/public/cnc_sim.js" in line:
|
||||
positions["copy_js"] = index
|
||||
if "cp build/wasm/cnc_sim.wasm web/public/cnc_sim.wasm" in line:
|
||||
positions["copy_wasm"] = index
|
||||
|
||||
missing = [
|
||||
name for name in (
|
||||
"tooldata_link",
|
||||
"tooldata_common",
|
||||
"tooldata_mmap",
|
||||
"tooldata_runtime",
|
||||
"copy_js",
|
||||
"copy_wasm",
|
||||
)
|
||||
if name not in positions
|
||||
]
|
||||
if missing:
|
||||
raise SystemExit(f"build-wasm.sh missing tooldata/copy ordering anchor: {', '.join(missing)}")
|
||||
for probe in ("tooldata_link", "tooldata_common", "tooldata_mmap", "tooldata_runtime"):
|
||||
if not (positions[probe] < positions["copy_js"] and positions[probe] < positions["copy_wasm"]):
|
||||
raise SystemExit("build-wasm.sh must run all tooldata link/symbol probes before copying browser artifacts")
|
||||
|
||||
for path in [
|
||||
"core/wasm_shims/tooldata/tooldata_mmap_backend.cc",
|
||||
"core/wasm_shims/tooldata/tooldata_runtime_stubs.cc",
|
||||
"test-linuxcnc-wasm-tooldata-link.sh",
|
||||
"test-linuxcnc-wasm-tooldata-common-link.sh",
|
||||
"test-linuxcnc-wasm-tooldata-mmap-symbols.sh",
|
||||
"test-linuxcnc-wasm-tooldata-runtime-symbols.sh",
|
||||
]:
|
||||
if path not in doc:
|
||||
raise SystemExit(f"docs/linuxcnc-tooldata-source-map.md missing coverage path: {path}")
|
||||
|
||||
for phrase in [
|
||||
"must not add CNC behavior",
|
||||
"must not expand the temporary smoke parser",
|
||||
"source coverage only",
|
||||
"must not become browser API fields",
|
||||
"WASM-safe tooldata shims must preserve the LinuxCNC export surface",
|
||||
"must keep external DB services unavailable",
|
||||
"must not fork, exec, poll",
|
||||
"MAX_DB_PROGRAM_ARGS=10",
|
||||
"`strtok_r()` argument splitting",
|
||||
"access(..., X_OK)",
|
||||
"mmap tool table reader utility",
|
||||
"NML/mmap tool table watcher utility",
|
||||
"mmap creator/user/close lifecycle",
|
||||
"random-toolchanger flag",
|
||||
"last-index unavailable return",
|
||||
"in-memory replacement for native mmap",
|
||||
"inactive-DB return values",
|
||||
"./check-linuxcnc-tooldata-source-map.sh",
|
||||
"does not interpret G-code",
|
||||
]:
|
||||
if phrase not in doc:
|
||||
raise SystemExit(f"docs/linuxcnc-tooldata-source-map.md missing boundary phrase: {phrase}")
|
||||
|
||||
for entry in [
|
||||
"test-native.sh",
|
||||
"test-linuxcnc-source-link.sh",
|
||||
"build-wasm.sh",
|
||||
]:
|
||||
text = Path(entry).read_text(encoding="utf-8")
|
||||
if "./check-linuxcnc-tooldata-source-map.sh" not in text:
|
||||
raise SystemExit(f"{entry} must run ./check-linuxcnc-tooldata-source-map.sh")
|
||||
PY
|
||||
190
check-linuxcnc-wasm-blockers-source-map.sh
Executable file
190
check-linuxcnc-wasm-blockers-source-map.sh
Executable file
@@ -0,0 +1,190 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# LinuxCNC source basis: this guard ties the documented WASM blocker map to
|
||||
# LinuxCNC RS274/Python/remap/tooldata sources, the rs274 WASM manifest, and
|
||||
# wasm-safe shim replacement sources. It validates source coverage only; it
|
||||
# does not add CNC behavior, expand smoke parsing, or interpret G-code.
|
||||
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
|
||||
manifest=${1:-linuxcnc-rs274-wasm-source-files.txt}
|
||||
|
||||
LINUXCNC_ROOT="$linuxcnc_root" ./check-linuxcnc-inputs-cached.sh "$manifest"
|
||||
linuxcnc_root=$(cd "$linuxcnc_root" && pwd)
|
||||
|
||||
grep -F 'LinuxCNC source basis: this blocker scan is constrained to the RS274/WASM' \
|
||||
analyze-linuxcnc-wasm-blockers.sh >/dev/null
|
||||
grep -F 'blocked replacement is not in wasm shim build set' \
|
||||
analyze-linuxcnc-wasm-blockers.sh >/dev/null
|
||||
grep -F 'shim_source_output=$(./list-linuxcnc-wasm-safe-shims.sh)' \
|
||||
analyze-linuxcnc-wasm-blockers.sh >/dev/null
|
||||
grep -F 'LinuxCNC source basis: this guardrail locks the blocker categories reported' \
|
||||
test-linuxcnc-wasm-blockers.sh >/dev/null
|
||||
grep -F 'Cache wasm blocker analyzer output' docs/linuxcnc-source-policy.md >/dev/null
|
||||
|
||||
grep -F '#include <Python.h>' "$linuxcnc_root/src/emc/rs274ngc/gcodemodule.cc" >/dev/null
|
||||
grep -F 'PyInit_gcode' "$linuxcnc_root/src/emc/rs274ngc/gcodemodule.cc" >/dev/null
|
||||
grep -F '#include <boost/python/module.hpp>' "$linuxcnc_root/src/emc/rs274ngc/interpmodule.cc" >/dev/null
|
||||
grep -F '#include "pythonplugin/python_plugin.hh"' "$linuxcnc_root/src/emc/rs274ngc/interp_python.cc" >/dev/null
|
||||
grep -F 'dlopen' "$linuxcnc_root/src/emc/rs274ngc/interp_base.cc" >/dev/null
|
||||
grep -F 'opendir(direct)' "$linuxcnc_root/src/emc/rs274ngc/interp_o_word.cc" >/dev/null
|
||||
grep -F 'readdir(aDir)' "$linuxcnc_root/src/emc/rs274ngc/interp_o_word.cc" >/dev/null
|
||||
grep -F 'std::string tempfile = std::string(filename) + ".new";' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F '+ RS274NGC_PARAMETER_FILE_BACKUP_SUFFIX;' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'unlink(bakfile.c_str());' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'if(link(filename, bakfile.c_str()) < 0)' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'if(rename(tempfile.c_str(), filename) < 0)' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F '#define TOOL_MMAP_FILENAME ".tool.mmap"' "$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'int tool_mmap_creator(' "$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
|
||||
python3 - "$linuxcnc_root" "$manifest" <<'PY'
|
||||
from pathlib import Path
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
linuxcnc_root = Path(sys.argv[1])
|
||||
manifest = Path(sys.argv[2])
|
||||
source_map = Path("docs/linuxcnc-wasm-blockers-source-map.md").read_text(encoding="utf-8")
|
||||
manifest_lines = [
|
||||
line for line in manifest.read_text(encoding="utf-8").splitlines()
|
||||
if line and not line.startswith("#")
|
||||
]
|
||||
manifest_counts = {"core": 0, "blocked": 0, "header": 0, "blocked-header": 0, "metadata": 0}
|
||||
for line in manifest_lines:
|
||||
group = line.split(":", 1)[0]
|
||||
if group not in manifest_counts:
|
||||
raise SystemExit(f"unexpected WASM manifest group in blocker source map guard: {group}")
|
||||
manifest_counts[group] += 1
|
||||
for group, count in manifest_counts.items():
|
||||
if f"| `{group}` | {count} |" not in source_map:
|
||||
raise SystemExit(f"docs/linuxcnc-wasm-blockers-source-map.md count mismatch for {group}")
|
||||
|
||||
output = subprocess.check_output(
|
||||
["./analyze-linuxcnc-wasm-blockers.sh", str(manifest)],
|
||||
text=True,
|
||||
env={"LINUXCNC_ROOT": str(linuxcnc_root)},
|
||||
)
|
||||
sections = {}
|
||||
current = None
|
||||
for line in output.splitlines():
|
||||
if line.startswith("[") and line.endswith("]"):
|
||||
current = line[1:-1]
|
||||
sections[current] = []
|
||||
elif current and line:
|
||||
sections[current].append(line)
|
||||
|
||||
expected_counts = {
|
||||
"manifest-core": "core=26",
|
||||
"manifest-blocked": "blocked=9",
|
||||
"python": 8,
|
||||
"tooldata": 1,
|
||||
"native-backend": 1,
|
||||
"native-fs": 1,
|
||||
"blocked-replacements": 9,
|
||||
"core-python-shimmed": 6,
|
||||
"core-dlopen-shimmed": 1,
|
||||
"core-tooldata-shimmed": 1,
|
||||
"core-tooldata-users-shimmed": 2,
|
||||
"core-native-fs-shimmed": 16,
|
||||
}
|
||||
manifest_section = sections.get("manifest", [])
|
||||
if expected_counts["manifest-core"] not in manifest_section:
|
||||
raise SystemExit("WASM blocker analyzer core count changed")
|
||||
if expected_counts["manifest-blocked"] not in manifest_section:
|
||||
raise SystemExit("WASM blocker analyzer blocked count changed")
|
||||
for section, count in expected_counts.items():
|
||||
if section.startswith("manifest-"):
|
||||
continue
|
||||
entries = [entry for entry in sections.get(section, []) if entry != "(none)"]
|
||||
if len(entries) != count:
|
||||
raise SystemExit(f"WASM blocker analyzer section {section} count changed: {len(entries)}")
|
||||
if f"| `{section}` | {count} |" not in source_map:
|
||||
raise SystemExit(f"docs/linuxcnc-wasm-blockers-source-map.md analyzer count mismatch for {section}")
|
||||
if sections.get("dlopen") != ["(none)"]:
|
||||
raise SystemExit("blocked dlopen section is no longer empty")
|
||||
if sections.get("tooldata-users") != ["(none)"]:
|
||||
raise SystemExit("blocked tooldata-users section is no longer empty")
|
||||
|
||||
shim_paths = set(Path(line).as_posix() for line in subprocess.check_output(
|
||||
["./list-linuxcnc-wasm-safe-shims.sh"],
|
||||
text=True,
|
||||
).splitlines() if line)
|
||||
required_tracked_entries = [
|
||||
"src/emc/rs274ngc/interp_base.cc -> core/wasm_shims/dlfcn.cc",
|
||||
"src/emc/rs274ngc/gcodemodule.cc",
|
||||
"src/emc/rs274ngc/interpmodule.cc",
|
||||
"src/emc/tooldata/tooldata_mmap.cc",
|
||||
"src/emc/rs274ngc/interp_base.cc",
|
||||
"src/emc/rs274ngc/interp_o_word.cc",
|
||||
"src/emc/rs274ngc/rs274ngc_pre.cc",
|
||||
]
|
||||
required_replacements = [
|
||||
"src/emc/rs274ngc/canonmodule.cc -> core/wasm_shims/linuxcnc_runtime_shim.cc",
|
||||
"src/emc/rs274ngc/gcodemodule.cc -> core/wasm_shims/linuxcnc_runtime_shim.cc",
|
||||
"src/emc/rs274ngc/interpmodule.cc -> core/wasm_shims/linuxcnc_runtime_shim.cc",
|
||||
"src/emc/rs274ngc/pyarrays.cc -> core/wasm_shims/python_c_api_shim.cc",
|
||||
"src/emc/rs274ngc/pyblock.cc -> core/wasm_shims/python_c_api_shim.cc",
|
||||
"src/emc/rs274ngc/pyemctypes.cc -> core/wasm_shims/python_c_api_shim.cc",
|
||||
"src/emc/rs274ngc/pyinterp1.cc -> core/wasm_shims/python_c_api_shim.cc",
|
||||
"src/emc/rs274ngc/pyparamclass.cc -> core/wasm_shims/python_c_api_shim.cc",
|
||||
"src/emc/tooldata/tooldata_mmap.cc -> core/wasm_shims/tooldata/tooldata_mmap_backend.cc",
|
||||
]
|
||||
for entry in required_tracked_entries:
|
||||
if " -> " in entry:
|
||||
source, shim = entry.split(" -> ", 1)
|
||||
if source not in sections.get("core-dlopen-shimmed", []):
|
||||
raise SystemExit(f"WASM blocker analyzer output missing core dlopen shimmed source: {source}")
|
||||
if shim not in shim_paths:
|
||||
raise SystemExit(f"WASM blocker analyzer core dlopen shim is absent from wasm-safe shim set: {shim}")
|
||||
elif entry not in output:
|
||||
raise SystemExit(f"WASM blocker analyzer output missing required entry: {entry}")
|
||||
if entry not in source_map:
|
||||
raise SystemExit(f"docs/linuxcnc-wasm-blockers-source-map.md missing required entry: {entry}")
|
||||
replacement_entries = [entry for entry in sections.get("blocked-replacements", []) if entry != "(none)"]
|
||||
if replacement_entries != required_replacements:
|
||||
raise SystemExit(f"WASM blocker replacement set changed: {replacement_entries}")
|
||||
if "Required replacement set:" not in source_map:
|
||||
raise SystemExit("docs/linuxcnc-wasm-blockers-source-map.md must document the complete replacement set")
|
||||
for entry in required_replacements:
|
||||
if entry not in source_map:
|
||||
raise SystemExit(f"docs/linuxcnc-wasm-blockers-source-map.md missing required replacement: {entry}")
|
||||
|
||||
for replacement in re.findall(r"-> (core/wasm_shims/[^\s]+)", output):
|
||||
if replacement not in shim_paths:
|
||||
raise SystemExit(f"blocked replacement is absent from wasm-safe shim set: {replacement}")
|
||||
for phrase in [
|
||||
"does not add CNC behavior",
|
||||
"must not become smoke parser behavior",
|
||||
"blocked `dlopen` and blocked tooldata-users remain empty",
|
||||
'parameter-file replacement through `filename + ".new"`',
|
||||
"O-word lookup and parameter-file replacement",
|
||||
"Python/Boost.Python remap paths remain tracked blockers",
|
||||
"./check-linuxcnc-wasm-blockers-source-map.sh",
|
||||
"does not interpret G-code",
|
||||
]:
|
||||
if phrase not in source_map:
|
||||
raise SystemExit(f"docs/linuxcnc-wasm-blockers-source-map.md missing boundary phrase: {phrase}")
|
||||
|
||||
for entry in [
|
||||
"test-native.sh",
|
||||
"test-linuxcnc-source-link.sh",
|
||||
"build-wasm.sh",
|
||||
]:
|
||||
text = Path(entry).read_text(encoding="utf-8")
|
||||
if "./check-linuxcnc-wasm-blockers-source-map.sh" not in text:
|
||||
raise SystemExit(f"{entry} must run ./check-linuxcnc-wasm-blockers-source-map.sh")
|
||||
for entry in [
|
||||
"test-native.sh",
|
||||
"test-linuxcnc-source-link.sh",
|
||||
]:
|
||||
text = Path(entry).read_text(encoding="utf-8")
|
||||
if "CNC_SIM_WASM_BLOCKERS_SELF_CHECKS=1" not in text:
|
||||
raise SystemExit(f"{entry} must run wasm blocker analyzer self-checks")
|
||||
PY
|
||||
499
check-linuxcnc-wasm-shims-source-map.sh
Executable file
499
check-linuxcnc-wasm-shims-source-map.sh
Executable file
@@ -0,0 +1,499 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# LinuxCNC source basis: this guard ties the documented wasm-safe shim map to
|
||||
# the linuxcnc_wasm_safe_probe_shims CMake set, the RS274/WASM source manifest,
|
||||
# and the LinuxCNC sources each shim cites. It validates source coverage only;
|
||||
# it does not add CNC behavior, expand smoke parsing, or interpret G-code.
|
||||
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
|
||||
manifest=${1:-linuxcnc-rs274-wasm-source-files.txt}
|
||||
|
||||
LINUXCNC_ROOT="$linuxcnc_root" ./check-linuxcnc-inputs-cached.sh "$manifest"
|
||||
linuxcnc_root=$(cd "$linuxcnc_root" && pwd)
|
||||
|
||||
grep -F 'LinuxCNC source basis: wasm-safe shim probe sources are limited to the' \
|
||||
list-linuxcnc-wasm-safe-shims.sh >/dev/null
|
||||
grep -F 'set(linuxcnc_wasm_safe_probe_shims' core/CMakeLists.txt >/dev/null
|
||||
grep -F 'LinuxCNC source basis: this guard ties the documented WASM blocker map' \
|
||||
check-linuxcnc-wasm-blockers-source-map.sh >/dev/null
|
||||
|
||||
grep -F 'dlopen(NULL, RTLD_GLOBAL);' "$linuxcnc_root/src/emc/rs274ngc/interp_base.cc" >/dev/null
|
||||
grep -F 'interp_lib = dlopen(interp_path, RTLD_NOW);' "$linuxcnc_root/src/emc/rs274ngc/interp_base.cc" >/dev/null
|
||||
grep -F 'Constructor constructor = (Constructor)dlsym(interp_lib, "makeInterp");' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/interp_base.cc" >/dev/null
|
||||
grep -F 'dlerror()' "$linuxcnc_root/src/emc/rs274ngc/interp_base.cc" >/dev/null
|
||||
grep -F '#include "libintl.h"' "$linuxcnc_root/src/emc/rs274ngc/interp_internal.hh" >/dev/null
|
||||
grep -F '#define _(s) gettext(s)' "$linuxcnc_root/src/emc/rs274ngc/interp_internal.hh" >/dev/null
|
||||
grep -F 'CHKS((!_readers[(int)' "$linuxcnc_root/src/emc/rs274ngc/interp_internal.cc" >/dev/null
|
||||
grep -F 'Cannot use polar coordinate on a machine lacking X or Y axes' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/interp_internal.cc" >/dev/null
|
||||
grep -F 'int _task = 0;' "$linuxcnc_root/src/emc/rs274ngc/gcodemodule.cc" >/dev/null
|
||||
grep -F 'int _task = 1;' "$linuxcnc_root/src/emc/task/emctaskmain.cc" >/dev/null
|
||||
grep -F '{ "interpreter", PyInit_interpreter },' "$linuxcnc_root/src/emc/rs274ngc/gcodemodule.cc" >/dev/null
|
||||
grep -F '{ "emccanon", PyInit_emccanon },' "$linuxcnc_root/src/emc/rs274ngc/gcodemodule.cc" >/dev/null
|
||||
grep -F 'struct _inittab builtin_modules[]' "$linuxcnc_root/src/emc/task/taskclass.cc" >/dev/null
|
||||
grep -F 'int Interp::fetch_hal_param(' "$linuxcnc_root/src/emc/rs274ngc/interp_namedparams.cc" >/dev/null
|
||||
grep -F 'hal_get_pin_value_by_name(hal_name, &type, &ptr, &conn)' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/interp_namedparams.cc" >/dev/null
|
||||
grep -F 'hal_get_signal_value_by_name(hal_name, &type, &ptr, &conn)' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/interp_namedparams.cc" >/dev/null
|
||||
grep -F 'hal_get_param_value_by_name(hal_name, &type, &ptr)' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/interp_namedparams.cc" >/dev/null
|
||||
grep -F 'HAL_TYPE_UNINITIALIZED = 0,' "$linuxcnc_root/include/hal.h" >/dev/null
|
||||
grep -F 'extern int hal_get_pin_value_by_name(' "$linuxcnc_root/include/hal.h" >/dev/null
|
||||
grep -F 'extern int hal_get_signal_value_by_name(' "$linuxcnc_root/include/hal.h" >/dev/null
|
||||
grep -F 'extern int hal_get_param_value_by_name(' "$linuxcnc_root/include/hal.h" >/dev/null
|
||||
grep -F 'int hal_get_pin_value_by_name(' "$linuxcnc_root/src/hal/hal_lib.c" >/dev/null
|
||||
grep -F 'int hal_get_signal_value_by_name(' "$linuxcnc_root/src/hal/hal_lib.c" >/dev/null
|
||||
grep -F 'int hal_get_param_value_by_name(' "$linuxcnc_root/src/hal/hal_lib.c" >/dev/null
|
||||
grep -F 'wordexp(basename, &exp_result, 0);' "$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'wordexp(settings->program_prefix, &exp_result, 0);' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'wordexp(settings->subroutines[dct], &exp_result, 0);' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'wordfree(&exp_result);' "$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F '#include "nml_intf/emc_nml.hh"' "$linuxcnc_root/src/emc/sai/dummyemcstat.cc" >/dev/null
|
||||
grep -F 'EMC_STAT *emcStatus = new EMC_STAT;' "$linuxcnc_root/src/emc/sai/dummyemcstat.cc" >/dev/null
|
||||
grep -F 'int NMLmsg::automatically_clear = 1;' \
|
||||
"$linuxcnc_root/src/libnml/nml/nmlmsg.cc" >/dev/null
|
||||
grep -F 'NMLmsg::NMLmsg' "$linuxcnc_root/src/libnml/nml/nmlmsg.cc" >/dev/null
|
||||
grep -F 'void NMLmsg::clear()' "$linuxcnc_root/src/libnml/nml/nmlmsg.cc" >/dev/null
|
||||
grep -F 'memset((void *) this, 0, size);' \
|
||||
"$linuxcnc_root/src/libnml/nml/nmlmsg.cc" >/dev/null
|
||||
grep -F 'RCS_STAT_MSG::RCS_STAT_MSG' "$linuxcnc_root/src/libnml/nml/stat_msg.cc" >/dev/null
|
||||
grep -F 'command_type = -1;' "$linuxcnc_root/src/libnml/nml/stat_msg.cc" >/dev/null
|
||||
grep -F 'echo_serial_number = -1;' "$linuxcnc_root/src/libnml/nml/stat_msg.cc" >/dev/null
|
||||
grep -F 'status = RCS_STATUS::UNINITIALIZED;' "$linuxcnc_root/src/libnml/nml/stat_msg.cc" >/dev/null
|
||||
grep -F '_state = -1;' "$linuxcnc_root/src/libnml/nml/stat_msg.cc" >/dev/null
|
||||
grep -F 'extern int set_print_rcs_error_info(const char *file, int line);' \
|
||||
"$linuxcnc_root/src/libnml/rcs/rcs_print.hh" >/dev/null
|
||||
grep -F 'extern int print_rcs_error_new(const char *_fmt, ...)' \
|
||||
"$linuxcnc_root/src/libnml/rcs/rcs_print.hh" >/dev/null
|
||||
grep -F '#define rcs_print_error set_print_rcs_error_info( __FILE__, __LINE__); print_rcs_error_new' \
|
||||
"$linuxcnc_root/src/libnml/rcs/rcs_print.hh" >/dev/null
|
||||
grep -F 'int set_print_rcs_error_info(const char *file, int line)' \
|
||||
"$linuxcnc_root/src/libnml/rcs/rcs_print.cc" >/dev/null
|
||||
grep -F 'print_rcs_error_new' "$linuxcnc_root/src/libnml/rcs/rcs_print.cc" >/dev/null
|
||||
grep -F 'retval = rcs_vprint(_fmt, args, 1);' \
|
||||
"$linuxcnc_root/src/libnml/rcs/rcs_print.cc" >/dev/null
|
||||
grep -F 'extern int rtapi_snprintf(char *buf, unsigned long int size,' \
|
||||
"$linuxcnc_root/src/rtapi/rtapi.h" >/dev/null
|
||||
grep -F 'extern int rtapi_vsnprintf(char *buf, unsigned long size,' \
|
||||
"$linuxcnc_root/src/rtapi/rtapi.h" >/dev/null
|
||||
grep -F 'int rtapi_snprintf(char *buffer, unsigned long int size, const char *msg, ...) {' \
|
||||
"$linuxcnc_root/src/rtapi/uspace_common.h" >/dev/null
|
||||
grep -F 'result = vsnprintf(buffer, size, msg, args);' \
|
||||
"$linuxcnc_root/src/rtapi/uspace_common.h" >/dev/null
|
||||
grep -F 'int rtapi_vsnprintf(char *buffer, unsigned long int size, const char *fmt,' \
|
||||
"$linuxcnc_root/src/rtapi/uspace_common.h" >/dev/null
|
||||
grep -F 'return vsnprintf(buffer, size, fmt, args);' \
|
||||
"$linuxcnc_root/src/rtapi/uspace_common.h" >/dev/null
|
||||
grep -F 'class PythonPlugin' "$linuxcnc_root/src/emc/pythonplugin/python_plugin.hh" >/dev/null
|
||||
grep -F 'PLUGIN_PYTHON_NOT_INITIALIZED = -12,' "$linuxcnc_root/src/emc/pythonplugin/python_plugin.hh" >/dev/null
|
||||
grep -F 'PLUGIN_BAD_PATH = -5,' "$linuxcnc_root/src/emc/pythonplugin/python_plugin.hh" >/dev/null
|
||||
grep -F 'PLUGIN_INITTAB_FAILED = -7 ,' "$linuxcnc_root/src/emc/pythonplugin/python_plugin.hh" >/dev/null
|
||||
grep -F 'PLUGIN_EXCEPTION_DURING_PATH_PREPEND = -9,' "$linuxcnc_root/src/emc/pythonplugin/python_plugin.hh" >/dev/null
|
||||
grep -F 'PLUGIN_EXCEPTION_DURING_PATH_APPEND = -10,' "$linuxcnc_root/src/emc/pythonplugin/python_plugin.hh" >/dev/null
|
||||
grep -F 'PLUGIN_NO_CALLABLE = 1,' "$linuxcnc_root/src/emc/pythonplugin/python_plugin.hh" >/dev/null
|
||||
grep -F 'PLUGIN_EXCEPTION = 2' "$linuxcnc_root/src/emc/pythonplugin/python_plugin.hh" >/dev/null
|
||||
grep -F 'PythonPlugin::instantiate' "$linuxcnc_root/src/emc/pythonplugin/python_plugin.cc" >/dev/null
|
||||
grep -F 'for (int i = 0; inittab[i].name != NULL; i++) {' "$linuxcnc_root/src/emc/pythonplugin/python_plugin.cc" >/dev/null
|
||||
grep -F 'if (module == NULL) {' "$linuxcnc_root/src/emc/pythonplugin/python_plugin.cc" >/dev/null
|
||||
grep -F 'status = PLUGIN_INITTAB_FAILED;' "$linuxcnc_root/src/emc/pythonplugin/python_plugin.cc" >/dev/null
|
||||
grep -F 'if (status < PLUGIN_OK)' "$linuxcnc_root/src/emc/pythonplugin/python_plugin.cc" >/dev/null
|
||||
grep -F 'if (auto inistring = inifile.findString("TOPLEVEL", section)) {' \
|
||||
"$linuxcnc_root/src/emc/pythonplugin/python_plugin.cc" >/dev/null
|
||||
grep -F 'if (realpath(toplevel, real_path) == NULL) {' \
|
||||
"$linuxcnc_root/src/emc/pythonplugin/python_plugin.cc" >/dev/null
|
||||
grep -F 'status = PLUGIN_BAD_PATH;' "$linuxcnc_root/src/emc/pythonplugin/python_plugin.cc" >/dev/null
|
||||
grep -F 'while (auto inistring = inifile.findString(n, "PATH_PREPEND", "PYTHON")) {' \
|
||||
"$linuxcnc_root/src/emc/pythonplugin/python_plugin.cc" >/dev/null
|
||||
grep -F 'while (auto inistring = inifile.findString(n, "PATH_APPEND", "PYTHON")) {' \
|
||||
"$linuxcnc_root/src/emc/pythonplugin/python_plugin.cc" >/dev/null
|
||||
grep -F 'status = PLUGIN_EXCEPTION_DURING_PATH_PREPEND;' \
|
||||
"$linuxcnc_root/src/emc/pythonplugin/python_plugin.cc" >/dev/null
|
||||
grep -F 'status = PLUGIN_EXCEPTION_DURING_PATH_APPEND;' \
|
||||
"$linuxcnc_root/src/emc/pythonplugin/python_plugin.cc" >/dev/null
|
||||
grep -F 'int IniFile::tildeExpand(const std::string &path, std::string &result)' \
|
||||
"$linuxcnc_root/src/emc/ini/inifile.cc" >/dev/null
|
||||
grep -F "if(!home)" "$linuxcnc_root/src/emc/ini/inifile.cc" >/dev/null
|
||||
grep -F 'IniFile::trim(sect);' "$linuxcnc_root/src/emc/ini/inifile.cc" >/dev/null
|
||||
grep -F 'Section header has trailing content, ignored' "$linuxcnc_root/src/emc/ini/inifile.cc" >/dev/null
|
||||
grep -F 'retval = bp::exec_file(cmd, main_namespace, main_namespace);' \
|
||||
"$linuxcnc_root/src/emc/pythonplugin/python_plugin.cc" >/dev/null
|
||||
grep -F 'retval = bp::exec(cmd, main_namespace, main_namespace);' \
|
||||
"$linuxcnc_root/src/emc/pythonplugin/python_plugin.cc" >/dev/null
|
||||
grep -F 'PyObject *rv = PyObject_Call(function.ptr(), tupleargs.ptr(), kwargs.ptr());' \
|
||||
"$linuxcnc_root/src/emc/pythonplugin/python_plugin.cc" >/dev/null
|
||||
grep -F 'PyErr_Fetch(&exc,&val,&tb);' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/interp_python.cc" >/dev/null
|
||||
grep -F 'PyErr_NormalizeException(&exc,&val,&tb);' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/interp_python.cc" >/dev/null
|
||||
grep -F 'if (Py_IsInitialized()) {' \
|
||||
"$linuxcnc_root/src/emc/pythonplugin/python_plugin.cc" >/dev/null
|
||||
grep -F '#define callmethod(o, m, f, ...) PyObject_CallMethod((o), (char*)(m), (char*)(f), ## __VA_ARGS__)' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/gcodemodule.cc" >/dev/null
|
||||
grep -F 'PyObject *result = PyObject_GetAttrString(callback, "parameter_file");' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/gcodemodule.cc" >/dev/null
|
||||
grep -F 'PyErr_Format(PyExc_TypeError,' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/gcodemodule.cc" >/dev/null
|
||||
grep -F 'return Py_BuildValue("[ddd][ddd][ddd][ddd]",' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/gcodemodule.cc" >/dev/null
|
||||
grep -F 'PyObject *m = PyModule_Create(&gcode_moduledef);' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/gcodemodule.cc" >/dev/null
|
||||
grep -F 'PyType_Ready(&LineCodeType);' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/gcodemodule.cc" >/dev/null
|
||||
grep -F 'PyModule_AddObject(m, "linecode", (PyObject*)&LineCodeType);' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/gcodemodule.cc" >/dev/null
|
||||
grep -F 'PyObject_SetAttrString(m, "MAX_ERROR", PyLong_FromLong(maxerror));' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/gcodemodule.cc" >/dev/null
|
||||
grep -F '#define TOOL_MMAP_FILENAME ".tool.mmap"' "$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'int tool_nml_register(CANON_TOOL_TABLE *tblptr)' "$linuxcnc_root/src/emc/tooldata/tooldata_nml.cc" >/dev/null
|
||||
grep -F 'int tooldata_db_init(char progname_plus_args[]' "$linuxcnc_root/src/emc/tooldata/tooldata_db.cc" >/dev/null
|
||||
grep -F 'if (!db_live) {return -1;}' "$linuxcnc_root/src/emc/tooldata/tooldata_db.cc" >/dev/null
|
||||
grep -F 'if (!db_live) return 0;' "$linuxcnc_root/src/emc/tooldata/tooldata_db.cc" >/dev/null
|
||||
|
||||
python3 - "$manifest" <<'PY'
|
||||
from pathlib import Path
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
manifest = Path(sys.argv[1])
|
||||
source_map = Path("docs/linuxcnc-wasm-shims-source-map.md").read_text(encoding="utf-8")
|
||||
manifest_text = manifest.read_text(encoding="utf-8")
|
||||
shim_paths = [
|
||||
line for line in subprocess.check_output(["./list-linuxcnc-wasm-safe-shims.sh"], text=True).splitlines()
|
||||
if line
|
||||
]
|
||||
if len(shim_paths) != 11:
|
||||
raise SystemExit(f"expected 11 wasm-safe CMake shim sources, found {len(shim_paths)}")
|
||||
if f"| CMake `linuxcnc_wasm_safe_probe_shims` sources | {len(shim_paths)} |" not in source_map:
|
||||
raise SystemExit("docs/linuxcnc-wasm-shims-source-map.md shim count mismatch")
|
||||
|
||||
expected_shims = {
|
||||
"core/wasm_shims/dlfcn.cc": ["src/emc/rs274ngc/interp_base.cc"],
|
||||
"core/wasm_shims/emc_status_shim.cc": ["src/emc/sai/dummyemcstat.cc"],
|
||||
"core/wasm_shims/gettext_shim.cc": ["src/emc/rs274ngc/interp_internal.hh"],
|
||||
"core/wasm_shims/linuxcnc_runtime_shim.cc": [
|
||||
"src/emc/rs274ngc/gcodemodule.cc",
|
||||
"src/emc/task/emctaskmain.cc",
|
||||
"src/emc/task/taskclass.cc",
|
||||
"src/emc/rs274ngc/interp_namedparams.cc",
|
||||
"include/hal.h",
|
||||
"src/hal/hal_lib.c",
|
||||
"src/emc/rs274ngc/rs274ngc_pre.cc",
|
||||
],
|
||||
"core/wasm_shims/nml_status_shim.cc": [
|
||||
"src/libnml/nml/nmlmsg.cc",
|
||||
"src/libnml/nml/stat_msg.cc",
|
||||
],
|
||||
"core/wasm_shims/python_c_api_shim.cc": [
|
||||
"src/emc/rs274ngc/interp_python.cc",
|
||||
"src/emc/rs274ngc/interp_namedparams.cc",
|
||||
"src/emc/rs274ngc/gcodemodule.cc",
|
||||
"src/emc/pythonplugin/python_plugin.cc",
|
||||
],
|
||||
"core/wasm_shims/rcs_print_shim.cc": [
|
||||
"src/libnml/rcs/rcs_print.cc",
|
||||
"src/libnml/rcs/rcs_print.hh",
|
||||
],
|
||||
"core/wasm_shims/rtapi_compat.cc": [
|
||||
"src/rtapi/uspace_common.h",
|
||||
"src/rtapi/rtapi.h",
|
||||
],
|
||||
"core/wasm_shims/tooldata/tooldata_mmap_backend.cc": [
|
||||
"src/emc/tooldata/tooldata_mmap.cc",
|
||||
],
|
||||
"core/wasm_shims/tooldata/tooldata_runtime_stubs.cc": [
|
||||
"src/emc/tooldata/tooldata_nml.cc",
|
||||
"src/emc/tooldata/tooldata_db.cc",
|
||||
],
|
||||
"core/wasm_shims/pythonplugin/python_plugin.cc": [
|
||||
"src/emc/pythonplugin/python_plugin.cc",
|
||||
"src/emc/pythonplugin/python_plugin.hh",
|
||||
"src/emc/ini/inifile.cc",
|
||||
],
|
||||
}
|
||||
if shim_paths != list(expected_shims):
|
||||
raise SystemExit("wasm-safe shim CMake order no longer matches docs/linuxcnc-wasm-shims-source-map.md")
|
||||
|
||||
for shim_path, linuxcnc_sources in expected_shims.items():
|
||||
shim_text = Path(shim_path).read_text(encoding="utf-8")
|
||||
if "LinuxCNC source basis:" not in shim_text:
|
||||
raise SystemExit(f"{shim_path} is missing a LinuxCNC source basis comment")
|
||||
if f"| `{shim_path}` |" not in source_map:
|
||||
raise SystemExit(f"docs/linuxcnc-wasm-shims-source-map.md missing shim row: {shim_path}")
|
||||
for source in linuxcnc_sources:
|
||||
if source not in source_map:
|
||||
raise SystemExit(f"docs/linuxcnc-wasm-shims-source-map.md missing source {source} for {shim_path}")
|
||||
if source not in manifest_text:
|
||||
raise SystemExit(f"{source} is not tracked in {manifest}")
|
||||
|
||||
runtime_shim = Path("core/wasm_shims/linuxcnc_runtime_shim.cc").read_text(encoding="utf-8")
|
||||
runtime_probe = Path("core/wasm_shims/cnc_sim_wasm_runtime_probe_main.cc").read_text(encoding="utf-8")
|
||||
dlfcn_shim = Path("core/wasm_shims/dlfcn.cc").read_text(encoding="utf-8")
|
||||
dlfcn_header = Path("core/wasm_shims/dlfcn.h").read_text(encoding="utf-8")
|
||||
emc_status_shim = Path("core/wasm_shims/emc_status_shim.cc").read_text(encoding="utf-8")
|
||||
gettext_shim = Path("core/wasm_shims/gettext_shim.cc").read_text(encoding="utf-8")
|
||||
for needle in [
|
||||
"#define RTLD_GLOBAL 0x00100",
|
||||
"#define RTLD_NOW 0x00002",
|
||||
"void *dlopen(const char *filename, int flags);",
|
||||
"void *dlsym(void *handle, const char *symbol);",
|
||||
"char *dlerror(void);",
|
||||
"int dlclose(void *handle);",
|
||||
]:
|
||||
if needle not in dlfcn_header:
|
||||
raise SystemExit(f"dlfcn shim header missing LinuxCNC loader boundary: {needle}")
|
||||
for needle in [
|
||||
"dynamic loading is unavailable in wasm-safe probe",
|
||||
"void *dlopen(const char *, int)",
|
||||
"return nullptr;",
|
||||
"void *dlsym(void *, const char *)",
|
||||
"char *dlerror(void)",
|
||||
"return last_error;",
|
||||
"int dlclose(void *)",
|
||||
"return 0;",
|
||||
]:
|
||||
if needle not in dlfcn_shim:
|
||||
raise SystemExit(f"dlfcn shim missing unavailable-loader boundary: {needle}")
|
||||
for needle in [
|
||||
'#include "nml_intf/emc_nml.hh"',
|
||||
"EMC_STAT *emcStatus = new EMC_STAT;",
|
||||
]:
|
||||
if needle not in emc_status_shim:
|
||||
raise SystemExit(f"EMC status shim missing detached LinuxCNC status singleton: {needle}")
|
||||
for needle in [
|
||||
"extern \"C\" char *gettext(const char *msgid)",
|
||||
"return const_cast<char *>(msgid ? msgid : \"\");",
|
||||
]:
|
||||
if needle not in gettext_shim:
|
||||
raise SystemExit(f"gettext shim missing diagnostic passthrough boundary: {needle}")
|
||||
nml_status_shim = Path("core/wasm_shims/nml_status_shim.cc").read_text(encoding="utf-8")
|
||||
for needle in [
|
||||
"int NMLmsg::automatically_clear = 1;",
|
||||
"void NMLmsg::clear()",
|
||||
"std::memset(static_cast<void *>(this), 0, static_cast<size_t>(size));",
|
||||
"command_type = -1;",
|
||||
"echo_serial_number = -1;",
|
||||
"status = RCS_STATUS::UNINITIALIZED;",
|
||||
"_state = -1;",
|
||||
]:
|
||||
if needle not in nml_status_shim:
|
||||
raise SystemExit(f"NML status shim missing LinuxCNC constructor boundary: {needle}")
|
||||
for needle in [
|
||||
"int _task = 0;",
|
||||
'extern "C" PyObject *PyInit_interpreter(void)',
|
||||
'extern "C" PyObject *PyInit_emccanon(void)',
|
||||
'extern "C" PyObject *PyInit_gcode(void)',
|
||||
"return nullptr;",
|
||||
'struct _inittab builtin_modules[] = {',
|
||||
'{"interpreter", PyInit_interpreter}',
|
||||
'{"emccanon", PyInit_emccanon}',
|
||||
]:
|
||||
if needle not in runtime_shim:
|
||||
raise SystemExit(f"linuxcnc runtime shim missing preview/builtin module boundary: {needle}")
|
||||
for needle in [
|
||||
"std::string expand_home_directory(const char *words)",
|
||||
"std::string expand_environment_variables(const std::string &words)",
|
||||
"extern \"C\" int wordexp(const char *words, wordexp_t *pwordexp, int)",
|
||||
"return WRDE_BADVAL;",
|
||||
"return WRDE_NOSPACE;",
|
||||
"pwordexp->we_wordc = 1;",
|
||||
"pwordexp->we_offs = 0;",
|
||||
"extern \"C\" void wordfree(wordexp_t *pwordexp)",
|
||||
"pwordexp->we_wordc = 0;",
|
||||
"pwordexp->we_wordv = nullptr;",
|
||||
]:
|
||||
if needle not in runtime_shim:
|
||||
raise SystemExit(f"linuxcnc runtime shim missing limited wordexp boundary: {needle}")
|
||||
for needle in [
|
||||
'extern "C" int hal_get_pin_value_by_name',
|
||||
'extern "C" int hal_get_signal_value_by_name',
|
||||
'extern "C" int hal_get_param_value_by_name',
|
||||
"*type = HAL_TYPE_UNINITIALIZED;",
|
||||
"*data = nullptr;",
|
||||
"return -1;",
|
||||
]:
|
||||
if needle not in runtime_shim:
|
||||
raise SystemExit(f"linuxcnc runtime shim missing HAL unavailable boundary: {needle}")
|
||||
for needle in [
|
||||
"bool hal_lookup_is_unavailable()",
|
||||
'hal_get_pin_value_by_name("cnc-sim.missing-pin", &type, &data, &connected) != -1',
|
||||
'hal_get_signal_value_by_name("cnc-sim.missing-signal", &type, &data, &has_writers) != -1',
|
||||
'hal_get_param_value_by_name("cnc-sim.missing-param", &type, &data) != -1',
|
||||
"type != HAL_TYPE_UNINITIALIZED",
|
||||
"data != nullptr",
|
||||
]:
|
||||
if needle not in runtime_probe:
|
||||
raise SystemExit(f"runtime probe missing HAL unavailable assertion: {needle}")
|
||||
|
||||
python_plugin_shim = Path("core/wasm_shims/pythonplugin/python_plugin.cc").read_text(encoding="utf-8")
|
||||
python_plugin_probe = Path("core/wasm_shims/pythonplugin/python_plugin_probe_main.cc").read_text(encoding="utf-8")
|
||||
python_plugin_inittab_probe = Path("core/wasm_shims/pythonplugin/python_plugin_inittab_probe_main.cc").read_text(encoding="utf-8")
|
||||
python_c_api_shim = Path("core/wasm_shims/python_c_api_shim.cc").read_text(encoding="utf-8")
|
||||
for forbidden in [
|
||||
"bp::exec(",
|
||||
"bp::exec_file(",
|
||||
"PyObject_Call(",
|
||||
]:
|
||||
if forbidden in python_plugin_shim:
|
||||
raise SystemExit(f"PythonPlugin wasm shim must not execute Python: {forbidden}")
|
||||
for needle in [
|
||||
"python disabled in wasm-safe probe",
|
||||
'find_ini_value(iniFilename, section, "TOPLEVEL", toplevel)',
|
||||
"realpath(toplevel.c_str(), resolved_path) == nullptr",
|
||||
"status = PLUGIN_BAD_PATH;",
|
||||
"status = PLUGIN_INITTAB_FAILED;",
|
||||
"failed to initialize built-in module",
|
||||
"read_ini_section(text, section_name)",
|
||||
"section_name = trim_ini_value(text.substr(1, close - 1));",
|
||||
'check_python_path_entries(iniFilename,',
|
||||
"PLUGIN_EXCEPTION_DURING_PATH_PREPEND",
|
||||
"PLUGIN_EXCEPTION_DURING_PATH_APPEND",
|
||||
"tilde_expand_path(entry, expanded)",
|
||||
"status = PLUGIN_PYTHON_NOT_INITIALIZED;",
|
||||
"return PLUGIN_NO_CALLABLE;",
|
||||
"status = PLUGIN_EXCEPTION;",
|
||||
"if (status < PLUGIN_OK)",
|
||||
]:
|
||||
if needle not in python_plugin_shim:
|
||||
raise SystemExit(f"PythonPlugin wasm shim missing disabled-python boundary: {needle}")
|
||||
for needle in [
|
||||
"PythonPlugin::PythonPlugin(struct _inittab*) reports PLUGIN_INITTAB_FAILED",
|
||||
"PythonPlugin *plugin = PythonPlugin::instantiate(bad_modules);",
|
||||
"plugin != nullptr",
|
||||
"python_plugin->plugin_status() != PLUGIN_INITTAB_FAILED",
|
||||
"python_plugin->usable()",
|
||||
'python_plugin->last_errmsg() != "failed to initialize built-in module"',
|
||||
]:
|
||||
if needle not in python_plugin_inittab_probe:
|
||||
raise SystemExit(f"PythonPlugin inittab probe missing first-caller status assertion: {needle}")
|
||||
for needle in [
|
||||
"[ PYTHON ] ; section comment",
|
||||
"PLUGIN_NO_SECTION",
|
||||
"PLUGIN_BAD_INIFILE",
|
||||
"PLUGIN_BAD_PATH",
|
||||
"PLUGIN_EXCEPTION_DURING_PATH_PREPEND",
|
||||
"PLUGIN_EXCEPTION_DURING_PATH_APPEND",
|
||||
"PLUGIN_PYTHON_NOT_INITIALIZED",
|
||||
"PLUGIN_NO_CALLABLE",
|
||||
"PLUGIN_EXCEPTION",
|
||||
"handle_pyerror().empty()",
|
||||
]:
|
||||
if needle not in python_plugin_probe:
|
||||
raise SystemExit(f"PythonPlugin probe missing disabled-python status assertion: {needle}")
|
||||
for needle in [
|
||||
"static PyTypeObject none_type = {\"NoneType\"};",
|
||||
"static PyObject none_object = {&none_type};",
|
||||
"PyObject *_Py_NoneStructPtr = &none_object;",
|
||||
"int Py_IsInitialized(void)",
|
||||
"return 1;",
|
||||
"PyObject *PyErr_Occurred(void)",
|
||||
"return nullptr;",
|
||||
"void PyErr_Fetch(PyObject **exc, PyObject **val, PyObject **tb)",
|
||||
"*exc = nullptr;",
|
||||
"*val = nullptr;",
|
||||
"*tb = nullptr;",
|
||||
"int PyCallable_Check(PyObject *)",
|
||||
"return 0;",
|
||||
"PyObject *PyObject_CallMethod(PyObject *, char *, char *, ...)",
|
||||
"PyObject *PyObject_GetAttrString(PyObject *, const char *)",
|
||||
"return &none_object;",
|
||||
"PyObject *Py_BuildValue(const char *, ...)",
|
||||
"PyObject *PyModule_Create(PyModuleDef *)",
|
||||
"int PyModule_AddObject(PyObject *, const char *, PyObject *)",
|
||||
"int PyType_Ready(PyTypeObject *)",
|
||||
"void *PyObject_NewShim(std::size_t size, PyTypeObject *type)",
|
||||
"std::calloc(1, size)",
|
||||
]:
|
||||
if needle not in python_c_api_shim:
|
||||
raise SystemExit(f"Python C API shim missing symbol boundary: {needle}")
|
||||
|
||||
rcs_print_shim = Path("core/wasm_shims/rcs_print_shim.cc").read_text(encoding="utf-8")
|
||||
for needle in [
|
||||
"set_print_rcs_error_info",
|
||||
"print_rcs_error_new",
|
||||
"std::vfprintf(stderr, format, args)",
|
||||
]:
|
||||
if needle not in rcs_print_shim:
|
||||
raise SystemExit(f"RCS print shim missing split print-error boundary: {needle}")
|
||||
|
||||
rtapi_compat_shim = Path("core/wasm_shims/rtapi_compat.cc").read_text(encoding="utf-8")
|
||||
for needle in [
|
||||
"rtapi_snprintf",
|
||||
"std::vsnprintf(buf, static_cast<std::size_t>(size), fmt, ap)",
|
||||
]:
|
||||
if needle not in rtapi_compat_shim:
|
||||
raise SystemExit(f"RTAPI compatibility shim missing userspace snprintf boundary: {needle}")
|
||||
|
||||
for phrase in [
|
||||
"must not add CNC behavior",
|
||||
"must not expand the temporary smoke parser",
|
||||
"CMake `linuxcnc_wasm_safe_probe_shims` set",
|
||||
"RS274/WASM manifest",
|
||||
"browser-safe LinuxCNC adaptations",
|
||||
"LinuxCNC `interp_base.cc` dynamic loader calls",
|
||||
"unavailable-loader returns",
|
||||
"detached LinuxCNC `EMC_STAT` singleton",
|
||||
"LinuxCNC `_()` diagnostic call sites",
|
||||
"browser gettext catalogs unavailable",
|
||||
"LinuxCNC NML status constructors",
|
||||
"`RCS_STAT_MSG` default status fields",
|
||||
"dynamic loading unavailable",
|
||||
"unavailable HAL lookup",
|
||||
"must leave HAL values unavailable",
|
||||
"preview `_task=0`",
|
||||
"builtin module stubs",
|
||||
"must not switch browser-safe probes into task mode",
|
||||
"single-word `wordexp()` path expansion",
|
||||
"`wordfree()` cleanup",
|
||||
"must not become a shell expansion feature",
|
||||
"must not become Python execution",
|
||||
"Python C API shim must return inert objects",
|
||||
"must not call into CPython runtime",
|
||||
"keeping Python execution disabled",
|
||||
"must not execute `bp::exec`, `bp::exec_file`, or",
|
||||
"inactive-DB return values",
|
||||
"negative-status short-circuit behavior",
|
||||
"first-caller `_inittab` `PLUGIN_INITTAB_FAILED` edge",
|
||||
"preserve the `TOPLEVEL` missing-path `PLUGIN_BAD_PATH` edge",
|
||||
"preserve `PATH_PREPEND` and `PATH_APPEND` tilde-expansion failure statuses",
|
||||
"preserve LinuxCNC INI section-name trimming and trailing section-comment handling",
|
||||
"LinuxCNC `rcs_print_error` split entry points",
|
||||
"without native print routing",
|
||||
"LinuxCNC userspace `rtapi_snprintf()` formatting",
|
||||
"`uspace_common.h` `vsnprintf()` implementation path",
|
||||
"./check-linuxcnc-wasm-shims-source-map.sh",
|
||||
"does not interpret G-code",
|
||||
]:
|
||||
if phrase not in source_map:
|
||||
raise SystemExit(f"docs/linuxcnc-wasm-shims-source-map.md missing boundary phrase: {phrase}")
|
||||
|
||||
for entry in [
|
||||
"test-native.sh",
|
||||
"test-linuxcnc-source-link.sh",
|
||||
"build-wasm.sh",
|
||||
]:
|
||||
text = Path(entry).read_text(encoding="utf-8")
|
||||
if "./check-linuxcnc-wasm-shims-source-map.sh" not in text:
|
||||
raise SystemExit(f"{entry} must run ./check-linuxcnc-wasm-shims-source-map.sh")
|
||||
|
||||
cmake_text = Path("core/CMakeLists.txt").read_text(encoding="utf-8")
|
||||
for shim_path in shim_paths:
|
||||
cmake_suffix = shim_path.removeprefix("core/")
|
||||
if cmake_suffix not in cmake_text:
|
||||
raise SystemExit(f"{shim_path} is not listed in linuxcnc_wasm_safe_probe_shims")
|
||||
|
||||
blocker_map = Path("docs/linuxcnc-wasm-blockers-source-map.md").read_text(encoding="utf-8")
|
||||
for shim_path in [
|
||||
"core/wasm_shims/linuxcnc_runtime_shim.cc",
|
||||
"core/wasm_shims/python_c_api_shim.cc",
|
||||
"core/wasm_shims/tooldata/tooldata_mmap_backend.cc",
|
||||
]:
|
||||
if shim_path not in blocker_map:
|
||||
raise SystemExit(f"docs/linuxcnc-wasm-blockers-source-map.md no longer references {shim_path}")
|
||||
PY
|
||||
204
check-linuxcnc-wasm-smoke-source-map.sh
Executable file
204
check-linuxcnc-wasm-smoke-source-map.sh
Executable file
@@ -0,0 +1,204 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# LinuxCNC source basis: this guard ties Node/browser WASM smoke coverage to
|
||||
# LinuxCNC RS274 parameter/INI handling, M-code canon side effects, generated
|
||||
# switchkins/remap config cases, kinematics sources, and OPFS-only browser
|
||||
# persistence. It validates smoke-test source coverage only; it does not add
|
||||
# CNC behavior, expand smoke parsing, or interpret G-code.
|
||||
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
|
||||
linuxcnc_root=$(cd "$linuxcnc_root" && pwd)
|
||||
|
||||
grep -F 'int Interp::ini_load(const char *filename)' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'int Interp::restore_parameters(const char *filename)' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'int Interp::save_parameters(const char *filename,' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'std::string tempfile = std::string(filename) + ".new";' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'unlink(bakfile.c_str());' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'if(link(filename, bakfile.c_str()) < 0)' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'if(rename(tempfile.c_str(), filename) < 0)' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'read_text(command, _setup.file_pointer, _setup.linetext,' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'int read_text(const char *command, FILE * inport, char *raw_line,' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_interp.hh" >/dev/null
|
||||
|
||||
grep -F 'int Interp::convert_m(block_pointer block' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/interp_convert.cc" >/dev/null
|
||||
grep -F 'int ret = WAIT(round_to_int(block->p_number), DIGITAL_INPUT, type, timeout);' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/interp_convert.cc" >/dev/null
|
||||
grep -F 'SET_AUX_OUTPUT_VALUE(round_to_int(block->e_number), block->q_number);' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/interp_convert.cc" >/dev/null
|
||||
grep -F 'extern int WAIT(int index' "$linuxcnc_root/src/emc/nml_intf/canon.hh" >/dev/null
|
||||
grep -F 'extern void SET_AUX_OUTPUT_VALUE(int index, double value);' \
|
||||
"$linuxcnc_root/src/emc/nml_intf/canon.hh" >/dev/null
|
||||
|
||||
grep -F 'kp->kinsname = "5axiskins";' "$linuxcnc_root/src/emc/kinematics/5axiskins.c" >/dev/null
|
||||
grep -F 'int xyzbcKinematicsInverse(const EmcPose * pos' \
|
||||
"$linuxcnc_root/src/emc/kinematics/trtfuncs.c" >/dev/null
|
||||
grep -F 'int xyzacKinematicsInverse(const EmcPose * pos' \
|
||||
"$linuxcnc_root/src/emc/kinematics/trtfuncs.c" >/dev/null
|
||||
grep -F '*kinv1 = xyzacKinematicsInverse;' \
|
||||
"$linuxcnc_root/src/emc/kinematics/xyzac-trt-kins.c" >/dev/null
|
||||
grep -F '*kinv1 = xyzbcKinematicsInverse;' \
|
||||
"$linuxcnc_root/src/emc/kinematics/xyzbc-trt-kins.c" >/dev/null
|
||||
grep -F 'int userkKinematicsInverse(const EmcPose * pos' \
|
||||
"$linuxcnc_root/src/emc/kinematics/userkfuncs.c" >/dev/null
|
||||
|
||||
grep -F 'LinuxCNC WASM smoke source map' docs/linuxcnc-wasm-smoke-source-map.md >/dev/null
|
||||
grep -F 'must not expand the temporary smoke parser' docs/linuxcnc-wasm-smoke-source-map.md >/dev/null
|
||||
grep -F 'OPFS-only' docs/linuxcnc-wasm-smoke-source-map.md >/dev/null
|
||||
grep -F '`src/emc/rs274ngc/interp_convert.cc` provides `convert_m()` coverage' \
|
||||
docs/linuxcnc-wasm-smoke-source-map.md >/dev/null
|
||||
grep -F 'unlinking `filename + ".bak"`' docs/linuxcnc-wasm-smoke-source-map.md >/dev/null
|
||||
grep -F '`src/emc/kinematics/5axiskins.c`, `src/emc/kinematics/trtfuncs.c`' \
|
||||
docs/linuxcnc-wasm-smoke-source-map.md >/dev/null
|
||||
grep -F 'Generated switchkins config smoke cases must continue to come from' \
|
||||
docs/linuxcnc-wasm-smoke-source-map.md >/dev/null
|
||||
|
||||
grep -F 'LinuxCNC source basis: Node smoke only verifies the wasm/API bridge around' \
|
||||
test-web-wasm-node-smoke.sh >/dev/null
|
||||
grep -F 'minimum_steps=${WASM_NODE_SMOKE_MIN_STEPS:-50}' test-web-wasm-node-smoke.sh >/dev/null
|
||||
grep -F 'WASM Node smoke covered $passed_steps steps, expected at least $minimum_steps' \
|
||||
test-web-wasm-node-smoke.sh >/dev/null
|
||||
grep -F 'expected Node wasm-core wrapper to leave OPFS disabled' test-web-wasm-node-smoke.cjs >/dev/null
|
||||
grep -F 'expected Node wasm-core parseFile to require OPFS' test-web-wasm-node-smoke.cjs >/dev/null
|
||||
grep -F 'linuxcnc_switchkins_remap_config_cases.json' test-web-wasm-node-smoke.cjs >/dev/null
|
||||
grep -F 'expected LinuxCNC WASM M68 E3 Q${kinstype} remap side effect' \
|
||||
test-web-wasm-node-smoke.cjs >/dev/null
|
||||
grep -F 'expected LinuxCNC WASM M66 E0 L0 remap side effect' \
|
||||
test-web-wasm-node-smoke.cjs >/dev/null
|
||||
grep -F 'expected LinuxCNC WASM 5axiskins RTCP pivot from LinuxCNC 5axiskins inverse' \
|
||||
test-web-wasm-node-smoke.cjs >/dev/null
|
||||
grep -F 'expected LinuxCNC WASM configured xyzbc-trt RTCP pivot from LinuxCNC trtfuncs inverse' \
|
||||
test-web-wasm-node-smoke.cjs >/dev/null
|
||||
grep -F 'expected LinuxCNC WASM configured xyzac-trt RTCP pivot from LinuxCNC xyzab_tdr inverse' \
|
||||
test-web-wasm-node-smoke.cjs >/dev/null
|
||||
|
||||
grep -F 'LinuxCNC source basis: browser smoke verifies OPFS-backed wasm/API/app flows' \
|
||||
test-web-wasm-browser-smoke.sh >/dev/null
|
||||
grep -F 'minimum_sections=${BROWSER_SMOKE_MIN_SECTIONS:-50}' test-web-wasm-browser-smoke.sh >/dev/null
|
||||
grep -F 'BROWSER_SMOKE_MIN_SECTIONS must be a positive integer' test-web-wasm-browser-smoke.sh >/dev/null
|
||||
grep -F 'browser WASM smoke covered $passed_sections sections, expected at least $minimum_sections' \
|
||||
test-web-wasm-browser-smoke.sh >/dev/null
|
||||
grep -F 'required_browser_sections = {' test-web-wasm-browser-smoke.sh >/dev/null
|
||||
grep -F 'runSection("linuxcnc generated switchkins cases load"' test-web-wasm-browser-smoke.sh >/dev/null
|
||||
grep -F 'runSection("opfs parameter restore in new instance"' test-web-wasm-browser-smoke.sh >/dev/null
|
||||
grep -F 'runSection("opfs directory persist and load"' test-web-wasm-browser-smoke.sh >/dev/null
|
||||
grep -F 'runSection("browser opfs policy"' test-web-wasm-browser-smoke.sh >/dev/null
|
||||
grep -F 'runSection("browser app opfs restore"' test-web-wasm-browser-smoke.sh >/dev/null
|
||||
grep -F 'runLinuxCncBrowserSections(context, simulator)' web/test-browser-wasm-smoke-sections.js >/dev/null
|
||||
grep -F 'runBrowserOpfsWorkspaceSections(context, simulator)' web/test-browser-wasm-smoke-sections.js >/dev/null
|
||||
grep -F 'runBrowserOpfsPolicySections(context)' web/test-browser-wasm-smoke-sections.js >/dev/null
|
||||
grep -F 'runBrowserAppOpfsSections(context)' web/test-browser-wasm-smoke-sections.js >/dev/null
|
||||
grep -F 'runBrowserOpfsBasicSections(context, simulator)' \
|
||||
web/test-browser-wasm-smoke-opfs-workspace-sections.js >/dev/null
|
||||
grep -F 'runBrowserOpfsParameterSections(context, simulator)' \
|
||||
web/test-browser-wasm-smoke-opfs-workspace-sections.js >/dev/null
|
||||
grep -F 'runBrowserOpfsMirrorSections(context, simulator)' \
|
||||
web/test-browser-wasm-smoke-opfs-workspace-sections.js >/dev/null
|
||||
grep -F 'runBrowserOpfsDirectorySections(context, simulator)' \
|
||||
web/test-browser-wasm-smoke-opfs-workspace-sections.js >/dev/null
|
||||
grep -F 'linuxcnc_switchkins_remap_config_cases.json' \
|
||||
web/test-browser-wasm-smoke-linuxcnc-sections.js >/dev/null
|
||||
grep -F 'missing LinuxCNC switchkins config cases after INI_FILE_NAME remap-load filtering' \
|
||||
web/test-browser-wasm-smoke-linuxcnc-sections.js >/dev/null
|
||||
grep -F 'LinuxCNC source basis: rs274ngc_pre.cc restore_parameters()' \
|
||||
web/test-browser-wasm-smoke-opfs-parameter-sections.js >/dev/null
|
||||
grep -F 'LinuxCNC source basis: rs274ngc_pre.cc save_parameters()' \
|
||||
web/test-browser-wasm-smoke-opfs-parameter-sections.js >/dev/null
|
||||
grep -F 'LinuxCNC source basis: rs274ngc_pre.cc read_text() reads' \
|
||||
web/test-browser-wasm-smoke-opfs-basic-sections.js >/dev/null
|
||||
grep -F 'runSection("opfs directory persist and load"' \
|
||||
web/test-browser-wasm-smoke-opfs-directory-sections.js >/dev/null
|
||||
grep -F 'runSection("opfs metadata queries avoid wasm mirror pollution"' \
|
||||
web/test-browser-wasm-smoke-opfs-directory-sections.js >/dev/null
|
||||
grep -F 'runSection("browser opfs policy"' \
|
||||
web/test-browser-wasm-smoke-opfs-policy-sections.js >/dev/null
|
||||
grep -F 'app frame did not persist current program into OPFS' \
|
||||
web/test-browser-wasm-smoke-app-sections.js >/dev/null
|
||||
grep -F 'app frame did not persist LinuxCNC parameter backup into OPFS' \
|
||||
web/test-browser-wasm-smoke-app-sections.js >/dev/null
|
||||
grep -F 'app frame did not clean up LinuxCNC temporary parameter file in OPFS' \
|
||||
web/test-browser-wasm-smoke-app-sections.js >/dev/null
|
||||
|
||||
if grep -R -n -E 'localStorage|sessionStorage|indexedDB|showOpenFilePicker|showSaveFilePicker|showDirectoryPicker|webkitRequestFileSystem|FileReader' web/src; then
|
||||
echo "browser app/wasm code must not add filesystem persistence outside OPFS" >&2
|
||||
exit 1
|
||||
fi
|
||||
if grep -n -E 'localStorage|sessionStorage|indexedDB|showOpenFilePicker|showSaveFilePicker|showDirectoryPicker|webkitRequestFileSystem|FileReader' \
|
||||
web/test-browser-wasm-smoke-*.js \
|
||||
web/test-browser-wasm-smoke.html \
|
||||
test-web-wasm-browser-smoke.sh; then
|
||||
echo "browser WASM smoke harness must not add filesystem persistence outside OPFS" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
python3 - <<'PY'
|
||||
from pathlib import Path
|
||||
import json
|
||||
import re
|
||||
|
||||
source_map = Path("docs/linuxcnc-wasm-smoke-source-map.md").read_text(encoding="utf-8")
|
||||
json_cases = json.loads(Path("web/public/linuxcnc_switchkins_remap_config_cases.json").read_text(encoding="utf-8"))
|
||||
if not isinstance(json_cases, list) or len(json_cases) == 0:
|
||||
raise SystemExit("generated LinuxCNC switchkins browser config cases are missing")
|
||||
|
||||
node_wrapper = Path("test-web-wasm-node-smoke.sh").read_text(encoding="utf-8")
|
||||
browser_wrapper = Path("test-web-wasm-browser-smoke.sh").read_text(encoding="utf-8")
|
||||
node_min = re.search(r"minimum_steps=\$\{WASM_NODE_SMOKE_MIN_STEPS:-(\d+)\}", node_wrapper)
|
||||
browser_min = re.search(r"minimum_sections=\$\{BROWSER_SMOKE_MIN_SECTIONS:-(\d+)\}", browser_wrapper)
|
||||
if not node_min or int(node_min.group(1)) < 50:
|
||||
raise SystemExit("Node WASM smoke minimum step threshold is missing or below 50")
|
||||
if not browser_min or int(browser_min.group(1)) < 50:
|
||||
raise SystemExit("browser WASM smoke minimum section threshold is missing or below 50")
|
||||
|
||||
for path in [
|
||||
"test-web-wasm-node-smoke.sh",
|
||||
"test-web-wasm-node-smoke.cjs",
|
||||
"test-web-wasm-browser-smoke.sh",
|
||||
"web/test-browser-wasm-smoke-linuxcnc-sections.js",
|
||||
"web/test-browser-wasm-smoke-opfs-workspace-sections.js",
|
||||
"web/test-browser-wasm-smoke-opfs-basic-sections.js",
|
||||
"web/test-browser-wasm-smoke-opfs-parameter-sections.js",
|
||||
"web/test-browser-wasm-smoke-opfs-mirror-sections.js",
|
||||
"web/test-browser-wasm-smoke-opfs-directory-sections.js",
|
||||
"web/test-browser-wasm-smoke-opfs-policy-sections.js",
|
||||
"web/test-browser-wasm-smoke-app-sections.js",
|
||||
]:
|
||||
if f"| `{path}` |" not in source_map:
|
||||
raise SystemExit(f"docs/linuxcnc-wasm-smoke-source-map.md missing smoke entry: {path}")
|
||||
|
||||
required_phrases = [
|
||||
"must not add CNC behavior",
|
||||
"must not expand the temporary smoke parser",
|
||||
"persistence OPFS-only",
|
||||
"Node smoke must leave OPFS disabled",
|
||||
"Browser smoke harness files must not use Local Storage",
|
||||
"Generated switchkins config smoke cases",
|
||||
"browser smoke shell guard also pins required section names",
|
||||
"OPFS workspace/policy/directory handling",
|
||||
'unlinking `filename + ".bak"`',
|
||||
"./check-linuxcnc-wasm-smoke-source-map.sh",
|
||||
"does not interpret G-code",
|
||||
]
|
||||
for phrase in required_phrases:
|
||||
if phrase not in source_map:
|
||||
raise SystemExit(f"docs/linuxcnc-wasm-smoke-source-map.md missing boundary phrase: {phrase}")
|
||||
|
||||
for entry in [
|
||||
"test-native.sh",
|
||||
"test-linuxcnc-source-link.sh",
|
||||
"build-wasm.sh",
|
||||
]:
|
||||
text = Path(entry).read_text(encoding="utf-8")
|
||||
if "./check-linuxcnc-wasm-smoke-source-map.sh" not in text:
|
||||
raise SystemExit(f"{entry} must run ./check-linuxcnc-wasm-smoke-source-map.sh")
|
||||
PY
|
||||
132
check-linuxcnc-workstreams-source-map.sh
Executable file
132
check-linuxcnc-workstreams-source-map.sh
Executable file
@@ -0,0 +1,132 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# LinuxCNC source basis: this guard ties the six active workstream contexts to
|
||||
# their source-map guards and to LinuxCNC source/config anchors. It validates
|
||||
# coordination policy only; it does not add CNC behavior or expand smoke
|
||||
# parsing.
|
||||
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
|
||||
linuxcnc_root=$(cd "$linuxcnc_root" && pwd)
|
||||
|
||||
grep -F '1. `switchkins/remap` generator and tables' docs/architecture.md >/dev/null
|
||||
grep -F '2. `linuxcnc-kinematics` source manifest' docs/architecture.md >/dev/null
|
||||
grep -F '3. WASM filesystem and OPFS persistence' docs/architecture.md >/dev/null
|
||||
grep -F '4. browser app integration' docs/architecture.md >/dev/null
|
||||
grep -F '5. Node and browser smoke coverage' docs/architecture.md >/dev/null
|
||||
grep -F '6. source-link, build, and documentation constraints' docs/architecture.md >/dev/null
|
||||
grep -F 'The synchronized source-map guard for these contexts is' docs/architecture.md >/dev/null
|
||||
grep -F '`docs/linuxcnc-workstreams-source-map.md`.' docs/architecture.md >/dev/null
|
||||
|
||||
grep -F 'REMAP = M428' "$linuxcnc_root/configs/sim/axis/vismach/5axis/bridgemill/5axis.ini" >/dev/null
|
||||
grep -F '#<kinstype>' "$linuxcnc_root/configs/sim/axis/vismach/5axis/bridgemill/remap_subs/428remap.ngc" >/dev/null
|
||||
grep -F 'GENSERKINSSRCS := emc/kinematics/ugenserkins.c' \
|
||||
"$linuxcnc_root/src/emc/kinematics/Submakefile" >/dev/null
|
||||
grep -F 'extern int kinematicsInverse(const struct EmcPose * world,' \
|
||||
"$linuxcnc_root/src/emc/kinematics/kinematics.h" >/dev/null
|
||||
grep -F '#define RS274NGC_PARAMETER_FILE_NAME_DEFAULT "rs274ngc.var"' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/interp_internal.hh" >/dev/null
|
||||
grep -F 'int Interp::save_parameters(const char *filename,' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'LIBRS274SRCS := $(addprefix emc/rs274ngc/,' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/Submakefile" >/dev/null
|
||||
grep -F 'LIBTOOLDATA_SRCS += emc/tooldata/tooldata_common.cc' \
|
||||
"$linuxcnc_root/src/emc/tooldata/Submakefile" >/dev/null
|
||||
grep -F 'LIBLCNCINISRCS := emc/ini/inifile.cc' \
|
||||
"$linuxcnc_root/src/emc/ini/Submakefile" >/dev/null
|
||||
grep -F 'LIBPPSRCS := $(addprefix emc/pythonplugin/,' \
|
||||
"$linuxcnc_root/src/emc/pythonplugin/Submakefile" >/dev/null
|
||||
|
||||
grep -F 'LinuxCNC workstreams source map' docs/linuxcnc-workstreams-source-map.md >/dev/null
|
||||
grep -F 'must not add CNC' docs/linuxcnc-workstreams-source-map.md >/dev/null
|
||||
grep -F 'temporary smoke parser' docs/linuxcnc-workstreams-source-map.md >/dev/null
|
||||
grep -F 'Every active workstream must have at least one source-map document and guard' \
|
||||
docs/linuxcnc-workstreams-source-map.md >/dev/null
|
||||
grep -F 'docs/linuxcnc-source-policy.md` must keep the same one-context workflow' \
|
||||
docs/linuxcnc-workstreams-source-map.md >/dev/null
|
||||
grep -F 'Browser filesystem persistence remains OPFS-only.' docs/linuxcnc-workstreams-source-map.md >/dev/null
|
||||
grep -F 'Smoke coverage remains verification only' docs/linuxcnc-workstreams-source-map.md >/dev/null
|
||||
grep -F 'Keep the change inside one active workstream context unless a dependency is' \
|
||||
docs/linuxcnc-source-policy.md >/dev/null
|
||||
grep -F 'Each pass should advance one reasonable, reviewable context.' \
|
||||
docs/linuxcnc-source-policy.md >/dev/null
|
||||
grep -F 'Keep the six active workstream contexts synchronized with' \
|
||||
docs/linuxcnc-source-policy.md >/dev/null
|
||||
grep -F '`docs/linuxcnc-workstreams-source-map.md` so source-map guards' \
|
||||
docs/linuxcnc-source-policy.md >/dev/null
|
||||
grep -F 'Smoke tests are verification guardrails. They must not be expanded with new' \
|
||||
docs/linuxcnc-source-policy.md >/dev/null
|
||||
grep -F 'Do not mix generator/table work, manifests, OPFS/browser work, and build' \
|
||||
docs/linuxcnc-source-policy.md >/dev/null
|
||||
grep -F 'Browser-side wasm filesystem behavior must use OPFS-backed storage.' \
|
||||
docs/linuxcnc-source-policy.md >/dev/null
|
||||
|
||||
python3 - <<'PY'
|
||||
from pathlib import Path
|
||||
|
||||
doc = Path("docs/linuxcnc-workstreams-source-map.md").read_text(encoding="utf-8")
|
||||
policy = Path("docs/linuxcnc-source-policy.md").read_text(encoding="utf-8")
|
||||
expected = {
|
||||
"switchkins/remap": [
|
||||
"docs/linuxcnc-switchkins-remap-source-map.md",
|
||||
"check-linuxcnc-switchkins-remap-source-map.sh",
|
||||
],
|
||||
"linuxcnc-kinematics": [
|
||||
"docs/linuxcnc-kinematics-source-map.md",
|
||||
"check-linuxcnc-kinematics-source-map.sh",
|
||||
],
|
||||
"WASM filesystem and OPFS persistence": [
|
||||
"docs/linuxcnc-opfs-source-map.md",
|
||||
"docs/linuxcnc-wasm-shims-source-map.md",
|
||||
"docs/linuxcnc-wasm-blockers-source-map.md",
|
||||
"docs/linuxcnc-tooldata-source-map.md",
|
||||
"check-linuxcnc-opfs-source-map.sh",
|
||||
"check-linuxcnc-wasm-shims-source-map.sh",
|
||||
"check-linuxcnc-wasm-blockers-source-map.sh",
|
||||
"check-linuxcnc-tooldata-source-map.sh",
|
||||
],
|
||||
"browser app integration": [
|
||||
"docs/linuxcnc-browser-app-source-map.md",
|
||||
"check-linuxcnc-browser-app-source-map.sh",
|
||||
],
|
||||
"Node and browser smoke coverage": [
|
||||
"docs/linuxcnc-wasm-smoke-source-map.md",
|
||||
"check-linuxcnc-wasm-smoke-source-map.sh",
|
||||
],
|
||||
"source-link, build, and documentation constraints": [
|
||||
"docs/linuxcnc-rs274-source-map.md",
|
||||
"docs/linuxcnc-build-source-map.md",
|
||||
"docs/linuxcnc-tooldata-source-map.md",
|
||||
"check-linuxcnc-rs274-source-map.sh",
|
||||
"check-linuxcnc-build-source-map.sh",
|
||||
"check-linuxcnc-tooldata-source-map.sh",
|
||||
],
|
||||
}
|
||||
for workstream, paths in expected.items():
|
||||
if workstream not in doc:
|
||||
raise SystemExit(f"missing workstream row in docs/linuxcnc-workstreams-source-map.md: {workstream}")
|
||||
policy_terms = {
|
||||
"switchkins/remap": ["switchkins/remap", "M428/M429/M430"],
|
||||
"linuxcnc-kinematics": ["kinematics manifest", "RTCP coverage"],
|
||||
"WASM filesystem and OPFS persistence": ["OPFS", "filesystem"],
|
||||
"browser app integration": ["Browser app", "wasm bridge"],
|
||||
"Node and browser smoke coverage": ["Smoke tests are verification guardrails", "temporary smoke parser"],
|
||||
"source-link, build, and documentation constraints": ["source-link", "build-policy"],
|
||||
}[workstream]
|
||||
if not any(term in policy for term in policy_terms):
|
||||
raise SystemExit(f"docs/linuxcnc-source-policy.md no longer references workstream boundary: {workstream}")
|
||||
for path in paths:
|
||||
if path not in doc:
|
||||
raise SystemExit(f"missing source-map path in workstream index: {path}")
|
||||
if not Path(path).exists():
|
||||
raise SystemExit(f"source-map path listed in workstream index does not exist: {path}")
|
||||
if path.startswith("check-") and not Path(path).stat().st_mode & 0o111:
|
||||
raise SystemExit(f"source-map guard is not executable: {path}")
|
||||
|
||||
for test_entry in ["test-native.sh", "test-linuxcnc-source-link.sh", "build-wasm.sh"]:
|
||||
text = Path(test_entry).read_text(encoding="utf-8")
|
||||
for guard in sorted({path for paths in expected.values() for path in paths if path.startswith("check-")}):
|
||||
if f"./{guard}" not in text:
|
||||
raise SystemExit(f"{test_entry} does not run workstream source-map guard: {guard}")
|
||||
PY
|
||||
@@ -234,6 +234,41 @@ void CanonEventSink::set_xy_rotation(double angle_degrees, int line) {
|
||||
}
|
||||
|
||||
void CanonEventSink::use_length_units(double scale, int line) {
|
||||
use_length_units(scale, line, false);
|
||||
}
|
||||
|
||||
void CanonEventSink::use_length_units(double scale, int line, bool rescale_linear_state) {
|
||||
if (rescale_linear_state && unit_scale_ != 0.0 && scale != unit_scale_) {
|
||||
const double factor = unit_scale_ / scale;
|
||||
// LinuxCNC src/emc/rs274ngc/interp_convert.cc convert_length_units()
|
||||
// rescales linear current axes on G20/G21; A/B/C remain angular.
|
||||
position_.x *= factor;
|
||||
position_.y *= factor;
|
||||
position_.z *= factor;
|
||||
position_.u *= factor;
|
||||
position_.v *= factor;
|
||||
position_.w *= factor;
|
||||
tool_length_offset_.x *= factor;
|
||||
tool_length_offset_.y *= factor;
|
||||
tool_length_offset_.z *= factor;
|
||||
tool_length_offset_.u *= factor;
|
||||
tool_length_offset_.v *= factor;
|
||||
tool_length_offset_.w *= factor;
|
||||
probe_position_.x *= factor;
|
||||
probe_position_.y *= factor;
|
||||
probe_position_.z *= factor;
|
||||
probe_position_.u *= factor;
|
||||
probe_position_.v *= factor;
|
||||
probe_position_.w *= factor;
|
||||
if (has_pending_motion_start_) {
|
||||
pending_motion_start_.x *= factor;
|
||||
pending_motion_start_.y *= factor;
|
||||
pending_motion_start_.z *= factor;
|
||||
pending_motion_start_.u *= factor;
|
||||
pending_motion_start_.v *= factor;
|
||||
pending_motion_start_.w *= factor;
|
||||
}
|
||||
}
|
||||
unit_scale_ = scale;
|
||||
CncSimEvent event = base_event(CNC_SIM_EVENT_SET_UNITS, line);
|
||||
event.feed = scale;
|
||||
|
||||
@@ -29,6 +29,7 @@ public:
|
||||
void set_xy_rotation(double angle_degrees, int line);
|
||||
|
||||
void use_length_units(double scale, int line);
|
||||
void use_length_units(double scale, int line, bool rescale_linear_state);
|
||||
void select_plane(int plane, int line);
|
||||
void set_traverse_rate(double rate);
|
||||
void set_feed_rate(double feed, int line);
|
||||
|
||||
@@ -193,7 +193,7 @@ void INIT_CANON() {
|
||||
void USE_LENGTH_UNITS(CANON_UNITS units) {
|
||||
trace_call("USE_LENGTH_UNITS");
|
||||
if (active_sink) {
|
||||
active_sink->use_length_units(units_to_scale(units), event_line());
|
||||
active_sink->use_length_units(units_to_scale(units), event_line(), true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,10 +211,10 @@ void SET_FEED_RATE(double rate) {
|
||||
}
|
||||
}
|
||||
|
||||
void SET_SPINDLE_SPEED(int, double speed) {
|
||||
void SET_SPINDLE_SPEED(int spindle, double speed) {
|
||||
trace_call("SET_SPINDLE_SPEED");
|
||||
if (active_sink) {
|
||||
active_sink->set_spindle_speed(speed, event_line());
|
||||
active_sink->set_spindle_speed(spindle, speed, event_line());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -402,6 +402,15 @@ void SET_MOTION_CONTROL_MODE(CANON_MOTION_MODE mode, double tolerance) {
|
||||
|
||||
void SET_NAIVECAM_TOLERANCE(double tolerance) {
|
||||
naivecam_tolerance = tolerance;
|
||||
if (active_sink) {
|
||||
CncSimEvent event{};
|
||||
event.version = 1;
|
||||
event.type = CNC_SIM_EVENT_COMMENT;
|
||||
event.line = event_line();
|
||||
event.feed = tolerance;
|
||||
event.reserved = 641;
|
||||
active_sink->emit_raw(event);
|
||||
}
|
||||
}
|
||||
|
||||
void SET_CUTTER_RADIUS_COMPENSATION(double) {
|
||||
@@ -477,21 +486,21 @@ void SET_SPINDLE_MODE(int spindle, double mode) {
|
||||
void SPINDLE_RETRACT_TRAVERSE() {
|
||||
}
|
||||
|
||||
void START_SPINDLE_CLOCKWISE(int, int) {
|
||||
void START_SPINDLE_CLOCKWISE(int spindle, int) {
|
||||
if (active_sink) {
|
||||
active_sink->start_spindle(1, event_line());
|
||||
active_sink->start_spindle(spindle, 1, event_line());
|
||||
}
|
||||
}
|
||||
|
||||
void START_SPINDLE_COUNTERCLOCKWISE(int, int) {
|
||||
void START_SPINDLE_COUNTERCLOCKWISE(int spindle, int) {
|
||||
if (active_sink) {
|
||||
active_sink->start_spindle(-1, event_line());
|
||||
active_sink->start_spindle(spindle, -1, event_line());
|
||||
}
|
||||
}
|
||||
|
||||
void STOP_SPINDLE_TURNING(int) {
|
||||
void STOP_SPINDLE_TURNING(int spindle) {
|
||||
if (active_sink) {
|
||||
active_sink->stop_spindle(event_line());
|
||||
active_sink->stop_spindle(spindle, event_line());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -773,11 +782,16 @@ int GET_EXTERNAL_FLOOD() {
|
||||
}
|
||||
|
||||
CANON_UNITS GET_EXTERNAL_LENGTH_UNIT_TYPE() {
|
||||
return active_sink && active_sink->unit_scale() == 25.4 ? CANON_UNITS_INCHES : CANON_UNITS_MM;
|
||||
// LinuxCNC src/emc/task/emccanon.cc derives this from INI machine/user
|
||||
// units, not from the active G20/G21 program units.
|
||||
return CANON_UNITS_MM;
|
||||
}
|
||||
|
||||
double GET_EXTERNAL_LENGTH_UNITS() {
|
||||
return active_sink ? active_sink->unit_scale() : 1.0;
|
||||
// LinuxCNC src/emc/task/emccanon.cc returns traj.linearUnits here:
|
||||
// external/user units per internal millimeter. The simulator has no INI
|
||||
// machine-units bridge yet, so the source-linked default is metric.
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
double GET_EXTERNAL_ANGLE_UNITS() {
|
||||
|
||||
@@ -160,6 +160,7 @@ int main() {
|
||||
bool saw_adaptive_feed_off = false;
|
||||
bool saw_feed_hold_on = false;
|
||||
bool saw_feed_hold_off = false;
|
||||
bool saw_naivecam_tolerance = false;
|
||||
bool saw_speed_feed_sync_start = false;
|
||||
bool saw_speed_feed_sync_stop = false;
|
||||
bool saw_arc = false;
|
||||
@@ -284,9 +285,13 @@ int main() {
|
||||
event.reserved == 53 &&
|
||||
event.feed == 1.0);
|
||||
saw_feed_hold_off = saw_feed_hold_off || (event.type == CNC_SIM_EVENT_COMMENT &&
|
||||
event.line == 29 &&
|
||||
event.reserved == 53 &&
|
||||
event.feed == 0.0);
|
||||
event.line == 29 &&
|
||||
event.reserved == 53 &&
|
||||
event.feed == 0.0);
|
||||
saw_naivecam_tolerance = saw_naivecam_tolerance || (event.type == CNC_SIM_EVENT_COMMENT &&
|
||||
event.line == 30 &&
|
||||
event.reserved == 641 &&
|
||||
event.feed == 0.025);
|
||||
saw_speed_feed_sync_start = saw_speed_feed_sync_start || (event.type == CNC_SIM_EVENT_COMMENT &&
|
||||
event.reserved == 3301 &&
|
||||
event.feed == 1.25 &&
|
||||
@@ -387,6 +392,7 @@ int main() {
|
||||
ok &= expect(external_motion_mode, "expected external motion-control mode query to reflect SET_MOTION_CONTROL_MODE");
|
||||
ok &= expect(external_motion_tolerance, "expected external motion-control tolerance query to reflect SET_MOTION_CONTROL_MODE");
|
||||
ok &= expect(external_naivecam_tolerance, "expected external naivecam tolerance query to reflect SET_NAIVECAM_TOLERANCE");
|
||||
ok &= expect(saw_naivecam_tolerance, "expected naivecam tolerance state event");
|
||||
ok &= expect(external_block_delete_on, "expected block-delete query to reflect enable");
|
||||
ok &= expect(external_block_delete_off, "expected block-delete query to reflect disable");
|
||||
ok &= expect(external_optional_stop_on, "expected optional-stop query to reflect enable");
|
||||
|
||||
@@ -85,6 +85,18 @@ struct _inittab {
|
||||
PyObject *(*initfunc)(void);
|
||||
};
|
||||
|
||||
struct PyStatus {
|
||||
int _type;
|
||||
const char *func;
|
||||
const char *err_msg;
|
||||
int exitcode;
|
||||
};
|
||||
|
||||
struct PyConfig {
|
||||
wchar_t *program_name;
|
||||
int buffered_stdio;
|
||||
};
|
||||
|
||||
using PyCFunction = PyObject *(*)(PyObject *, PyObject *);
|
||||
using getter = PyObject *(*)(PyObject *, void *);
|
||||
using setter = int (*)(PyObject *, PyObject *, void *);
|
||||
@@ -146,6 +158,7 @@ void Py_DecRef(PyObject *);
|
||||
int PyArg_ParseTuple(PyObject *, const char *, ...);
|
||||
int PyArg_VaParse(PyObject *, const char *, va_list);
|
||||
PyObject *PyObject_CallMethod(PyObject *, char *, char *, ...);
|
||||
PyObject *PyObject_Call(PyObject *, PyObject *, PyObject *);
|
||||
PyObject *PyObject_GetAttrString(PyObject *, const char *);
|
||||
int PyObject_SetAttrString(PyObject *, const char *, PyObject *);
|
||||
int PyObject_IsTrue(PyObject *);
|
||||
@@ -165,6 +178,17 @@ Py_ssize_t PySequence_Length(PyObject *);
|
||||
PyObject *Py_BuildValue(const char *, ...);
|
||||
PyObject *PyModule_Create(PyModuleDef *);
|
||||
int PyModule_AddObject(PyObject *, const char *, PyObject *);
|
||||
int PyImport_ExtendInittab(_inittab *);
|
||||
PyObject *PyImport_GetModuleDict(void);
|
||||
PyObject *PyImport_AddModule(const char *);
|
||||
int PyDict_SetItemString(PyObject *, const char *, PyObject *);
|
||||
void PyConfig_InitPythonConfig(PyConfig *);
|
||||
PyStatus PyConfig_SetString(PyConfig *, wchar_t **, const wchar_t *);
|
||||
void PyConfig_Clear(PyConfig *);
|
||||
PyStatus Py_InitializeFromConfig(PyConfig *);
|
||||
wchar_t *Py_DecodeLocale(const char *, std::size_t *);
|
||||
int PyRun_SimpleString(const char *);
|
||||
const char *Py_GetVersion(void);
|
||||
int PyType_Ready(PyTypeObject *);
|
||||
PyObject *PyType_GenericNew(PyTypeObject *, PyObject *, PyObject *);
|
||||
void *PyObject_NewShim(std::size_t, PyTypeObject *);
|
||||
|
||||
@@ -1,14 +1,30 @@
|
||||
#include "cnc_sim_api.h"
|
||||
#include "boost/python/object.hpp"
|
||||
#include "hal.h"
|
||||
#include "libnml/nml/stat_msg.hh"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdarg>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <wordexp.h>
|
||||
|
||||
extern int _task;
|
||||
|
||||
extern "C" {
|
||||
extern PyObject *PyInit_interpreter(void);
|
||||
extern PyObject *PyInit_emccanon(void);
|
||||
extern struct _inittab builtin_modules[];
|
||||
extern int rtapi_snprintf(char *buf, unsigned long size, const char *fmt, ...);
|
||||
extern int rtapi_vsnprintf(char *buf, unsigned long size, const char *fmt, va_list ap);
|
||||
}
|
||||
|
||||
// LinuxCNC source basis: src/emc/rs274ngc/rs274ngc_pre.cc provides read(),
|
||||
// execute(), and wordexp() paths; interp_convert.cc converts G0, G2, and M30.
|
||||
// src/emc/rs274ngc/interp_namedparams.cc calls the HAL lookup functions
|
||||
// declared in include/hal.h and implemented by src/hal/hal_lib.c.
|
||||
namespace {
|
||||
|
||||
int collect_event(const CncSimEvent *event, void *user_data) {
|
||||
@@ -57,6 +73,119 @@ bool wordexp_expands_environment_variables() {
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool wordexp_expands_braced_environment_variables() {
|
||||
setenv("CNC_SIM_WORDEXP_BRACED_PROBE", "linuxcnc-braced-wordexp", 1);
|
||||
|
||||
wordexp_t expanded{};
|
||||
if (wordexp("${CNC_SIM_WORDEXP_BRACED_PROBE}/subroutines", &expanded, 0) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool ok = expanded.we_wordc == 1 &&
|
||||
expanded.we_wordv &&
|
||||
expanded.we_wordv[0] &&
|
||||
std::strcmp(expanded.we_wordv[0], "linuxcnc-braced-wordexp/subroutines") == 0;
|
||||
wordfree(&expanded);
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool hal_lookup_is_unavailable() {
|
||||
if (hal_init("cnc_sim_wasm_runtime_probe") != 1) {
|
||||
return false;
|
||||
}
|
||||
if (hal_ready(1) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
hal_data_u dummy{};
|
||||
hal_data_u *data = &dummy;
|
||||
hal_type_t type = HAL_FLOAT;
|
||||
bool connected = true;
|
||||
if (hal_get_pin_value_by_name("cnc-sim.missing-pin", &type, &data, &connected) != -1 ||
|
||||
type != HAL_TYPE_UNINITIALIZED ||
|
||||
data != nullptr ||
|
||||
connected) {
|
||||
return false;
|
||||
}
|
||||
|
||||
data = &dummy;
|
||||
type = HAL_FLOAT;
|
||||
bool has_writers = true;
|
||||
if (hal_get_signal_value_by_name("cnc-sim.missing-signal", &type, &data, &has_writers) != -1 ||
|
||||
type != HAL_TYPE_UNINITIALIZED ||
|
||||
data != nullptr ||
|
||||
has_writers) {
|
||||
return false;
|
||||
}
|
||||
|
||||
data = &dummy;
|
||||
type = HAL_FLOAT;
|
||||
if (hal_get_param_value_by_name("cnc-sim.missing-param", &type, &data) != -1 ||
|
||||
type != HAL_TYPE_UNINITIALIZED ||
|
||||
data != nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool nml_status_constructors_match_linuxcnc() {
|
||||
// LinuxCNC source basis: src/libnml/nml/nmlmsg.cc and stat_msg.cc
|
||||
// initialize RCS status messages before EMC status objects use them.
|
||||
RCS_GENERIC_STATUS status;
|
||||
return status._type == RCS_GENERIC_STATUS_TYPE &&
|
||||
status.size == static_cast<long>(sizeof(RCS_GENERIC_STATUS)) &&
|
||||
status.command_type == -1 &&
|
||||
status.echo_serial_number == -1 &&
|
||||
status.status == RCS_STATUS::UNINITIALIZED &&
|
||||
status._state == -1;
|
||||
}
|
||||
|
||||
bool builtin_modules_match_linuxcnc_preview_runtime() {
|
||||
// LinuxCNC source basis: src/emc/rs274ngc/gcodemodule.cc defines _task=0
|
||||
// for preview and registers interpreter/emccanon builtin module entries;
|
||||
// src/emc/task/taskclass.cc uses the same builtin module table shape.
|
||||
return _task == 0 &&
|
||||
builtin_modules[0].name &&
|
||||
std::strcmp(builtin_modules[0].name, "interpreter") == 0 &&
|
||||
builtin_modules[0].initfunc == PyInit_interpreter &&
|
||||
builtin_modules[0].initfunc() == nullptr &&
|
||||
builtin_modules[1].name &&
|
||||
std::strcmp(builtin_modules[1].name, "emccanon") == 0 &&
|
||||
builtin_modules[1].initfunc == PyInit_emccanon &&
|
||||
builtin_modules[1].initfunc() == nullptr &&
|
||||
builtin_modules[2].name == nullptr &&
|
||||
builtin_modules[2].initfunc == nullptr;
|
||||
}
|
||||
|
||||
int call_rtapi_vsnprintf(char *buffer, unsigned long size, const char *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
const int result = rtapi_vsnprintf(buffer, size, format, args);
|
||||
va_end(args);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool rtapi_formatting_matches_linuxcnc_userspace() {
|
||||
// LinuxCNC source basis: src/rtapi/uspace_common.h implements both
|
||||
// rtapi_snprintf() and rtapi_vsnprintf() as userspace vsnprintf() wrappers.
|
||||
char formatted[32]{};
|
||||
if (rtapi_snprintf(formatted, sizeof(formatted), "HAL_%s_%d", "probe", 7) != 11 ||
|
||||
std::strcmp(formatted, "HAL_probe_7") != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char via_va_list[32]{};
|
||||
if (call_rtapi_vsnprintf(via_va_list, sizeof(via_va_list), "%s.%02d", "axis", 3) != 7 ||
|
||||
std::strcmp(via_va_list, "axis.03") != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char truncated[5]{};
|
||||
return rtapi_snprintf(truncated, sizeof(truncated), "abcdef") == 6 &&
|
||||
std::strcmp(truncated, "abcd") == 0;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main() {
|
||||
@@ -66,6 +195,21 @@ int main() {
|
||||
if (!wordexp_expands_environment_variables()) {
|
||||
return 6;
|
||||
}
|
||||
if (!wordexp_expands_braced_environment_variables()) {
|
||||
return 8;
|
||||
}
|
||||
if (!hal_lookup_is_unavailable()) {
|
||||
return 7;
|
||||
}
|
||||
if (!nml_status_constructors_match_linuxcnc()) {
|
||||
return 9;
|
||||
}
|
||||
if (!builtin_modules_match_linuxcnc_preview_runtime()) {
|
||||
return 10;
|
||||
}
|
||||
if (!rtapi_formatting_matches_linuxcnc_userspace()) {
|
||||
return 11;
|
||||
}
|
||||
|
||||
std::vector<CncSimEvent> events;
|
||||
CncSimHandle *sim = cnc_sim_create();
|
||||
|
||||
@@ -1,8 +1,38 @@
|
||||
#include "dlfcn.h"
|
||||
#include "interp_base.hh"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
// LinuxCNC source basis: src/emc/rs274ngc/interp_base.cc provides
|
||||
// interp_from_shlib(), with the declaration in interp_base.hh.
|
||||
// interp_from_shlib(), with the declaration in interp_base.hh. Its native
|
||||
// dlopen()/dlsym() loader edge is intentionally unavailable in WASM probes.
|
||||
int main() {
|
||||
InterpBase *interp = interp_from_shlib("nonexistent-interpreter.so");
|
||||
return interp == nullptr ? 0 : 1;
|
||||
if (dlopen(nullptr, RTLD_GLOBAL) != nullptr) {
|
||||
return 2;
|
||||
}
|
||||
if (dlopen("/tmp/cnc_sim_missing_interpreter.so", RTLD_NOW) != nullptr) {
|
||||
return 3;
|
||||
}
|
||||
if (dlsym(nullptr, "makeInterp") != nullptr) {
|
||||
return 4;
|
||||
}
|
||||
const char *error = dlerror();
|
||||
if (!error || !std::strstr(error, "dynamic loading is unavailable")) {
|
||||
return 5;
|
||||
}
|
||||
if (dlclose(nullptr) != 0) {
|
||||
return 6;
|
||||
}
|
||||
|
||||
// LinuxCNC src/emc/rs274ngc/interp_base.cc uses absolute interpreter
|
||||
// paths directly before calling dlopen().
|
||||
if (interp_from_shlib("/tmp/cnc_sim_missing_absolute_interpreter.so") != nullptr) {
|
||||
return 7;
|
||||
}
|
||||
// Relative interpreter names are resolved through EMC2_HOME/lib/linuxcnc
|
||||
// before the same unavailable dynamic-loading edge is reached.
|
||||
if (interp_from_shlib("nonexistent-interpreter.so") != nullptr) {
|
||||
return 8;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -71,3 +71,10 @@ RCS_STAT_MSG::RCS_STAT_MSG(NMLTYPE t, size_t sz) : NMLmsg(t, sz) {
|
||||
status = RCS_STATUS::UNINITIALIZED;
|
||||
_state = -1;
|
||||
}
|
||||
|
||||
RCS_GENERIC_STATUS::RCS_GENERIC_STATUS()
|
||||
: RCS_STAT_MSG(RCS_GENERIC_STATUS_TYPE, sizeof(RCS_GENERIC_STATUS)) {
|
||||
}
|
||||
|
||||
void RCS_GENERIC_STATUS::update(CMS *) {
|
||||
}
|
||||
|
||||
252
core/wasm_shims/python_c_api_probe_main.cc
Normal file
252
core/wasm_shims/python_c_api_probe_main.cc
Normal file
@@ -0,0 +1,252 @@
|
||||
#include "boost/python/class.hpp"
|
||||
#include "boost/python/converter/registry.hpp"
|
||||
#include "boost/python/def.hpp"
|
||||
#include "boost/python/dict.hpp"
|
||||
#include "boost/python/enum.hpp"
|
||||
#include "boost/python/exception_translator.hpp"
|
||||
#include "boost/python/extract.hpp"
|
||||
#include "boost/python/import.hpp"
|
||||
#include "boost/python/list.hpp"
|
||||
#include "boost/python/module.hpp"
|
||||
#include "boost/python/object.hpp"
|
||||
#include "boost/python/object/class_detail.hpp"
|
||||
#include "boost/python/return_internal_reference.hpp"
|
||||
#include "boost/python/scope.hpp"
|
||||
#include "boost/python/str.hpp"
|
||||
#include "boost/python/suite/indexing/map_indexing_suite.hpp"
|
||||
#include "boost/python/tuple.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
// LinuxCNC source basis: src/emc/rs274ngc/gcodemodule.cc,
|
||||
// interpmodule.cc, py*.cc, interp_python.cc, interp_namedparams.cc, and
|
||||
// src/emc/pythonplugin/python_plugin.cc use these Python C API and
|
||||
// Boost.Python entry points. The WASM shim keeps the API inert and link-safe
|
||||
// while browser Python execution remains disabled.
|
||||
namespace {
|
||||
|
||||
struct ProbeObject {
|
||||
PyObject_HEAD
|
||||
int value;
|
||||
};
|
||||
|
||||
struct ProbeCppObject {
|
||||
int value = 0;
|
||||
};
|
||||
|
||||
PyObject *probe_getter(PyObject *, void *) {
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
int probe_setter(PyObject *, PyObject *, void *) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyObject *probe_method(PyObject *, PyObject *) {
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
void translate_probe_exception(const std::runtime_error &) {
|
||||
}
|
||||
|
||||
bool boost_python_shims_are_inert() {
|
||||
namespace bp = boost::python;
|
||||
|
||||
bp::object object;
|
||||
if (object.ptr() != nullptr || object.attr("missing").operator bp::object().ptr() != nullptr ||
|
||||
object["missing"].ptr() != nullptr || object[0].ptr() != nullptr ||
|
||||
object().ptr() != nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bp::list list;
|
||||
list.append(object);
|
||||
list.extend(list);
|
||||
bp::tuple tuple(list);
|
||||
bp::dict dict;
|
||||
if (bp::tuple().ptr() != nullptr || tuple.ptr() != nullptr ||
|
||||
bp::make_tuple(1, 2.0, "three").ptr() != nullptr ||
|
||||
dict.keys().ptr() != nullptr || bp::len(list) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((object % tuple).ptr() != nullptr || ("linuxcnc" % tuple).ptr() != nullptr ||
|
||||
(object + object).ptr() != nullptr || (object + "suffix").ptr() != nullptr ||
|
||||
("prefix" + object).ptr() != nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bp::scope scope(object);
|
||||
scope.attr("this") = object;
|
||||
if (scope.attr("this").operator bp::object().ptr() != nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bp::getattr(object, "__next__").ptr() != nullptr ||
|
||||
bp::make_function(probe_method).ptr() != nullptr ||
|
||||
bp::make_getter(probe_getter).ptr() != nullptr ||
|
||||
bp::make_setter(probe_setter).ptr() != nullptr ||
|
||||
bp::import("traceback").ptr() != nullptr ||
|
||||
bp::str("\n").join(object).ptr() != nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (static_cast<int>(bp::extract<int>(object)) != 0 ||
|
||||
static_cast<double>(bp::extract<double>(object)) != 0.0 ||
|
||||
static_cast<std::string>(bp::extract<std::string>(object)) != std::string() ||
|
||||
static_cast<char *>(bp::extract<char *>(object)) != nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bp::handle<> default_handle;
|
||||
bp::handle<> null_handle(bp::allow_null(static_cast<PyObject *>(nullptr)));
|
||||
bp::handle<> borrowed_handle(bp::borrowed(Py_None));
|
||||
if (default_handle || default_handle.get() != nullptr ||
|
||||
null_handle || null_handle.get() != nullptr ||
|
||||
borrowed_handle || borrowed_handle.get() != nullptr) {
|
||||
return false;
|
||||
}
|
||||
bp::handle_exception();
|
||||
|
||||
bp::class_<ProbeCppObject>("ProbeCppObject")
|
||||
.def("method", probe_method)
|
||||
.def_readwrite("value", &ProbeCppObject::value)
|
||||
.add_property("property", bp::make_getter(probe_getter), bp::make_setter(probe_setter));
|
||||
bp::class_<ProbeCppObject>("ProbeCppObjectNoInit", bp::no_init);
|
||||
bp::class_<ProbeCppObject>("ProbeCppObjectDoc", "doc");
|
||||
bp::class_<ProbeCppObject>("ProbeCppObjectDocNoInit", "doc", bp::no_init);
|
||||
|
||||
bp::enum_<int>("ProbeEnum").value("one", 1).export_values();
|
||||
bp::def("probe", probe_method);
|
||||
bp::register_exception_translator<std::runtime_error>(translate_probe_exception);
|
||||
bp::return_internal_reference<1, bp::default_call_policies> reference_policy;
|
||||
(void)reference_policy;
|
||||
bp::map_indexing_suite<std::map<int, int>> map_suite;
|
||||
(void)map_suite;
|
||||
if (bp::objects::registered_class_object(bp::type_id<ProbeCppObject>()) != nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
BOOST_PYTHON_MODULE(cnc_sim_python_c_api_probe_module) {
|
||||
}
|
||||
|
||||
int main() {
|
||||
if (Py_IsInitialized() != 1) {
|
||||
return 1;
|
||||
}
|
||||
if (PyErr_Occurred() != nullptr) {
|
||||
return 2;
|
||||
}
|
||||
PyObject *exc = reinterpret_cast<PyObject *>(1);
|
||||
PyObject *val = reinterpret_cast<PyObject *>(1);
|
||||
PyObject *tb = reinterpret_cast<PyObject *>(1);
|
||||
PyErr_Fetch(&exc, &val, &tb);
|
||||
if (exc || val || tb) {
|
||||
return 3;
|
||||
}
|
||||
if (!Py_None || !Py_TYPE(Py_None) || std::strcmp(Py_TYPE(Py_None)->tp_name, "NoneType") != 0) {
|
||||
return 4;
|
||||
}
|
||||
if (PyUnicode_FromString("linuxcnc") != Py_None) {
|
||||
return 5;
|
||||
}
|
||||
if (PyObject_Str(Py_None) != Py_None) {
|
||||
return 16;
|
||||
}
|
||||
if (std::strcmp(PyUnicode_AsUTF8(Py_None), "") != 0) {
|
||||
return 6;
|
||||
}
|
||||
if (PyUnicode_Check(Py_None) != 0 || PyLong_Check(Py_None) != 0 || PyFloat_Check(Py_None) != 0 ||
|
||||
PyGen_Check(Py_None) != 0 || PyErr_ExceptionMatches(PyExc_KeyError) != 0) {
|
||||
return 17;
|
||||
}
|
||||
if (PyLong_FromLong(7) != Py_None || PyLong_AsLong(Py_None) != 0) {
|
||||
return 7;
|
||||
}
|
||||
if (PyFloat_AsDouble(Py_None) != 0.0) {
|
||||
return 8;
|
||||
}
|
||||
if (PyTuple_New(2) != Py_None || PyTuple_SetItem(Py_None, 0, Py_None) != 0 || PyTuple_Size(Py_None) != 0) {
|
||||
return 9;
|
||||
}
|
||||
if (PyList_New(2) != Py_None || PyList_SetItem(Py_None, 0, Py_None) != 0 || PyList_Size(Py_None) != 0) {
|
||||
return 10;
|
||||
}
|
||||
if (PyTuple_GetItem(Py_None, 0) != Py_None || PyList_GetItem(Py_None, 0) != Py_None ||
|
||||
PySequence_GetItem(Py_None, 0) != Py_None || PySequence_Length(Py_None) != 0) {
|
||||
return 18;
|
||||
}
|
||||
if (PyObject_IsTrue(Py_None) != 0 || PyCallable_Check(Py_None) != 0 || PyObject_IsInstance(Py_None, Py_None) != 0) {
|
||||
return 11;
|
||||
}
|
||||
if (PyObject_CallMethod(Py_None, const_cast<char *>("noop"), const_cast<char *>("")) != Py_None ||
|
||||
PyObject_Call(Py_None, Py_None, Py_None) != Py_None ||
|
||||
PyObject_GetAttrString(Py_None, "noop") != Py_None ||
|
||||
PyObject_SetAttrString(Py_None, "noop", Py_None) != 0) {
|
||||
return 19;
|
||||
}
|
||||
if (PyArg_ParseTuple(Py_None, "") != 0 || Py_BuildValue("i", 1) != Py_None) {
|
||||
return 20;
|
||||
}
|
||||
ProbeObject *probe = PyObject_New(ProbeObject, &PyList_Type);
|
||||
if (!probe || Py_TYPE(reinterpret_cast<PyObject *>(probe)) != &PyList_Type) {
|
||||
std::free(probe);
|
||||
return 12;
|
||||
}
|
||||
std::free(probe);
|
||||
if (PyModule_Create(nullptr) != Py_None || PyModule_AddObject(Py_None, "value", Py_None) != 0) {
|
||||
return 13;
|
||||
}
|
||||
_inittab inittab[] = {
|
||||
{"interpreter", nullptr},
|
||||
{nullptr, nullptr},
|
||||
};
|
||||
if (PyImport_ExtendInittab(inittab) != 0 || PyImport_GetModuleDict() == Py_None ||
|
||||
PyImport_AddModule("interpreter") == Py_None ||
|
||||
PyDict_SetItemString(PyImport_GetModuleDict(), "interpreter", PyImport_AddModule("interpreter")) != 0) {
|
||||
return 21;
|
||||
}
|
||||
PyConfig config{};
|
||||
PyConfig_InitPythonConfig(&config);
|
||||
if (config.program_name != nullptr || config.buffered_stdio != 1) {
|
||||
return 22;
|
||||
}
|
||||
const wchar_t program_name[] = L"linuxcnc";
|
||||
PyStatus config_status = PyConfig_SetString(&config, &config.program_name, program_name);
|
||||
if (config_status._type != 0 || config.program_name != program_name) {
|
||||
return 23;
|
||||
}
|
||||
PyStatus init_status = Py_InitializeFromConfig(&config);
|
||||
if (init_status._type != 0) {
|
||||
return 24;
|
||||
}
|
||||
std::size_t decoded_size = 99;
|
||||
if (Py_DecodeLocale("linuxcnc", &decoded_size) != nullptr || decoded_size != 8) {
|
||||
return 25;
|
||||
}
|
||||
if (PyRun_SimpleString("pass") != 0 || std::strcmp(Py_GetVersion(), "wasm-python-disabled") != 0) {
|
||||
return 26;
|
||||
}
|
||||
PyConfig_Clear(&config);
|
||||
if (config.program_name != nullptr || config.buffered_stdio != 0) {
|
||||
return 27;
|
||||
}
|
||||
if (PyType_Ready(&PyList_Type) != 0 || PyType_GenericNew(&PyList_Type, Py_None, Py_None) != Py_None) {
|
||||
return 14;
|
||||
}
|
||||
if (PyErr_Format(PyExc_TypeError, "linuxcnc") != nullptr) {
|
||||
return 15;
|
||||
}
|
||||
if (!boost_python_shims_are_inert()) {
|
||||
return 28;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "boost/python/object.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
// LinuxCNC source basis: src/emc/rs274ngc/interp_python.cc,
|
||||
// interp_namedparams.cc, gcodemodule.cc, and src/emc/pythonplugin/python_plugin.cc
|
||||
@@ -8,7 +9,11 @@
|
||||
extern "C" {
|
||||
|
||||
static PyTypeObject none_type = {"NoneType"};
|
||||
static PyTypeObject module_type = {"module"};
|
||||
static PyTypeObject dict_type = {"dict"};
|
||||
static PyObject none_object = {&none_type};
|
||||
static PyObject module_object = {&module_type};
|
||||
static PyObject dict_object = {&dict_type};
|
||||
|
||||
PyObject *PyExc_KeyError = reinterpret_cast<PyObject *>(1);
|
||||
PyObject *PyExc_KeyboardInterrupt = reinterpret_cast<PyObject *>(2);
|
||||
@@ -111,6 +116,10 @@ PyObject *PyObject_CallMethod(PyObject *, char *, char *, ...) {
|
||||
return &none_object;
|
||||
}
|
||||
|
||||
PyObject *PyObject_Call(PyObject *, PyObject *, PyObject *) {
|
||||
return &none_object;
|
||||
}
|
||||
|
||||
PyObject *PyObject_GetAttrString(PyObject *, const char *) {
|
||||
return &none_object;
|
||||
}
|
||||
@@ -187,6 +196,64 @@ int PyModule_AddObject(PyObject *, const char *, PyObject *) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PyImport_ExtendInittab(_inittab *) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyObject *PyImport_GetModuleDict(void) {
|
||||
return &dict_object;
|
||||
}
|
||||
|
||||
PyObject *PyImport_AddModule(const char *) {
|
||||
return &module_object;
|
||||
}
|
||||
|
||||
int PyDict_SetItemString(PyObject *, const char *, PyObject *) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PyConfig_InitPythonConfig(PyConfig *config) {
|
||||
if (!config) {
|
||||
return;
|
||||
}
|
||||
config->program_name = nullptr;
|
||||
config->buffered_stdio = 1;
|
||||
}
|
||||
|
||||
PyStatus PyConfig_SetString(PyConfig *, wchar_t **config_str, const wchar_t *value) {
|
||||
if (config_str) {
|
||||
*config_str = const_cast<wchar_t *>(value);
|
||||
}
|
||||
return PyStatus{0, nullptr, nullptr, 0};
|
||||
}
|
||||
|
||||
void PyConfig_Clear(PyConfig *config) {
|
||||
if (!config) {
|
||||
return;
|
||||
}
|
||||
config->program_name = nullptr;
|
||||
config->buffered_stdio = 0;
|
||||
}
|
||||
|
||||
PyStatus Py_InitializeFromConfig(PyConfig *) {
|
||||
return PyStatus{0, nullptr, nullptr, 0};
|
||||
}
|
||||
|
||||
wchar_t *Py_DecodeLocale(const char *arg, std::size_t *size) {
|
||||
if (size) {
|
||||
*size = arg ? std::strlen(arg) : 0;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int PyRun_SimpleString(const char *) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *Py_GetVersion(void) {
|
||||
return "wasm-python-disabled";
|
||||
}
|
||||
|
||||
int PyType_Ready(PyTypeObject *) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
#include "pythonplugin/python_plugin.hh"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <limits.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unistd.h>
|
||||
|
||||
// LinuxCNC source basis: src/emc/pythonplugin/python_plugin.cc provides the
|
||||
// native PythonPlugin implementation called by RS274 Python/remap paths.
|
||||
@@ -11,10 +17,139 @@ __attribute__((weak)) std::string handle_pyerror() {
|
||||
|
||||
PythonPlugin *python_plugin = nullptr;
|
||||
|
||||
PythonPlugin *PythonPlugin::instantiate(struct _inittab *) {
|
||||
namespace {
|
||||
|
||||
std::string trim_ini_value(std::string value) {
|
||||
const auto first = std::find_if_not(value.begin(), value.end(), [](unsigned char ch) {
|
||||
return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n';
|
||||
});
|
||||
const auto last = std::find_if_not(value.rbegin(), value.rend(), [](unsigned char ch) {
|
||||
return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n';
|
||||
}).base();
|
||||
if (first >= last) {
|
||||
return {};
|
||||
}
|
||||
return std::string(first, last);
|
||||
}
|
||||
|
||||
bool read_ini_section(const std::string &text, std::string §ion_name) {
|
||||
if (text.empty() || text.front() != '[') {
|
||||
return false;
|
||||
}
|
||||
const auto close = text.find(']');
|
||||
if (close == std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// LinuxCNC source basis: IniFile::processLine() trims the section name
|
||||
// between '[' and ']' and ignores text after the closing bracket.
|
||||
section_name = trim_ini_value(text.substr(1, close - 1));
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<std::string> find_ini_values(const char *iniFilename,
|
||||
const char *section,
|
||||
const char *key) {
|
||||
std::vector<std::string> values;
|
||||
FILE *file = std::fopen(iniFilename, "r");
|
||||
if (!file) {
|
||||
return values;
|
||||
}
|
||||
|
||||
bool in_section = false;
|
||||
char line[PATH_MAX + 256];
|
||||
while (std::fgets(line, sizeof(line), file)) {
|
||||
std::string text = trim_ini_value(line);
|
||||
if (text.empty() || text[0] == ';' || text[0] == '#') {
|
||||
continue;
|
||||
}
|
||||
std::string section_name;
|
||||
if (read_ini_section(text, section_name)) {
|
||||
in_section = section_name == section;
|
||||
continue;
|
||||
}
|
||||
if (!in_section) {
|
||||
continue;
|
||||
}
|
||||
const auto equals = text.find('=');
|
||||
if (equals == std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
if (trim_ini_value(text.substr(0, equals)) == key) {
|
||||
values.push_back(trim_ini_value(text.substr(equals + 1)));
|
||||
}
|
||||
}
|
||||
|
||||
std::fclose(file);
|
||||
return values;
|
||||
}
|
||||
|
||||
bool find_ini_value(const char *iniFilename,
|
||||
const char *section,
|
||||
const char *key,
|
||||
std::string &value) {
|
||||
const std::vector<std::string> values = find_ini_values(iniFilename, section, key);
|
||||
if (values.empty()) {
|
||||
return false;
|
||||
}
|
||||
value = values.front();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tilde_expand_path(const std::string &path, std::string &expanded) {
|
||||
// LinuxCNC source basis: IniFile::tildeExpand() copies non-"~/" paths and
|
||||
// returns failure for "~/" paths when HOME is unavailable.
|
||||
if (path.size() < 2 || path[0] != '~' || path[1] != '/') {
|
||||
expanded = path;
|
||||
return true;
|
||||
}
|
||||
const char *home = std::getenv("HOME");
|
||||
if (!home) {
|
||||
return false;
|
||||
}
|
||||
expanded = std::string(home) + path.substr(1);
|
||||
return true;
|
||||
}
|
||||
|
||||
int check_python_path_entries(const char *iniFilename,
|
||||
const char *key,
|
||||
pp_status failure_status) {
|
||||
for (const std::string &entry : find_ini_values(iniFilename, "PYTHON", key)) {
|
||||
std::string expanded;
|
||||
// LinuxCNC source basis: python_plugin.cc configure() runs
|
||||
// TildeExpansion on [PYTHON] PATH_PREPEND/PATH_APPEND before
|
||||
// PyRun_SimpleString(); browser-safe probes preserve the expansion
|
||||
// failure status without executing Python path mutation.
|
||||
if (!tilde_expand_path(entry, expanded)) {
|
||||
return failure_status;
|
||||
}
|
||||
}
|
||||
return PLUGIN_OK;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
PythonPlugin *PythonPlugin::instantiate(struct _inittab *inittab) {
|
||||
static PythonPlugin plugin;
|
||||
python_plugin = &plugin;
|
||||
python_plugin->status = PLUGIN_OK;
|
||||
if (!python_plugin) {
|
||||
python_plugin = &plugin;
|
||||
python_plugin->status = PLUGIN_OK;
|
||||
if (inittab) {
|
||||
for (int i = 0; inittab[i].name != nullptr; ++i) {
|
||||
// LinuxCNC source basis: python_plugin.cc reports
|
||||
// PLUGIN_INITTAB_FAILED when a built-in module from the
|
||||
// _inittab cannot be initialized.
|
||||
if (!inittab[i].initfunc || inittab[i].initfunc() == nullptr) {
|
||||
python_plugin->error_msg = "failed to initialize built-in module";
|
||||
python_plugin->status = PLUGIN_INITTAB_FAILED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!python_plugin->usable()) {
|
||||
return nullptr;
|
||||
}
|
||||
return python_plugin;
|
||||
}
|
||||
|
||||
@@ -42,8 +177,35 @@ int PythonPlugin::configure(const char *iniFilename, const char *section) {
|
||||
}
|
||||
std::fclose(file);
|
||||
|
||||
status = PLUGIN_OK;
|
||||
return status;
|
||||
std::string toplevel;
|
||||
if (find_ini_value(iniFilename, section, "TOPLEVEL", toplevel)) {
|
||||
char resolved_path[PATH_MAX];
|
||||
// LinuxCNC source basis: python_plugin.cc configure() expands and
|
||||
// resolves [PYTHON] TOPLEVEL before initialize(); a missing path
|
||||
// returns PLUGIN_BAD_PATH before Python runtime status is considered.
|
||||
if (realpath(toplevel.c_str(), resolved_path) == nullptr) {
|
||||
error_msg = "bad path";
|
||||
status = PLUGIN_BAD_PATH;
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
status = check_python_path_entries(iniFilename,
|
||||
"PATH_PREPEND",
|
||||
PLUGIN_EXCEPTION_DURING_PATH_PREPEND);
|
||||
if (status != PLUGIN_OK) {
|
||||
error_msg = "bad path prepend";
|
||||
return status;
|
||||
}
|
||||
status = check_python_path_entries(iniFilename,
|
||||
"PATH_APPEND",
|
||||
PLUGIN_EXCEPTION_DURING_PATH_APPEND);
|
||||
if (status != PLUGIN_OK) {
|
||||
error_msg = "bad path append";
|
||||
return status;
|
||||
}
|
||||
|
||||
return initialize();
|
||||
}
|
||||
|
||||
bool PythonPlugin::is_callable(const char *, const char *) {
|
||||
@@ -58,6 +220,9 @@ int PythonPlugin::call(const char *,
|
||||
if (!callable) {
|
||||
return PLUGIN_NO_CALLABLE;
|
||||
}
|
||||
if (status < PLUGIN_OK) {
|
||||
return status;
|
||||
}
|
||||
|
||||
retval = boost::python::object();
|
||||
exception_msg = handle_pyerror();
|
||||
@@ -72,12 +237,21 @@ int PythonPlugin::run_string(const char *, boost::python::object &retval, bool)
|
||||
}
|
||||
|
||||
int PythonPlugin::call_method(boost::python::object, boost::python::object &retval) {
|
||||
// LinuxCNC source basis: src/emc/pythonplugin/python_plugin.cc returns the
|
||||
// existing negative plugin status before invoking a Python callable.
|
||||
if (status < PLUGIN_OK) {
|
||||
return status;
|
||||
}
|
||||
retval = boost::python::object();
|
||||
status = PLUGIN_OK;
|
||||
return status;
|
||||
}
|
||||
|
||||
int PythonPlugin::initialize() {
|
||||
status = PLUGIN_OK;
|
||||
// LinuxCNC source basis: src/emc/pythonplugin/python_plugin.cc sets
|
||||
// PLUGIN_PYTHON_NOT_INITIALIZED when initialize() runs without an active
|
||||
// Python runtime. Browser-safe probes keep Python execution disabled.
|
||||
error_msg = "python disabled in wasm-safe probe";
|
||||
status = PLUGIN_PYTHON_NOT_INITIALIZED;
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
#include "pythonplugin/python_plugin.hh"
|
||||
|
||||
namespace {
|
||||
|
||||
PyObject *init_bad_module() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// LinuxCNC source basis: src/emc/pythonplugin/python_plugin.cc
|
||||
// PythonPlugin::PythonPlugin(struct _inittab*) reports PLUGIN_INITTAB_FAILED
|
||||
// when a built-in Python module from the first caller's inittab cannot be
|
||||
// initialized; instantiate() then returns nullptr for the unusable plugin.
|
||||
int main() {
|
||||
_inittab bad_modules[] = {
|
||||
{"cnc_sim_bad_module", init_bad_module},
|
||||
{nullptr, nullptr},
|
||||
};
|
||||
|
||||
PythonPlugin *plugin = PythonPlugin::instantiate(bad_modules);
|
||||
if (plugin != nullptr) {
|
||||
return 1;
|
||||
}
|
||||
if (python_plugin == nullptr) {
|
||||
return 2;
|
||||
}
|
||||
if (python_plugin->plugin_status() != PLUGIN_INITTAB_FAILED) {
|
||||
return 3;
|
||||
}
|
||||
if (python_plugin->usable()) {
|
||||
return 4;
|
||||
}
|
||||
if (python_plugin->last_errmsg() != "failed to initialize built-in module") {
|
||||
return 5;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,5 +1,9 @@
|
||||
#include "pythonplugin/python_plugin.hh"
|
||||
|
||||
#include <string>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
|
||||
// LinuxCNC source basis: src/emc/pythonplugin/python_plugin.cc and
|
||||
// python_plugin.hh define the PythonPlugin API exercised by this link probe.
|
||||
int main() {
|
||||
@@ -13,13 +17,233 @@ int main() {
|
||||
if (plugin->configure(nullptr, nullptr) != PLUGIN_NO_SECTION) {
|
||||
return 6;
|
||||
}
|
||||
if (plugin->usable()) {
|
||||
return 26;
|
||||
}
|
||||
if (plugin->last_errmsg() != "no section") {
|
||||
return 23;
|
||||
}
|
||||
if (plugin->configure("/tmp/cnc_sim_missing_python_plugin_probe.ini", "PYTHON") != PLUGIN_BAD_INIFILE) {
|
||||
return 7;
|
||||
}
|
||||
if (plugin->usable()) {
|
||||
return 27;
|
||||
}
|
||||
boost::python::object retval;
|
||||
if (plugin->call(nullptr, "noop", boost::python::object(), boost::python::object(), retval) != PLUGIN_BAD_INIFILE) {
|
||||
return 14;
|
||||
}
|
||||
if (plugin->is_callable(nullptr, "noop")) {
|
||||
return 28;
|
||||
}
|
||||
if (plugin->call_method(boost::python::object(), retval) != PLUGIN_BAD_INIFILE) {
|
||||
return 15;
|
||||
}
|
||||
if (plugin->run_string("noop", retval, false) != PLUGIN_OK) {
|
||||
return 3;
|
||||
}
|
||||
if (!plugin->usable()) {
|
||||
return 29;
|
||||
}
|
||||
unsetenv("INI_FILE_NAME");
|
||||
if (plugin->configure(nullptr, "PYTHON") != PLUGIN_NO_INIFILE) {
|
||||
return 21;
|
||||
}
|
||||
if (plugin->last_errmsg() != "no inifile") {
|
||||
return 24;
|
||||
}
|
||||
const char *ini = "/tmp/cnc_sim_python_plugin_probe.ini";
|
||||
{
|
||||
FILE *file = std::fopen(ini, "w");
|
||||
if (!file) {
|
||||
return 16;
|
||||
}
|
||||
std::fputs("[PYTHON]\n", file);
|
||||
std::fclose(file);
|
||||
}
|
||||
const char *bad_path_ini = "/tmp/cnc_sim_python_plugin_probe_bad_path.ini";
|
||||
{
|
||||
FILE *file = std::fopen(bad_path_ini, "w");
|
||||
if (!file) {
|
||||
std::remove(ini);
|
||||
return 33;
|
||||
}
|
||||
std::fputs("[PYTHON]\nTOPLEVEL = /tmp/cnc_sim_missing_python_toplevel.py\n", file);
|
||||
std::fclose(file);
|
||||
}
|
||||
if (plugin->configure(bad_path_ini, "PYTHON") != PLUGIN_BAD_PATH) {
|
||||
std::remove(ini);
|
||||
std::remove(bad_path_ini);
|
||||
return 34;
|
||||
}
|
||||
if (plugin->usable()) {
|
||||
std::remove(ini);
|
||||
std::remove(bad_path_ini);
|
||||
return 35;
|
||||
}
|
||||
if (plugin->last_errmsg() != "bad path") {
|
||||
std::remove(ini);
|
||||
std::remove(bad_path_ini);
|
||||
return 36;
|
||||
}
|
||||
std::remove(bad_path_ini);
|
||||
const char *path_prepend_ini = "/tmp/cnc_sim_python_plugin_probe_path_prepend.ini";
|
||||
{
|
||||
FILE *file = std::fopen(path_prepend_ini, "w");
|
||||
if (!file) {
|
||||
std::remove(ini);
|
||||
return 37;
|
||||
}
|
||||
std::fputs("[PYTHON]\nPATH_PREPEND = ~/linuxcnc-python\n", file);
|
||||
std::fclose(file);
|
||||
}
|
||||
const char *saved_home = std::getenv("HOME");
|
||||
const std::string saved_home_value = saved_home ? saved_home : "";
|
||||
unsetenv("HOME");
|
||||
if (plugin->configure(path_prepend_ini, "PYTHON") != PLUGIN_EXCEPTION_DURING_PATH_PREPEND) {
|
||||
if (saved_home) {
|
||||
setenv("HOME", saved_home_value.c_str(), 1);
|
||||
}
|
||||
std::remove(ini);
|
||||
std::remove(path_prepend_ini);
|
||||
return 38;
|
||||
}
|
||||
if (plugin->usable()) {
|
||||
if (saved_home) {
|
||||
setenv("HOME", saved_home_value.c_str(), 1);
|
||||
}
|
||||
std::remove(ini);
|
||||
std::remove(path_prepend_ini);
|
||||
return 39;
|
||||
}
|
||||
if (plugin->last_errmsg() != "bad path prepend") {
|
||||
if (saved_home) {
|
||||
setenv("HOME", saved_home_value.c_str(), 1);
|
||||
}
|
||||
std::remove(ini);
|
||||
std::remove(path_prepend_ini);
|
||||
return 40;
|
||||
}
|
||||
if (saved_home) {
|
||||
setenv("HOME", saved_home_value.c_str(), 1);
|
||||
}
|
||||
std::remove(path_prepend_ini);
|
||||
const char *spaced_section_ini = "/tmp/cnc_sim_python_plugin_probe_spaced_section.ini";
|
||||
{
|
||||
FILE *file = std::fopen(spaced_section_ini, "w");
|
||||
if (!file) {
|
||||
std::remove(ini);
|
||||
return 47;
|
||||
}
|
||||
std::fputs("[ PYTHON ] ; section comment\nPATH_PREPEND = ~/linuxcnc-python\n", file);
|
||||
std::fclose(file);
|
||||
}
|
||||
unsetenv("HOME");
|
||||
if (plugin->configure(spaced_section_ini, "PYTHON") != PLUGIN_EXCEPTION_DURING_PATH_PREPEND) {
|
||||
if (saved_home) {
|
||||
setenv("HOME", saved_home_value.c_str(), 1);
|
||||
}
|
||||
std::remove(ini);
|
||||
std::remove(spaced_section_ini);
|
||||
return 48;
|
||||
}
|
||||
if (plugin->last_errmsg() != "bad path prepend") {
|
||||
if (saved_home) {
|
||||
setenv("HOME", saved_home_value.c_str(), 1);
|
||||
}
|
||||
std::remove(ini);
|
||||
std::remove(spaced_section_ini);
|
||||
return 49;
|
||||
}
|
||||
if (saved_home) {
|
||||
setenv("HOME", saved_home_value.c_str(), 1);
|
||||
}
|
||||
std::remove(spaced_section_ini);
|
||||
const char *path_append_ini = "/tmp/cnc_sim_python_plugin_probe_path_append.ini";
|
||||
{
|
||||
FILE *file = std::fopen(path_append_ini, "w");
|
||||
if (!file) {
|
||||
std::remove(ini);
|
||||
return 41;
|
||||
}
|
||||
std::fputs("[PYTHON]\nPATH_APPEND = ~/linuxcnc-python\n", file);
|
||||
std::fclose(file);
|
||||
}
|
||||
unsetenv("HOME");
|
||||
if (plugin->configure(path_append_ini, "PYTHON") != PLUGIN_EXCEPTION_DURING_PATH_APPEND) {
|
||||
if (saved_home) {
|
||||
setenv("HOME", saved_home_value.c_str(), 1);
|
||||
}
|
||||
std::remove(ini);
|
||||
std::remove(path_append_ini);
|
||||
return 42;
|
||||
}
|
||||
if (plugin->usable()) {
|
||||
if (saved_home) {
|
||||
setenv("HOME", saved_home_value.c_str(), 1);
|
||||
}
|
||||
std::remove(ini);
|
||||
std::remove(path_append_ini);
|
||||
return 43;
|
||||
}
|
||||
if (plugin->last_errmsg() != "bad path append") {
|
||||
if (saved_home) {
|
||||
setenv("HOME", saved_home_value.c_str(), 1);
|
||||
}
|
||||
std::remove(ini);
|
||||
std::remove(path_append_ini);
|
||||
return 44;
|
||||
}
|
||||
if (saved_home) {
|
||||
setenv("HOME", saved_home_value.c_str(), 1);
|
||||
}
|
||||
std::remove(path_append_ini);
|
||||
const char *plain_path_ini = "/tmp/cnc_sim_python_plugin_probe_plain_path.ini";
|
||||
{
|
||||
FILE *file = std::fopen(plain_path_ini, "w");
|
||||
if (!file) {
|
||||
std::remove(ini);
|
||||
return 45;
|
||||
}
|
||||
std::fputs("[PYTHON]\nPATH_PREPEND = /tmp\nPATH_APPEND = /tmp\n", file);
|
||||
std::fclose(file);
|
||||
}
|
||||
if (plugin->configure(plain_path_ini, "PYTHON") != PLUGIN_PYTHON_NOT_INITIALIZED) {
|
||||
std::remove(ini);
|
||||
std::remove(plain_path_ini);
|
||||
return 46;
|
||||
}
|
||||
std::remove(plain_path_ini);
|
||||
setenv("INI_FILE_NAME", ini, 1);
|
||||
if (plugin->configure(nullptr, "PYTHON") != PLUGIN_PYTHON_NOT_INITIALIZED) {
|
||||
std::remove(ini);
|
||||
return 22;
|
||||
}
|
||||
if (plugin->usable()) {
|
||||
std::remove(ini);
|
||||
return 30;
|
||||
}
|
||||
unsetenv("INI_FILE_NAME");
|
||||
if (plugin->configure(ini, "PYTHON") != PLUGIN_PYTHON_NOT_INITIALIZED) {
|
||||
std::remove(ini);
|
||||
return 17;
|
||||
}
|
||||
std::remove(ini);
|
||||
if (plugin->call(nullptr, "noop", boost::python::object(), boost::python::object(), retval) != PLUGIN_PYTHON_NOT_INITIALIZED) {
|
||||
return 18;
|
||||
}
|
||||
if (plugin->call_method(boost::python::object(), retval) != PLUGIN_PYTHON_NOT_INITIALIZED) {
|
||||
return 19;
|
||||
}
|
||||
if (plugin->is_callable(nullptr, "noop")) {
|
||||
return 31;
|
||||
}
|
||||
if (plugin->run_string("noop", retval, false) != PLUGIN_OK) {
|
||||
return 20;
|
||||
}
|
||||
if (plugin->is_callable(nullptr, nullptr)) {
|
||||
return 32;
|
||||
}
|
||||
if (plugin->call(nullptr, nullptr, boost::python::object(), boost::python::object(), retval) != PLUGIN_NO_CALLABLE) {
|
||||
return 8;
|
||||
}
|
||||
@@ -35,6 +259,9 @@ int main() {
|
||||
if (plugin->last_exception().empty()) {
|
||||
return 12;
|
||||
}
|
||||
if (plugin->last_exception() != handle_pyerror()) {
|
||||
return 25;
|
||||
}
|
||||
if (plugin->run_string("noop", retval, false) != PLUGIN_OK) {
|
||||
return 13;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
#include <cstdio>
|
||||
|
||||
// LinuxCNC source basis: src/rtapi/uspace_common.h provides rtapi_snprintf()
|
||||
// for userspace RTAPI formatting; src/rtapi/rtapi.h declares the API.
|
||||
// and rtapi_vsnprintf() for userspace RTAPI formatting; src/rtapi/rtapi.h
|
||||
// declares both APIs.
|
||||
extern "C" int rtapi_snprintf(char *buf, unsigned long size, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
@@ -10,3 +11,7 @@ extern "C" int rtapi_snprintf(char *buf, unsigned long size, const char *fmt, ..
|
||||
va_end(ap);
|
||||
return rc;
|
||||
}
|
||||
|
||||
extern "C" int rtapi_vsnprintf(char *buf, unsigned long size, const char *fmt, va_list ap) {
|
||||
return std::vsnprintf(buf, static_cast<std::size_t>(size), fmt, ap);
|
||||
}
|
||||
|
||||
@@ -89,6 +89,42 @@ int main() {
|
||||
return 9;
|
||||
}
|
||||
|
||||
tooldata_init(false);
|
||||
std::string nonrandom_path_template = make_temp_template("cnc_tooldata_common_nonrandom_probe_XXXXXX");
|
||||
std::vector<char> nonrandom_path(nonrandom_path_template.begin(), nonrandom_path_template.end());
|
||||
nonrandom_path.push_back('\0');
|
||||
const int nonrandom_fd = mkstemp(nonrandom_path.data());
|
||||
if (nonrandom_fd < 0) {
|
||||
return 16;
|
||||
}
|
||||
FILE *nonrandom_fp = fdopen(nonrandom_fd, "w");
|
||||
if (!nonrandom_fp) {
|
||||
close(nonrandom_fd);
|
||||
std::remove(nonrandom_path.data());
|
||||
return 17;
|
||||
}
|
||||
std::fputs("T-1 P5 Z4.25\n", nonrandom_fp);
|
||||
std::fclose(nonrandom_fp);
|
||||
|
||||
if (tooldata_load(nonrandom_path.data()) != 0) {
|
||||
std::remove(nonrandom_path.data());
|
||||
return 18;
|
||||
}
|
||||
std::remove(nonrandom_path.data());
|
||||
|
||||
// LinuxCNC source basis: src/emc/tooldata/tooldata_common.cc
|
||||
// tooldata_load() mirrors a matching nonrandom table entry into spindle
|
||||
// pocket 0 after tooldata_read_entry() assigns fake pocket indices.
|
||||
CANON_TOOL_TABLE nonrandom_spindle = tooldata_entry_init();
|
||||
if (tooldata_get(&nonrandom_spindle, 0) != IDX_OK) {
|
||||
return 19;
|
||||
}
|
||||
if (nonrandom_spindle.toolno != -1 || nonrandom_spindle.pocketno != 5 ||
|
||||
nonrandom_spindle.offset.tran.z != 4.25) {
|
||||
return 20;
|
||||
}
|
||||
|
||||
tooldata_init(true);
|
||||
tooldata_set_db(DB_ACTIVE);
|
||||
if (tooldata_load(path.data()) != -1) {
|
||||
return 10;
|
||||
|
||||
@@ -84,6 +84,71 @@ int main() {
|
||||
return 45;
|
||||
}
|
||||
|
||||
const pid_t nonrandom_t0_child = fork();
|
||||
if (nonrandom_t0_child < 0) {
|
||||
return 64;
|
||||
}
|
||||
if (nonrandom_t0_child == 0) {
|
||||
if (tool_mmap_creator(nullptr, 0) != 0) {
|
||||
_exit(65);
|
||||
}
|
||||
CANON_TOOL_TABLE nonrandom_t0 = tooldata_entry_init();
|
||||
nonrandom_t0.toolno = 0;
|
||||
nonrandom_t0.pocketno = 12;
|
||||
if (tooldata_put(nonrandom_t0, 12) == IDX_FAIL) {
|
||||
_exit(66);
|
||||
}
|
||||
// LinuxCNC src/emc/tooldata/tooldata_mmap.cc returns pocket 0 for T0
|
||||
// before scanning table entries when the toolchanger is not random.
|
||||
if (tooldata_find_index_for_tool(0) != 0) {
|
||||
_exit(67);
|
||||
}
|
||||
_exit(0);
|
||||
}
|
||||
int nonrandom_t0_status = 0;
|
||||
if (waitpid(nonrandom_t0_child, &nonrandom_t0_status, 0) != nonrandom_t0_child) {
|
||||
return 68;
|
||||
}
|
||||
if (!WIFEXITED(nonrandom_t0_status) || WEXITSTATUS(nonrandom_t0_status) != 0) {
|
||||
return 69;
|
||||
}
|
||||
|
||||
const pid_t random_t0_child = fork();
|
||||
if (random_t0_child < 0) {
|
||||
return 70;
|
||||
}
|
||||
if (random_t0_child == 0) {
|
||||
if (tool_mmap_creator(nullptr, 1) != 0) {
|
||||
_exit(71);
|
||||
}
|
||||
tooldata_reset();
|
||||
CANON_TOOL_TABLE spindle_t0 = tooldata_entry_init();
|
||||
spindle_t0.toolno = 0;
|
||||
spindle_t0.pocketno = 0;
|
||||
if (tooldata_put(spindle_t0, 0) == IDX_FAIL) {
|
||||
_exit(72);
|
||||
}
|
||||
CANON_TOOL_TABLE random_t0 = tooldata_entry_init();
|
||||
random_t0.toolno = 0;
|
||||
random_t0.pocketno = 15;
|
||||
if (tooldata_put(random_t0, 15) == IDX_FAIL) {
|
||||
_exit(73);
|
||||
}
|
||||
// LinuxCNC src/emc/tooldata/tooldata_mmap.cc continues past pocket 0
|
||||
// while scanning random toolchanger entries, so a nonzero T0 pocket wins.
|
||||
if (tooldata_find_index_for_tool(0) != 15) {
|
||||
_exit(74);
|
||||
}
|
||||
_exit(0);
|
||||
}
|
||||
int random_t0_status = 0;
|
||||
if (waitpid(random_t0_child, &random_t0_status, 0) != random_t0_child) {
|
||||
return 75;
|
||||
}
|
||||
if (!WIFEXITED(random_t0_status) || WEXITSTATUS(random_t0_status) != 0) {
|
||||
return 76;
|
||||
}
|
||||
|
||||
if (tool_mmap_user() != -1) {
|
||||
return 25;
|
||||
}
|
||||
@@ -113,6 +178,18 @@ int main() {
|
||||
if (tooldata_db_getall() != -1) {
|
||||
return 28;
|
||||
}
|
||||
// LinuxCNC source basis: src/emc/tooldata/tooldata_db.cc
|
||||
// tooldata_db_notify() returns 0 without side effects while db_live is
|
||||
// false, which is the browser-safe shim state for external DB services.
|
||||
if (tooldata_db_notify(SPINDLE_LOAD, 7, 12, uncreated_tool) != 0) {
|
||||
return 57;
|
||||
}
|
||||
if (tooldata_db_notify(SPINDLE_UNLOAD, 7, 12, uncreated_tool) != 0) {
|
||||
return 58;
|
||||
}
|
||||
if (tooldata_db_notify(TOOL_OFFSET, 7, 12, uncreated_tool) != 0) {
|
||||
return 59;
|
||||
}
|
||||
std::string missing_db_program_with_arg_string =
|
||||
make_temp_path("cnc_tooldata_probe_missing_db_program arg");
|
||||
std::vector<char> missing_db_program_with_arg(
|
||||
@@ -147,6 +224,12 @@ int main() {
|
||||
}
|
||||
alignas(EMC_TOOL_STAT) unsigned char toolstat_storage[sizeof(EMC_TOOL_STAT)] = {};
|
||||
auto *toolstat = reinterpret_cast<EMC_TOOL_STAT *>(toolstat_storage);
|
||||
// LinuxCNC src/emc/tooldata/tooldata_nml.cc accepts a non-null table
|
||||
// pointer before NML-backed tooldata operations can use it.
|
||||
CANON_TOOL_TABLE nml_tool_table[CANON_POCKETS_MAX] = {};
|
||||
if (tool_nml_register(nml_tool_table) != 0) {
|
||||
return 77;
|
||||
}
|
||||
if (tool_mmap_creator(toolstat, 1) != 0) {
|
||||
return 15;
|
||||
}
|
||||
@@ -300,6 +383,16 @@ int main() {
|
||||
reloaded.offset.tran.z != 3.5 || reloaded.diameter != 8.0) {
|
||||
return 14;
|
||||
}
|
||||
tooldata_last_index_set(12);
|
||||
tooldata_reset();
|
||||
// LinuxCNC src/emc/tooldata/tooldata_mmap.cc clears table entries in
|
||||
// tooldata_reset() without changing the mmap header last_index.
|
||||
if (tooldata_last_index_get() != 12) {
|
||||
return 78;
|
||||
}
|
||||
if (tooldata_find_index_for_tool(7) != -1) {
|
||||
return 79;
|
||||
}
|
||||
|
||||
tooldata_init(false);
|
||||
std::string nonrandom_path_template = make_temp_path("cnc_tooldata_nonrandom_probe_XXXXXX");
|
||||
@@ -338,5 +431,21 @@ int main() {
|
||||
return 39;
|
||||
}
|
||||
|
||||
const pid_t recreate_child = fork();
|
||||
if (recreate_child < 0) {
|
||||
return 60;
|
||||
}
|
||||
if (recreate_child == 0) {
|
||||
tool_mmap_creator(nullptr, 1);
|
||||
_exit(61);
|
||||
}
|
||||
int recreate_status = 0;
|
||||
if (waitpid(recreate_child, &recreate_status, 0) != recreate_child) {
|
||||
return 62;
|
||||
}
|
||||
if (!WIFEXITED(recreate_status) || WEXITSTATUS(recreate_status) == 0) {
|
||||
return 63;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -48,6 +48,8 @@ int tooldata_db_init(char progname_plus_args[], int) {
|
||||
}
|
||||
|
||||
int tooldata_db_notify(tool_notify_t, int, int, CANON_TOOL_TABLE) {
|
||||
// LinuxCNC source basis: src/emc/tooldata/tooldata_db.cc returns 0 when
|
||||
// db_live is false, before formatting or sending any DB notification.
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,8 @@ advanced in this order:
|
||||
Each step should stay source-backed and close one small gap at a time. A single
|
||||
pass should advance one workstream context only; crossing into another context
|
||||
requires naming the dependency and keeping the edit set minimal.
|
||||
The synchronized source-map guard for these contexts is
|
||||
`docs/linuxcnc-workstreams-source-map.md`.
|
||||
|
||||
## Dialect expansion
|
||||
|
||||
|
||||
60
docs/linuxcnc-browser-app-source-map.md
Normal file
60
docs/linuxcnc-browser-app-source-map.md
Normal file
@@ -0,0 +1,60 @@
|
||||
# LinuxCNC browser app source map
|
||||
|
||||
This map records the source basis and boundaries for the browser application
|
||||
entry point. It is an app/bridge guard only; it must not add CNC behavior and
|
||||
must not expand the temporary smoke parser.
|
||||
|
||||
## LinuxCNC Source Basis
|
||||
|
||||
- `src/emc/rs274ngc/interp_internal.hh` defines
|
||||
`RS274NGC_PARAMETER_FILE_NAME_DEFAULT` as `rs274ngc.var`.
|
||||
- `src/emc/rs274ngc/interp_internal.hh` defines
|
||||
`RS274NGC_PARAMETER_FILE_BACKUP_SUFFIX` as `.bak`.
|
||||
- `src/emc/rs274ngc/rs274ngc_pre.cc` restores parameter files through
|
||||
`Interp::restore_parameters()`.
|
||||
- `src/emc/rs274ngc/rs274ngc_pre.cc` saves parameter files through
|
||||
`Interp::save_parameters()`, including `filename + ".new"` and
|
||||
`filename + ".bak"` behavior.
|
||||
- `src/emc/rs274ngc/rs274ngc_pre.cc` orders parameter saves as backup unlink,
|
||||
backup link, then temporary-file rename.
|
||||
- `src/emc/rs274ngc/rs274ngc_pre.cc` reads program blocks through `read_text()`
|
||||
after the browser bridge mirrors the OPFS program into the WASM filesystem.
|
||||
|
||||
## App Coverage
|
||||
|
||||
| Entry | Boundary |
|
||||
| --- | --- |
|
||||
| `web/index.html` | Loads the browser app module and exposes only the LinuxCNC backend selector. |
|
||||
| `web/src/app.js` | Creates a required OPFS-backed simulator workspace and parses browser programs with a LinuxCNC parameter file. |
|
||||
| `web/test-browser-wasm-smoke-app-sections.js` | Verifies app-level OPFS program save, parameter save, parameter backup, and reload behavior. |
|
||||
|
||||
## Boundaries
|
||||
|
||||
- The app must use the existing `createWasmSimulator()` OPFS API; it must not
|
||||
add browser filesystem persistence outside OPFS.
|
||||
- The app must persist the current program at `programs/current.ngc`.
|
||||
- The app must persist LinuxCNC parameter state at `parameters/rs274ngc.var`.
|
||||
- The app must require OPFS for browser program parsing and call
|
||||
`parseFileWithParameterFile(programPath, parameterPath, "linuxcnc", ...)`.
|
||||
- The visible backend selector must stay limited to the LinuxCNC RS274 backend.
|
||||
- The app must not read the backend selector as a dynamic backend source; it
|
||||
must force `linuxCncBackend` for browser parsing.
|
||||
- `test-native.sh`, `test-linuxcnc-source-link.sh`, and `build-wasm.sh` must
|
||||
run `./check-linuxcnc-browser-app-source-map.sh` before consuming app-backed
|
||||
browser artifacts or source-linked LinuxCNC objects.
|
||||
- The browser app source-map guard validates LinuxCNC source-backed bridge
|
||||
routing and OPFS policy only; it does not interpret G-code.
|
||||
|
||||
## Checks
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
./check-linuxcnc-browser-app-source-map.sh
|
||||
./test-native.sh
|
||||
./test-linuxcnc-source-link.sh
|
||||
./build-wasm.sh
|
||||
```
|
||||
|
||||
`check-linuxcnc-browser-app-source-map.sh` keeps this document, LinuxCNC source
|
||||
anchors, app OPFS paths, app parse routing, and app smoke coverage synchronized.
|
||||
69
docs/linuxcnc-build-source-map.md
Normal file
69
docs/linuxcnc-build-source-map.md
Normal file
@@ -0,0 +1,69 @@
|
||||
# LinuxCNC build source map
|
||||
|
||||
This map records the source basis and boundaries for native, source-link, and
|
||||
WASM build entry points. It is a build-policy guard only; it must not add CNC
|
||||
behavior and must not expand the temporary smoke parser.
|
||||
|
||||
## LinuxCNC Source Basis
|
||||
|
||||
- `src/emc/rs274ngc/Submakefile` defines `LIBRS274SRCS`, including
|
||||
`rs274ngc_pre.cc`, and links RS274 against LinuxCNC INI, HAL, Python plugin,
|
||||
and tooldata libraries.
|
||||
- `src/emc/tooldata/Submakefile` defines the LinuxCNC tooldata common, mmap,
|
||||
NML, database, reader, and watcher sources tracked by native and WASM
|
||||
manifests.
|
||||
- `src/emc/ini/Submakefile` defines `liblinuxcncini` and exported INI headers
|
||||
used by source-linked and WASM-safe probes.
|
||||
- `src/emc/pythonplugin/Submakefile` defines `libpyplugin`, which remains a
|
||||
source-tracked Python/remap dependency for source-link and WASM blocker
|
||||
coverage.
|
||||
- `src/emc/kinematics/Submakefile` and `src/emc/kinematics/kinematics.h`
|
||||
define the kinematics source/header surface consumed by switchkins and RTCP
|
||||
build coverage.
|
||||
|
||||
## Build Coverage
|
||||
|
||||
| Entry | Boundary |
|
||||
| --- | --- |
|
||||
| `test-native.sh` | Runs source-map guards, cached manifest checks, native bridge/API/RS274 probes, and Node/browser smoke after LinuxCNC source-backed native coverage. |
|
||||
| `test-linuxcnc-source-link.sh` | Compiles manifest-selected LinuxCNC RS274 objects directly with source-link support objects and project dump bridges. |
|
||||
| `test-linuxcnc-source-syntax.sh` | Keeps native source syntax validation on persistent dependency-tracked stamps. |
|
||||
| `test-linuxcnc-wasm-cmake-safe-probe.sh` | Configures source-backed WASM-safe probe targets with persistent CMake signatures. |
|
||||
| `build-wasm.sh` | Runs source-map guards, blocker, syntax, object, CMake, tooldata, interp, Python, `rs274ngc_pre`, and runtime probes before copying browser artifacts. |
|
||||
|
||||
## Boundaries
|
||||
|
||||
- Default WASM manifest partition must remain 26 wasm-safe `core` sources and
|
||||
9 `blocked` sources.
|
||||
- Build paths must keep `CNC_SIM_BUILD_JOBS` as scheduling only. Persistent
|
||||
object/configure signatures must not include it.
|
||||
- Hot object probes must use explicit `BUILD_RULE_VERSION` or
|
||||
`CONFIGURE_RULE_VERSION` fields instead of hashing whole scripts.
|
||||
- `build-wasm.sh` must configure with `CNC_SIM_ENABLE_SMOKE_BACKEND=OFF` and
|
||||
`CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE=ON`.
|
||||
- `test-native.sh`, `test-linuxcnc-source-link.sh`, and `build-wasm.sh` must
|
||||
run the same source-map guards before consuming generated config aliases,
|
||||
source-linked LinuxCNC objects, or browser artifacts.
|
||||
- `build-wasm.sh` must build `cnc_sim_wasm_runtime_probe` before
|
||||
`cnc_sim_wasm`, copy `cnc_sim.js` and `cnc_sim.wasm` exactly once, compare
|
||||
copied artifacts with `cmp -s`, and run Node smoke before browser smoke.
|
||||
- Build directory overrides must be non-empty, whitespace-free, and outside the
|
||||
filesystem root.
|
||||
- The build source-map guard validates LinuxCNC build-source ownership,
|
||||
manifest partitions, and artifact ordering only; it does not interpret
|
||||
G-code.
|
||||
|
||||
## Checks
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
./check-linuxcnc-build-source-map.sh
|
||||
./test-native.sh
|
||||
./test-linuxcnc-source-link.sh
|
||||
./build-wasm.sh
|
||||
```
|
||||
|
||||
`check-linuxcnc-build-source-map.sh` keeps this document, LinuxCNC build-source
|
||||
anchors, manifest partition assumptions, build script ordering, and
|
||||
source-backed build-policy boundaries synchronized.
|
||||
69
docs/linuxcnc-kinematics-source-map.md
Normal file
69
docs/linuxcnc-kinematics-source-map.md
Normal file
@@ -0,0 +1,69 @@
|
||||
# LinuxCNC kinematics source map
|
||||
|
||||
This map tracks the LinuxCNC source/configuration basis for kinematics,
|
||||
switchkins, RTCP, and M428/M429/M430 remap coverage. It is intentionally a
|
||||
source-coverage document: the manifest entries here must not become browser or
|
||||
application behavior by themselves. It must not add CNC behavior and must not
|
||||
expand the temporary smoke parser.
|
||||
|
||||
## Manifest groups
|
||||
|
||||
The kinematics manifest currently contains these LinuxCNC-root relative source
|
||||
groups:
|
||||
|
||||
| Group | Count | Source coverage role |
|
||||
| --- | ---: | --- |
|
||||
| `core` | 30 | LinuxCNC kinematics and posemath C/C++ sources. |
|
||||
| `config` | 33 | LinuxCNC switchkins INI/HAL/POSTGUI sources used by M428/M429/M430 and RTCP coverage. |
|
||||
| `remap` | 31 | LinuxCNC M428/M429/M430 remap subroutines. |
|
||||
| `component` | 8 | LinuxCNC halcompile component sources referenced by kinematics configs. |
|
||||
| `generated` | 8 | LinuxCNC halcompile-generated C sources adjacent to component coverage. |
|
||||
| `header` | 13 | LinuxCNC kinematics and posemath declarations. |
|
||||
| `metadata` | 34 | LinuxCNC build/manpage metadata adjacent to covered kinematics sources. |
|
||||
| `asset` | 122 | LinuxCNC INI-adjacent HAL, README, GUI, demo, PYVCP, and other source assets. |
|
||||
| `tooldata` | 10 | LinuxCNC tool table files referenced by covered M428/M429/M430 INI files. |
|
||||
|
||||
## LinuxCNC Source Anchors
|
||||
|
||||
- `src/emc/kinematics/Submakefile` defines the kinematics build source surface,
|
||||
including `GENSERKINSSRCS`.
|
||||
- `src/emc/kinematics/kinematics.h` declares `kinematicsInverse()` and
|
||||
`kinematicsSwitch()` for switchkins-capable modules.
|
||||
- `configs/sim/axis/vismach/5axis/bridgemill/5axis.ini` wires
|
||||
`motion.switchkins-type` and representative M428/M429/M430 switchkins
|
||||
configuration.
|
||||
- `configs/sim/axis/vismach/5axis/bridgemill/remap_subs/428remap.ngc`
|
||||
provides a representative `#<kinstype>` remap assignment.
|
||||
|
||||
## Boundaries
|
||||
|
||||
- `asset`, `metadata`, `header`, and `tooldata` entries are source coverage,
|
||||
not browser API surface.
|
||||
- Browser-side file persistence remains OPFS-only and is not expanded by this
|
||||
manifest.
|
||||
- Switchkins/remap generation must continue to derive M428/M429/M430 cases from
|
||||
LinuxCNC INI/HAL/remap sources, not from hand-authored behavior.
|
||||
- RTCP and five-axis coverage must remain tied to LinuxCNC kinematics sources,
|
||||
remap files, and configuration files.
|
||||
- `test-native.sh`, `test-linuxcnc-source-link.sh`, and `build-wasm.sh` must
|
||||
run `./check-linuxcnc-kinematics-source-map.sh` before consuming generated
|
||||
config aliases, source-linked LinuxCNC objects, or browser artifacts.
|
||||
- The kinematics source-map guard validates LinuxCNC source/config ownership
|
||||
and manifest drift only; it does not interpret G-code.
|
||||
|
||||
## Checks
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
./check-linuxcnc-kinematics-source-map.sh
|
||||
./check-linuxcnc-inputs.sh linuxcnc-kinematics-source-files.txt --require-kinematics-complete
|
||||
./check-linuxcnc-switchkins-remap-table.sh linuxcnc-kinematics-source-files.txt
|
||||
./test-native.sh
|
||||
./test-linuxcnc-source-link.sh
|
||||
```
|
||||
|
||||
`check-linuxcnc-kinematics-source-map.sh` keeps this document's group counts in
|
||||
sync with `linuxcnc-kinematics-source-files.txt`; the input and table checkers
|
||||
validate LinuxCNC source existence, directory completeness, remap kinstype
|
||||
notes, and switchkins/remap table generation.
|
||||
74
docs/linuxcnc-opfs-source-map.md
Normal file
74
docs/linuxcnc-opfs-source-map.md
Normal file
@@ -0,0 +1,74 @@
|
||||
# LinuxCNC OPFS source map
|
||||
|
||||
This map records the source basis for browser-side LinuxCNC parameter-file
|
||||
persistence. It is a policy and bridge map only; it must not add independent filesystem behavior or expand the temporary smoke parser.
|
||||
|
||||
## LinuxCNC Source Basis
|
||||
|
||||
- `src/emc/rs274ngc/interp_internal.hh` defines
|
||||
`RS274NGC_PARAMETER_FILE_NAME_DEFAULT` as `rs274ngc.var`.
|
||||
- `src/emc/rs274ngc/interp_internal.hh` defines
|
||||
`RS274NGC_PARAMETER_FILE_BACKUP_SUFFIX` as `.bak`.
|
||||
- `src/emc/rs274ngc/rs274ngc_pre.cc` implements
|
||||
`Interp::restore_parameters()` for parameter-file reads.
|
||||
- `src/emc/rs274ngc/rs274ngc_pre.cc` implements `Interp::open()` by opening
|
||||
the NC program file with `fopen(filename, "r")`, then `Interp::_read()`
|
||||
feeds `_setup.file_pointer` into `read_text()`.
|
||||
- `src/emc/rs274ngc/rs274ngc_pre.cc` implements
|
||||
`Interp::save_parameters()` for `filename + ".new"`, backup, and replacement
|
||||
writes.
|
||||
- `src/emc/rs274ngc/rs274ngc_pre.cc` unlinks `filename + ".bak"`, links the
|
||||
previous parameter file to that backup path, then renames `filename + ".new"`
|
||||
over the configured parameter file.
|
||||
|
||||
## OPFS Coverage
|
||||
|
||||
| Entry | Boundary |
|
||||
| --- | --- |
|
||||
| `web/src/wasm-core.js` | Keeps LinuxCNC program reads and parameter restore/save bridge files under the OPFS workspace and cleans WASM scratch files. |
|
||||
| `web/src/wasm-core.d.ts` | Exposes only the OPFS-backed workspace, directory, parameter-file, and mount/workspace option types used by the bridge. |
|
||||
| `web/src/app.js` | Persists browser programs at `programs/current.ngc` and LinuxCNC parameters at `parameters/rs274ngc.var`. |
|
||||
| `web/test-browser-wasm-smoke-opfs-basic-sections.js` | Verifies OPFS program file reads through LinuxCNC `read_text()` and rejects unsafe paths. |
|
||||
| `web/test-browser-wasm-smoke-opfs-parameter-sections.js` | Verifies OPFS parameter restore, save, `.new`, `.bak`, failure, and stale-state semantics. |
|
||||
| `web/test-browser-wasm-smoke-opfs-workspace-sections.js` | Aggregates OPFS basic, parameter, mirror, and directory checks under browser OPFS availability. |
|
||||
| `web/test-browser-wasm-smoke-opfs-mirror-sections.js` | Verifies OPFS/WASM mirror persistence used by source-backed file parsing and parameter movement. |
|
||||
| `web/test-browser-wasm-smoke-opfs-directory-sections.js` | Verifies OPFS directory persistence and WASM mirror refresh without polluting mirrors during metadata queries. |
|
||||
| `web/test-browser-wasm-smoke-opfs-policy-sections.js` | Verifies OPFS workspace and mount policy, including the browser rule that OPFS cannot be disabled. |
|
||||
| `web/test-browser-wasm-smoke-app-sections.js` | Verifies app-level OPFS program, parameter, backup, and reload behavior. |
|
||||
|
||||
## Browser Bridge Boundary
|
||||
|
||||
- `web/src/wasm-core.js` must keep LinuxCNC parameter persistence routed
|
||||
through an OPFS workspace.
|
||||
- Browser contexts with OPFS support must not disable OPFS.
|
||||
- OPFS workspace paths must remain relative paths inside the CNC workspace, and
|
||||
OPFS mount points must remain absolute paths inside the Emscripten
|
||||
filesystem.
|
||||
- Browser app and wasm bridge code must not use Local Storage, IndexedDB,
|
||||
File Picker, Directory Picker, WebKit filesystem, or FileReader persistence
|
||||
paths for CNC programs, LinuxCNC parameter files, or mirrored workspace files.
|
||||
- Browser OPFS smoke harness files must also stay free of Local Storage,
|
||||
IndexedDB, File Picker, Directory Picker, WebKit filesystem, and FileReader
|
||||
persistence paths; they may only verify OPFS-backed browser persistence.
|
||||
- `web/src/app.js` must parse browser programs through
|
||||
`parseFileWithParameterFile()` so the program file and LinuxCNC parameter
|
||||
state both live under OPFS.
|
||||
- `test-native.sh`, `test-linuxcnc-source-link.sh`, and `build-wasm.sh` must
|
||||
run `./check-linuxcnc-opfs-source-map.sh` before consuming app-backed browser
|
||||
artifacts or source-linked LinuxCNC objects.
|
||||
- The OPFS source-map guard validates LinuxCNC source-backed filesystem bridge
|
||||
policy only; it does not interpret G-code.
|
||||
|
||||
## Checks
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
./check-linuxcnc-opfs-source-map.sh
|
||||
./test-native.sh
|
||||
./test-linuxcnc-source-link.sh
|
||||
./build-wasm.sh
|
||||
```
|
||||
|
||||
`check-linuxcnc-opfs-source-map.sh` keeps this document, the LinuxCNC source
|
||||
anchors, and the browser bridge guardrails synchronized.
|
||||
@@ -209,7 +209,7 @@ This matrix tracks LinuxCNC feature coverage for the web/WASM simulator. A featu
|
||||
| Modal state save/restore `M70`-`M73` | covered for main-program save/invalidate/restore plus O-word subroutine autorestore in smoke parser, with native/source regressions checking restored distance mode, units, and XY plane motion | `tests/gcode/linuxcnc_modal_state.ngc`, `tests/gcode/linuxcnc_modal_autorestore.ngc` |
|
||||
| LinuxCNC read-only named parameters | common modal/unit/feed/spindle reads and additional ccomp/spindle-mode readonly reads are covered through LinuxCNC native/source backends | `tests/gcode/linuxcnc_readonly_named_parameters.ngc`, `tests/gcode/linuxcnc_readonly_named_parameters_extra.ngc`, `tests/gcode/linuxcnc_lathe_diameter_mode.ngc` |
|
||||
| LinuxCNC numbered parameters | native/source coverage checks readonly numbered-parameter rejection plus probe, tool, G28/G30, G52/G92, G5X/G59.3, debug/M66 result, tool-offset, current-position, `restore_parameters()`/`save_parameters()` persistence, and volatile global numbered parameters from LinuxCNC source state | `tests/gcode/linuxcnc_numbered_parameters.ngc`, `tests/gcode/linuxcnc_rotary_probe_numbered_parameters.ngc`, `tests/gcode/linuxcnc_multi_rotary_probe_numbered_parameters.ngc`, `tests/gcode/linuxcnc_tool_info_zero_parameter.ngc`, `tests/gcode/linuxcnc_spindle_tool_info_parameter.ngc`, `tests/gcode/linuxcnc_readonly_numbered_parameter_assign_error.ngc`, `tests/gcode/linuxcnc_g28_g30_numbered_parameters.ngc`, `tests/gcode/linuxcnc_rotary_g28_g30_numbered_parameters.ngc`, `tests/gcode/linuxcnc_g92_numbered_parameters.ngc`, `tests/gcode/linuxcnc_rotary_g92_numbered_parameters.ngc`, `tests/gcode/linuxcnc_g52_g92_numbered_interaction.ngc`, `tests/gcode/linuxcnc_g5x_numbered_parameters.ngc`, `tests/gcode/linuxcnc_g59_3_numbered_parameters.ngc`, `tests/gcode/linuxcnc_g59_3_rotary_numbered_parameters.ngc`, `tests/gcode/linuxcnc_g5x_rotary_numbered_parameters.ngc`, `tests/gcode/linuxcnc_g54_rotary_numbered_parameters.ngc`, `tests/gcode/linuxcnc_debug_level_parameter.ngc`, `tests/gcode/linuxcnc_m66_result_parameter.ngc`, `tests/gcode/linuxcnc_tool_offset_numbered_parameters.ngc`, `tests/gcode/linuxcnc_rotary_tool_offset_numbered_parameters.ngc`, `tests/gcode/linuxcnc_current_position_numbered_parameters.ngc`, `tests/gcode/linuxcnc_persistent_parameters_set.ngc`, `tests/gcode/linuxcnc_persistent_parameters_check.ngc`, `tests/gcode/linuxcnc_rotary_persistent_parameters_set.ngc`, `tests/gcode/linuxcnc_rotary_persistent_parameters_check.ngc`, `tests/gcode/linuxcnc_g54_persistent_parameters_set.ngc`, `tests/gcode/linuxcnc_g54_persistent_parameters_check.ngc`, `tests/gcode/linuxcnc_user_persistent_parameter_set.ngc`, `tests/gcode/linuxcnc_user_persistent_parameter_check.ngc`, `tests/gcode/linuxcnc_user_persistent_parameter_existing_check.ngc`, `tests/gcode/linuxcnc_user_persistent_parameter_boundary_set.ngc`, `tests/gcode/linuxcnc_user_persistent_parameter_boundary_check.ngc`, `tests/gcode/linuxcnc_volatile_global_parameter_set.ngc`, `tests/gcode/linuxcnc_volatile_global_parameter_check.ngc` |
|
||||
| Feed and motion control modes `G93/G94/G95`, `G61/G61.1/G64` | covered through LinuxCNC native/source backends | `tests/gcode/linuxcnc_feed_modes.ngc`, `tests/gcode/linuxcnc_motion_modes.ngc` |
|
||||
| Feed and motion control modes `G93/G94/G95`, `G61/G61.1/G64` | covered through LinuxCNC native/source backends, including `G64 P` path tolerance and `G64 Q` naivecam tolerance from `convert_control_mode()` | `tests/gcode/linuxcnc_feed_modes.ngc`, `tests/gcode/linuxcnc_motion_modes.ngc`, `tests/gcode/linuxcnc_control_mode_tolerances.ngc` |
|
||||
| Dwell `G4 P...` | covered through LinuxCNC native/source backends for missing-P rejection and boundary values around LinuxCNC's exact `P-1.0` missing-value sentinel; neighboring negative P values are passed through to `DWELL` by `convert_dwell()` | `tests/gcode/linuxcnc_g4_missing_p_error.ngc`, `tests/gcode/linuxcnc_g4_negative_p_error.ngc`, `tests/gcode/linuxcnc_g4_dwell_boundaries.ngc` |
|
||||
| Canned cycle `G73`-`G89`/`G80` | covered for drilling expand-to-canon path, `G18/G19` plane-specific depth-axis mapping for representative drilling/boring cycles, `G17.1` extended-plane depth/retract mapping, and native/source LinuxCNC `interp_cycles.cc` validation of repeat counts, required R/depth words, invalid rotary axes including follow-up modal-cycle blocks, Q/P words, and spindle state | `tests/gcode/linuxcnc_canned_cycle.ngc`, `tests/gcode/linuxcnc_canned_cycles_extended.ngc`, `tests/gcode/linuxcnc_canned_cycle_planes.ngc`, `tests/gcode/linuxcnc_extended_plane_cycle.ngc`, `tests/gcode/linuxcnc_canned_cycle_l0_error.ngc`, `tests/gcode/linuxcnc_canned_cycle_missing_r_error.ngc`, `tests/gcode/linuxcnc_canned_cycle_missing_z_error.ngc`, `tests/gcode/linuxcnc_canned_cycle_g18_missing_y_error.ngc`, `tests/gcode/linuxcnc_canned_cycle_g19_missing_x_error.ngc`, `tests/gcode/linuxcnc_canned_cycle_r_less_z_error.ngc`, `tests/gcode/linuxcnc_canned_cycle_g18_r_less_y_error.ngc`, `tests/gcode/linuxcnc_canned_cycle_g19_r_less_x_error.ngc`, `tests/gcode/linuxcnc_canned_cycle_u_in_xy_error.ngc`, `tests/gcode/linuxcnc_canned_cycle_a_error.ngc`, `tests/gcode/linuxcnc_canned_cycle_b_error.ngc`, `tests/gcode/linuxcnc_canned_cycle_c_error.ngc`, `tests/gcode/linuxcnc_canned_cycle_reject_rotary_followup.ngc`, `tests/gcode/linuxcnc_canned_cycle_g73_missing_q_error.ngc`, `tests/gcode/linuxcnc_canned_cycle_g83_missing_q_error.ngc`, `tests/gcode/linuxcnc_canned_cycle_g73_q0_error.ngc`, `tests/gcode/linuxcnc_canned_cycle_g83_q0_error.ngc`, `tests/gcode/linuxcnc_canned_cycle_g82_missing_p_error.ngc`, `tests/gcode/linuxcnc_canned_cycle_g86_missing_p_error.ngc`, `tests/gcode/linuxcnc_canned_cycle_g88_missing_p_error.ngc`, `tests/gcode/linuxcnc_canned_cycle_g89_missing_p_error.ngc`, `tests/gcode/linuxcnc_canned_cycle_g74_clockwise_error.ngc`, `tests/gcode/linuxcnc_canned_cycle_g84_counterclockwise_error.ngc`, `tests/gcode/linuxcnc_canned_cycle_g74_stopped_spindle_error.ngc`, `tests/gcode/linuxcnc_canned_cycle_g84_stopped_spindle_error.ngc`, `tests/gcode/linuxcnc_canned_cycle_g86_stopped_spindle_error.ngc`, `tests/gcode/linuxcnc_canned_cycle_g88_stopped_spindle_error.ngc`, `tests/gcode/linuxcnc_canned_cycle_g87_stopped_spindle_error.ngc`, `tests/gcode/linuxcnc_canned_cycle_g87_missing_k_error.ngc`, `tests/gcode/linuxcnc_canned_cycle_g87_missing_i_error.ngc`, `tests/gcode/linuxcnc_canned_cycle_g87_missing_j_error.ngc` |
|
||||
| Coordinate offset Canon events `G10 L2`, `G10 L20`, `G10 P0 active-system targeting`, `G54`-`G59.3` selection, `G52`, `G92/G92.1/G92.2/G92.3` | covered through LinuxCNC native/source backends, including all nine G5X indices | `tests/gcode/linuxcnc_coordinate_offsets.ngc`, `tests/gcode/linuxcnc_coordinate_l20.ngc`, `tests/gcode/linuxcnc_coordinate_p0.ngc`, `tests/gcode/linuxcnc_coordinate_select_all.ngc`, `tests/gcode/linuxcnc_g92_restore.ngc`, `tests/gcode/linuxcnc_g52_offset.ngc` |
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
# LinuxCNC rs274 source map
|
||||
|
||||
This is the working map for moving from native `librs274` linking to source-level compilation and then to wasm.
|
||||
This is the working map for moving from native `librs274` linking to
|
||||
source-level compilation and then to wasm. It is a source-manifest guard only;
|
||||
it must not add CNC behavior and must not expand the temporary smoke parser.
|
||||
|
||||
## Compile assumptions
|
||||
|
||||
@@ -108,6 +110,66 @@ dependencies are replaced:
|
||||
- `src/emc/rs274ngc/pyinterp1.cc`
|
||||
- `src/emc/rs274ngc/pyparamclass.cc`
|
||||
|
||||
### WASM-tracked headers
|
||||
|
||||
These LinuxCNC headers are tracked by the wasm manifest because the
|
||||
browser-safe source-link probes compile against them or shim their declarations:
|
||||
|
||||
- `src/emc/rs274ngc/array1.hh`
|
||||
- `src/emc/rs274ngc/interp_array_types.hh`
|
||||
- `src/emc/rs274ngc/interp_base.hh`
|
||||
- `src/emc/rs274ngc/interp_fwd.hh`
|
||||
- `src/emc/rs274ngc/interp_inspection.hh`
|
||||
- `src/emc/rs274ngc/interp_internal.hh`
|
||||
- `src/emc/rs274ngc/interp_parameter_def.hh`
|
||||
- `src/emc/rs274ngc/interp_python.hh`
|
||||
- `src/emc/rs274ngc/interp_queue.hh`
|
||||
- `src/emc/rs274ngc/modal_state.hh`
|
||||
- `src/emc/rs274ngc/paramclass.hh`
|
||||
- `src/emc/rs274ngc/rs274ngc.hh`
|
||||
- `src/emc/rs274ngc/rs274ngc_interp.hh`
|
||||
- `src/emc/rs274ngc/rs274ngc_return.hh`
|
||||
- `src/emc/rs274ngc/units.h`
|
||||
- `src/emc/pythonplugin/python_plugin.hh`
|
||||
- `src/emc/ini/inifile.h`
|
||||
- `src/emc/ini/inifile.hh`
|
||||
- `src/emc/nml_intf/emc.hh`
|
||||
- `src/emc/nml_intf/emc_nml.hh`
|
||||
- `include/hal.h`
|
||||
- `src/libnml/nml/nmlmsg.hh`
|
||||
- `src/libnml/nml/stat_msg.hh`
|
||||
- `src/libnml/rcs/rcs_print.hh`
|
||||
- `src/rtapi/rtapi.h`
|
||||
- `src/rtapi/rtapi_string.h`
|
||||
|
||||
### WASM-blocked headers
|
||||
|
||||
These headers are tracked for source coverage but should not become browser API
|
||||
surface until their Boost.Python dependency is replaced:
|
||||
|
||||
- `src/emc/rs274ngc/boost_pyenum_macros.hh`
|
||||
|
||||
### WASM metadata sources
|
||||
|
||||
These LinuxCNC source and build metadata files document the source basis for
|
||||
the browser-safe shims and manifest completeness checks:
|
||||
|
||||
- `src/emc/rs274ngc/Submakefile`
|
||||
- `src/emc/rs274ngc/meson.build`
|
||||
- `src/emc/pythonplugin/python_plugin.cc`
|
||||
- `src/emc/task/emctaskmain.cc`
|
||||
- `src/emc/task/taskclass.cc`
|
||||
- `src/emc/task/emccanon.cc`
|
||||
- `src/emc/sai/dummyemcstat.cc`
|
||||
- `src/emc/ini/Submakefile`
|
||||
- `src/libnml/nml/stat_msg.cc`
|
||||
- `src/libnml/nml/nmlmsg.cc`
|
||||
- `src/libnml/rcs/rcs_print.cc`
|
||||
- `src/rtapi/uspace_common.h`
|
||||
- `src/hal/hal_lib.c`
|
||||
- `src/emc/tooldata/tooldata_db.cc`
|
||||
- `src/emc/tooldata/tooldata_nml.cc`
|
||||
|
||||
### Browser-hostile dependencies to replace
|
||||
|
||||
- Python/Boost.Python remap and named parameter hooks.
|
||||
@@ -116,6 +178,33 @@ dependencies are replaced:
|
||||
- persistent parameter file writes.
|
||||
- dynamic INI/HAL queries.
|
||||
|
||||
## Boundaries
|
||||
|
||||
- Native and WASM source lists in this document must match
|
||||
`linuxcnc-rs274-source-files.txt` and
|
||||
`linuxcnc-rs274-wasm-source-files.txt` exactly.
|
||||
- Python binding modules, WASM-blocked sources, and WASM-blocked headers are
|
||||
source coverage only.
|
||||
- They must not become browser API fields or temporary smoke parser fallback behavior.
|
||||
- Browser-hostile dependencies must remain tracked blockers until they are
|
||||
ported, trimmed, wrapped, or replaced by source-backed browser-safe LinuxCNC
|
||||
adaptations.
|
||||
- `test-native.sh`, `test-linuxcnc-source-link.sh`, and `build-wasm.sh` must
|
||||
run `./check-linuxcnc-rs274-source-map.sh` before consuming generated native
|
||||
objects, source-linked LinuxCNC objects, or browser artifacts.
|
||||
- The RS274 source-map guard validates LinuxCNC source ownership and manifest
|
||||
drift only; it does not interpret G-code.
|
||||
|
||||
## Checks
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
./check-linuxcnc-rs274-source-map.sh
|
||||
./test-native.sh
|
||||
./test-linuxcnc-source-link.sh
|
||||
```
|
||||
|
||||
The wasm-safe runtime now constructs its detached `EMC_STAT` through LinuxCNC
|
||||
`src/emc/nml_intf/emcops.cc`. The singleton follows LinuxCNC
|
||||
`src/emc/sai/dummyemcstat.cc`, and the required `NMLmsg`/`RCS_STAT_MSG`
|
||||
|
||||
@@ -63,6 +63,9 @@ Efficiency rules:
|
||||
- Each pass should advance one reasonable, reviewable context. Do not use a
|
||||
nearby failing smoke assertion, broad fixture, or convenient touched file as
|
||||
permission to expand the pass into another workstream.
|
||||
- Keep the six active workstream contexts synchronized with
|
||||
`docs/linuxcnc-workstreams-source-map.md` so source-map guards, architecture,
|
||||
and this policy stay aligned.
|
||||
- Do not add a smoke-only behavior path when the LinuxCNC-backed route already
|
||||
exists; add coverage to the source-backed route instead.
|
||||
- The legacy explicit smoke backend must not be enabled together with the
|
||||
|
||||
54
docs/linuxcnc-switchkins-remap-source-map.md
Normal file
54
docs/linuxcnc-switchkins-remap-source-map.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# LinuxCNC switchkins/remap source map
|
||||
|
||||
This map records the source basis for generated M428/M429/M430 switchkins
|
||||
aliases and config cases. It is a generator/table map only; it must not add CNC behavior, must not expand the temporary smoke parser, and must not expose LinuxCNC source-only assets as browser API fields.
|
||||
|
||||
## LinuxCNC Source Basis
|
||||
|
||||
- `configs/sim/**.ini` files with `REMAP = M428`, `REMAP = M429`, or
|
||||
`REMAP = M430` provide the switchkins configuration roots.
|
||||
- `remap_subs/{428,429,430}remap.ngc` files provide the adjacent
|
||||
`#<kinstype>` assignments.
|
||||
- `src/hal/utils/halcmd_commands.cc` `do_loadusr_cmd()` and
|
||||
`getopt("+wWin:")` define the `loadusr` option model used by the generator.
|
||||
- `src/hal/utils/halcmd_completion.c` documents common `loadusr`
|
||||
`-W/-Wn/-w/-iw` forms preserved by the generator.
|
||||
|
||||
## Generated Coverage
|
||||
|
||||
| Output | Count | Source coverage role |
|
||||
| --- | ---: | --- |
|
||||
| `core/src/linuxcnc_switchkins_remap_table.inc` | 177 | Generated switchkins aliases from LinuxCNC INI/HAL/remap sources. |
|
||||
| `core/tests/linuxcnc_switchkins_remap_config_cases.inc` | 616 | Generated C++ config cases for accepted switchkins config fields. |
|
||||
| `web/public/linuxcnc_switchkins_remap_config_cases.json` | 616 | Generated browser-readable config cases mirroring the C++ cases. |
|
||||
| LinuxCNC M428/M429/M430 remap sources | 31 | LinuxCNC `#<kinstype>` source assignments. |
|
||||
| LinuxCNC switchkins REMAP INI sources | 16 | LinuxCNC configs that declare M428/M429/M430 remaps. |
|
||||
|
||||
## Boundaries
|
||||
|
||||
- `[EMCIO] TOOL_TABLE` entries are source coverage only. They must stay in the kinematics manifest as `tooldata` entries and must not become generated switchkins aliases, config fields, or browser option keys.
|
||||
- `asset`, `metadata`, and `tooldata` inputs referenced by switchkins configs
|
||||
are source coverage, not browser API surface.
|
||||
- Generated tables must continue to derive M428/M429/M430 kinstypes from
|
||||
LinuxCNC remap `#<kinstype>` assignments, not from hand-authored behavior.
|
||||
- `test-native.sh`, `test-linuxcnc-source-link.sh`, and `build-wasm.sh` must
|
||||
run `./check-linuxcnc-switchkins-remap-source-map.sh` before consuming
|
||||
generated config aliases, source-linked LinuxCNC objects, or browser
|
||||
artifacts.
|
||||
- The switchkins/remap source-map guard validates LinuxCNC source/config
|
||||
ownership and generated table drift only; it does not interpret G-code.
|
||||
|
||||
## Checks
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
./check-linuxcnc-switchkins-remap-source-map.sh
|
||||
./check-linuxcnc-switchkins-remap-table.sh linuxcnc-kinematics-source-files.txt
|
||||
./test-native.sh
|
||||
./test-linuxcnc-source-link.sh
|
||||
```
|
||||
|
||||
`check-linuxcnc-switchkins-remap-source-map.sh` keeps this document, generator
|
||||
source anchors, generated output counts, and source-only `TOOL_TABLE` boundary
|
||||
synchronized.
|
||||
99
docs/linuxcnc-tooldata-source-map.md
Normal file
99
docs/linuxcnc-tooldata-source-map.md
Normal file
@@ -0,0 +1,99 @@
|
||||
# LinuxCNC tooldata source map
|
||||
|
||||
This map records the source basis and boundaries for LinuxCNC tooldata coverage
|
||||
in native, source-link, switchkins, and WASM-safe build paths. It is a
|
||||
source-link/shim guard only; it must not add CNC behavior and must not expand the temporary smoke parser.
|
||||
|
||||
## LinuxCNC Source Basis
|
||||
|
||||
- `src/emc/tooldata/Submakefile` selects `tooldata_mmap.cc` or
|
||||
`tooldata_nml.cc`, and always includes `tooldata_common.cc`,
|
||||
`tooldata_db.cc`, and `tool_watch.cc`.
|
||||
- `src/emc/tooldata/tooldata_common.cc` provides tool table parsing,
|
||||
formatting, load/save, and database-mode entry points.
|
||||
- `src/emc/tooldata/tooldata_mmap.cc` provides native mmap tool table storage.
|
||||
- `src/emc/tooldata/tooldata_nml.cc` provides the NML tool table registration
|
||||
backend selected by `TOOL_NML_FLAG`.
|
||||
- `src/emc/tooldata/tooldata_db.cc` provides external database entry points.
|
||||
- `src/emc/tooldata/tooldata_db.cc` returns `-1` from
|
||||
`tooldata_db_getall()` when the external DB is not live, and returns `0`
|
||||
from `tooldata_db_notify()` without side effects in that same state.
|
||||
- `src/emc/tooldata/tool_mmap_read.cc` is the mmap tool table reader utility
|
||||
source from the same LinuxCNC tooldata build metadata; it reads through
|
||||
`tool_mmap_user()`, `tooldata_last_index_get()`, and `tooldata_get()`.
|
||||
- `src/emc/tooldata/tool_watch.cc` is the NML/mmap tool table watcher utility
|
||||
source from the same LinuxCNC tooldata build metadata; it reads
|
||||
`EMC_STAT::io.tool` fields through `RCS_STAT_CHANNEL`.
|
||||
- `src/emc/tooldata/tooldata.hh` declares the tooldata API used by RS274 and
|
||||
WASM-safe shims.
|
||||
|
||||
## Manifest And Shim Coverage
|
||||
|
||||
| Coverage | Boundary |
|
||||
| --- | --- |
|
||||
| `linuxcnc-rs274-source-files.txt` | Tracks the full LinuxCNC `src/emc/tooldata` source directory and `tooldata.hh`. |
|
||||
| `linuxcnc-rs274-wasm-source-files.txt` | Links `tooldata_common.cc`, blocks native `tooldata_mmap.cc`, and records runtime shim source bases for `tooldata_db.cc` and `tooldata_nml.cc`. |
|
||||
| `linuxcnc-kinematics-source-files.txt` | Tracks 10 LinuxCNC `TOOL_TABLE` files referenced by covered M428/M429/M430 INI sources as `tooldata` source coverage only. |
|
||||
| `core/wasm_shims/tooldata/tooldata_mmap_backend.cc` | Adapts LinuxCNC `tooldata_mmap.cc` exports to WASM-safe in-memory storage. |
|
||||
| `core/wasm_shims/tooldata/tooldata_runtime_stubs.cc` | Adapts LinuxCNC `tooldata_nml.cc` and `tooldata_db.cc` runtime entry points without native services. |
|
||||
| `test-linuxcnc-wasm-tooldata-link.sh` | Links the wasm-safe tooldata shim against LinuxCNC tooldata runtime expectations. |
|
||||
| `test-linuxcnc-wasm-tooldata-common-link.sh` | Links LinuxCNC `tooldata_common.cc` through the wasm-safe standalone probe. |
|
||||
| `test-linuxcnc-wasm-tooldata-mmap-symbols.sh` | Compares wasm mmap backend exports with LinuxCNC `tooldata_mmap.cc`. |
|
||||
| `test-linuxcnc-wasm-tooldata-runtime-symbols.sh` | Compares runtime stub exports with LinuxCNC `tooldata_db.cc` and `tooldata_nml.cc`. |
|
||||
|
||||
## External DB Stub Boundaries
|
||||
|
||||
- `core/wasm_shims/tooldata/tooldata_runtime_stubs.cc` must keep external DB services unavailable for browser-safe probes; it must not fork, exec, poll,
|
||||
or keep a live external database process.
|
||||
- `tooldata_db_init()` must preserve the LinuxCNC `MAX_DB_PROGRAM_ARGS=10`, `strtok_r()` argument splitting, and `access(..., X_OK)` rejection edges from
|
||||
`src/emc/tooldata/tooldata_db.cc` before returning `-1`.
|
||||
- `tooldata_db_getall()` must return `-1` while `db_live` is false, and
|
||||
`tooldata_db_notify()` must return `0` without side effects while `db_live`
|
||||
is false.
|
||||
|
||||
## Mmap Backend Boundaries
|
||||
|
||||
- `core/wasm_shims/tooldata/tooldata_mmap_backend.cc` must preserve the
|
||||
LinuxCNC `tooldata_mmap.cc` export surface for the mmap creator/user/close lifecycle while using an in-memory replacement for native mmap.
|
||||
- The mmap backend must keep the LinuxCNC random-toolchanger flag and
|
||||
`last_index` initialization edges from `tool_mmap_creator()`, and
|
||||
`tooldata_last_index_get()` must preserve the last-index unavailable return.
|
||||
- The mmap backend must keep LinuxCNC's single-creator process boundary from
|
||||
the `static inited` guard in `tool_mmap_creator()`, including after
|
||||
`tool_mmap_close()` clears browser-safe in-memory state.
|
||||
- `tool_mmap_user()` must keep LinuxCNC's unavailable mmap failure boundary,
|
||||
and `tool_mmap_close()` must clear the browser-safe in-memory state without
|
||||
adding filesystem mmap behavior.
|
||||
|
||||
## Boundaries
|
||||
|
||||
- Tool table files referenced by switchkins INI files are source coverage only;
|
||||
they must not become browser API fields or generated switchkins aliases.
|
||||
- WASM-safe tooldata shims must preserve the LinuxCNC export surface checked by
|
||||
symbol probes.
|
||||
- WASM-safe tooldata runtime stubs must keep external database services
|
||||
unavailable while preserving LinuxCNC inactive-DB return values.
|
||||
- Native and source-link paths must keep the full LinuxCNC `src/emc/tooldata`
|
||||
source directory tracked in the native RS274 manifest.
|
||||
- `build-wasm.sh` must run tooldata link and symbol probes before copying
|
||||
browser artifacts.
|
||||
- `test-native.sh`, `test-linuxcnc-source-link.sh`, and `build-wasm.sh` must
|
||||
run `./check-linuxcnc-tooldata-source-map.sh` before consuming tooldata-backed
|
||||
native objects, source-linked LinuxCNC objects, or browser artifacts.
|
||||
- The tooldata source-map guard validates LinuxCNC source/shim ownership and
|
||||
manifest drift only; it does not interpret G-code.
|
||||
|
||||
## Checks
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
./check-linuxcnc-tooldata-source-map.sh
|
||||
./test-native.sh
|
||||
./test-linuxcnc-source-link.sh
|
||||
./build-wasm.sh
|
||||
```
|
||||
|
||||
`check-linuxcnc-tooldata-source-map.sh` keeps this document, LinuxCNC tooldata
|
||||
source anchors, manifest coverage, WASM shim/probe boundaries, and switchkins
|
||||
TOOL_TABLE source-only policy synchronized.
|
||||
98
docs/linuxcnc-wasm-blockers-source-map.md
Normal file
98
docs/linuxcnc-wasm-blockers-source-map.md
Normal file
@@ -0,0 +1,98 @@
|
||||
# LinuxCNC WASM blockers source map
|
||||
|
||||
This map records the source basis for the WASM blocker categories used by
|
||||
`analyze-linuxcnc-wasm-blockers.sh` and `test-linuxcnc-wasm-blockers.sh`. It is
|
||||
a source-link/build guard only; it does not add CNC behavior and must not become smoke parser behavior.
|
||||
|
||||
## LinuxCNC Source Basis
|
||||
|
||||
- `src/emc/rs274ngc/gcodemodule.cc`, `canonmodule.cc`, `interpmodule.cc`, and
|
||||
`py*.cc` provide the Python and Boost.Python module binding blockers.
|
||||
- `src/emc/rs274ngc/interp_python.cc`, `interp_remap.cc`,
|
||||
`interp_namedparams.cc`, `interp_o_word.cc`, `interp_setup.cc`, and
|
||||
`rs274ngc_pre.cc` keep Python/Boost.Python remap paths as shimmed core
|
||||
sources.
|
||||
- `src/emc/rs274ngc/interp_base.cc` is the core source that still carries
|
||||
`dlopen` use satisfied by the wasm dlfcn shim.
|
||||
- `src/emc/tooldata/tooldata_mmap.cc` is the native mmap backend blocker
|
||||
replaced by the wasm-safe tooldata mmap backend shim.
|
||||
- `src/emc/rs274ngc/interp_o_word.cc` uses native directory traversal for
|
||||
O-word subroutine lookup; browser persistence remains OPFS-only.
|
||||
- `src/emc/rs274ngc/rs274ngc_pre.cc` implements LinuxCNC parameter-file replacement through `filename + ".new"`, `filename + ".bak"`, `unlink`, `link`, and `rename`; browser persistence remains OPFS-only.
|
||||
|
||||
## Manifest Coverage
|
||||
|
||||
| Manifest group | Count | Role |
|
||||
| --- | ---: | --- |
|
||||
| `core` | 26 | LinuxCNC RS274/tooldata/INI/NML sources compiled or shim-satisfied by WASM probes. |
|
||||
| `blocked` | 9 | LinuxCNC Python binding and native tooldata sources tracked but replaced for WASM. |
|
||||
| `header` | 26 | LinuxCNC headers needed by the WASM-safe source probes and shims. |
|
||||
| `blocked-header` | 1 | Boost.Python helper header tracked as blocked browser API surface. |
|
||||
| `metadata` | 15 | LinuxCNC build/source-basis files for shim coverage. |
|
||||
|
||||
## Analyzer Coverage
|
||||
|
||||
| Analyzer section | Count | Boundary |
|
||||
| --- | ---: | --- |
|
||||
| `python` | 8 | Blocked Python/Boost.Python module sources. |
|
||||
| `dlopen` | 0 | blocked `dlopen` and blocked tooldata-users remain empty. |
|
||||
| `tooldata` | 1 | Native tooldata mmap blocker. |
|
||||
| `tooldata-users` | 0 | Blocked tooldata user sources remain empty. |
|
||||
| `native-backend` | 1 | Native backend source excluded from browser linking. |
|
||||
| `native-fs` | 1 | Native filesystem blocker excluded from browser linking. |
|
||||
| `blocked-replacements` | 9 | Blocked LinuxCNC sources mapped to wasm-safe shim files. |
|
||||
| `core-python-shimmed` | 6 | Core LinuxCNC Python/remap users compiled with Python/Boost.Python shims. |
|
||||
| `core-dlopen-shimmed` | 1 | Core LinuxCNC `dlopen` user compiled with dlfcn shim. |
|
||||
| `core-tooldata-shimmed` | 1 | Core LinuxCNC tooldata source compiled with wasm tooldata shims. |
|
||||
| `core-tooldata-users-shimmed` | 2 | Core RS274/NML users of tooldata declarations. |
|
||||
| `core-native-fs-shimmed` | 16 | Core sources with native filesystem includes or calls covered by WASM shims, including O-word lookup and parameter-file replacement. |
|
||||
|
||||
Required replacement set:
|
||||
|
||||
- `src/emc/rs274ngc/canonmodule.cc -> core/wasm_shims/linuxcnc_runtime_shim.cc`
|
||||
- `src/emc/rs274ngc/gcodemodule.cc -> core/wasm_shims/linuxcnc_runtime_shim.cc`
|
||||
- `src/emc/rs274ngc/interpmodule.cc -> core/wasm_shims/linuxcnc_runtime_shim.cc`
|
||||
- `src/emc/rs274ngc/pyarrays.cc -> core/wasm_shims/python_c_api_shim.cc`
|
||||
- `src/emc/rs274ngc/pyblock.cc -> core/wasm_shims/python_c_api_shim.cc`
|
||||
- `src/emc/rs274ngc/pyemctypes.cc -> core/wasm_shims/python_c_api_shim.cc`
|
||||
- `src/emc/rs274ngc/pyinterp1.cc -> core/wasm_shims/python_c_api_shim.cc`
|
||||
- `src/emc/rs274ngc/pyparamclass.cc -> core/wasm_shims/python_c_api_shim.cc`
|
||||
- `src/emc/tooldata/tooldata_mmap.cc -> core/wasm_shims/tooldata/tooldata_mmap_backend.cc`
|
||||
|
||||
Required tracked core examples:
|
||||
|
||||
- `src/emc/rs274ngc/interp_base.cc -> core/wasm_shims/dlfcn.cc`
|
||||
- `src/emc/rs274ngc/gcodemodule.cc`
|
||||
- `src/emc/rs274ngc/interpmodule.cc`
|
||||
- `src/emc/tooldata/tooldata_mmap.cc`
|
||||
- `src/emc/rs274ngc/interp_base.cc`
|
||||
- `src/emc/rs274ngc/interp_o_word.cc`
|
||||
- `src/emc/rs274ngc/rs274ngc_pre.cc`
|
||||
|
||||
## Boundaries
|
||||
|
||||
- `test-native.sh`, `test-linuxcnc-source-link.sh`, and `build-wasm.sh` must
|
||||
run `./check-linuxcnc-wasm-blockers-source-map.sh` before consuming blocker
|
||||
analyzer output, source-linked LinuxCNC objects, or browser artifacts.
|
||||
- `test-native.sh` and `test-linuxcnc-source-link.sh` must run
|
||||
`test-linuxcnc-wasm-blockers.sh` with `CNC_SIM_WASM_BLOCKERS_SELF_CHECKS=1`
|
||||
so bad manifests, missing LinuxCNC roots, duplicate entries, and missing
|
||||
blocked-source replacements stay executable failures.
|
||||
- The WASM blockers source-map guard validates LinuxCNC source/blocker
|
||||
ownership and manifest drift only; it does not interpret G-code.
|
||||
|
||||
## Checks
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
./check-linuxcnc-wasm-blockers-source-map.sh
|
||||
./test-linuxcnc-wasm-blockers.sh linuxcnc-rs274-wasm-source-files.txt
|
||||
./test-native.sh
|
||||
./test-linuxcnc-source-link.sh
|
||||
./build-wasm.sh
|
||||
```
|
||||
|
||||
`check-linuxcnc-wasm-blockers-source-map.sh` keeps this document, the
|
||||
RS274/WASM manifest, LinuxCNC source anchors, analyzer output, and wasm-safe
|
||||
shim replacement set synchronized. Python/Boost.Python remap paths remain tracked blockers until they are ported, wrapped, or replaced by source-backed browser-safe LinuxCNC adaptations.
|
||||
102
docs/linuxcnc-wasm-shims-source-map.md
Normal file
102
docs/linuxcnc-wasm-shims-source-map.md
Normal file
@@ -0,0 +1,102 @@
|
||||
# LinuxCNC WASM shims source map
|
||||
|
||||
This map records the source basis for the C++ sources in the
|
||||
CMake `linuxcnc_wasm_safe_probe_shims` set. It is a build/source-link guard
|
||||
only; it must not add CNC behavior and must not expand the temporary smoke parser.
|
||||
|
||||
## Generated Coverage
|
||||
|
||||
| Output | Count | Source coverage role |
|
||||
| --- | ---: | --- |
|
||||
| CMake `linuxcnc_wasm_safe_probe_shims` sources | 11 | Browser-safe LinuxCNC adaptation shims linked into WASM source probes. |
|
||||
|
||||
## Shim Map
|
||||
|
||||
| Shim | LinuxCNC source basis | Boundary |
|
||||
| --- | --- | --- |
|
||||
| `core/wasm_shims/dlfcn.cc` | `src/emc/rs274ngc/interp_base.cc` | Satisfies LinuxCNC `interp_base.cc` dynamic loader calls and RTLD flags for browser-safe probes while keeping dynamic loading unavailable. |
|
||||
| `core/wasm_shims/emc_status_shim.cc` | `src/emc/sai/dummyemcstat.cc` | Provides the detached LinuxCNC `EMC_STAT` singleton shape without task/NML startup. |
|
||||
| `core/wasm_shims/gettext_shim.cc` | `src/emc/rs274ngc/interp_internal.hh` | Preserves LinuxCNC `_()` diagnostic call sites by satisfying `gettext()` while leaving browser gettext catalogs unavailable. |
|
||||
| `core/wasm_shims/linuxcnc_runtime_shim.cc` | `src/emc/rs274ngc/gcodemodule.cc`, `src/emc/task/emctaskmain.cc`, `src/emc/task/taskclass.cc`, `src/emc/rs274ngc/interp_namedparams.cc`, `include/hal.h`, `src/hal/hal_lib.c`, `src/emc/rs274ngc/rs274ngc_pre.cc` | Keeps preview/task, builtin module stubs, unavailable HAL lookup, and `wordexp()` edges compile-safe. |
|
||||
| `core/wasm_shims/nml_status_shim.cc` | `src/libnml/nml/nmlmsg.cc`, `src/libnml/nml/stat_msg.cc` | Provides LinuxCNC NML status constructors, clear behavior, and `RCS_STAT_MSG` default status fields needed by source-linked EMC status objects. |
|
||||
| `core/wasm_shims/python_c_api_shim.cc` | `src/emc/rs274ngc/interp_python.cc`, `src/emc/rs274ngc/interp_namedparams.cc`, `src/emc/rs274ngc/gcodemodule.cc`, `src/emc/pythonplugin/python_plugin.cc` | Satisfies Python C API symbols while Python/Boost.Python remap paths remain tracked blockers. |
|
||||
| `core/wasm_shims/rcs_print_shim.cc` | `src/libnml/rcs/rcs_print.cc`, `src/libnml/rcs/rcs_print.hh` | Provides the LinuxCNC `rcs_print_error` split entry points used by NML validation without native print routing. |
|
||||
| `core/wasm_shims/rtapi_compat.cc` | `src/rtapi/uspace_common.h`, `src/rtapi/rtapi.h` | Provides LinuxCNC userspace `rtapi_snprintf()` formatting by following the `rtapi.h` declaration and `uspace_common.h` `vsnprintf()` implementation path. |
|
||||
| `core/wasm_shims/tooldata/tooldata_mmap_backend.cc` | `src/emc/tooldata/tooldata_mmap.cc` | Replaces native mmap storage with an in-memory WASM-safe backend for probes. |
|
||||
| `core/wasm_shims/tooldata/tooldata_runtime_stubs.cc` | `src/emc/tooldata/tooldata_nml.cc`, `src/emc/tooldata/tooldata_db.cc` | Satisfies NML and external tool database entry points without native services, preserving inactive-DB return values. |
|
||||
| `core/wasm_shims/pythonplugin/python_plugin.cc` | `src/emc/pythonplugin/python_plugin.cc`, `src/emc/pythonplugin/python_plugin.hh`, `src/emc/ini/inifile.cc` | Keeps LinuxCNC PythonPlugin API and negative-status short-circuit behavior available while Python execution is disabled for browser-safe probes. |
|
||||
|
||||
## Runtime Shim Boundaries
|
||||
|
||||
- `core/wasm_shims/dlfcn.cc` and `core/wasm_shims/dlfcn.h` cover the
|
||||
LinuxCNC `interp_base.cc` dynamic loader calls to `dlopen()`, `dlsym()`,
|
||||
`dlerror()`, `RTLD_GLOBAL`, and `RTLD_NOW`; their unavailable-loader returns
|
||||
must keep handles and symbols null, keep `dlerror()` diagnostic text stable,
|
||||
and leave `dlclose()` side-effect free.
|
||||
- `core/wasm_shims/emc_status_shim.cc` must stay limited to the detached
|
||||
LinuxCNC `EMC_STAT` singleton from `src/emc/sai/dummyemcstat.cc`; it must not
|
||||
pull in task startup, NML channels, or operator callback behavior.
|
||||
- `core/wasm_shims/linuxcnc_runtime_shim.cc` must keep preview `_task=0`,
|
||||
matching `src/emc/rs274ngc/gcodemodule.cc`; it must not switch browser-safe probes into task mode.
|
||||
- The runtime shim's builtin module stubs must match LinuxCNC's
|
||||
`interpreter`/`emccanon` inittab shape from `gcodemodule.cc` and
|
||||
`taskclass.cc` while returning null module pointers; they must not become
|
||||
Python execution.
|
||||
- The HAL lookup shim covers `hal_get_pin_value_by_name()`,
|
||||
`hal_get_signal_value_by_name()`, and `hal_get_param_value_by_name()` from
|
||||
`src/emc/rs274ngc/interp_namedparams.cc`, `include/hal.h`, and
|
||||
`src/hal/hal_lib.c`; it must leave HAL values unavailable by returning `-1`,
|
||||
`HAL_TYPE_UNINITIALIZED`, and null data pointers.
|
||||
- `wordexp()` support is limited to the single-word `wordexp()` path expansion
|
||||
and `wordfree()` cleanup needed by `src/emc/rs274ngc/rs274ngc_pre.cc` for
|
||||
basename, program prefix, and subroutine-directory lookups; it must not become a shell expansion feature.
|
||||
|
||||
## Python Shim Boundaries
|
||||
|
||||
- `core/wasm_shims/python_c_api_shim.cc` satisfies Python C API symbols used by
|
||||
LinuxCNC RS274/remap sources; it must not become Python execution.
|
||||
- The Python C API shim must return inert objects, null exceptions, false
|
||||
callable/type checks, and successful module/type registration statuses only
|
||||
to satisfy LinuxCNC `interp_python.cc`, `gcodemodule.cc`, and
|
||||
`python_plugin.cc` link expectations; it must not call into CPython runtime.
|
||||
- `core/wasm_shims/pythonplugin/python_plugin.cc` must preserve LinuxCNC
|
||||
`PythonPlugin` status edges for `PLUGIN_NO_SECTION`, `PLUGIN_BAD_INIFILE`,
|
||||
`PLUGIN_BAD_PATH`, `PLUGIN_INITTAB_FAILED`,
|
||||
`PLUGIN_PYTHON_NOT_INITIALIZED`, `PLUGIN_NO_CALLABLE`, and
|
||||
`PLUGIN_EXCEPTION` while keeping Python execution disabled.
|
||||
- The PythonPlugin shim must preserve the first-caller `_inittab` `PLUGIN_INITTAB_FAILED` edge from `src/emc/pythonplugin/python_plugin.cc` when a built-in module init function fails, while keeping browser-safe probes detached from real Python module execution.
|
||||
- The PythonPlugin shim must preserve the `TOPLEVEL` missing-path `PLUGIN_BAD_PATH` edge from `src/emc/pythonplugin/python_plugin.cc` before reporting the browser-safe disabled Python runtime status.
|
||||
- The PythonPlugin shim must preserve `PATH_PREPEND` and `PATH_APPEND` tilde-expansion failure statuses from `src/emc/pythonplugin/python_plugin.cc` and `src/emc/ini/inifile.cc` without executing Python path mutation in browser-safe probes.
|
||||
- The PythonPlugin shim must preserve LinuxCNC INI section-name trimming and trailing section-comment handling from `src/emc/ini/inifile.cc` for Python/remap configuration keys.
|
||||
- The PythonPlugin shim must not execute `bp::exec`, `bp::exec_file`, or real
|
||||
Python callable dispatch; `PyObject_Call` is an inert C API symbol only.
|
||||
Browser Python execution remains blocked until implemented as a source-backed
|
||||
browser-safe LinuxCNC adaptation.
|
||||
|
||||
## Boundaries
|
||||
|
||||
- The CMake `linuxcnc_wasm_safe_probe_shims` set and `list-linuxcnc-wasm-safe-shims.sh` must stay synchronized.
|
||||
- Each shim source must keep a nearby `LinuxCNC source basis:` comment naming the LinuxCNC source it adapts.
|
||||
- Every LinuxCNC source named above must remain tracked in the RS274/WASM manifest as `core`, `header`, or `metadata`.
|
||||
- These shims are browser-safe LinuxCNC adaptations for source-link probes; they are not new interpreter behavior.
|
||||
- `test-native.sh`, `test-linuxcnc-source-link.sh`, and `build-wasm.sh` must
|
||||
run `./check-linuxcnc-wasm-shims-source-map.sh` before consuming shim-backed
|
||||
source-linked LinuxCNC objects or browser artifacts.
|
||||
- The WASM shims source-map guard validates LinuxCNC source/shim ownership and
|
||||
manifest drift only; it does not interpret G-code.
|
||||
|
||||
## Checks
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
./check-linuxcnc-wasm-shims-source-map.sh
|
||||
./test-linuxcnc-wasm-cmake-safe-probe.sh
|
||||
./test-native.sh
|
||||
./test-linuxcnc-source-link.sh
|
||||
./build-wasm.sh
|
||||
```
|
||||
|
||||
`check-linuxcnc-wasm-shims-source-map.sh` keeps this document, the CMake shim
|
||||
set, `list-linuxcnc-wasm-safe-shims.sh`, LinuxCNC source anchors, and the
|
||||
RS274/WASM manifest synchronized.
|
||||
79
docs/linuxcnc-wasm-smoke-source-map.md
Normal file
79
docs/linuxcnc-wasm-smoke-source-map.md
Normal file
@@ -0,0 +1,79 @@
|
||||
# LinuxCNC WASM smoke source map
|
||||
|
||||
This map records the source basis and boundaries for the Node and browser WASM
|
||||
smoke wrappers. It is a smoke-test guard only; it must not add CNC behavior,
|
||||
must not expand the temporary smoke parser, and must keep browser filesystem
|
||||
persistence OPFS-only. In browser contexts, browser filesystem persistence
|
||||
OPFS-only is the required boundary.
|
||||
|
||||
## LinuxCNC Source Basis
|
||||
|
||||
- `src/emc/rs274ngc/rs274ngc_pre.cc` provides `Interp::ini_load()`,
|
||||
`Interp::restore_parameters()`, `Interp::save_parameters()`, and `read_text()`
|
||||
behavior exercised by Node/browser bridge tests.
|
||||
- `src/emc/rs274ngc/rs274ngc_pre.cc` saves parameters by writing
|
||||
`filename + ".new"`, unlinking `filename + ".bak"`, linking the previous file
|
||||
to `filename + ".bak"`, and renaming the temporary file over the main file.
|
||||
- `src/emc/rs274ngc/interp_convert.cc` provides `convert_m()` coverage for
|
||||
M66 waits and M68 analog output side effects used by generated remap cases.
|
||||
- `src/emc/nml_intf/canon.hh` declares the `WAIT()` and
|
||||
`SET_AUX_OUTPUT_VALUE()` canon entry points surfaced through the event bridge.
|
||||
- `src/emc/kinematics/5axiskins.c`, `src/emc/kinematics/trtfuncs.c`,
|
||||
`src/emc/kinematics/xyzac-trt-kins.c`,
|
||||
`src/emc/kinematics/xyzbc-trt-kins.c`, and
|
||||
`src/emc/kinematics/userkfuncs.c` provide the RTCP/kinematics inverse paths
|
||||
covered by WASM smoke tests.
|
||||
- `configs/sim/**.ini` files and `remap_subs/{428,429,430}remap.ngc` sources
|
||||
generate `web/public/linuxcnc_switchkins_remap_config_cases.json`.
|
||||
|
||||
## Smoke Coverage
|
||||
|
||||
| Smoke entry | Boundary |
|
||||
| --- | --- |
|
||||
| `test-web-wasm-node-smoke.sh` | Runs the Node WASM wrapper with generated LinuxCNC switchkins cases and LinuxCNC-backed RTCP checks. |
|
||||
| `test-web-wasm-node-smoke.cjs` | Exercises the C ABI, `web/src/wasm-core.js`, generated switchkins config cases, and source-backed kinematics events. |
|
||||
| `test-web-wasm-browser-smoke.sh` | Runs browser checks after verifying copied WASM artifacts and smoke module structure. |
|
||||
| `web/test-browser-wasm-smoke-linuxcnc-sections.js` | Exercises LinuxCNC browser parsing and generated switchkins cases without INI_FILE_NAME remap-load aliases. |
|
||||
| `web/test-browser-wasm-smoke-opfs-workspace-sections.js` | Aggregates OPFS basic, parameter, mirror, and directory sections under browser OPFS availability. |
|
||||
| `web/test-browser-wasm-smoke-opfs-basic-sections.js` | Exercises OPFS-backed program file reads through LinuxCNC `read_text()` and rejects unsafe paths. |
|
||||
| `web/test-browser-wasm-smoke-opfs-parameter-sections.js` | Exercises LinuxCNC parameter restore/save/backup semantics through OPFS. |
|
||||
| `web/test-browser-wasm-smoke-opfs-mirror-sections.js` | Exercises OPFS/WASM mirror persistence used by source-backed program parsing and parameter movement. |
|
||||
| `web/test-browser-wasm-smoke-opfs-directory-sections.js` | Exercises OPFS directory persistence and WASM mirror refresh without filesystem persistence outside OPFS. |
|
||||
| `web/test-browser-wasm-smoke-opfs-policy-sections.js` | Exercises browser OPFS workspace and mount policy, including the rule that OPFS cannot be disabled. |
|
||||
| `web/test-browser-wasm-smoke-app-sections.js` | Verifies the browser app uses OPFS program and parameter persistence. |
|
||||
|
||||
## Boundaries
|
||||
|
||||
- Node smoke must leave OPFS disabled and must reject `parseFile*` methods that
|
||||
require an OPFS workspace.
|
||||
- Browser smoke must keep program files, LinuxCNC parameter files, temporary
|
||||
`.new` files, and `.bak` backups under OPFS-backed storage.
|
||||
- Browser smoke harness files must not use Local Storage, IndexedDB, File
|
||||
Picker, Directory Picker, WebKit filesystem, or FileReader persistence paths.
|
||||
- Generated switchkins config smoke cases must continue to come from
|
||||
`web/public/linuxcnc_switchkins_remap_config_cases.json`.
|
||||
- The browser smoke shell guard also pins required section names for LinuxCNC
|
||||
browser parsing, OPFS workspace/policy/directory handling, OPFS parameter
|
||||
restore/save failure handling, and browser app OPFS reload coverage.
|
||||
- Smoke wrappers must keep positive minimum coverage thresholds so accidental
|
||||
section loss is visible.
|
||||
- `test-native.sh`, `test-linuxcnc-source-link.sh`, and `build-wasm.sh` must
|
||||
run `./check-linuxcnc-wasm-smoke-source-map.sh` before consuming Node/browser
|
||||
WASM smoke coverage or browser artifacts.
|
||||
- The WASM smoke source-map guard validates LinuxCNC source-backed smoke
|
||||
coverage only; it does not interpret G-code.
|
||||
|
||||
## Checks
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
./check-linuxcnc-wasm-smoke-source-map.sh
|
||||
./test-native.sh
|
||||
./test-linuxcnc-source-link.sh
|
||||
./build-wasm.sh
|
||||
```
|
||||
|
||||
`check-linuxcnc-wasm-smoke-source-map.sh` keeps this document, LinuxCNC source
|
||||
anchors, smoke wrapper boundaries, OPFS-only policy, and generated switchkins
|
||||
case usage synchronized.
|
||||
59
docs/linuxcnc-workstreams-source-map.md
Normal file
59
docs/linuxcnc-workstreams-source-map.md
Normal file
@@ -0,0 +1,59 @@
|
||||
# LinuxCNC workstreams source map
|
||||
|
||||
This map ties the six active workstream contexts to their source-map guards. It
|
||||
is a coordination guard only; it must not add CNC behavior and must not expand
|
||||
the temporary smoke parser.
|
||||
|
||||
## Workstream Coverage
|
||||
|
||||
| Workstream | Source-map documents | Guard scripts |
|
||||
| --- | --- | --- |
|
||||
| `switchkins/remap` generator and tables | `docs/linuxcnc-switchkins-remap-source-map.md` | `check-linuxcnc-switchkins-remap-source-map.sh` |
|
||||
| `linuxcnc-kinematics` source manifest | `docs/linuxcnc-kinematics-source-map.md` | `check-linuxcnc-kinematics-source-map.sh` |
|
||||
| WASM filesystem and OPFS persistence | `docs/linuxcnc-opfs-source-map.md`, `docs/linuxcnc-wasm-shims-source-map.md`, `docs/linuxcnc-wasm-blockers-source-map.md`, `docs/linuxcnc-tooldata-source-map.md` | `check-linuxcnc-opfs-source-map.sh`, `check-linuxcnc-wasm-shims-source-map.sh`, `check-linuxcnc-wasm-blockers-source-map.sh`, `check-linuxcnc-tooldata-source-map.sh` |
|
||||
| browser app integration | `docs/linuxcnc-browser-app-source-map.md` | `check-linuxcnc-browser-app-source-map.sh` |
|
||||
| Node and browser smoke coverage | `docs/linuxcnc-wasm-smoke-source-map.md` | `check-linuxcnc-wasm-smoke-source-map.sh` |
|
||||
| source-link, build, and documentation constraints | `docs/linuxcnc-rs274-source-map.md`, `docs/linuxcnc-build-source-map.md`, `docs/linuxcnc-tooldata-source-map.md` | `check-linuxcnc-rs274-source-map.sh`, `check-linuxcnc-build-source-map.sh`, `check-linuxcnc-tooldata-source-map.sh` |
|
||||
|
||||
## LinuxCNC Source Basis
|
||||
|
||||
- `configs/sim/**.ini` and `remap_subs/{428,429,430}remap.ngc` back the
|
||||
switchkins/remap workstream.
|
||||
- `src/emc/kinematics/Submakefile` and `src/emc/kinematics/kinematics.h` back
|
||||
the kinematics manifest workstream.
|
||||
- `src/emc/rs274ngc/interp_internal.hh` and
|
||||
`src/emc/rs274ngc/rs274ngc_pre.cc` back the OPFS/browser parameter-file
|
||||
workstreams.
|
||||
- `src/emc/rs274ngc/Submakefile`, `src/emc/tooldata/Submakefile`,
|
||||
`src/emc/ini/Submakefile`, and `src/emc/pythonplugin/Submakefile` back the
|
||||
source-link and build-policy workstream.
|
||||
|
||||
## Boundaries
|
||||
|
||||
- Every active workstream must have at least one source-map document and guard
|
||||
script.
|
||||
- `docs/linuxcnc-source-policy.md` must keep the same one-context workflow
|
||||
boundary and smoke-verification-only rule used by this index.
|
||||
- `test-native.sh`, `test-linuxcnc-source-link.sh`, and `build-wasm.sh` must
|
||||
run the workstream source-map guard before consuming generated config aliases,
|
||||
source-linked LinuxCNC objects, or browser artifacts.
|
||||
- WASM blocker and shim maps remain source coverage guards, not browser API
|
||||
expansion points.
|
||||
- Browser filesystem persistence remains OPFS-only.
|
||||
- Smoke coverage remains verification only and must not become a functional CNC
|
||||
behavior path.
|
||||
|
||||
## Checks
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
./check-linuxcnc-workstreams-source-map.sh
|
||||
./test-native.sh
|
||||
./test-linuxcnc-source-link.sh
|
||||
./build-wasm.sh
|
||||
```
|
||||
|
||||
`check-linuxcnc-workstreams-source-map.sh` keeps the six-workstream architecture
|
||||
list, source-map documents, guard scripts, LinuxCNC source anchors, and native /
|
||||
source-link / build-wasm guard entry points synchronized.
|
||||
@@ -141,6 +141,47 @@ grep -F 'CNC_SIM_ALL_NATIVE_GUARDRAILS_ONLY must be 0 or 1: $guardrails_only' te
|
||||
grep -F 'all native guardrail checks passed' test-all-native.sh >/dev/null
|
||||
grep -F 'LinuxCNC source basis: the wasm build preflights and compiles the' build-wasm.sh >/dev/null
|
||||
grep -F 'LinuxCNC source basis: manifest validation checks LinuxCNC-root relative' check-linuxcnc-inputs.sh >/dev/null
|
||||
grep -F 'LinuxCNC source basis: this guard keeps the local source map aligned' check-linuxcnc-rs274-source-map.sh >/dev/null
|
||||
grep -F './check-linuxcnc-rs274-source-map.sh' test-native.sh >/dev/null
|
||||
grep -F './check-linuxcnc-rs274-source-map.sh' build-wasm.sh >/dev/null
|
||||
grep -F 'LinuxCNC source basis: this guard keeps the kinematics source map aligned' check-linuxcnc-kinematics-source-map.sh >/dev/null
|
||||
grep -F './check-linuxcnc-kinematics-source-map.sh' test-native.sh >/dev/null
|
||||
grep -F './check-linuxcnc-kinematics-source-map.sh' build-wasm.sh >/dev/null
|
||||
grep -F 'LinuxCNC source basis: this guard ties browser OPFS parameter persistence' check-linuxcnc-opfs-source-map.sh >/dev/null
|
||||
grep -F './check-linuxcnc-opfs-source-map.sh' test-native.sh >/dev/null
|
||||
grep -F './check-linuxcnc-opfs-source-map.sh' build-wasm.sh >/dev/null
|
||||
grep -F 'LinuxCNC source basis: this guard ties generated switchkins/remap aliases' check-linuxcnc-switchkins-remap-source-map.sh >/dev/null
|
||||
grep -F './check-linuxcnc-switchkins-remap-source-map.sh' test-native.sh >/dev/null
|
||||
grep -F './check-linuxcnc-switchkins-remap-source-map.sh' test-linuxcnc-source-link.sh >/dev/null
|
||||
grep -F './check-linuxcnc-switchkins-remap-source-map.sh' build-wasm.sh >/dev/null
|
||||
grep -F 'LinuxCNC source basis: this guard ties Node/browser WASM smoke coverage' check-linuxcnc-wasm-smoke-source-map.sh >/dev/null
|
||||
grep -F './check-linuxcnc-wasm-smoke-source-map.sh' test-native.sh >/dev/null
|
||||
grep -F './check-linuxcnc-wasm-smoke-source-map.sh' test-linuxcnc-source-link.sh >/dev/null
|
||||
grep -F './check-linuxcnc-wasm-smoke-source-map.sh' build-wasm.sh >/dev/null
|
||||
grep -F 'LinuxCNC source basis: this guard ties native/source-link/WASM build entry' check-linuxcnc-build-source-map.sh >/dev/null
|
||||
grep -F './check-linuxcnc-build-source-map.sh' test-native.sh >/dev/null
|
||||
grep -F './check-linuxcnc-build-source-map.sh' test-linuxcnc-source-link.sh >/dev/null
|
||||
grep -F './check-linuxcnc-build-source-map.sh' build-wasm.sh >/dev/null
|
||||
grep -F 'LinuxCNC source basis: this guard ties the browser app entry point' check-linuxcnc-browser-app-source-map.sh >/dev/null
|
||||
grep -F './check-linuxcnc-browser-app-source-map.sh' test-native.sh >/dev/null
|
||||
grep -F './check-linuxcnc-browser-app-source-map.sh' test-linuxcnc-source-link.sh >/dev/null
|
||||
grep -F './check-linuxcnc-browser-app-source-map.sh' build-wasm.sh >/dev/null
|
||||
grep -F 'LinuxCNC source basis: this guard ties the six active workstream contexts' check-linuxcnc-workstreams-source-map.sh >/dev/null
|
||||
grep -F './check-linuxcnc-workstreams-source-map.sh' test-native.sh >/dev/null
|
||||
grep -F './check-linuxcnc-workstreams-source-map.sh' test-linuxcnc-source-link.sh >/dev/null
|
||||
grep -F './check-linuxcnc-workstreams-source-map.sh' build-wasm.sh >/dev/null
|
||||
grep -F 'LinuxCNC source basis: this guard ties LinuxCNC tooldata/Submakefile' check-linuxcnc-tooldata-source-map.sh >/dev/null
|
||||
grep -F './check-linuxcnc-tooldata-source-map.sh' test-native.sh >/dev/null
|
||||
grep -F './check-linuxcnc-tooldata-source-map.sh' test-linuxcnc-source-link.sh >/dev/null
|
||||
grep -F './check-linuxcnc-tooldata-source-map.sh' build-wasm.sh >/dev/null
|
||||
grep -F 'LinuxCNC source basis: this guard ties the documented WASM blocker map' check-linuxcnc-wasm-blockers-source-map.sh >/dev/null
|
||||
grep -F './check-linuxcnc-wasm-blockers-source-map.sh' test-native.sh >/dev/null
|
||||
grep -F './check-linuxcnc-wasm-blockers-source-map.sh' test-linuxcnc-source-link.sh >/dev/null
|
||||
grep -F './check-linuxcnc-wasm-blockers-source-map.sh' build-wasm.sh >/dev/null
|
||||
grep -F 'LinuxCNC source basis: this guard ties the documented wasm-safe shim map' check-linuxcnc-wasm-shims-source-map.sh >/dev/null
|
||||
grep -F './check-linuxcnc-wasm-shims-source-map.sh' test-native.sh >/dev/null
|
||||
grep -F './check-linuxcnc-wasm-shims-source-map.sh' test-linuxcnc-source-link.sh >/dev/null
|
||||
grep -F './check-linuxcnc-wasm-shims-source-map.sh' build-wasm.sh >/dev/null
|
||||
grep -F 'LinuxCNC source basis: the cached input checker keys check-linuxcnc-inputs.sh' check-linuxcnc-inputs-cached.sh >/dev/null
|
||||
grep -F 'LinuxCNC source basis: switchkins/remap table validation derives M428/M429/M430' check-linuxcnc-switchkins-remap-table.sh >/dev/null
|
||||
grep -F 'LINUXCNC_ROOT="$linuxcnc_root" ./check-linuxcnc-inputs-cached.sh "$manifest" --require-kinematics-complete' check-linuxcnc-switchkins-remap-table.sh >/dev/null
|
||||
@@ -203,6 +244,39 @@ grep -F '`src/hal/utils/halcmd_completion.c`' docs/linuxcnc-source-policy.md >/d
|
||||
grep -F 'must not become new generated API aliases or browser cases.' docs/linuxcnc-source-policy.md >/dev/null
|
||||
grep -F 'The kinematics manifest lister must preserve every allowed manifest group' docs/linuxcnc-source-policy.md >/dev/null
|
||||
grep -F 'including `asset`, `tooldata`, and' docs/linuxcnc-source-policy.md >/dev/null
|
||||
grep -F 'LinuxCNC kinematics source map' docs/linuxcnc-kinematics-source-map.md >/dev/null
|
||||
grep -F '| `tooldata` | 10 | LinuxCNC tool table files referenced by covered M428/M429/M430 INI files. |' docs/linuxcnc-kinematics-source-map.md >/dev/null
|
||||
grep -F 'Browser-side file persistence remains OPFS-only' docs/linuxcnc-kinematics-source-map.md >/dev/null
|
||||
grep -F 'LinuxCNC OPFS source map' docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F '`Interp::save_parameters()` for `filename + ".new"`' docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F 'Browser contexts with OPFS support must not disable OPFS.' docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F 'LinuxCNC switchkins/remap source map' docs/linuxcnc-switchkins-remap-source-map.md >/dev/null
|
||||
grep -F '| `core/src/linuxcnc_switchkins_remap_table.inc` | 177 | Generated switchkins aliases from LinuxCNC INI/HAL/remap sources. |' docs/linuxcnc-switchkins-remap-source-map.md >/dev/null
|
||||
grep -F '[EMCIO] TOOL_TABLE` entries are source coverage only' docs/linuxcnc-switchkins-remap-source-map.md >/dev/null
|
||||
grep -F './check-linuxcnc-switchkins-remap-source-map.sh' test-linuxcnc-source-link.sh >/dev/null
|
||||
grep -F 'LinuxCNC WASM blockers source map' docs/linuxcnc-wasm-blockers-source-map.md >/dev/null
|
||||
grep -F '| `blocked-replacements` | 9 | Blocked LinuxCNC sources mapped to wasm-safe shim files. |' docs/linuxcnc-wasm-blockers-source-map.md >/dev/null
|
||||
grep -F 'Python/Boost.Python remap paths remain tracked blockers' docs/linuxcnc-wasm-blockers-source-map.md >/dev/null
|
||||
grep -F 'LinuxCNC WASM shims source map' docs/linuxcnc-wasm-shims-source-map.md >/dev/null
|
||||
grep -F '| CMake `linuxcnc_wasm_safe_probe_shims` sources | 11 | Browser-safe LinuxCNC adaptation shims linked into WASM source probes. |' docs/linuxcnc-wasm-shims-source-map.md >/dev/null
|
||||
grep -F 'must not expand the temporary smoke parser' docs/linuxcnc-wasm-shims-source-map.md >/dev/null
|
||||
grep -F 'LinuxCNC WASM smoke source map' docs/linuxcnc-wasm-smoke-source-map.md >/dev/null
|
||||
grep -F 'Node smoke must leave OPFS disabled' docs/linuxcnc-wasm-smoke-source-map.md >/dev/null
|
||||
grep -F 'Generated switchkins config smoke cases must continue to come from' docs/linuxcnc-wasm-smoke-source-map.md >/dev/null
|
||||
grep -F 'LinuxCNC build source map' docs/linuxcnc-build-source-map.md >/dev/null
|
||||
grep -F 'Default WASM manifest partition must remain 26 wasm-safe `core` sources' docs/linuxcnc-build-source-map.md >/dev/null
|
||||
grep -F '`build-wasm.sh` must configure with `CNC_SIM_ENABLE_SMOKE_BACKEND=OFF`' docs/linuxcnc-build-source-map.md >/dev/null
|
||||
grep -F 'LinuxCNC browser app source map' docs/linuxcnc-browser-app-source-map.md >/dev/null
|
||||
grep -F 'The app must persist the current program at `programs/current.ngc`.' docs/linuxcnc-browser-app-source-map.md >/dev/null
|
||||
grep -F 'The visible backend selector must stay limited to the LinuxCNC RS274 backend.' docs/linuxcnc-browser-app-source-map.md >/dev/null
|
||||
grep -F 'LinuxCNC workstreams source map' docs/linuxcnc-workstreams-source-map.md >/dev/null
|
||||
grep -F '| `switchkins/remap` generator and tables | `docs/linuxcnc-switchkins-remap-source-map.md` |' docs/linuxcnc-workstreams-source-map.md >/dev/null
|
||||
grep -F 'Every active workstream must have at least one source-map document and guard' docs/linuxcnc-workstreams-source-map.md >/dev/null
|
||||
grep -F 'docs/linuxcnc-source-policy.md` must keep the same one-context workflow' docs/linuxcnc-workstreams-source-map.md >/dev/null
|
||||
grep -F 'Smoke tests are verification guardrails. They must not be expanded with new' docs/linuxcnc-source-policy.md >/dev/null
|
||||
grep -F 'LinuxCNC tooldata source map' docs/linuxcnc-tooldata-source-map.md >/dev/null
|
||||
grep -F '`src/emc/tooldata/Submakefile` selects `tooldata_mmap.cc`' docs/linuxcnc-tooldata-source-map.md >/dev/null
|
||||
grep -F 'Tool table files referenced by switchkins INI files are source coverage only' docs/linuxcnc-tooldata-source-map.md >/dev/null
|
||||
grep -F 'check-linuxcnc-switchkins-remap-table-cached.sh --cache-dir "$preflight_cache_dir" linuxcnc-kinematics-source-files.txt' test-native.sh >/dev/null
|
||||
grep -F 'check-linuxcnc-switchkins-remap-table-cached.sh --cache-dir "$preflight_cache_dir" linuxcnc-kinematics-source-files.txt' test-linuxcnc-source-link.sh >/dev/null
|
||||
grep -F 'check-linuxcnc-switchkins-remap-table-cached.sh --cache-dir "$preflight_cache_dir" linuxcnc-kinematics-source-files.txt' build-wasm.sh >/dev/null
|
||||
@@ -853,38 +927,98 @@ wasm_manifest_blocked = [
|
||||
for line in Path("linuxcnc-rs274-wasm-source-files.txt").read_text(encoding="utf-8").splitlines()
|
||||
if line.startswith("blocked:")
|
||||
]
|
||||
wasm_manifest_headers = [
|
||||
line.split(":", 2)[1]
|
||||
for line in Path("linuxcnc-rs274-wasm-source-files.txt").read_text(encoding="utf-8").splitlines()
|
||||
if line.startswith("header:")
|
||||
]
|
||||
wasm_manifest_blocked_headers = [
|
||||
line.split(":", 2)[1]
|
||||
for line in Path("linuxcnc-rs274-wasm-source-files.txt").read_text(encoding="utf-8").splitlines()
|
||||
if line.startswith("blocked-header:")
|
||||
]
|
||||
wasm_manifest_metadata = [
|
||||
line.split(":", 2)[1]
|
||||
for line in Path("linuxcnc-rs274-wasm-source-files.txt").read_text(encoding="utf-8").splitlines()
|
||||
if line.startswith("metadata:")
|
||||
]
|
||||
source_map_core = []
|
||||
source_map_bindings = []
|
||||
source_map_wasm_core = []
|
||||
source_map_wasm_blocked = []
|
||||
source_map_wasm_headers = []
|
||||
source_map_wasm_blocked_headers = []
|
||||
source_map_wasm_metadata = []
|
||||
in_core_section = False
|
||||
in_binding_section = False
|
||||
in_wasm_core_section = False
|
||||
in_wasm_blocked_section = False
|
||||
in_wasm_header_section = False
|
||||
in_wasm_blocked_header_section = False
|
||||
in_wasm_metadata_section = False
|
||||
for line in source_map.splitlines():
|
||||
if line == "### Interpreter core":
|
||||
in_core_section = True
|
||||
in_binding_section = False
|
||||
in_wasm_core_section = False
|
||||
in_wasm_blocked_section = False
|
||||
in_wasm_header_section = False
|
||||
in_wasm_blocked_header_section = False
|
||||
in_wasm_metadata_section = False
|
||||
continue
|
||||
if line == "### Python binding modules":
|
||||
in_core_section = False
|
||||
in_binding_section = True
|
||||
in_wasm_core_section = False
|
||||
in_wasm_blocked_section = False
|
||||
in_wasm_header_section = False
|
||||
in_wasm_blocked_header_section = False
|
||||
in_wasm_metadata_section = False
|
||||
continue
|
||||
if line == "### WASM-safe source core":
|
||||
in_core_section = False
|
||||
in_binding_section = False
|
||||
in_wasm_core_section = True
|
||||
in_wasm_blocked_section = False
|
||||
in_wasm_header_section = False
|
||||
in_wasm_blocked_header_section = False
|
||||
in_wasm_metadata_section = False
|
||||
continue
|
||||
if line == "### WASM-blocked sources":
|
||||
in_core_section = False
|
||||
in_binding_section = False
|
||||
in_wasm_core_section = False
|
||||
in_wasm_blocked_section = True
|
||||
in_wasm_header_section = False
|
||||
in_wasm_blocked_header_section = False
|
||||
in_wasm_metadata_section = False
|
||||
continue
|
||||
if line == "### WASM-tracked headers":
|
||||
in_core_section = False
|
||||
in_binding_section = False
|
||||
in_wasm_core_section = False
|
||||
in_wasm_blocked_section = False
|
||||
in_wasm_header_section = True
|
||||
in_wasm_blocked_header_section = False
|
||||
in_wasm_metadata_section = False
|
||||
continue
|
||||
if line == "### WASM-blocked headers":
|
||||
in_core_section = False
|
||||
in_binding_section = False
|
||||
in_wasm_core_section = False
|
||||
in_wasm_blocked_section = False
|
||||
in_wasm_header_section = False
|
||||
in_wasm_blocked_header_section = True
|
||||
in_wasm_metadata_section = False
|
||||
continue
|
||||
if line == "### WASM metadata sources":
|
||||
in_core_section = False
|
||||
in_binding_section = False
|
||||
in_wasm_core_section = False
|
||||
in_wasm_blocked_section = False
|
||||
in_wasm_header_section = False
|
||||
in_wasm_blocked_header_section = False
|
||||
in_wasm_metadata_section = True
|
||||
continue
|
||||
if in_core_section and line.startswith("### "):
|
||||
break
|
||||
@@ -894,6 +1028,12 @@ for line in source_map.splitlines():
|
||||
in_wasm_core_section = False
|
||||
if in_wasm_blocked_section and line.startswith("### "):
|
||||
in_wasm_blocked_section = False
|
||||
if in_wasm_header_section and line.startswith("### "):
|
||||
in_wasm_header_section = False
|
||||
if in_wasm_blocked_header_section and line.startswith("### "):
|
||||
in_wasm_blocked_header_section = False
|
||||
if in_wasm_metadata_section and line.startswith("### "):
|
||||
in_wasm_metadata_section = False
|
||||
if in_core_section and line.startswith("- `"):
|
||||
source_map_core.append(line.split("`", 2)[1])
|
||||
if in_binding_section and line.startswith("- `"):
|
||||
@@ -902,6 +1042,12 @@ for line in source_map.splitlines():
|
||||
source_map_wasm_core.append(line.split("`", 2)[1])
|
||||
if in_wasm_blocked_section and line.startswith("- `"):
|
||||
source_map_wasm_blocked.append(line.split("`", 2)[1])
|
||||
if in_wasm_header_section and line.startswith("- `"):
|
||||
source_map_wasm_headers.append(line.split("`", 2)[1])
|
||||
if in_wasm_blocked_header_section and line.startswith("- `"):
|
||||
source_map_wasm_blocked_headers.append(line.split("`", 2)[1])
|
||||
if in_wasm_metadata_section and line.startswith("- `"):
|
||||
source_map_wasm_metadata.append(line.split("`", 2)[1])
|
||||
if source_map_core != manifest_core:
|
||||
raise SystemExit(
|
||||
"docs/linuxcnc-rs274-source-map.md interpreter core list no longer matches linuxcnc-rs274-source-files.txt core manifest"
|
||||
@@ -918,6 +1064,18 @@ if source_map_wasm_blocked != wasm_manifest_blocked:
|
||||
raise SystemExit(
|
||||
"docs/linuxcnc-rs274-source-map.md WASM-blocked source list no longer matches linuxcnc-rs274-wasm-source-files.txt blocked manifest"
|
||||
)
|
||||
if source_map_wasm_headers != wasm_manifest_headers:
|
||||
raise SystemExit(
|
||||
"docs/linuxcnc-rs274-source-map.md WASM-tracked header list no longer matches linuxcnc-rs274-wasm-source-files.txt header manifest"
|
||||
)
|
||||
if source_map_wasm_blocked_headers != wasm_manifest_blocked_headers:
|
||||
raise SystemExit(
|
||||
"docs/linuxcnc-rs274-source-map.md WASM-blocked header list no longer matches linuxcnc-rs274-wasm-source-files.txt blocked-header manifest"
|
||||
)
|
||||
if source_map_wasm_metadata != wasm_manifest_metadata:
|
||||
raise SystemExit(
|
||||
"docs/linuxcnc-rs274-source-map.md WASM metadata source list no longer matches linuxcnc-rs274-wasm-source-files.txt metadata manifest"
|
||||
)
|
||||
PY
|
||||
|
||||
for script in \
|
||||
@@ -1894,6 +2052,9 @@ if ! grep -F "missing manifest source: src/emc/rs274ngc/does_not_exist.cc" "$mis
|
||||
exit 1
|
||||
fi
|
||||
|
||||
./check-linuxcnc-wasm-blockers-source-map.sh linuxcnc-rs274-wasm-source-files.txt
|
||||
./check-linuxcnc-wasm-shims-source-map.sh linuxcnc-rs274-wasm-source-files.txt
|
||||
|
||||
if [[ "$guardrails_only" == "1" ]]; then
|
||||
echo "all native guardrail checks passed"
|
||||
exit 0
|
||||
|
||||
@@ -42,6 +42,10 @@ flock 9
|
||||
var_file="$build_dir/rs274ngc.var"
|
||||
base_var_file="$build_dir/rs274ngc-base.var"
|
||||
ini_named_parameter_file="$(pwd)/tests/gcode/linuxcnc_ini_named_parameter.ini"
|
||||
disable_g92_persistence_ini_file="$(pwd)/tests/gcode/linuxcnc_disable_g92_persistence.ini"
|
||||
disable_fanuc_style_sub_ini_file="$(pwd)/tests/gcode/linuxcnc_disable_fanuc_style_sub.ini"
|
||||
tight_arc_center_tolerance_ini_file="$(pwd)/tests/gcode/linuxcnc_tight_arc_center_tolerance.ini"
|
||||
g64_default_tolerances_ini_file="$(pwd)/tests/gcode/linuxcnc_g64_default_tolerances.ini"
|
||||
output_dir="$build_dir/outputs"
|
||||
mkdir -p "$output_dir"
|
||||
cp "$linuxcnc_root/tests/halui/jogging/sim.var" "$base_var_file"
|
||||
@@ -495,10 +499,14 @@ for case in "${threading_check_error_cases[@]}"; do
|
||||
grep -Fq "$expected" "$output_dir/cnc_sim_linuxcnc_$fixture.err"
|
||||
done
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/interp_convert.cc
|
||||
# convert_straight() and convert_threading_cycle() reject invalid
|
||||
# spindle state/selector, rotary-axis motion, and G76 I/J/K geometry
|
||||
# before issuing synchronized threading motion.
|
||||
# convert_arc(), convert_straight(), and convert_threading_cycle() reject invalid
|
||||
# feed/spindle state, spindle selectors, rotary-axis motion, and G76 I/J/K
|
||||
# geometry before issuing arc, straight, or synchronized threading motion.
|
||||
threading_convert_error_cases=(
|
||||
"linuxcnc_arc_inverse_time_missing_f_error|F word missing with inverse time arc move"
|
||||
"linuxcnc_g1_zero_feed_error|Cannot do g1 with zero feed rate"
|
||||
"linuxcnc_g1_inverse_time_missing_f_error|F word missing with inverse time g1 move"
|
||||
"linuxcnc_g95_zero_spindle_speed_error|Cannot feed with zero spindle speed in feed per rev mode"
|
||||
"linuxcnc_g33_stopped_spindle_error|Spindle not turning in G33"
|
||||
"linuxcnc_g33_1_stopped_spindle_error|Spindle not turning in G33.1"
|
||||
"linuxcnc_g33_spindle_dollar_out_of_range_error|Invalid spindle (\$) number in G33 move"
|
||||
@@ -521,6 +529,26 @@ for case in "${threading_convert_error_cases[@]}"; do
|
||||
fi
|
||||
grep -Fq "$expected" "$output_dir/cnc_sim_linuxcnc_$fixture.err"
|
||||
done
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/interp_convert.cc convert_probe()
|
||||
# rejects active cutter compensation, zero feed, feed-per-revolution mode, and
|
||||
# degenerate probe moves before issuing STRAIGHT_PROBE().
|
||||
probe_convert_error_cases=(
|
||||
"linuxcnc_probe_cutter_comp_error|Cannot probe with cutter radius comp on"
|
||||
"linuxcnc_probe_zero_feed_error|Cannot probe with zero feed rate"
|
||||
"linuxcnc_probe_feed_per_rev_error|Cannot probe with feed per rev mode"
|
||||
"linuxcnc_probe_start_too_close_error|Start point too close to probe point"
|
||||
)
|
||||
for case in "${probe_convert_error_cases[@]}"; do
|
||||
fixture=${case%%|*}
|
||||
expected=${case#*|}
|
||||
if CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_dump" "tests/gcode/$fixture.ngc" \
|
||||
>"$output_dir/cnc_sim_linuxcnc_$fixture.json" 2>"$output_dir/cnc_sim_linuxcnc_$fixture.err"; then
|
||||
echo "expected $fixture.ngc to fail" >&2
|
||||
exit 1
|
||||
fi
|
||||
grep -Fq "$expected" "$output_dir/cnc_sim_linuxcnc_$fixture.err"
|
||||
done
|
||||
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_threading_sync.ngc >"$output_dir/cnc_sim_linuxcnc_threading_sync.json"
|
||||
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_threading_cycle.ngc >"$output_dir/cnc_sim_linuxcnc_threading_cycle.json"
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/interp_convert.cc
|
||||
@@ -565,6 +593,14 @@ CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linux
|
||||
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_coolant.ngc >"$output_dir/cnc_sim_linuxcnc_coolant.json"
|
||||
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_feed_modes.ngc >"$output_dir/cnc_sim_linuxcnc_feed_modes.json"
|
||||
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_motion_modes.ngc >"$output_dir/cnc_sim_linuxcnc_motion_modes.json"
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/interp_convert.cc
|
||||
# convert_control_mode() sends G64 P through SET_MOTION_CONTROL_MODE()
|
||||
# and G64 Q through SET_NAIVECAM_TOLERANCE(), defaulting Q to P when Q is omitted.
|
||||
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_control_mode_tolerances.ngc >"$output_dir/cnc_sim_linuxcnc_control_mode_tolerances.json"
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/rs274ngc_pre.cc init reads
|
||||
# [RS274NGC] G64_DEFAULT_TOLERANCE/G64_DEFAULT_NAIVETOLERANCE, and
|
||||
# interp_convert.cc convert_control_mode() uses them when G64 omits P/Q.
|
||||
INI_FILE_NAME="$g64_default_tolerances_ini_file" CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_g64_default_tolerances.ngc >"$output_dir/cnc_sim_linuxcnc_g64_default_tolerances.json"
|
||||
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_tool_length.ngc >"$output_dir/cnc_sim_linuxcnc_tool_length.json"
|
||||
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_dynamic_tool_length.ngc >"$output_dir/cnc_sim_linuxcnc_dynamic_tool_length.json"
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/interp_convert.cc
|
||||
@@ -591,9 +627,11 @@ done
|
||||
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_canned_cycle.ngc >"$output_dir/cnc_sim_linuxcnc_canned_cycle.json"
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/interp_cycles.cc
|
||||
# convert_cycle() and the G73/G74/G82-G89 helpers validate canned-cycle
|
||||
# repeat counts, plane-specific axis/R words, Q/P requirements, and spindle
|
||||
# state before expanding cycles to Canon motion.
|
||||
# feed mode, repeat counts, plane-specific axis/R words, Q/P requirements,
|
||||
# and spindle state before expanding cycles to Canon motion.
|
||||
canned_cycle_error_cases=(
|
||||
"linuxcnc_canned_cycle_inverse_time_error|Cannot use inverse time feed with canned cycles"
|
||||
"linuxcnc_canned_cycle_cutter_comp_error|Cannot use canned cycles with cutter compensation on"
|
||||
"linuxcnc_canned_cycle_l0_error|Cannot do zero repeats of cycle"
|
||||
"linuxcnc_canned_cycle_missing_r_error|R clearance plane unspecified in cycle"
|
||||
"linuxcnc_canned_cycle_missing_z_error|Z value unspecified in xy plane canned cycle"
|
||||
@@ -656,6 +694,15 @@ CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linux
|
||||
# passes unit-specific center-arc tolerance to src/emc/rs274ngc/interp_arc.cc
|
||||
# arc_data_ijk(), which rejects excessive start/end radius mismatch.
|
||||
CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_arc_center_tolerance_good_imperial.ngc >"$output_dir/cnc_sim_linuxcnc_arc_center_tolerance_good_imperial.json"
|
||||
CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_arc_center_tolerance_tight_metric.ngc >"$output_dir/cnc_sim_linuxcnc_arc_center_tolerance_tight_metric_default.json"
|
||||
if INI_FILE_NAME="$tight_arc_center_tolerance_ini_file" CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_arc_center_tolerance_tight_metric.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_arc_center_tolerance_tight_metric_ini.json" 2>"$output_dir/cnc_sim_linuxcnc_arc_center_tolerance_tight_metric_ini.err"; then
|
||||
echo "expected linuxcnc_arc_center_tolerance_tight_metric.ngc to fail with tight INI tolerance" >&2
|
||||
exit 1
|
||||
fi
|
||||
grep -Fq "Radius to end of arc differs from radius to start" \
|
||||
"$output_dir/cnc_sim_linuxcnc_arc_center_tolerance_tight_metric_ini.err"
|
||||
if CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_arc_center_tolerance_bad_metric.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_arc_center_tolerance_bad_metric.json" 2>"$output_dir/cnc_sim_linuxcnc_arc_center_tolerance_bad_metric.err"; then
|
||||
@@ -716,11 +763,19 @@ CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linux
|
||||
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_machine_coordinates.ngc >"$output_dir/cnc_sim_linuxcnc_machine_coordinates.json"
|
||||
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_cutter_comp.ngc >"$output_dir/cnc_sim_linuxcnc_cutter_comp.json"
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/interp_convert.cc rejects
|
||||
# M6, M66, G71.0, and G98/G99 while cutter compensation is active;
|
||||
# compensated corner and G40 exit checks also reject gouging/arc exits.
|
||||
# G28/G30, G52/G92, G53, G54-G59.3, G61/G64, G17/G18/G19, M6, M66, G43,
|
||||
# G71.0, and G98/G99 while cutter compensation is active; compensated corner
|
||||
# and G40 exit checks also reject gouging/arc exits.
|
||||
cutter_comp_execution_error_cases=(
|
||||
"linuxcnc_cutter_comp_axis_offset_error|Cannot change axis offsets with cutter radius comp"
|
||||
"linuxcnc_cutter_comp_control_mode_error|Cannot change control mode with cutter radius compensation on"
|
||||
"linuxcnc_cutter_comp_coordinate_system_error|Cannot change coordinate systems with cutter radius compensation on"
|
||||
"linuxcnc_cutter_comp_g53_error|Cannot use g53 with cutter radius comp"
|
||||
"linuxcnc_cutter_comp_home_error|Cannot use g28 or g30 with cutter radius comp"
|
||||
"linuxcnc_cutter_comp_plane_change_error|Cannot change planes with cutter radius compensation on"
|
||||
"linuxcnc_cutter_comp_tool_change_error|Cannot change tools with cutter radius compensation on"
|
||||
"linuxcnc_cutter_comp_wait_input_error|Cannot wait for digital input with cutter radius compensation on"
|
||||
"linuxcnc_cutter_comp_tool_offset_error|Cannot change tool offset with cutter radius compensation on"
|
||||
"linuxcnc_cutter_comp_g71_error|G71.0 cannot be used with cutter compensation enabled"
|
||||
"linuxcnc_canned_cycle_g98_retract_error|Cannot change retract mode with cutter radius compensation on"
|
||||
"linuxcnc_ccomp_arcexit_error|The move just after exiting cutter compensation mode must be straight, not an arc"
|
||||
@@ -784,6 +839,25 @@ for case in "${oword_reader_error_cases[@]}"; do
|
||||
fi
|
||||
grep -Fq "$expected" "$output_dir/cnc_sim_linuxcnc_$fixture.err"
|
||||
done
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/rs274ngc_pre.cc init reads
|
||||
# [RS274NGC] DISABLE_FANUC_STYLE_SUB, and interp_read.cc rejects
|
||||
# Fanuc-style M98/M99 and bare O-word subroutine forms when enabled.
|
||||
disable_fanuc_style_error_cases=(
|
||||
"linuxcnc_disable_fanuc_style_m98_error|DISABLE_FANUC_STYLE_SUB set in INI file, but found m98"
|
||||
"linuxcnc_disable_fanuc_style_m99_error|DISABLE_FANUC_STYLE_SUB set in INI file, but found m99"
|
||||
"linuxcnc_disable_fanuc_style_bare_oword_error|DISABLE_FANUC_STYLE_SUB disabled in INI file, but found bare O-word"
|
||||
)
|
||||
for case in "${disable_fanuc_style_error_cases[@]}"; do
|
||||
fixture=${case%%|*}
|
||||
expected=${case#*|}
|
||||
if INI_FILE_NAME="$disable_fanuc_style_sub_ini_file" CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_dump" "tests/gcode/$fixture.ngc" \
|
||||
>"$output_dir/cnc_sim_linuxcnc_$fixture.json" 2>"$output_dir/cnc_sim_linuxcnc_$fixture.err"; then
|
||||
echo "expected $fixture.ngc to fail" >&2
|
||||
exit 1
|
||||
fi
|
||||
grep -Fq "$expected" "$output_dir/cnc_sim_linuxcnc_$fixture.err"
|
||||
done
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/interp_o_word.cc
|
||||
# convert_control_functions() rejects unmatched, duplicate, and
|
||||
# out-of-context O-word control labels during execution. control_save_offset()
|
||||
@@ -841,9 +915,11 @@ INI_FILE_NAME="$ini_named_parameter_file" CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS27
|
||||
# and close_and_downcase() accept whitespace around bracketed word values.
|
||||
CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_word_bracket_whitespace.ngc >"$output_dir/cnc_sim_linuxcnc_word_bracket_whitespace.json"
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/interp_namedparams.cc lookup_named_param()
|
||||
# and init_readonly_param() expose modal/unit/feed/spindle readonly parameters.
|
||||
# and init_readonly_param() expose modal/unit/feed/spindle readonly parameters
|
||||
# plus current-position #<_x> through #<_w> aliases.
|
||||
CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_readonly_named_parameters.ngc >"$output_dir/cnc_sim_linuxcnc_readonly_named_parameters.json"
|
||||
CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_readonly_named_parameters_extra.ngc >"$output_dir/cnc_sim_linuxcnc_readonly_named_parameters_extra.json"
|
||||
CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_readonly_named_current_position.ngc >"$output_dir/cnc_sim_linuxcnc_readonly_named_current_position.json"
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/interp_array.cc defines
|
||||
# required/readonly numbered parameters; interp_internal.cc set_probe_data()
|
||||
# and interp_convert.cc update probe, tool, G28/G30, G92, G5X, and current
|
||||
@@ -884,6 +960,17 @@ cp "$base_var_file" "$var_file"
|
||||
# save_parameters() writes required and changed persistent ranges.
|
||||
CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_persistent_parameters_set.ngc >"$output_dir/cnc_sim_linuxcnc_persistent_parameters_set.json"
|
||||
CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_persistent_parameters_check.ngc >"$output_dir/cnc_sim_linuxcnc_persistent_parameters_check.json"
|
||||
disable_g92_startup_var_file="$build_dir/rs274ngc-disable-g92-startup.var"
|
||||
printf '5210\t1.000000\n5211\t-4.000000\n5212\t-5.000000\n5213\t-6.000000\n5220\t1.000000\n' > "$disable_g92_startup_var_file"
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/rs274ngc_pre.cc init reads
|
||||
# [RS274NGC] DISABLE_G92_PERSISTENCE and clears restored #5210-#5219.
|
||||
INI_FILE_NAME="$disable_g92_persistence_ini_file" CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$disable_g92_startup_var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_g92_disable_persistence_startup.ngc >"$output_dir/cnc_sim_linuxcnc_g92_disable_persistence_startup.json"
|
||||
disable_g92_stop_var_file="$build_dir/rs274ngc-disable-g92-stop.var"
|
||||
: > "$disable_g92_stop_var_file"
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/interp_convert.cc convert_stop()
|
||||
# clears #5210-#5219 on M2/M30 when DISABLE_G92_PERSISTENCE is enabled.
|
||||
INI_FILE_NAME="$disable_g92_persistence_ini_file" CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$disable_g92_stop_var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_g92_disable_persistence_set.ngc >"$output_dir/cnc_sim_linuxcnc_g92_disable_persistence_set.json"
|
||||
CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$disable_g92_stop_var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_g92_disable_persistence_check.ngc >"$output_dir/cnc_sim_linuxcnc_g92_disable_persistence_check.json"
|
||||
rotary_persistent_var_file="$build_dir/rs274ngc-rotary-persistent.var"
|
||||
: > "$rotary_persistent_var_file"
|
||||
CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$rotary_persistent_var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_rotary_persistent_parameters_set.ngc >"$output_dir/cnc_sim_linuxcnc_rotary_persistent_parameters_set.json"
|
||||
@@ -1036,6 +1123,7 @@ nurbs_error_cases=(
|
||||
"linuxcnc_g52_missing_subsequent_weight_error|Must specify positive weight P for every Control Point"
|
||||
"linuxcnc_g52_noninteger_l_error|Non integer value for integer"
|
||||
"linuxcnc_g52_zero_feed_error|Cannot make a NURBS with 0 feedrate"
|
||||
"linuxcnc_g53_non_g52_motion_error|Between G5.2 and G5.3 codes, only additional G5.2 codes are allowed."
|
||||
"linuxcnc_g53_without_g52_error|Cannot use G5.3 without G5.2 first"
|
||||
"linuxcnc_g53_short_control_points_error|You must specify a number of control points at least equal to the order L = 3"
|
||||
"linuxcnc_g53_after_intervening_motion_error|Cannot use G5.3 without G5.2 first"
|
||||
@@ -1058,6 +1146,9 @@ for case in "${nurbs_error_cases[@]}"; do
|
||||
fi
|
||||
grep -Fq "$expected" "$output_dir/cnc_sim_linuxcnc_$fixture.err"
|
||||
done
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/interp_convert.cc convert_setup()
|
||||
# stores G10 L2 U/V/W through PROGRAM_TO_USER_LEN, and
|
||||
# convert_coordinate_system() emits them through SET_G5X_OFFSET.
|
||||
cp "$base_var_file" "$var_file"
|
||||
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_coordinate_offsets.ngc >"$output_dir/cnc_sim_linuxcnc_coordinate_offsets.json"
|
||||
cp "$base_var_file" "$var_file"
|
||||
@@ -1088,6 +1179,14 @@ CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linux
|
||||
# src/emc/rs274ngc/interp_read.cc returns INTERP_ENDFILE at the matching '%',
|
||||
# so later lines are ignored.
|
||||
CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_percent_file_ignores_trailing.ngc >"$output_dir/cnc_sim_linuxcnc_percent_file_ignores_trailing.json"
|
||||
# Source basis: LinuxCNC unit_tests/interp/test_interp_basics.cc Convert G20 / G21
|
||||
# asserts that unit changes rescale current linear axes and work/G92 linear
|
||||
# offsets while rotary axes remain angular values.
|
||||
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_units_current_position.ngc >"$output_dir/cnc_sim_linuxcnc_units_current_position.json"
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/interp_convert.cc convert_axis_offsets()
|
||||
# stores G92 offsets through PROGRAM_TO_USER_LEN and restores them through
|
||||
# USER_TO_PROGRAM_LEN after convert_length_units() changes active program units.
|
||||
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_units_g92_restore.ngc >"$output_dir/cnc_sim_linuxcnc_units_g92_restore.json"
|
||||
CNC_SIM_RS274_NATIVE_OUTPUT_DIR="$output_dir" python3 - <<'PY'
|
||||
import json
|
||||
import os
|
||||
@@ -1113,6 +1212,56 @@ required_motion = {"set-units", "set-plane", "set-spindle", "rapid", "set-feed",
|
||||
check(OUTPUT_DIR / "cnc_sim_linuxcnc_basic_motion.json", required_motion)
|
||||
check(OUTPUT_DIR / "cnc_sim_linuxcnc_basic_mill.json", required_motion | {"tool-change"})
|
||||
|
||||
units_current_position = load("cnc_sim_linuxcnc_units_current_position.json")
|
||||
units_rapid = [
|
||||
event
|
||||
for event in units_current_position
|
||||
if event["type"] == "rapid"
|
||||
]
|
||||
if len(units_rapid) != 3:
|
||||
raise SystemExit(f"unexpected unit-current-position rapid count: {len(units_rapid)}")
|
||||
if units_rapid[1]["start"] != units_rapid[1]["end"]:
|
||||
raise SystemExit(
|
||||
"LinuxCNC G21 current-position rescale was not reflected before the metric no-op rapid: "
|
||||
f"{units_rapid[1]!r}"
|
||||
)
|
||||
if units_rapid[2]["start"] != units_rapid[2]["end"]:
|
||||
raise SystemExit(
|
||||
"LinuxCNC G20 current-position rescale was not reflected before the inch no-op rapid: "
|
||||
f"{units_rapid[2]!r}"
|
||||
)
|
||||
if (units_rapid[1]["end"]["a"], units_rapid[1]["end"]["b"], units_rapid[1]["end"]["c"]) != (4, 5, 6):
|
||||
raise SystemExit("LinuxCNC G21 unit change unexpectedly scaled rotary axes")
|
||||
if (units_rapid[1]["end"]["u"], units_rapid[1]["end"]["v"], units_rapid[1]["end"]["w"]) != (177.8, 203.2, 228.6):
|
||||
raise SystemExit("LinuxCNC G21 unit change did not scale U/V/W linear axes")
|
||||
if (units_rapid[2]["end"]["u"], units_rapid[2]["end"]["v"], units_rapid[2]["end"]["w"]) != (7, 8, 9):
|
||||
raise SystemExit("LinuxCNC G20 unit change did not restore U/V/W linear axes")
|
||||
|
||||
units_g92_restore = load("cnc_sim_linuxcnc_units_g92_restore.json")
|
||||
units_g92_states = [
|
||||
(
|
||||
event["line"],
|
||||
event["start"]["x"],
|
||||
event["start"]["y"],
|
||||
event["start"]["z"],
|
||||
event["start"]["a"],
|
||||
event["start"]["b"],
|
||||
event["start"]["c"],
|
||||
event["start"]["u"],
|
||||
event["start"]["v"],
|
||||
event["start"]["w"],
|
||||
)
|
||||
for event in units_g92_restore
|
||||
if event["type"] == "set-g92-offset" and event["line"] > 0
|
||||
]
|
||||
expected_units_g92_states = [
|
||||
(3, -1, -2, -3, -4, -5, -6, -7, -8, -9),
|
||||
(5, 0, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
(6, -25.4, -50.8, -76.2, -4, -5, -6, -177.8, -203.2, -228.6),
|
||||
]
|
||||
if units_g92_states != expected_units_g92_states:
|
||||
raise SystemExit(f"unexpected LinuxCNC G20/G21 G92 restore states: {units_g92_states!r}")
|
||||
|
||||
fractional_linenumbers = load("cnc_sim_linuxcnc_fractional_linenumbers.json")
|
||||
fractional_spindle_states = [
|
||||
(event["line"], event["spindle"])
|
||||
@@ -1518,6 +1667,36 @@ for expected in [(2, 611, 0), (3, 612, 0), (4, 640, 0.05)]:
|
||||
if expected not in motion_mode_states:
|
||||
raise SystemExit(f"missing motion mode state {expected!r}")
|
||||
|
||||
control_mode_tolerances = load("cnc_sim_linuxcnc_control_mode_tolerances.json")
|
||||
control_mode_tolerance_states = [
|
||||
(event["line"], event["reserved"], event["feed"])
|
||||
for event in control_mode_tolerances
|
||||
if event["type"] == "comment" and event["reserved"] in {611, 612, 640, 641}
|
||||
]
|
||||
expected_control_mode_tolerance_states = [
|
||||
(2, 640, 0.05),
|
||||
(2, 641, 0.02),
|
||||
(3, 640, 0.03),
|
||||
(3, 641, 0.03),
|
||||
(4, 611, 0),
|
||||
(5, 612, 0),
|
||||
]
|
||||
if control_mode_tolerance_states != expected_control_mode_tolerance_states:
|
||||
raise SystemExit(f"unexpected G64 P/Q control mode tolerance states: {control_mode_tolerance_states!r}")
|
||||
|
||||
g64_default_tolerances = load("cnc_sim_linuxcnc_g64_default_tolerances.json")
|
||||
g64_default_tolerance_states = [
|
||||
(event["line"], event["reserved"], event["feed"])
|
||||
for event in g64_default_tolerances
|
||||
if event["type"] == "comment" and event["reserved"] in {640, 641}
|
||||
]
|
||||
expected_g64_default_tolerance_states = [
|
||||
(3, 640, 0.07),
|
||||
(3, 641, 0.04),
|
||||
]
|
||||
if g64_default_tolerance_states != expected_g64_default_tolerance_states:
|
||||
raise SystemExit(f"unexpected INI-backed G64 default tolerance states: {g64_default_tolerance_states!r}")
|
||||
|
||||
tool_length = load("cnc_sim_linuxcnc_tool_length.json")
|
||||
if not any(
|
||||
event["type"] == "comment" and
|
||||
@@ -1965,6 +2144,15 @@ if not any(
|
||||
):
|
||||
raise SystemExit("missing LinuxCNC small imperial center-format arc within tolerance")
|
||||
|
||||
arc_center_tolerance_tight_metric_default = load("cnc_sim_linuxcnc_arc_center_tolerance_tight_metric_default.json")
|
||||
if not any(
|
||||
event["type"] == "arc-feed" and
|
||||
event["line"] == 5 and
|
||||
event["end"]["x"] == 2
|
||||
for event in arc_center_tolerance_tight_metric_default
|
||||
):
|
||||
raise SystemExit("missing LinuxCNC metric center-format arc under default tolerance")
|
||||
|
||||
incremental_r_arc = load("cnc_sim_linuxcnc_incremental_and_r_arc.json")
|
||||
if not any(
|
||||
event["type"] == "linear-feed" and
|
||||
@@ -2437,6 +2625,23 @@ expected_readonly_moves = [
|
||||
if readonly_moves != expected_readonly_moves:
|
||||
raise SystemExit(f"unexpected LinuxCNC readonly named parameter motions: {readonly_moves!r}")
|
||||
|
||||
readonly_current = load("cnc_sim_linuxcnc_readonly_named_current_position.json")
|
||||
if not any(
|
||||
event["type"] == "linear-feed" and
|
||||
event["line"] == 6 and
|
||||
event["end"]["x"] == 10 and
|
||||
event["end"]["y"] == 2 and
|
||||
event["end"]["z"] == 3 and
|
||||
event["end"]["a"] == 4 and
|
||||
event["end"]["b"] == 5 and
|
||||
event["end"]["c"] == 6 and
|
||||
event["end"]["u"] == 7 and
|
||||
event["end"]["v"] == 8 and
|
||||
event["end"]["w"] == 9
|
||||
for event in readonly_current
|
||||
):
|
||||
raise SystemExit("missing LinuxCNC readonly named current-position branch motion")
|
||||
|
||||
numbered_parameters = load("cnc_sim_linuxcnc_numbered_parameters.json")
|
||||
if not any(
|
||||
event["type"] == "linear-feed" and
|
||||
@@ -2681,6 +2886,23 @@ if not any(
|
||||
):
|
||||
raise SystemExit("missing LinuxCNC persistent parameter reload branch motion")
|
||||
|
||||
disable_g92_startup = load("cnc_sim_linuxcnc_g92_disable_persistence_startup.json")
|
||||
if not any(
|
||||
event["type"] == "linear-feed" and
|
||||
event["line"] == 5 and
|
||||
event["end"]["x"] == 2
|
||||
for event in disable_g92_startup
|
||||
):
|
||||
raise SystemExit("missing LinuxCNC DISABLE_G92_PERSISTENCE startup clear branch motion")
|
||||
disable_g92_check = load("cnc_sim_linuxcnc_g92_disable_persistence_check.json")
|
||||
if not any(
|
||||
event["type"] == "linear-feed" and
|
||||
event["line"] == 5 and
|
||||
event["end"]["x"] == 1
|
||||
for event in disable_g92_check
|
||||
):
|
||||
raise SystemExit("missing LinuxCNC DISABLE_G92_PERSISTENCE program-end clear branch motion")
|
||||
|
||||
rotary_persistent_parameters_check = load("cnc_sim_linuxcnc_rotary_persistent_parameters_check.json")
|
||||
if not any(
|
||||
event["type"] == "linear-feed" and
|
||||
@@ -2744,7 +2966,10 @@ if not any(
|
||||
event["tool"] == 1 and
|
||||
event["start"]["x"] == 12.5 and
|
||||
event["start"]["y"] == -3 and
|
||||
event["start"]["z"] == 4
|
||||
event["start"]["z"] == 4 and
|
||||
event["start"]["u"] == 7 and
|
||||
event["start"]["v"] == 8 and
|
||||
event["start"]["w"] == 9
|
||||
for event in g5x
|
||||
):
|
||||
raise SystemExit("missing G10 L2 G5X offset event")
|
||||
@@ -2764,29 +2989,35 @@ if not any(event["type"] == "program-end" and event["line"] == 5 for event in co
|
||||
l20 = load("cnc_sim_linuxcnc_coordinate_l20.json")
|
||||
if not any(
|
||||
event["type"] == "set-g5x-offset" and
|
||||
event["line"] == 4 and
|
||||
event["line"] == 5 and
|
||||
event["tool"] == 2 and
|
||||
event["start"]["x"] == 4 and
|
||||
event["start"]["y"] == 4 and
|
||||
event["start"]["z"] == 4
|
||||
event["start"]["z"] == 4 and
|
||||
event["start"]["u"] == 4 and
|
||||
event["start"]["v"] == 4 and
|
||||
event["start"]["w"] == 4
|
||||
for event in l20
|
||||
):
|
||||
raise SystemExit("missing G10 L20 P2 offset event after G55 selection")
|
||||
if not any(event["type"] == "program-end" and event["line"] == 5 for event in l20):
|
||||
if not any(event["type"] == "program-end" and event["line"] == 6 for event in l20):
|
||||
raise SystemExit("missing G10 L20 program end line number")
|
||||
|
||||
p0 = load("cnc_sim_linuxcnc_coordinate_p0.json")
|
||||
if not any(
|
||||
event["type"] == "set-g5x-offset" and
|
||||
event["line"] == 3 and
|
||||
event["line"] == 4 and
|
||||
event["tool"] == 2 and
|
||||
event["start"]["x"] == 7 and
|
||||
event["start"]["y"] == 8 and
|
||||
event["start"]["z"] == 9
|
||||
event["start"]["z"] == 9 and
|
||||
event["start"]["u"] == 10 and
|
||||
event["start"]["v"] == 11 and
|
||||
event["start"]["w"] == 12
|
||||
for event in p0
|
||||
):
|
||||
raise SystemExit("missing G10 L2 P0 active G55 offset event")
|
||||
if not any(event["type"] == "program-end" and event["line"] == 4 for event in p0):
|
||||
if not any(event["type"] == "program-end" and event["line"] == 5 for event in p0):
|
||||
raise SystemExit("missing G10 P0 program end line number")
|
||||
|
||||
select_all = load("cnc_sim_linuxcnc_coordinate_select_all.json")
|
||||
@@ -2829,20 +3060,28 @@ if not any(event["type"] == "program-end" and event["line"] == 7 for event in g9
|
||||
|
||||
g52_offset = load("cnc_sim_linuxcnc_g52_offset.json")
|
||||
g52_states = [
|
||||
(event["line"], event["start"]["x"], event["start"]["y"], event["start"]["z"])
|
||||
(
|
||||
event["line"],
|
||||
event["start"]["x"],
|
||||
event["start"]["y"],
|
||||
event["start"]["z"],
|
||||
event["start"]["u"],
|
||||
event["start"]["v"],
|
||||
event["start"]["w"],
|
||||
)
|
||||
for event in g52_offset
|
||||
if event["type"] == "set-g92-offset" and event["line"] > 0
|
||||
]
|
||||
expected_g52_states = [
|
||||
(2, 1, 2, 0),
|
||||
(3, 1, 3, 0),
|
||||
(4, 0, 0, 0),
|
||||
(5, 1, 3, 0),
|
||||
(6, 0, 0, 0),
|
||||
(3, 1, 2, 0, 4, 5, 0),
|
||||
(4, 1, 3, 0, 4, 6, 0),
|
||||
(5, 0, 0, 0, 0, 0, 0),
|
||||
(6, 1, 3, 0, 4, 6, 0),
|
||||
(7, 0, 0, 0, 0, 0, 0),
|
||||
]
|
||||
if g52_states != expected_g52_states:
|
||||
raise SystemExit(f"unexpected G52 shared offset sequence: {g52_states!r}")
|
||||
if not any(event["type"] == "program-end" and event["line"] == 7 for event in g52_offset):
|
||||
if not any(event["type"] == "program-end" and event["line"] == 8 for event in g52_offset):
|
||||
raise SystemExit("missing G52 offset program end line number")
|
||||
|
||||
g52_xz_nurbs = load("cnc_sim_linuxcnc_g52_xz_nurbs.json")
|
||||
@@ -2896,6 +3135,7 @@ echo "dumped $output_dir/cnc_sim_linuxcnc_program_end_m99.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_coolant.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_feed_modes.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_motion_modes.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_g64_default_tolerances.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_tool_length.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_dynamic_tool_length.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_canned_cycle.json"
|
||||
@@ -2905,6 +3145,10 @@ echo "dumped $output_dir/cnc_sim_linuxcnc_extended_plane_cycle.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_arc_planes.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_arc_distance_modes.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_arc_center_tolerance_good_imperial.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_arc_center_tolerance_tight_metric_default.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_arc_center_tolerance_tight_metric_ini.err"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_units_current_position.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_units_g92_restore.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_predefined_positions.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_machine_coordinates.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_cutter_comp.json"
|
||||
@@ -2926,6 +3170,7 @@ echo "dumped $output_dir/cnc_sim_linuxcnc_named_parameter_normalization.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_ini_named_parameter.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_readonly_named_parameters.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_readonly_named_parameters_extra.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_readonly_named_current_position.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_numbered_parameters.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_rotary_probe_numbered_parameters.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_multi_rotary_probe_numbered_parameters.json"
|
||||
@@ -2948,6 +3193,9 @@ echo "dumped $output_dir/cnc_sim_linuxcnc_rotary_tool_offset_numbered_parameters
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_current_position_numbered_parameters.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_persistent_parameters_set.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_persistent_parameters_check.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_g92_disable_persistence_startup.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_g92_disable_persistence_set.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_g92_disable_persistence_check.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_rotary_persistent_parameters_set.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_rotary_persistent_parameters_check.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_g54_persistent_parameters_set.json"
|
||||
|
||||
@@ -36,6 +36,19 @@ fi
|
||||
preflight_cache_dir="$build_dir/preflight-cache"
|
||||
LINUXCNC_ROOT="$linuxcnc_root" ./check-linuxcnc-inputs-cached.sh --cache-dir "$preflight_cache_dir" "$manifest"
|
||||
|
||||
./check-linuxcnc-rs274-source-map.sh
|
||||
./check-linuxcnc-kinematics-source-map.sh
|
||||
./check-linuxcnc-opfs-source-map.sh
|
||||
./check-linuxcnc-switchkins-remap-source-map.sh
|
||||
./check-linuxcnc-wasm-smoke-source-map.sh
|
||||
./check-linuxcnc-build-source-map.sh
|
||||
./check-linuxcnc-browser-app-source-map.sh
|
||||
./check-linuxcnc-workstreams-source-map.sh
|
||||
./check-linuxcnc-tooldata-source-map.sh
|
||||
./check-linuxcnc-wasm-shims-source-map.sh
|
||||
./check-linuxcnc-wasm-blockers-source-map.sh
|
||||
CNC_SIM_PREFLIGHT_CACHE_DIR="$preflight_cache_dir" CNC_SIM_WASM_BLOCKERS_SELF_CHECKS=1 \
|
||||
./test-linuxcnc-wasm-blockers.sh linuxcnc-rs274-wasm-source-files.txt
|
||||
LINUXCNC_ROOT="$linuxcnc_root" ./check-linuxcnc-switchkins-remap-table-cached.sh --cache-dir "$preflight_cache_dir" linuxcnc-kinematics-source-files.txt
|
||||
# The LinuxCNC source-linked dump path is not concurrency-safe under parallel execution.
|
||||
exec 9>"${TMPDIR:-/tmp}/cnc_sim_rs274_source_link.lock"
|
||||
@@ -162,6 +175,13 @@ make --output-sync=target -j"$build_jobs" -f "$source_link_makefile"
|
||||
var_file="$build_dir/rs274ngc-source.var"
|
||||
base_var_file="$build_dir/rs274ngc-source-base.var"
|
||||
ini_named_parameter_file="$(pwd)/tests/gcode/linuxcnc_ini_named_parameter.ini"
|
||||
disable_g92_persistence_ini_file="$(pwd)/tests/gcode/linuxcnc_disable_g92_persistence.ini"
|
||||
disable_fanuc_style_sub_ini_file="$(pwd)/tests/gcode/linuxcnc_disable_fanuc_style_sub.ini"
|
||||
tight_arc_center_tolerance_ini_file="$(pwd)/tests/gcode/linuxcnc_tight_arc_center_tolerance.ini"
|
||||
g64_default_tolerances_ini_file="$(pwd)/tests/gcode/linuxcnc_g64_default_tolerances.ini"
|
||||
multi_spindle_modes_file="$(pwd)/tests/gcode/linuxcnc_multi_spindle_modes.ini"
|
||||
multi_spindle_override_file="$(pwd)/tests/gcode/linuxcnc_multi_spindle_override.ini"
|
||||
multi_spindle_threading_file="$(pwd)/tests/gcode/linuxcnc_multi_spindle_threading.ini"
|
||||
output_dir="$build_dir/outputs"
|
||||
mkdir -p "$output_dir"
|
||||
cp "$linuxcnc_root/tests/halui/jogging/sim.var" "$base_var_file"
|
||||
@@ -196,12 +216,50 @@ CNC_SIM_RS274_VAR="$var_file" \
|
||||
CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_spindle_direction.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_spindle_direction.json"
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/rs274ngc_pre.cc init reads
|
||||
# [TRAJ] SPINDLES from INI_FILE_NAME, interp_execute.cc passes S-word $
|
||||
# through convert_speed(), and interp_convert.cc routes M3/M4/M5 with a $
|
||||
# selector to the selected spindle.
|
||||
INI_FILE_NAME="$multi_spindle_modes_file" CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_multi_spindle_direction.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_multi_spindle_direction.json"
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/rs274ngc_pre.cc init reads
|
||||
# [TRAJ] SPINDLES from INI_FILE_NAME, interp_execute.cc expands S-word $-1
|
||||
# over all configured spindles, and interp_convert.cc expands M3/M4/M5 $-1
|
||||
# over all configured spindles.
|
||||
INI_FILE_NAME="$multi_spindle_modes_file" CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_multi_spindle_all_direction.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_multi_spindle_all_direction.json"
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/rs274ngc_pre.cc init reads
|
||||
# [TRAJ] SPINDLES from INI_FILE_NAME, and interp_convert.cc M3/M4 without a $
|
||||
# selector start only the default spindle.
|
||||
INI_FILE_NAME="$multi_spindle_modes_file" CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_multi_spindle_default_start.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_multi_spindle_default_start.json"
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/rs274ngc_pre.cc init reads
|
||||
# [TRAJ] SPINDLES from INI_FILE_NAME, and interp_convert.cc M5 without a $
|
||||
# selector stops every configured spindle.
|
||||
INI_FILE_NAME="$multi_spindle_modes_file" CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_multi_spindle_default_stop.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_multi_spindle_default_stop.json"
|
||||
CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_spindle_modes.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_spindle_modes.json"
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/rs274ngc_pre.cc init reads
|
||||
# [TRAJ] SPINDLES from INI_FILE_NAME, and interp_execute.cc assigns
|
||||
# active_spindle from $ before G95/G96/G97 conversion.
|
||||
INI_FILE_NAME="$multi_spindle_modes_file" CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_multi_spindle_modes.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_multi_spindle_modes.json"
|
||||
CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_spindle_orient.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_spindle_orient.json"
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/rs274ngc_pre.cc init reads
|
||||
# [TRAJ] SPINDLES from INI_FILE_NAME, and interp_convert.cc routes M19 with a
|
||||
# $ selector to the selected spindle for orient and wait Canon calls.
|
||||
INI_FILE_NAME="$multi_spindle_modes_file" CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_multi_spindle_orient.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_multi_spindle_orient.json"
|
||||
CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_io_controls.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_io_controls.json"
|
||||
@@ -246,6 +304,18 @@ done
|
||||
CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_override_controls.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_override_controls.json"
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/rs274ngc_pre.cc init reads
|
||||
# [TRAJ] SPINDLES from INI_FILE_NAME, and interp_convert.cc M51 applies
|
||||
# speed override changes only to the selected $ spindle when present.
|
||||
INI_FILE_NAME="$multi_spindle_override_file" CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_multi_spindle_override.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_multi_spindle_override.json"
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/rs274ngc_pre.cc init reads
|
||||
# [TRAJ] SPINDLES from INI_FILE_NAME, and interp_convert.cc M51 without a $
|
||||
# selector applies speed override changes to every configured spindle.
|
||||
INI_FILE_NAME="$multi_spindle_override_file" CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_multi_spindle_override_all.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_multi_spindle_override_all.json"
|
||||
CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_modal_state.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_modal_state.json"
|
||||
@@ -261,6 +331,18 @@ fi
|
||||
CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_threading_sync.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_threading_sync.json"
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/rs274ngc_pre.cc init reads
|
||||
# [TRAJ] SPINDLES from INI_FILE_NAME, and interp_convert.cc G33/G33.1
|
||||
# assign active_spindle from the $ selector before START_SPEED_FEED_SYNCH().
|
||||
INI_FILE_NAME="$multi_spindle_threading_file" CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_multi_spindle_threading.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_multi_spindle_threading.json"
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/rs274ngc_pre.cc init reads
|
||||
# [TRAJ] SPINDLES from INI_FILE_NAME, and interp_convert.cc assigns
|
||||
# active_spindle from the G76 $ selector before convert_threading_cycle().
|
||||
INI_FILE_NAME="$multi_spindle_threading_file" CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_multi_spindle_g76.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_multi_spindle_g76.json"
|
||||
CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_threading_cycle.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_threading_cycle.json"
|
||||
@@ -325,6 +407,18 @@ CNC_SIM_RS274_VAR="$var_file" \
|
||||
CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_motion_modes.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_motion_modes.json"
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/interp_convert.cc
|
||||
# convert_control_mode() sends G64 P through SET_MOTION_CONTROL_MODE()
|
||||
# and G64 Q through SET_NAIVECAM_TOLERANCE(), defaulting Q to P when Q is omitted.
|
||||
CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_control_mode_tolerances.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_control_mode_tolerances.json"
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/rs274ngc_pre.cc init reads
|
||||
# [RS274NGC] G64_DEFAULT_TOLERANCE/G64_DEFAULT_NAIVETOLERANCE, and
|
||||
# interp_convert.cc convert_control_mode() uses them when G64 omits P/Q.
|
||||
INI_FILE_NAME="$g64_default_tolerances_ini_file" CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_g64_default_tolerances.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_g64_default_tolerances.json"
|
||||
CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_tool_length.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_tool_length.json"
|
||||
@@ -355,6 +449,25 @@ done
|
||||
CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_canned_cycle.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_canned_cycle.json"
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/interp_cycles.cc
|
||||
# convert_cycle() rejects inverse-time feed mode and active cutter
|
||||
# compensation before expanding canned cycles through convert_cycle_xy()/yz()/zx().
|
||||
if CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_canned_cycle_inverse_time_error.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_canned_cycle_inverse_time_error.json" \
|
||||
2>"$output_dir/cnc_sim_linuxcnc_source_canned_cycle_inverse_time_error.err"; then
|
||||
echo "expected linuxcnc_canned_cycle_inverse_time_error.ngc to fail" >&2
|
||||
exit 1
|
||||
fi
|
||||
grep -q "Cannot use inverse time feed with canned cycles" "$output_dir/cnc_sim_linuxcnc_source_canned_cycle_inverse_time_error.err"
|
||||
if CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_canned_cycle_cutter_comp_error.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_canned_cycle_cutter_comp_error.json" \
|
||||
2>"$output_dir/cnc_sim_linuxcnc_source_canned_cycle_cutter_comp_error.err"; then
|
||||
echo "expected linuxcnc_canned_cycle_cutter_comp_error.ngc to fail" >&2
|
||||
exit 1
|
||||
fi
|
||||
grep -q "Cannot use canned cycles with cutter compensation on" "$output_dir/cnc_sim_linuxcnc_source_canned_cycle_cutter_comp_error.err"
|
||||
if CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_canned_cycle_l0_error.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_canned_cycle_l0_error.json" \
|
||||
@@ -774,6 +887,9 @@ CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" \
|
||||
CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_readonly_named_parameters_extra.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_readonly_named_parameters_extra.json"
|
||||
CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_readonly_named_current_position.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_readonly_named_current_position.json"
|
||||
if CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_readonly_named_parameter_assign_error.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_readonly_named_parameter_assign_error.json" 2>"$output_dir/cnc_sim_linuxcnc_source_readonly_named_parameter_assign_error.err"; then
|
||||
@@ -1049,10 +1165,14 @@ for case in "${threading_check_error_cases[@]}"; do
|
||||
grep -Fq "$expected" "$output_dir/cnc_sim_linuxcnc_source_$fixture.err"
|
||||
done
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/interp_convert.cc
|
||||
# convert_straight() and convert_threading_cycle() reject invalid
|
||||
# spindle state/selector, rotary-axis motion, and G76 I/J/K geometry
|
||||
# before issuing synchronized threading motion.
|
||||
# convert_arc(), convert_straight(), and convert_threading_cycle() reject invalid
|
||||
# feed/spindle state, spindle selectors, rotary-axis motion, and G76 I/J/K
|
||||
# geometry before issuing arc, straight, or synchronized threading motion.
|
||||
threading_convert_error_cases=(
|
||||
"linuxcnc_arc_inverse_time_missing_f_error|F word missing with inverse time arc move"
|
||||
"linuxcnc_g1_zero_feed_error|Cannot do g1 with zero feed rate"
|
||||
"linuxcnc_g1_inverse_time_missing_f_error|F word missing with inverse time g1 move"
|
||||
"linuxcnc_g95_zero_spindle_speed_error|Cannot feed with zero spindle speed in feed per rev mode"
|
||||
"linuxcnc_g33_stopped_spindle_error|Spindle not turning in G33"
|
||||
"linuxcnc_g33_1_stopped_spindle_error|Spindle not turning in G33.1"
|
||||
"linuxcnc_g33_spindle_dollar_out_of_range_error|Invalid spindle (\$) number in G33 move"
|
||||
@@ -1075,6 +1195,26 @@ for case in "${threading_convert_error_cases[@]}"; do
|
||||
fi
|
||||
grep -Fq "$expected" "$output_dir/cnc_sim_linuxcnc_source_$fixture.err"
|
||||
done
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/interp_convert.cc convert_probe()
|
||||
# rejects active cutter compensation, zero feed, feed-per-revolution mode, and
|
||||
# degenerate probe moves before issuing STRAIGHT_PROBE().
|
||||
probe_convert_error_cases=(
|
||||
"linuxcnc_probe_cutter_comp_error|Cannot probe with cutter radius comp on"
|
||||
"linuxcnc_probe_zero_feed_error|Cannot probe with zero feed rate"
|
||||
"linuxcnc_probe_feed_per_rev_error|Cannot probe with feed per rev mode"
|
||||
"linuxcnc_probe_start_too_close_error|Start point too close to probe point"
|
||||
)
|
||||
for case in "${probe_convert_error_cases[@]}"; do
|
||||
fixture=${case%%|*}
|
||||
expected=${case#*|}
|
||||
if CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" "tests/gcode/$fixture.ngc" \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_$fixture.json" 2>"$output_dir/cnc_sim_linuxcnc_source_$fixture.err"; then
|
||||
echo "expected $fixture.ngc to fail" >&2
|
||||
exit 1
|
||||
fi
|
||||
grep -Fq "$expected" "$output_dir/cnc_sim_linuxcnc_source_$fixture.err"
|
||||
done
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/interp_read.cc
|
||||
# read_items() only consumes a leading N word before item dispatch;
|
||||
# read_one_item() then uses the default reader table from interp_array.cc
|
||||
@@ -1227,6 +1367,25 @@ for case in "${oword_reader_error_cases[@]}"; do
|
||||
fi
|
||||
grep -Fq "$expected" "$output_dir/cnc_sim_linuxcnc_source_$fixture.err"
|
||||
done
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/rs274ngc_pre.cc init reads
|
||||
# [RS274NGC] DISABLE_FANUC_STYLE_SUB, and interp_read.cc rejects
|
||||
# Fanuc-style M98/M99 and bare O-word subroutine forms when enabled.
|
||||
disable_fanuc_style_error_cases=(
|
||||
"linuxcnc_disable_fanuc_style_m98_error|DISABLE_FANUC_STYLE_SUB set in INI file, but found m98"
|
||||
"linuxcnc_disable_fanuc_style_m99_error|DISABLE_FANUC_STYLE_SUB set in INI file, but found m99"
|
||||
"linuxcnc_disable_fanuc_style_bare_oword_error|DISABLE_FANUC_STYLE_SUB disabled in INI file, but found bare O-word"
|
||||
)
|
||||
for case in "${disable_fanuc_style_error_cases[@]}"; do
|
||||
fixture=${case%%|*}
|
||||
expected=${case#*|}
|
||||
if INI_FILE_NAME="$disable_fanuc_style_sub_ini_file" CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" "tests/gcode/$fixture.ngc" \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_$fixture.json" 2>"$output_dir/cnc_sim_linuxcnc_source_$fixture.err"; then
|
||||
echo "expected $fixture.ngc to fail" >&2
|
||||
exit 1
|
||||
fi
|
||||
grep -Fq "$expected" "$output_dir/cnc_sim_linuxcnc_source_$fixture.err"
|
||||
done
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/interp_o_word.cc
|
||||
# convert_control_functions() rejects unmatched, duplicate, and
|
||||
# out-of-context O-word control labels during execution.
|
||||
@@ -1318,6 +1477,69 @@ if CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" \
|
||||
fi
|
||||
grep -q "Cannot wait for digital input with cutter radius compensation on" \
|
||||
"$output_dir/cnc_sim_linuxcnc_source_cutter_comp_wait_input_error.err"
|
||||
if CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_cutter_comp_tool_offset_error.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_cutter_comp_tool_offset_error.json" 2>"$output_dir/cnc_sim_linuxcnc_source_cutter_comp_tool_offset_error.err"; then
|
||||
echo "expected linuxcnc_cutter_comp_tool_offset_error.ngc to fail" >&2
|
||||
exit 1
|
||||
fi
|
||||
grep -q "Cannot change tool offset with cutter radius compensation on" \
|
||||
"$output_dir/cnc_sim_linuxcnc_source_cutter_comp_tool_offset_error.err"
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/interp_convert.cc
|
||||
# convert_control_mode(), convert_coordinate_system(), and convert_home()
|
||||
# reject control-mode changes, coordinate-system changes, and G28/G30 while
|
||||
# cutter radius compensation is active.
|
||||
cutter_comp_g_error_cases=(
|
||||
"linuxcnc_cutter_comp_axis_offset_error|Cannot change axis offsets with cutter radius comp"
|
||||
"linuxcnc_cutter_comp_control_mode_error|Cannot change control mode with cutter radius compensation on"
|
||||
"linuxcnc_cutter_comp_coordinate_system_error|Cannot change coordinate systems with cutter radius compensation on"
|
||||
"linuxcnc_cutter_comp_g53_error|Cannot use g53 with cutter radius comp"
|
||||
"linuxcnc_cutter_comp_home_error|Cannot use g28 or g30 with cutter radius comp"
|
||||
"linuxcnc_cutter_comp_plane_change_error|Cannot change planes with cutter radius compensation on"
|
||||
)
|
||||
for case in "${cutter_comp_g_error_cases[@]}"; do
|
||||
fixture=${case%%|*}
|
||||
expected=${case#*|}
|
||||
if CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" "tests/gcode/$fixture.ngc" \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_$fixture.json" 2>"$output_dir/cnc_sim_linuxcnc_source_$fixture.err"; then
|
||||
echo "expected $fixture.ngc to fail" >&2
|
||||
exit 1
|
||||
fi
|
||||
grep -Fq "$expected" "$output_dir/cnc_sim_linuxcnc_source_$fixture.err"
|
||||
done
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/interp_convert.cc
|
||||
# convert_m() rejects M63-M65/M67-M68/M48-M53 while cutter radius
|
||||
# compensation is active before enqueueing digital/analog output or override
|
||||
# canon side effects.
|
||||
cutter_comp_m_error_cases=(
|
||||
"linuxcnc_cutter_comp_m63_error|Cannot set motion digital output with cutter radius compensation on"
|
||||
"linuxcnc_cutter_comp_m64_error|Cannot set auxiliary digital output with cutter radius compensation on"
|
||||
"linuxcnc_cutter_comp_m65_error|Cannot set auxiliary digital output with cutter radius compensation on"
|
||||
"linuxcnc_cutter_comp_m67_error|Cannot set motion analog output with cutter radius compensation on"
|
||||
"linuxcnc_cutter_comp_m68_error|Cannot set auxiliary analog output with cutter radius compensation on"
|
||||
"linuxcnc_cutter_comp_m48_error|Cannot enable overrides with cutter radius compensation on"
|
||||
"linuxcnc_cutter_comp_m49_error|Cannot disable overrides with cutter radius compensation on"
|
||||
"linuxcnc_cutter_comp_m50_enable_error|Cannot enable overrides with cutter radius compensation on"
|
||||
"linuxcnc_cutter_comp_m50_disable_error|Cannot disable overrides with cutter radius compensation on"
|
||||
"linuxcnc_cutter_comp_m51_enable_error|Cannot enable overrides with cutter radius compensation on"
|
||||
"linuxcnc_cutter_comp_m51_disable_error|Cannot disable overrides with cutter radius compensation on"
|
||||
"linuxcnc_cutter_comp_m52_enable_error|Cannot enable overrides with cutter radius compensation on"
|
||||
"linuxcnc_cutter_comp_m52_disable_error|Cannot disable overrides with cutter radius compensation on"
|
||||
"linuxcnc_cutter_comp_m53_enable_error|Cannot enable overrides with cutter radius compensation on"
|
||||
"linuxcnc_cutter_comp_m53_disable_error|Cannot disable overrides with cutter radius compensation on"
|
||||
)
|
||||
for case in "${cutter_comp_m_error_cases[@]}"; do
|
||||
fixture=${case%%|*}
|
||||
expected=${case#*|}
|
||||
if CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" "tests/gcode/$fixture.ngc" \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_$fixture.json" 2>"$output_dir/cnc_sim_linuxcnc_source_$fixture.err"; then
|
||||
echo "expected $fixture.ngc to fail" >&2
|
||||
exit 1
|
||||
fi
|
||||
grep -Fq "$expected" "$output_dir/cnc_sim_linuxcnc_source_$fixture.err"
|
||||
done
|
||||
if CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_cutter_comp_g71_error.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_cutter_comp_g71_error.json" 2>"$output_dir/cnc_sim_linuxcnc_source_cutter_comp_g71_error.err"; then
|
||||
@@ -1354,6 +1576,11 @@ if CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" \
|
||||
echo "expected linuxcnc_abort_hot_comment.ngc to fail" >&2
|
||||
exit 1
|
||||
fi
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/interp_convert.cc
|
||||
# convert_comment() routes ABORT hot comments through convert_param_comment()
|
||||
# and setSavedError(), preserving expanded numbered and named parameters.
|
||||
grep -Fq "execute failed: MixedCase param42=20.000000 named=4711.000000" \
|
||||
"$output_dir/cnc_sim_linuxcnc_source_abort_hot_comment.err"
|
||||
if CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_ccomp_gouging_error.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_ccomp_gouging_error.json" 2>"$output_dir/cnc_sim_linuxcnc_source_ccomp_gouging_error.err"; then
|
||||
@@ -1437,6 +1664,23 @@ CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" \
|
||||
CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_persistent_parameters_check.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_persistent_parameters_check.json"
|
||||
disable_g92_startup_var_file="$build_dir/rs274ngc-source-disable-g92-startup.var"
|
||||
printf '5210\t1.000000\n5211\t-4.000000\n5212\t-5.000000\n5213\t-6.000000\n5220\t1.000000\n' > "$disable_g92_startup_var_file"
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/rs274ngc_pre.cc init reads
|
||||
# [RS274NGC] DISABLE_G92_PERSISTENCE and clears restored #5210-#5219.
|
||||
INI_FILE_NAME="$disable_g92_persistence_ini_file" CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$disable_g92_startup_var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_g92_disable_persistence_startup.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_g92_disable_persistence_startup.json"
|
||||
disable_g92_stop_var_file="$build_dir/rs274ngc-source-disable-g92-stop.var"
|
||||
: > "$disable_g92_stop_var_file"
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/interp_convert.cc convert_stop()
|
||||
# clears #5210-#5219 on M2/M30 when DISABLE_G92_PERSISTENCE is enabled.
|
||||
INI_FILE_NAME="$disable_g92_persistence_ini_file" CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$disable_g92_stop_var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_g92_disable_persistence_set.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_g92_disable_persistence_set.json"
|
||||
CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$disable_g92_stop_var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_g92_disable_persistence_check.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_g92_disable_persistence_check.json"
|
||||
rotary_persistent_var_file="$build_dir/rs274ngc-rotary-persistent.var"
|
||||
: > "$rotary_persistent_var_file"
|
||||
CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$rotary_persistent_var_file" \
|
||||
@@ -1486,6 +1730,17 @@ CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" \
|
||||
CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_arc_center_tolerance_good_imperial.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_arc_center_tolerance_good_imperial.json"
|
||||
CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_arc_center_tolerance_tight_metric.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_arc_center_tolerance_tight_metric_default.json"
|
||||
if INI_FILE_NAME="$tight_arc_center_tolerance_ini_file" CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_arc_center_tolerance_tight_metric.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_arc_center_tolerance_tight_metric_ini.json" 2>"$output_dir/cnc_sim_linuxcnc_source_arc_center_tolerance_tight_metric_ini.err"; then
|
||||
echo "expected linuxcnc_arc_center_tolerance_tight_metric.ngc to fail with tight INI tolerance" >&2
|
||||
exit 1
|
||||
fi
|
||||
grep -Fq "Radius to end of arc differs from radius to start" \
|
||||
"$output_dir/cnc_sim_linuxcnc_source_arc_center_tolerance_tight_metric_ini.err"
|
||||
if CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_arc_center_tolerance_bad_metric.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_arc_center_tolerance_bad_metric.json" 2>"$output_dir/cnc_sim_linuxcnc_source_arc_center_tolerance_bad_metric.err"; then
|
||||
@@ -1524,6 +1779,7 @@ nurbs_error_cases=(
|
||||
"linuxcnc_g52_missing_subsequent_weight_error|Must specify positive weight P for every Control Point"
|
||||
"linuxcnc_g52_noninteger_l_error|Non integer value for integer"
|
||||
"linuxcnc_g52_zero_feed_error|Cannot make a NURBS with 0 feedrate"
|
||||
"linuxcnc_g53_non_g52_motion_error|Between G5.2 and G5.3 codes, only additional G5.2 codes are allowed."
|
||||
"linuxcnc_g53_without_g52_error|Cannot use G5.3 without G5.2 first"
|
||||
"linuxcnc_g53_short_control_points_error|You must specify a number of control points at least equal to the order L = 3"
|
||||
"linuxcnc_g53_after_intervening_motion_error|Cannot use G5.3 without G5.2 first"
|
||||
@@ -1549,6 +1805,9 @@ done
|
||||
CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_g76only.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_g76only.json"
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/interp_convert.cc convert_setup()
|
||||
# stores G10 L2 U/V/W through PROGRAM_TO_USER_LEN, and
|
||||
# convert_coordinate_system() emits them through SET_G5X_OFFSET.
|
||||
cp "$base_var_file" "$var_file"
|
||||
CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_coordinate_offsets.ngc \
|
||||
@@ -1605,6 +1864,18 @@ CNC_SIM_RS274_VAR="$var_file" \
|
||||
CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_percent_file_ignores_trailing.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_percent_file_ignores_trailing.json"
|
||||
# Source basis: LinuxCNC unit_tests/interp/test_interp_basics.cc Convert G20 / G21
|
||||
# asserts that unit changes rescale current linear axes while rotary axes remain
|
||||
# angular values.
|
||||
CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_units_current_position.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_units_current_position.json"
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/interp_convert.cc convert_axis_offsets()
|
||||
# stores G92 offsets through PROGRAM_TO_USER_LEN and restores them through
|
||||
# USER_TO_PROGRAM_LEN after convert_length_units() changes active program units.
|
||||
CNC_SIM_RS274_VAR="$var_file" \
|
||||
"$build_dir/linuxcnc_rs274_source_dump" tests/gcode/linuxcnc_units_g92_restore.ngc \
|
||||
>"$output_dir/cnc_sim_linuxcnc_source_units_g92_restore.json"
|
||||
|
||||
CNC_SIM_RS274_SOURCE_OUTPUT_DIR="$output_dir" python3 - <<'PY'
|
||||
import json
|
||||
@@ -1642,6 +1913,56 @@ required_motion = {
|
||||
check_motion("cnc_sim_linuxcnc_source_basic_motion.json", required_motion)
|
||||
check_motion("cnc_sim_linuxcnc_source_basic_mill.json", required_motion | {"tool-change"})
|
||||
|
||||
units_current_position = load("cnc_sim_linuxcnc_source_units_current_position.json")
|
||||
units_rapid = [
|
||||
event
|
||||
for event in units_current_position
|
||||
if event["type"] == "rapid"
|
||||
]
|
||||
if len(units_rapid) != 3:
|
||||
raise SystemExit(f"unexpected source-linked unit-current-position rapid count: {len(units_rapid)}")
|
||||
if units_rapid[1]["start"] != units_rapid[1]["end"]:
|
||||
raise SystemExit(
|
||||
"source-linked LinuxCNC G21 current-position rescale was not reflected before the metric no-op rapid: "
|
||||
f"{units_rapid[1]!r}"
|
||||
)
|
||||
if units_rapid[2]["start"] != units_rapid[2]["end"]:
|
||||
raise SystemExit(
|
||||
"source-linked LinuxCNC G20 current-position rescale was not reflected before the inch no-op rapid: "
|
||||
f"{units_rapid[2]!r}"
|
||||
)
|
||||
if (units_rapid[1]["end"]["a"], units_rapid[1]["end"]["b"], units_rapid[1]["end"]["c"]) != (4, 5, 6):
|
||||
raise SystemExit("source-linked LinuxCNC G21 unit change unexpectedly scaled rotary axes")
|
||||
if (units_rapid[1]["end"]["u"], units_rapid[1]["end"]["v"], units_rapid[1]["end"]["w"]) != (177.8, 203.2, 228.6):
|
||||
raise SystemExit("source-linked LinuxCNC G21 unit change did not scale U/V/W linear axes")
|
||||
if (units_rapid[2]["end"]["u"], units_rapid[2]["end"]["v"], units_rapid[2]["end"]["w"]) != (7, 8, 9):
|
||||
raise SystemExit("source-linked LinuxCNC G20 unit change did not restore U/V/W linear axes")
|
||||
|
||||
units_g92_restore = load("cnc_sim_linuxcnc_source_units_g92_restore.json")
|
||||
units_g92_states = [
|
||||
(
|
||||
event["line"],
|
||||
event["start"]["x"],
|
||||
event["start"]["y"],
|
||||
event["start"]["z"],
|
||||
event["start"]["a"],
|
||||
event["start"]["b"],
|
||||
event["start"]["c"],
|
||||
event["start"]["u"],
|
||||
event["start"]["v"],
|
||||
event["start"]["w"],
|
||||
)
|
||||
for event in units_g92_restore
|
||||
if event["type"] == "set-g92-offset" and event["line"] > 0
|
||||
]
|
||||
expected_units_g92_states = [
|
||||
(3, -1, -2, -3, -4, -5, -6, -7, -8, -9),
|
||||
(5, 0, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
(6, -25.4, -50.8, -76.2, -4, -5, -6, -177.8, -203.2, -228.6),
|
||||
]
|
||||
if units_g92_states != expected_units_g92_states:
|
||||
raise SystemExit(f"unexpected source-linked LinuxCNC G20/G21 G92 restore states: {units_g92_states!r}")
|
||||
|
||||
fractional_linenumbers = load("cnc_sim_linuxcnc_source_fractional_linenumbers.json")
|
||||
fractional_spindle_states = [
|
||||
(event["line"], event["spindle"])
|
||||
@@ -1728,6 +2049,78 @@ if (3, 1200, 2) not in spindle_states:
|
||||
if (4, 0, 0) not in spindle_states:
|
||||
raise SystemExit("missing source-linked M5 stopped spindle state")
|
||||
|
||||
multi_spindle_direction = json.loads((OUTPUT_DIR / "cnc_sim_linuxcnc_source_multi_spindle_direction.json").read_text())
|
||||
multi_spindle_direction_states = [
|
||||
(event["line"], event["tool"], event["spindle"], event["reserved"])
|
||||
for event in multi_spindle_direction
|
||||
if event["type"] == "set-spindle" and event["line"] in {5, 6, 7, 8}
|
||||
]
|
||||
expected_multi_spindle_direction_states = [
|
||||
(5, 1, 1200, 0),
|
||||
(6, 1, 1200, 1),
|
||||
(7, 1, 1200, 2),
|
||||
(8, 1, 0, 0),
|
||||
]
|
||||
if multi_spindle_direction_states != expected_multi_spindle_direction_states:
|
||||
raise SystemExit(
|
||||
"unexpected source-linked selected-spindle M3/M4/M5 states: "
|
||||
f"{multi_spindle_direction_states!r}"
|
||||
)
|
||||
|
||||
multi_spindle_all_direction = json.loads((OUTPUT_DIR / "cnc_sim_linuxcnc_source_multi_spindle_all_direction.json").read_text())
|
||||
multi_spindle_all_direction_states = [
|
||||
(event["line"], event["tool"], event["spindle"], event["reserved"])
|
||||
for event in multi_spindle_all_direction
|
||||
if event["type"] == "set-spindle" and event["line"] in {5, 6, 7, 8}
|
||||
]
|
||||
expected_multi_spindle_all_direction_states = [
|
||||
(5, 0, 1200, 0),
|
||||
(5, 1, 1200, 0),
|
||||
(6, 0, 1200, 1),
|
||||
(6, 1, 1200, 1),
|
||||
(7, 0, 1200, 2),
|
||||
(7, 1, 1200, 2),
|
||||
(8, 0, 0, 0),
|
||||
(8, 1, 0, 0),
|
||||
]
|
||||
if multi_spindle_all_direction_states != expected_multi_spindle_all_direction_states:
|
||||
raise SystemExit(
|
||||
"unexpected source-linked all-spindles S/M3/M4/M5 states: "
|
||||
f"{multi_spindle_all_direction_states!r}"
|
||||
)
|
||||
|
||||
multi_spindle_default_start = json.loads((OUTPUT_DIR / "cnc_sim_linuxcnc_source_multi_spindle_default_start.json").read_text())
|
||||
multi_spindle_default_start_states = [
|
||||
(event["line"], event["tool"], event["spindle"], event["reserved"])
|
||||
for event in multi_spindle_default_start
|
||||
if event["type"] == "set-spindle" and event["line"] in {5, 6}
|
||||
]
|
||||
expected_multi_spindle_default_start_states = [
|
||||
(5, 0, 1200, 1),
|
||||
(6, 0, 1200, 2),
|
||||
]
|
||||
if multi_spindle_default_start_states != expected_multi_spindle_default_start_states:
|
||||
raise SystemExit(
|
||||
"unexpected source-linked default M3/M4 spindle states: "
|
||||
f"{multi_spindle_default_start_states!r}"
|
||||
)
|
||||
|
||||
multi_spindle_default_stop = json.loads((OUTPUT_DIR / "cnc_sim_linuxcnc_source_multi_spindle_default_stop.json").read_text())
|
||||
multi_spindle_default_stop_states = [
|
||||
(event["line"], event["tool"], event["spindle"], event["reserved"])
|
||||
for event in multi_spindle_default_stop
|
||||
if event["type"] == "set-spindle" and event["line"] == 6
|
||||
]
|
||||
expected_multi_spindle_default_stop_states = [
|
||||
(6, 0, 0, 0),
|
||||
(6, 1, 0, 0),
|
||||
]
|
||||
if multi_spindle_default_stop_states != expected_multi_spindle_default_stop_states:
|
||||
raise SystemExit(
|
||||
"unexpected source-linked default M5 all-spindles stop states: "
|
||||
f"{multi_spindle_default_stop_states!r}"
|
||||
)
|
||||
|
||||
spindle_modes = json.loads((OUTPUT_DIR / "cnc_sim_linuxcnc_source_spindle_modes.json").read_text())
|
||||
spindle_mode_states = [
|
||||
(event["line"], event["reserved"], event["feed"], event["tool"])
|
||||
@@ -1742,6 +2135,27 @@ expected_spindle_mode_states = [
|
||||
if spindle_mode_states != expected_spindle_mode_states:
|
||||
raise SystemExit(f"unexpected source-linked G96/G97 spindle mode states: {spindle_mode_states!r}")
|
||||
|
||||
multi_spindle_modes = json.loads((OUTPUT_DIR / "cnc_sim_linuxcnc_source_multi_spindle_modes.json").read_text())
|
||||
multi_spindle_mode_states = [
|
||||
(event["line"], event["reserved"], event["feed"], event["tool"])
|
||||
for event in multi_spindle_modes
|
||||
if event["type"] == "comment" and event["line"] in {4, 5} and event["reserved"] in {960, 970}
|
||||
]
|
||||
expected_multi_spindle_mode_states = [
|
||||
(4, 970, 0, 1),
|
||||
(5, 960, 2500, 1),
|
||||
]
|
||||
if multi_spindle_mode_states != expected_multi_spindle_mode_states:
|
||||
raise SystemExit(f"unexpected source-linked selected-spindle G96/G97 states: {multi_spindle_mode_states!r}")
|
||||
if not any(
|
||||
event["type"] == "set-feed" and
|
||||
event["line"] == 6 and
|
||||
event["reserved"] == 1 and
|
||||
event["tool"] == 1
|
||||
for event in multi_spindle_modes
|
||||
):
|
||||
raise SystemExit("missing source-linked selected-spindle G95 feed mode event")
|
||||
|
||||
spindle_orient = json.loads((OUTPUT_DIR / "cnc_sim_linuxcnc_source_spindle_orient.json").read_text())
|
||||
if not any(
|
||||
event["type"] == "comment" and
|
||||
@@ -1763,6 +2177,27 @@ if not any(
|
||||
):
|
||||
raise SystemExit("missing source-linked M19 spindle orient wait state")
|
||||
|
||||
multi_spindle_orient = json.loads((OUTPUT_DIR / "cnc_sim_linuxcnc_source_multi_spindle_orient.json").read_text())
|
||||
if not any(
|
||||
event["type"] == "comment" and
|
||||
event["line"] == 4 and
|
||||
event["reserved"] == 1901 and
|
||||
event["tool"] == 1 and
|
||||
event["feed"] == 45 and
|
||||
event["arcTurns"] == 1
|
||||
for event in multi_spindle_orient
|
||||
):
|
||||
raise SystemExit("missing source-linked selected-spindle M19 orient state")
|
||||
if not any(
|
||||
event["type"] == "comment" and
|
||||
event["line"] == 4 and
|
||||
event["reserved"] == 1902 and
|
||||
event["tool"] == 1 and
|
||||
event["dwellSeconds"] == 2
|
||||
for event in multi_spindle_orient
|
||||
):
|
||||
raise SystemExit("missing source-linked selected-spindle M19 orient wait state")
|
||||
|
||||
io_controls = json.loads((OUTPUT_DIR / "cnc_sim_linuxcnc_source_io_controls.json").read_text())
|
||||
io_states = [
|
||||
(event["line"], event["reserved"], event["tool"], event["feed"], event["arcTurns"], event["dwellSeconds"])
|
||||
@@ -1806,6 +2241,70 @@ expected_override_states = [
|
||||
if override_states != expected_override_states:
|
||||
raise SystemExit(f"unexpected source-linked M48-M53 override states: {override_states!r}")
|
||||
|
||||
multi_spindle_override = json.loads((OUTPUT_DIR / "cnc_sim_linuxcnc_source_multi_spindle_override.json").read_text())
|
||||
multi_spindle_override_states = [
|
||||
(event["line"], event["reserved"], event["tool"], event["feed"])
|
||||
for event in multi_spindle_override
|
||||
if event["type"] == "comment" and event["reserved"] == 51
|
||||
]
|
||||
expected_multi_spindle_override_states = [
|
||||
(4, 51, 1, 0),
|
||||
(5, 51, 1, 1),
|
||||
]
|
||||
if multi_spindle_override_states != expected_multi_spindle_override_states:
|
||||
raise SystemExit(
|
||||
"unexpected source-linked M51 selected-spindle override states: "
|
||||
f"{multi_spindle_override_states!r}"
|
||||
)
|
||||
|
||||
multi_spindle_override_all = json.loads((OUTPUT_DIR / "cnc_sim_linuxcnc_source_multi_spindle_override_all.json").read_text())
|
||||
multi_spindle_override_all_states = [
|
||||
(event["line"], event["reserved"], event["tool"], event["feed"])
|
||||
for event in multi_spindle_override_all
|
||||
if event["type"] == "comment" and event["reserved"] == 51
|
||||
]
|
||||
expected_multi_spindle_override_all_states = [
|
||||
(4, 51, 0, 0),
|
||||
(4, 51, 1, 0),
|
||||
(5, 51, 0, 1),
|
||||
(5, 51, 1, 1),
|
||||
]
|
||||
if multi_spindle_override_all_states != expected_multi_spindle_override_all_states:
|
||||
raise SystemExit(
|
||||
"unexpected source-linked M51 all-spindles override states: "
|
||||
f"{multi_spindle_override_all_states!r}"
|
||||
)
|
||||
|
||||
control_mode_tolerances = json.loads((OUTPUT_DIR / "cnc_sim_linuxcnc_source_control_mode_tolerances.json").read_text())
|
||||
control_mode_tolerance_states = [
|
||||
(event["line"], event["reserved"], event["feed"])
|
||||
for event in control_mode_tolerances
|
||||
if event["type"] == "comment" and event["reserved"] in {611, 612, 640, 641}
|
||||
]
|
||||
expected_control_mode_tolerance_states = [
|
||||
(2, 640, 0.05),
|
||||
(2, 641, 0.02),
|
||||
(3, 640, 0.03),
|
||||
(3, 641, 0.03),
|
||||
(4, 611, 0),
|
||||
(5, 612, 0),
|
||||
]
|
||||
if control_mode_tolerance_states != expected_control_mode_tolerance_states:
|
||||
raise SystemExit(f"unexpected source-linked G64 P/Q control mode tolerance states: {control_mode_tolerance_states!r}")
|
||||
|
||||
g64_default_tolerances = json.loads((OUTPUT_DIR / "cnc_sim_linuxcnc_source_g64_default_tolerances.json").read_text())
|
||||
g64_default_tolerance_states = [
|
||||
(event["line"], event["reserved"], event["feed"])
|
||||
for event in g64_default_tolerances
|
||||
if event["type"] == "comment" and event["reserved"] in {640, 641}
|
||||
]
|
||||
expected_g64_default_tolerance_states = [
|
||||
(3, 640, 0.07),
|
||||
(3, 641, 0.04),
|
||||
]
|
||||
if g64_default_tolerance_states != expected_g64_default_tolerance_states:
|
||||
raise SystemExit(f"unexpected source-linked INI-backed G64 default tolerance states: {g64_default_tolerance_states!r}")
|
||||
|
||||
modal_state = json.loads((OUTPUT_DIR / "cnc_sim_linuxcnc_source_modal_state.json").read_text())
|
||||
if not any(
|
||||
event["type"] == "rapid" and
|
||||
@@ -1863,6 +2362,50 @@ if not any(
|
||||
):
|
||||
raise SystemExit("missing source-linked G33.1 rigid tap motion line")
|
||||
|
||||
multi_spindle_threading = json.loads((OUTPUT_DIR / "cnc_sim_linuxcnc_source_multi_spindle_threading.json").read_text())
|
||||
multi_spindle_sync_states = [
|
||||
(event["line"], event["reserved"], event["feed"], event["tool"])
|
||||
for event in multi_spindle_threading
|
||||
if event["type"] == "comment" and event["reserved"] in {3300, 3301, 3302}
|
||||
]
|
||||
expected_multi_spindle_sync_states = [
|
||||
(6, 3301, 1, 1),
|
||||
(6, 3300, 0, 0),
|
||||
(8, 3301, 1, 1),
|
||||
(8, 3300, 0, 0),
|
||||
]
|
||||
if multi_spindle_sync_states != expected_multi_spindle_sync_states:
|
||||
raise SystemExit(
|
||||
"unexpected source-linked G33/G33.1 selected-spindle sync states: "
|
||||
f"{multi_spindle_sync_states!r}"
|
||||
)
|
||||
if not any(
|
||||
event["type"] == "linear-feed" and event["line"] == 8 and event["end"]["z"] == 0
|
||||
for event in multi_spindle_threading
|
||||
):
|
||||
raise SystemExit("missing source-linked G33.1 selected-spindle rigid tap motion line")
|
||||
|
||||
multi_spindle_g76 = json.loads((OUTPUT_DIR / "cnc_sim_linuxcnc_source_multi_spindle_g76.json").read_text())
|
||||
if not any(
|
||||
event["type"] == "comment" and
|
||||
event["line"] == 6 and
|
||||
event["reserved"] == 3301 and
|
||||
event["tool"] == 1 and
|
||||
event["feed"] == 0.05
|
||||
for event in multi_spindle_g76
|
||||
):
|
||||
raise SystemExit("missing source-linked G76 selected-spindle sync start")
|
||||
if not any(
|
||||
event["type"] == "comment" and event["line"] == 6 and event["reserved"] == 3300
|
||||
for event in multi_spindle_g76
|
||||
):
|
||||
raise SystemExit("missing source-linked G76 selected-spindle sync stop")
|
||||
if not any(
|
||||
event["type"] == "linear-feed" and event["line"] == 6 and event["end"]["z"] == -1
|
||||
for event in multi_spindle_g76
|
||||
):
|
||||
raise SystemExit("missing source-linked G76 selected-spindle final threading pass")
|
||||
|
||||
threading_cycle = json.loads((OUTPUT_DIR / "cnc_sim_linuxcnc_source_threading_cycle.json").read_text())
|
||||
if not any(
|
||||
event["type"] == "comment" and
|
||||
@@ -2575,8 +3118,32 @@ if actual_cutter_comp != expected_cutter_comp:
|
||||
raise SystemExit(f"unexpected source-linked cutter compensation path: {actual_cutter_comp!r}")
|
||||
|
||||
comments = load("cnc_sim_linuxcnc_source_comments.json")
|
||||
if not any(event["type"] == "comment" and event["line"] == 2 for event in comments):
|
||||
raise SystemExit("missing source-linked LinuxCNC comment line event")
|
||||
# Source basis: LinuxCNC src/emc/rs274ngc/interp_read.cc read_comment()
|
||||
# stores parenthesized comments for convert_comment(), while read_semicolon()
|
||||
# skips ordinary semicolon comments to end-of-line unless the line starts
|
||||
# with ;py,. src/emc/rs274ngc/interp_convert.cc convert_comment() emits
|
||||
# ordinary parenthesized comments through enqueue_COMMENT().
|
||||
comment_events = [
|
||||
(index, event["line"])
|
||||
for index, event in enumerate(comments)
|
||||
if event["type"] == "comment" and event["reserved"] == 0
|
||||
]
|
||||
comment_lines = [line for _, line in comment_events]
|
||||
for expected_line in (2, 4):
|
||||
if expected_line not in comment_lines:
|
||||
raise SystemExit(f"missing source-linked LinuxCNC comment line event {expected_line}")
|
||||
for unexpected_line in (5, 6):
|
||||
if unexpected_line in comment_lines:
|
||||
raise SystemExit(f"unexpected source-linked ordinary semicolon comment event {unexpected_line}")
|
||||
motion_line4_index = next(
|
||||
index for index, event in enumerate(comments)
|
||||
if event["type"] == "rapid" and event["line"] == 4 and event["end"]["x"] == 1
|
||||
)
|
||||
comment_line4_index = next(index for index, line in comment_events if line == 4)
|
||||
if comment_line4_index >= motion_line4_index:
|
||||
raise SystemExit("source-linked parenthesized inline comment was not emitted before same-line motion")
|
||||
if not any(event["type"] == "rapid" and event["line"] == 5 and event["end"]["x"] == 2 for event in comments):
|
||||
raise SystemExit("source-linked semicolon-commented motion line did not execute before line-end comment")
|
||||
|
||||
probe = json.loads((OUTPUT_DIR / "cnc_sim_linuxcnc_source_probe_no_error.json").read_text())
|
||||
probe_events = [
|
||||
@@ -2817,6 +3384,23 @@ expected_readonly_common_moves = [
|
||||
if readonly_common_moves != expected_readonly_common_moves:
|
||||
raise SystemExit(f"unexpected source-linked readonly named parameter motions: {readonly_common_moves!r}")
|
||||
|
||||
readonly_current = json.loads((OUTPUT_DIR / "cnc_sim_linuxcnc_source_readonly_named_current_position.json").read_text())
|
||||
if not any(
|
||||
event["type"] == "linear-feed" and
|
||||
event["line"] == 6 and
|
||||
event["end"]["x"] == 10 and
|
||||
event["end"]["y"] == 2 and
|
||||
event["end"]["z"] == 3 and
|
||||
event["end"]["a"] == 4 and
|
||||
event["end"]["b"] == 5 and
|
||||
event["end"]["c"] == 6 and
|
||||
event["end"]["u"] == 7 and
|
||||
event["end"]["v"] == 8 and
|
||||
event["end"]["w"] == 9
|
||||
for event in readonly_current
|
||||
):
|
||||
raise SystemExit("missing source-linked readonly named current-position branch motion")
|
||||
|
||||
readonly_named = json.loads((OUTPUT_DIR / "cnc_sim_linuxcnc_source_readonly_named_parameters_extra.json").read_text())
|
||||
if not any(
|
||||
event["type"] == "linear-feed" and
|
||||
@@ -3063,6 +3647,15 @@ if not any(
|
||||
):
|
||||
raise SystemExit("missing source-linked small imperial center-format arc within tolerance")
|
||||
|
||||
arc_center_tolerance_tight_metric_default = json.loads((OUTPUT_DIR / "cnc_sim_linuxcnc_source_arc_center_tolerance_tight_metric_default.json").read_text())
|
||||
if not any(
|
||||
event["type"] == "arc-feed" and
|
||||
event["line"] == 5 and
|
||||
event["end"]["x"] == 2
|
||||
for event in arc_center_tolerance_tight_metric_default
|
||||
):
|
||||
raise SystemExit("missing source-linked metric center-format arc under default tolerance")
|
||||
|
||||
g76only = json.loads((OUTPUT_DIR / "cnc_sim_linuxcnc_source_g76only.json").read_text())
|
||||
if not any(
|
||||
event["type"] == "comment" and
|
||||
@@ -3322,6 +3915,23 @@ if not any(
|
||||
):
|
||||
raise SystemExit("missing source-linked persistent parameter reload branch motion")
|
||||
|
||||
disable_g92_startup = json.loads((OUTPUT_DIR / "cnc_sim_linuxcnc_source_g92_disable_persistence_startup.json").read_text())
|
||||
if not any(
|
||||
event["type"] == "linear-feed" and
|
||||
event["line"] == 5 and
|
||||
event["end"]["x"] == 2
|
||||
for event in disable_g92_startup
|
||||
):
|
||||
raise SystemExit("missing source-linked DISABLE_G92_PERSISTENCE startup clear branch motion")
|
||||
disable_g92_check = json.loads((OUTPUT_DIR / "cnc_sim_linuxcnc_source_g92_disable_persistence_check.json").read_text())
|
||||
if not any(
|
||||
event["type"] == "linear-feed" and
|
||||
event["line"] == 5 and
|
||||
event["end"]["x"] == 1
|
||||
for event in disable_g92_check
|
||||
):
|
||||
raise SystemExit("missing source-linked DISABLE_G92_PERSISTENCE program-end clear branch motion")
|
||||
|
||||
rotary_persistent_parameters_check = json.loads((OUTPUT_DIR / "cnc_sim_linuxcnc_source_rotary_persistent_parameters_check.json").read_text())
|
||||
if not any(
|
||||
event["type"] == "linear-feed" and
|
||||
@@ -3385,7 +3995,10 @@ if not any(
|
||||
event["tool"] == 1 and
|
||||
event["start"]["x"] == 12.5 and
|
||||
event["start"]["y"] == -3 and
|
||||
event["start"]["z"] == 4
|
||||
event["start"]["z"] == 4 and
|
||||
event["start"]["u"] == 7 and
|
||||
event["start"]["v"] == 8 and
|
||||
event["start"]["w"] == 9
|
||||
for event in g5x
|
||||
):
|
||||
raise SystemExit("missing source-linked G10 L2 G5X offset event")
|
||||
@@ -3405,29 +4018,35 @@ if not any(event["type"] == "program-end" and event["line"] == 5 for event in co
|
||||
l20 = json.loads((OUTPUT_DIR / "cnc_sim_linuxcnc_source_coordinate_l20.json").read_text())
|
||||
if not any(
|
||||
event["type"] == "set-g5x-offset" and
|
||||
event["line"] == 4 and
|
||||
event["line"] == 5 and
|
||||
event["tool"] == 2 and
|
||||
event["start"]["x"] == 4 and
|
||||
event["start"]["y"] == 4 and
|
||||
event["start"]["z"] == 4
|
||||
event["start"]["z"] == 4 and
|
||||
event["start"]["u"] == 4 and
|
||||
event["start"]["v"] == 4 and
|
||||
event["start"]["w"] == 4
|
||||
for event in l20
|
||||
):
|
||||
raise SystemExit("missing source-linked G10 L20 P2 offset event after G55 selection")
|
||||
if not any(event["type"] == "program-end" and event["line"] == 5 for event in l20):
|
||||
if not any(event["type"] == "program-end" and event["line"] == 6 for event in l20):
|
||||
raise SystemExit("missing source-linked G10 L20 program end line number")
|
||||
|
||||
p0 = json.loads((OUTPUT_DIR / "cnc_sim_linuxcnc_source_coordinate_p0.json").read_text())
|
||||
if not any(
|
||||
event["type"] == "set-g5x-offset" and
|
||||
event["line"] == 3 and
|
||||
event["line"] == 4 and
|
||||
event["tool"] == 2 and
|
||||
event["start"]["x"] == 7 and
|
||||
event["start"]["y"] == 8 and
|
||||
event["start"]["z"] == 9
|
||||
event["start"]["z"] == 9 and
|
||||
event["start"]["u"] == 10 and
|
||||
event["start"]["v"] == 11 and
|
||||
event["start"]["w"] == 12
|
||||
for event in p0
|
||||
):
|
||||
raise SystemExit("missing source-linked G10 L2 P0 active G55 offset event")
|
||||
if not any(event["type"] == "program-end" and event["line"] == 4 for event in p0):
|
||||
if not any(event["type"] == "program-end" and event["line"] == 5 for event in p0):
|
||||
raise SystemExit("missing source-linked G10 P0 program end line number")
|
||||
|
||||
select_all = json.loads((OUTPUT_DIR / "cnc_sim_linuxcnc_source_coordinate_select_all.json").read_text())
|
||||
@@ -3470,20 +4089,28 @@ if not any(event["type"] == "program-end" and event["line"] == 7 for event in g9
|
||||
|
||||
g52_offset = json.loads((OUTPUT_DIR / "cnc_sim_linuxcnc_source_g52_offset.json").read_text())
|
||||
g52_states = [
|
||||
(event["line"], event["start"]["x"], event["start"]["y"], event["start"]["z"])
|
||||
(
|
||||
event["line"],
|
||||
event["start"]["x"],
|
||||
event["start"]["y"],
|
||||
event["start"]["z"],
|
||||
event["start"]["u"],
|
||||
event["start"]["v"],
|
||||
event["start"]["w"],
|
||||
)
|
||||
for event in g52_offset
|
||||
if event["type"] == "set-g92-offset" and event["line"] > 0
|
||||
]
|
||||
expected_g52_states = [
|
||||
(2, 1, 2, 0),
|
||||
(3, 1, 3, 0),
|
||||
(4, 0, 0, 0),
|
||||
(5, 1, 3, 0),
|
||||
(6, 0, 0, 0),
|
||||
(3, 1, 2, 0, 4, 5, 0),
|
||||
(4, 1, 3, 0, 4, 6, 0),
|
||||
(5, 0, 0, 0, 0, 0, 0),
|
||||
(6, 1, 3, 0, 4, 6, 0),
|
||||
(7, 0, 0, 0, 0, 0, 0),
|
||||
]
|
||||
if g52_states != expected_g52_states:
|
||||
raise SystemExit(f"unexpected source-linked G52 shared offset sequence: {g52_states!r}")
|
||||
if not any(event["type"] == "program-end" and event["line"] == 7 for event in g52_offset):
|
||||
if not any(event["type"] == "program-end" and event["line"] == 8 for event in g52_offset):
|
||||
raise SystemExit("missing source-linked G52 offset program end line number")
|
||||
|
||||
g52_xz_nurbs = json.loads((OUTPUT_DIR / "cnc_sim_linuxcnc_source_g52_xz_nurbs.json").read_text())
|
||||
@@ -3517,14 +4144,21 @@ echo "dumped $output_dir/cnc_sim_linuxcnc_source_basic_mill.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_incremental_and_r_arc.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_rtcp_controls.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_spindle_direction.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_multi_spindle_direction.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_multi_spindle_all_direction.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_multi_spindle_default_start.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_multi_spindle_default_stop.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_spindle_modes.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_spindle_orient.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_multi_spindle_orient.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_io_controls.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_override_controls.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_multi_spindle_override_all.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_modal_state.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_modal_autorestore.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_threading_sync.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_threading_cycle.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_multi_spindle_g76.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_lathe_diameter_mode.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_lathe_diameter_g76.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_tool_number.json"
|
||||
@@ -3534,6 +4168,7 @@ echo "dumped $output_dir/cnc_sim_linuxcnc_source_program_end_m99.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_coolant.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_feed_modes.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_motion_modes.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_g64_default_tolerances.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_tool_length.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_dynamic_tool_length.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_canned_cycle.json"
|
||||
@@ -3557,6 +4192,7 @@ echo "dumped $output_dir/cnc_sim_linuxcnc_source_named_parameter_normalization.j
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_ini_named_parameter.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_readonly_named_parameters.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_readonly_named_parameters_extra.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_readonly_named_current_position.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_value_returned.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_call_level.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_exists_word_value.json"
|
||||
@@ -3565,6 +4201,8 @@ echo "dumped $output_dir/cnc_sim_linuxcnc_source_parameter_expression_assignment
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_word_bracket_whitespace.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_m98_mixed_styles_variables.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_arc_center_tolerance_good_imperial.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_arc_center_tolerance_tight_metric_default.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_arc_center_tolerance_tight_metric_ini.err"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_g76only.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_numbered_parameters.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_rotary_probe_numbered_parameters.json"
|
||||
@@ -3588,6 +4226,9 @@ echo "dumped $output_dir/cnc_sim_linuxcnc_source_rotary_tool_offset_numbered_par
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_current_position_numbered_parameters.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_persistent_parameters_set.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_persistent_parameters_check.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_g92_disable_persistence_startup.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_g92_disable_persistence_set.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_g92_disable_persistence_check.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_rotary_persistent_parameters_set.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_rotary_persistent_parameters_check.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_g54_persistent_parameters_set.json"
|
||||
@@ -3610,3 +4251,5 @@ echo "dumped $output_dir/cnc_sim_linuxcnc_source_fractional_linenumbers.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_extended_linenumbers.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_close_and_downcase_words.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_percent_file_ignores_trailing.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_units_current_position.json"
|
||||
echo "dumped $output_dir/cnc_sim_linuxcnc_source_units_g92_restore.json"
|
||||
|
||||
@@ -1531,6 +1531,10 @@ grep -F 'LinuxCNC source basis: src/emc/rs274ngc/interp_base.cc native loader fl
|
||||
grep -F 'LinuxCNC source basis: src/emc/rs274ngc/gcodemodule.cc defines _task=0' core/wasm_shims/linuxcnc_runtime_shim.cc >/dev/null
|
||||
grep -F 'LinuxCNC source basis: src/emc/task/taskclass.cc and' core/wasm_shims/linuxcnc_runtime_shim.cc >/dev/null
|
||||
grep -F 'LinuxCNC source basis: src/emc/rs274ngc/interp_namedparams.cc fetch_hal_param()' core/wasm_shims/linuxcnc_runtime_shim.cc >/dev/null
|
||||
grep -F 'src/emc/rs274ngc/interp_namedparams.cc calls the HAL lookup functions' core/wasm_shims/cnc_sim_wasm_runtime_probe_main.cc >/dev/null
|
||||
grep -F 'bool hal_lookup_is_unavailable()' core/wasm_shims/cnc_sim_wasm_runtime_probe_main.cc >/dev/null
|
||||
grep -F 'hal_get_pin_value_by_name("cnc-sim.missing-pin", &type, &data, &connected) != -1' core/wasm_shims/cnc_sim_wasm_runtime_probe_main.cc >/dev/null
|
||||
grep -F 'type != HAL_TYPE_UNINITIALIZED' core/wasm_shims/cnc_sim_wasm_runtime_probe_main.cc >/dev/null
|
||||
grep -F 'LinuxCNC source basis: src/emc/rs274ngc/rs274ngc_pre.cc uses wordexp()' core/wasm_shims/linuxcnc_runtime_shim.cc >/dev/null
|
||||
grep -F 'extern "C" int wordexp(const char *words, wordexp_t *pwordexp, int)' core/wasm_shims/linuxcnc_runtime_shim.cc >/dev/null
|
||||
grep -F 'extern "C" void wordfree(wordexp_t *pwordexp)' core/wasm_shims/linuxcnc_runtime_shim.cc >/dev/null
|
||||
|
||||
@@ -7,6 +7,10 @@ cd "$(dirname "$0")"
|
||||
# whose runtime dynamic loading edge is satisfied by the wasm-safe dlfcn shim.
|
||||
probe=$(./build-linuxcnc-wasm-standalone-probe.sh --mode interp-base-link)
|
||||
|
||||
"$probe"
|
||||
"$probe" 2>"$probe.err"
|
||||
grep -F "emcTaskInit: could not open interpreter '/tmp/cnc_sim_missing_absolute_interpreter.so': dynamic loading is unavailable in wasm-safe probe" \
|
||||
"$probe.err" >/dev/null
|
||||
grep -F "emcTaskInit: could not open interpreter '" "$probe.err" | \
|
||||
grep -F "/lib/linuxcnc/nonexistent-interpreter.so': dynamic loading is unavailable in wasm-safe probe" >/dev/null
|
||||
|
||||
echo "linuxcnc wasm interp_base link probe passed"
|
||||
|
||||
@@ -4,9 +4,9 @@ set -euo pipefail
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# LinuxCNC source basis: this probe derives required Python C API exports from
|
||||
# RS274 Python/remap sources in src/emc/rs274ngc, including
|
||||
# interp_namedparams.cc, interp_o_word.cc, interp_python.cc, interp_remap.cc,
|
||||
# rs274ngc_pre.cc, and the py*/module binding sources.
|
||||
# RS274 Python/remap sources in src/emc/rs274ngc and from
|
||||
# src/emc/pythonplugin/python_plugin.cc initialization/configuration paths,
|
||||
# while compiling only the RS274 binding objects that need wasm-safe symbols.
|
||||
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
|
||||
cxx=${CXX:-g++}
|
||||
if [[ -z ${CXX:-} ]] && command -v ccache >/dev/null 2>&1; then
|
||||
@@ -58,6 +58,10 @@ linuxcnc_source_output=$(LINUXCNC_ROOT="$linuxcnc_root" ./list-linuxcnc-source-f
|
||||
src/emc/rs274ngc/gcodemodule.cc)
|
||||
mapfile -t linuxcnc_sources <<<"$linuxcnc_source_output"
|
||||
python_binding_sources=("${linuxcnc_sources[@]:6}")
|
||||
python_plugin_source_output=$(LINUXCNC_ROOT="$linuxcnc_root" ./list-linuxcnc-source-files.sh \
|
||||
src/emc/pythonplugin/python_plugin.cc)
|
||||
mapfile -t python_plugin_sources <<<"$python_plugin_source_output"
|
||||
python_token_sources=("${linuxcnc_sources[@]}" "${python_plugin_sources[@]}")
|
||||
|
||||
common_flag_output=$(LINUXCNC_ROOT="$linuxcnc_root" ./list-linuxcnc-wasm-common-cxxflags.sh)
|
||||
mapfile -t common_flags <<<"$common_flag_output"
|
||||
@@ -70,6 +74,12 @@ object_sources=(
|
||||
"$python_c_api_shim"
|
||||
"$runtime_shim"
|
||||
)
|
||||
probe_objects=(
|
||||
"$build_dir/python_c_api_probe_main.o"
|
||||
)
|
||||
probe_sources=(
|
||||
core/wasm_shims/python_c_api_probe_main.cc
|
||||
)
|
||||
for source in "${python_binding_sources[@]}"; do
|
||||
object_name=$(basename "$source" .cc)
|
||||
objects+=("$build_dir/$object_name.o")
|
||||
@@ -88,9 +98,11 @@ next_signature="$build_dir/python-c-api.signature.next"
|
||||
printf '\n'
|
||||
printf 'SOURCES:\n'
|
||||
printf '%s\n' "${object_sources[@]}"
|
||||
printf 'PROBE_SOURCES:\n'
|
||||
printf '%s\n' "${probe_sources[@]}"
|
||||
} > "$next_signature"
|
||||
if [[ ! -f "$signature" ]] || ! cmp -s "$signature" "$next_signature"; then
|
||||
rm -f "$build_dir"/*.o "$build_dir"/*.d
|
||||
rm -f "$build_dir"/*.o "$build_dir"/*.d "$build_dir/python_c_api_probe"
|
||||
fi
|
||||
mv "$next_signature" "$signature"
|
||||
|
||||
@@ -107,8 +119,11 @@ makefile="$build_dir/python-c-api.mk"
|
||||
for object in "${objects[@]}"; do
|
||||
printf 'DEP_FILES += %s.d\n' "$object"
|
||||
done
|
||||
for object in "${probe_objects[@]}"; do
|
||||
printf 'DEP_FILES += %s.d\n' "$object"
|
||||
done
|
||||
printf '\n.PHONY: all\n'
|
||||
printf 'all: $(OBJECTS)\n\n'
|
||||
printf 'all: $(OBJECTS) %s\n\n' "$build_dir/python_c_api_probe"
|
||||
|
||||
object_index=0
|
||||
for source in "${object_sources[@]}"; do
|
||||
@@ -116,6 +131,14 @@ makefile="$build_dir/python-c-api.mk"
|
||||
printf '\t@$(CXX) $(COMMON_FLAGS) -MMD -MP -MF %s.d -c %s -o %s\n\n' "${objects[$object_index]}" "$source" "${objects[$object_index]}"
|
||||
object_index=$((object_index + 1))
|
||||
done
|
||||
probe_index=0
|
||||
for source in "${probe_sources[@]}"; do
|
||||
printf '%s: %s\n' "${probe_objects[$probe_index]}" "$source"
|
||||
printf '\t@$(CXX) $(COMMON_FLAGS) -MMD -MP -MF %s.d -c %s -o %s\n\n' "${probe_objects[$probe_index]}" "$source" "${probe_objects[$probe_index]}"
|
||||
probe_index=$((probe_index + 1))
|
||||
done
|
||||
printf '%s: %s %s\n' "$build_dir/python_c_api_probe" "$build_dir/python_c_api_shim.o" "${probe_objects[*]}"
|
||||
printf '\t@$(CXX) %s %s -o %s\n\n' "$build_dir/python_c_api_shim.o" "${probe_objects[*]}" "$build_dir/python_c_api_probe"
|
||||
printf '\n-include $(DEP_FILES)\n'
|
||||
} > "$makefile"
|
||||
make --output-sync=target -j"$build_jobs" -f "$makefile" >/dev/null
|
||||
@@ -124,14 +147,14 @@ source_symbols_signature="$build_dir/python-c-api.source-symbols.signature"
|
||||
source_symbols_next_signature="$build_dir/python-c-api.source-symbols.signature.next"
|
||||
{
|
||||
printf 'SOURCE_SYMBOL_RULE_VERSION=1\n'
|
||||
printf 'LINUXCNC_SOURCES:\n'
|
||||
printf '%s\n' "${linuxcnc_sources[@]}"
|
||||
printf 'LINUXCNC_TOKEN_SOURCES:\n'
|
||||
printf '%s\n' "${python_token_sources[@]}"
|
||||
printf 'SOURCE_STATS:\n'
|
||||
stat -c 'SOURCE=%n:%s:%y' "${linuxcnc_sources[@]}"
|
||||
stat -c 'SOURCE=%n:%s:%y' "${python_token_sources[@]}"
|
||||
} > "$source_symbols_next_signature"
|
||||
if [[ ! -f "$source_symbols_signature" || ! -f "$build_dir/linuxcnc.py-tokens" ]] ||
|
||||
! cmp -s "$source_symbols_signature" "$source_symbols_next_signature"; then
|
||||
rg -o 'Py[A-Za-z0-9_]+' "${linuxcnc_sources[@]}" \
|
||||
rg -o 'Py[A-Za-z0-9_]+' "${python_token_sources[@]}" \
|
||||
| sed 's/^.*://' \
|
||||
| LC_ALL=C sort -u \
|
||||
> "$build_dir/linuxcnc.py-tokens"
|
||||
@@ -185,12 +208,14 @@ awk '
|
||||
$0 == "PyModuleDef_HEAD_INIT" { next }
|
||||
$0 == "Py_TPFLAGS_DEFAULT" { next }
|
||||
$0 == "PyCFunction" { next }
|
||||
$0 == "PyConfig" { next }
|
||||
$0 == "PyGetSetDef" { next }
|
||||
$0 == "PyMemberDef" { next }
|
||||
$0 == "PyMethodDef" { next }
|
||||
$0 == "PyModuleDef" { next }
|
||||
$0 == "PyMODINIT_FUNC" { next }
|
||||
$0 == "PyObject_New" { next }
|
||||
$0 == "PyStatus" { next }
|
||||
$0 == "PyInit_emccanon" { next }
|
||||
$0 == "PyInit_gcode" { next }
|
||||
$0 == "PyInit_interpreter" { next }
|
||||
@@ -229,4 +254,6 @@ if [[ -s "$build_dir/object.missing-python" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
"$build_dir/python_c_api_probe"
|
||||
|
||||
echo "linuxcnc wasm Python C API symbol probe passed"
|
||||
|
||||
@@ -6,7 +6,9 @@ cd "$(dirname "$0")"
|
||||
# LinuxCNC source basis: src/emc/pythonplugin/python_plugin.cc and
|
||||
# python_plugin.hh define the PythonPlugin API covered by this wrapper.
|
||||
probe=$(./build-linuxcnc-wasm-standalone-probe.sh --mode python-plugin-link)
|
||||
inittab_probe=$(./build-linuxcnc-wasm-standalone-probe.sh --mode python-plugin-inittab-link)
|
||||
|
||||
"$probe"
|
||||
"$inittab_probe"
|
||||
|
||||
echo "linuxcnc wasm python_plugin link probe passed"
|
||||
|
||||
@@ -11,6 +11,7 @@ probe=$(./build-linuxcnc-wasm-standalone-probe.sh --mode tooldata-link)
|
||||
"$probe" 2>"$probe.err"
|
||||
grep -F "tool_mmap_user(): tool mmap not available" "$probe.err" >/dev/null
|
||||
grep -F "tooldata_put() no tool_mmap_base" "$probe.err" >/dev/null
|
||||
grep -F "Error: tool_mmap_creator already called BYE" "$probe.err" >/dev/null
|
||||
grep -F "!!!PROBLEM tool_nml_register()" "$probe.err" >/dev/null
|
||||
grep -F "!!!!db_init: <" "$probe.err" >/dev/null
|
||||
grep -F "not executable" "$probe.err" >/dev/null
|
||||
|
||||
@@ -34,6 +34,19 @@ preflight_cache_dir="$build_dir/preflight-cache"
|
||||
./check-linuxcnc-inputs-cached.sh --cache-dir "$preflight_cache_dir" linuxcnc-rs274-source-files.txt --require-rs274-complete
|
||||
./check-linuxcnc-inputs-cached.sh --cache-dir "$preflight_cache_dir" linuxcnc-rs274-wasm-source-files.txt --require-rs274-complete
|
||||
./check-linuxcnc-inputs-cached.sh --cache-dir "$preflight_cache_dir" linuxcnc-kinematics-source-files.txt --require-kinematics-complete
|
||||
./check-linuxcnc-rs274-source-map.sh
|
||||
./check-linuxcnc-kinematics-source-map.sh
|
||||
./check-linuxcnc-opfs-source-map.sh
|
||||
./check-linuxcnc-switchkins-remap-source-map.sh
|
||||
./check-linuxcnc-wasm-smoke-source-map.sh
|
||||
./check-linuxcnc-build-source-map.sh
|
||||
./check-linuxcnc-browser-app-source-map.sh
|
||||
./check-linuxcnc-workstreams-source-map.sh
|
||||
./check-linuxcnc-tooldata-source-map.sh
|
||||
./check-linuxcnc-wasm-shims-source-map.sh
|
||||
./check-linuxcnc-wasm-blockers-source-map.sh
|
||||
CNC_SIM_PREFLIGHT_CACHE_DIR="$preflight_cache_dir" CNC_SIM_WASM_BLOCKERS_SELF_CHECKS=1 \
|
||||
./test-linuxcnc-wasm-blockers.sh linuxcnc-rs274-wasm-source-files.txt
|
||||
./check-linuxcnc-switchkins-remap-table-cached.sh --cache-dir "$preflight_cache_dir" linuxcnc-kinematics-source-files.txt
|
||||
grep -F 'tooldata:src/emc/tooldata/tooldata_nml.cc:NML tool table backend selected by LinuxCNC TOOL_NML_FLAG' linuxcnc-rs274-source-files.txt >/dev/null
|
||||
grep -F 'tooldata:src/emc/tooldata/tool_mmap_read.cc:LinuxCNC tooldata mmap reader utility source from tooldata Submakefile' linuxcnc-rs274-source-files.txt >/dev/null
|
||||
@@ -67,6 +80,7 @@ grep -F 'LinuxCNC source basis: this probe derives required Python C API exports
|
||||
grep -F 'LinuxCNC source basis: this probe compares wasm-safe tooldata runtime stubs' test-linuxcnc-wasm-tooldata-runtime-symbols.sh >/dev/null
|
||||
grep -F 'LinuxCNC source basis: the standalone probe links src/emc/rs274ngc/interp_base.cc' test-linuxcnc-wasm-interp-base-link.sh >/dev/null
|
||||
grep -F 'LinuxCNC source basis: src/emc/pythonplugin/python_plugin.cc and' test-linuxcnc-wasm-python-plugin-link.sh >/dev/null
|
||||
grep -F 'python-plugin-inittab-link' test-linuxcnc-wasm-python-plugin-link.sh >/dev/null
|
||||
grep -F 'LinuxCNC source basis: src/emc/rs274ngc/rs274ngc_pre.cc is compiled directly' test-linuxcnc-wasm-rs274ngc-pre-object.sh >/dev/null
|
||||
grep -F 'LinuxCNC source basis: src/emc/rs274ngc/rs274ngc_pre.cc provides the Interp' test-linuxcnc-wasm-rs274ngc-pre-link.sh >/dev/null
|
||||
grep -F 'LinuxCNC source basis: src/emc/rs274ngc/rs274ngc_pre.cc provides read()' test-linuxcnc-wasm-runtime-link.sh >/dev/null
|
||||
|
||||
@@ -160,6 +160,42 @@ for imported_module in (
|
||||
if f'from "{imported_module}"' not in opfs_workspace:
|
||||
print(f"browser smoke OPFS workspace module must import {imported_module}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
required_browser_sections = {
|
||||
"web/test-browser-wasm-smoke-linuxcnc-sections.js": (
|
||||
'runSection("linuxcnc browser basic parse"',
|
||||
'runSection("linuxcnc generated switchkins cases load"',
|
||||
'runSection("linuxcnc browser parse parameter scratch cleanup"',
|
||||
),
|
||||
"web/test-browser-wasm-smoke-opfs-basic-sections.js": (
|
||||
'runSection("opfs program parse and restore"',
|
||||
),
|
||||
"web/test-browser-wasm-smoke-opfs-parameter-sections.js": (
|
||||
'runSection("opfs parameter restore in new instance"',
|
||||
'runSection("opfs default parameter backup"',
|
||||
'runSection("opfs invalid parameter restore failures"',
|
||||
'runSection("opfs stale parameter state cleanup"',
|
||||
),
|
||||
"web/test-browser-wasm-smoke-opfs-directory-sections.js": (
|
||||
'runSection("opfs directory persist and load"',
|
||||
'runSection("opfs metadata queries avoid wasm mirror pollution"',
|
||||
),
|
||||
"web/test-browser-wasm-smoke-opfs-mirror-sections.js": (
|
||||
'runSection("opfs copy and move mirror files"',
|
||||
),
|
||||
"web/test-browser-wasm-smoke-opfs-policy-sections.js": (
|
||||
'runSection("browser opfs policy"',
|
||||
),
|
||||
"web/test-browser-wasm-smoke-app-sections.js": (
|
||||
'runSection("browser app opfs save"',
|
||||
'runSection("browser app opfs restore"',
|
||||
),
|
||||
}
|
||||
for section_module, required_sections in required_browser_sections.items():
|
||||
section_text = Path(section_module).read_text(encoding="utf-8")
|
||||
for required_section in required_sections:
|
||||
if required_section not in section_text:
|
||||
print(f"browser smoke module {section_module} missing required section {required_section}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
app_html = Path("web/index.html").read_text(encoding="utf-8")
|
||||
if '<link rel="stylesheet" href="/styles.css" />' not in app_html:
|
||||
print("browser app HTML must load /styles.css", file=sys.stderr)
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
G21
|
||||
F1
|
||||
G0 X0 Y0 Z0
|
||||
(Source basis: LinuxCNC src/emc/rs274ngc/rs274ngc_pre.cc applies CENTER_ARC_RADIUS_TOLERANCE_MM from INI before interp_arc.cc checks IJK radius mismatch.)
|
||||
G2 X2 Y0 I[1 - 0.0011]
|
||||
M2
|
||||
@@ -0,0 +1,4 @@
|
||||
G21 G90 G17
|
||||
G0 X0 Y0
|
||||
G93
|
||||
G2 X1 Y0 R0.5
|
||||
4
tests/gcode/linuxcnc_canned_cycle_cutter_comp_error.ngc
Normal file
4
tests/gcode/linuxcnc_canned_cycle_cutter_comp_error.ngc
Normal file
@@ -0,0 +1,4 @@
|
||||
G21 G90 G17
|
||||
F100
|
||||
G41.1 D1
|
||||
G81 X1 Z-1 R1
|
||||
4
tests/gcode/linuxcnc_canned_cycle_inverse_time_error.ngc
Normal file
4
tests/gcode/linuxcnc_canned_cycle_inverse_time_error.ngc
Normal file
@@ -0,0 +1,4 @@
|
||||
G21 G90 G17
|
||||
F100
|
||||
G93
|
||||
G81 X1 Z-1 R1
|
||||
@@ -1,4 +1,7 @@
|
||||
G21 G90 G17
|
||||
(operator note)
|
||||
G0 X0 Y0 Z1
|
||||
G0 X1 (inline motion note)
|
||||
G0 X2 ;semicolon motion note
|
||||
;standalone semicolon note
|
||||
M30
|
||||
|
||||
6
tests/gcode/linuxcnc_control_mode_tolerances.ngc
Normal file
6
tests/gcode/linuxcnc_control_mode_tolerances.ngc
Normal file
@@ -0,0 +1,6 @@
|
||||
G21 G90 G17
|
||||
G64 P0.05 Q0.02
|
||||
G64 P0.03
|
||||
G61
|
||||
G61.1
|
||||
M30
|
||||
@@ -1,5 +1,6 @@
|
||||
G21 G90 G17
|
||||
G0 X5 Y6 Z7
|
||||
G10 L20 P2 X1 Y2 Z3
|
||||
(Source basis: LinuxCNC src/emc/rs274ngc/interp_convert.cc convert_setup computes G10 L20 linear offsets for X/Y/Z/U/V/W from the current position.)
|
||||
G0 X5 Y6 Z7 U8 V9 W10
|
||||
G10 L20 P2 X1 Y2 Z3 U4 V5 W6
|
||||
G55
|
||||
M30
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
G21 G90 G17
|
||||
G10 L2 P1 X12.5 Y-3 Z4 R30
|
||||
G10 L2 P1 X12.5 Y-3 Z4 U7 V8 W9 R30
|
||||
G92 X1 Y2 Z3
|
||||
G92.1
|
||||
M30
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
G21 G90 G17
|
||||
(Source basis: LinuxCNC src/emc/rs274ngc/interp_convert.cc convert_setup maps G10 P0 to the active coordinate system and stores U/V/W through PROGRAM_TO_USER_LEN.)
|
||||
G55
|
||||
G10 L2 P0 X7 Y8 Z9
|
||||
G10 L2 P0 X7 Y8 Z9 U10 V11 W12
|
||||
M30
|
||||
|
||||
3
tests/gcode/linuxcnc_cutter_comp_axis_offset_error.ngc
Normal file
3
tests/gcode/linuxcnc_cutter_comp_axis_offset_error.ngc
Normal file
@@ -0,0 +1,3 @@
|
||||
G21 G90 G17
|
||||
G41 D1
|
||||
G92 X1
|
||||
3
tests/gcode/linuxcnc_cutter_comp_control_mode_error.ngc
Normal file
3
tests/gcode/linuxcnc_cutter_comp_control_mode_error.ngc
Normal file
@@ -0,0 +1,3 @@
|
||||
G21 G90 G17
|
||||
G41 D1
|
||||
G64
|
||||
@@ -0,0 +1,3 @@
|
||||
G21 G90 G17
|
||||
G41 D1
|
||||
G55
|
||||
3
tests/gcode/linuxcnc_cutter_comp_g53_error.ngc
Normal file
3
tests/gcode/linuxcnc_cutter_comp_g53_error.ngc
Normal file
@@ -0,0 +1,3 @@
|
||||
G21 G90 G17
|
||||
G41 D1
|
||||
G53 G0 X0
|
||||
3
tests/gcode/linuxcnc_cutter_comp_home_error.ngc
Normal file
3
tests/gcode/linuxcnc_cutter_comp_home_error.ngc
Normal file
@@ -0,0 +1,3 @@
|
||||
G21 G90 G17
|
||||
G41 D1
|
||||
G28
|
||||
3
tests/gcode/linuxcnc_cutter_comp_m48_error.ngc
Normal file
3
tests/gcode/linuxcnc_cutter_comp_m48_error.ngc
Normal file
@@ -0,0 +1,3 @@
|
||||
G21 G90 G17
|
||||
G41 D1
|
||||
M48
|
||||
3
tests/gcode/linuxcnc_cutter_comp_m49_error.ngc
Normal file
3
tests/gcode/linuxcnc_cutter_comp_m49_error.ngc
Normal file
@@ -0,0 +1,3 @@
|
||||
G21 G90 G17
|
||||
G41 D1
|
||||
M49
|
||||
3
tests/gcode/linuxcnc_cutter_comp_m50_disable_error.ngc
Normal file
3
tests/gcode/linuxcnc_cutter_comp_m50_disable_error.ngc
Normal file
@@ -0,0 +1,3 @@
|
||||
G21 G90 G17
|
||||
G41 D1
|
||||
M50 P0
|
||||
3
tests/gcode/linuxcnc_cutter_comp_m50_enable_error.ngc
Normal file
3
tests/gcode/linuxcnc_cutter_comp_m50_enable_error.ngc
Normal file
@@ -0,0 +1,3 @@
|
||||
G21 G90 G17
|
||||
G41 D1
|
||||
M50 P1
|
||||
3
tests/gcode/linuxcnc_cutter_comp_m51_disable_error.ngc
Normal file
3
tests/gcode/linuxcnc_cutter_comp_m51_disable_error.ngc
Normal file
@@ -0,0 +1,3 @@
|
||||
G21 G90 G17
|
||||
G41 D1
|
||||
M51 P0
|
||||
3
tests/gcode/linuxcnc_cutter_comp_m51_enable_error.ngc
Normal file
3
tests/gcode/linuxcnc_cutter_comp_m51_enable_error.ngc
Normal file
@@ -0,0 +1,3 @@
|
||||
G21 G90 G17
|
||||
G41 D1
|
||||
M51 P1
|
||||
3
tests/gcode/linuxcnc_cutter_comp_m52_disable_error.ngc
Normal file
3
tests/gcode/linuxcnc_cutter_comp_m52_disable_error.ngc
Normal file
@@ -0,0 +1,3 @@
|
||||
G21 G90 G17
|
||||
G41 D1
|
||||
M52 P0
|
||||
3
tests/gcode/linuxcnc_cutter_comp_m52_enable_error.ngc
Normal file
3
tests/gcode/linuxcnc_cutter_comp_m52_enable_error.ngc
Normal file
@@ -0,0 +1,3 @@
|
||||
G21 G90 G17
|
||||
G41 D1
|
||||
M52 P1
|
||||
3
tests/gcode/linuxcnc_cutter_comp_m53_disable_error.ngc
Normal file
3
tests/gcode/linuxcnc_cutter_comp_m53_disable_error.ngc
Normal file
@@ -0,0 +1,3 @@
|
||||
G21 G90 G17
|
||||
G41 D1
|
||||
M53 P0
|
||||
3
tests/gcode/linuxcnc_cutter_comp_m53_enable_error.ngc
Normal file
3
tests/gcode/linuxcnc_cutter_comp_m53_enable_error.ngc
Normal file
@@ -0,0 +1,3 @@
|
||||
G21 G90 G17
|
||||
G41 D1
|
||||
M53 P1
|
||||
3
tests/gcode/linuxcnc_cutter_comp_m63_error.ngc
Normal file
3
tests/gcode/linuxcnc_cutter_comp_m63_error.ngc
Normal file
@@ -0,0 +1,3 @@
|
||||
G21 G90 G17
|
||||
G41 D1
|
||||
M63 P1
|
||||
3
tests/gcode/linuxcnc_cutter_comp_m64_error.ngc
Normal file
3
tests/gcode/linuxcnc_cutter_comp_m64_error.ngc
Normal file
@@ -0,0 +1,3 @@
|
||||
G21 G90 G17
|
||||
G41 D1
|
||||
M64 P1
|
||||
3
tests/gcode/linuxcnc_cutter_comp_m65_error.ngc
Normal file
3
tests/gcode/linuxcnc_cutter_comp_m65_error.ngc
Normal file
@@ -0,0 +1,3 @@
|
||||
G21 G90 G17
|
||||
G41 D1
|
||||
M65 P1
|
||||
3
tests/gcode/linuxcnc_cutter_comp_m67_error.ngc
Normal file
3
tests/gcode/linuxcnc_cutter_comp_m67_error.ngc
Normal file
@@ -0,0 +1,3 @@
|
||||
G21 G90 G17
|
||||
G41 D1
|
||||
M67 E0 Q1
|
||||
3
tests/gcode/linuxcnc_cutter_comp_m68_error.ngc
Normal file
3
tests/gcode/linuxcnc_cutter_comp_m68_error.ngc
Normal file
@@ -0,0 +1,3 @@
|
||||
G21 G90 G17
|
||||
G41 D1
|
||||
M68 E0 Q1
|
||||
3
tests/gcode/linuxcnc_cutter_comp_plane_change_error.ngc
Normal file
3
tests/gcode/linuxcnc_cutter_comp_plane_change_error.ngc
Normal file
@@ -0,0 +1,3 @@
|
||||
G21 G90 G17
|
||||
G41 D1
|
||||
G18
|
||||
3
tests/gcode/linuxcnc_cutter_comp_tool_offset_error.ngc
Normal file
3
tests/gcode/linuxcnc_cutter_comp_tool_offset_error.ngc
Normal file
@@ -0,0 +1,3 @@
|
||||
G21 G90 G17
|
||||
G41 D1
|
||||
G43 H1
|
||||
@@ -0,0 +1,5 @@
|
||||
G21 G90
|
||||
(Source basis: LinuxCNC src/emc/rs274ngc/interp_read.cc rejects bare O-word definitions when DISABLE_FANUC_STYLE_SUB is enabled.)
|
||||
O100
|
||||
M99
|
||||
M30
|
||||
6
tests/gcode/linuxcnc_disable_fanuc_style_m98_error.ngc
Normal file
6
tests/gcode/linuxcnc_disable_fanuc_style_m98_error.ngc
Normal file
@@ -0,0 +1,6 @@
|
||||
G21 G90
|
||||
(Source basis: LinuxCNC src/emc/rs274ngc/interp_read.cc rejects M98 when DISABLE_FANUC_STYLE_SUB is enabled.)
|
||||
M98 P100
|
||||
M30
|
||||
O100
|
||||
M99
|
||||
7
tests/gcode/linuxcnc_disable_fanuc_style_m99_error.ngc
Normal file
7
tests/gcode/linuxcnc_disable_fanuc_style_m99_error.ngc
Normal file
@@ -0,0 +1,7 @@
|
||||
G21 G90
|
||||
(Source basis: LinuxCNC src/emc/rs274ngc/interp_read.cc rejects Fanuc-style M99 when DISABLE_FANUC_STYLE_SUB is enabled.)
|
||||
O100 sub
|
||||
M99
|
||||
O100 endsub
|
||||
O100 call
|
||||
M30
|
||||
2
tests/gcode/linuxcnc_disable_fanuc_style_sub.ini
Normal file
2
tests/gcode/linuxcnc_disable_fanuc_style_sub.ini
Normal file
@@ -0,0 +1,2 @@
|
||||
[RS274NGC]
|
||||
DISABLE_FANUC_STYLE_SUB = 1
|
||||
2
tests/gcode/linuxcnc_disable_g92_persistence.ini
Normal file
2
tests/gcode/linuxcnc_disable_g92_persistence.ini
Normal file
@@ -0,0 +1,2 @@
|
||||
[RS274NGC]
|
||||
DISABLE_G92_PERSISTENCE = 1
|
||||
3
tests/gcode/linuxcnc_g1_inverse_time_missing_f_error.ngc
Normal file
3
tests/gcode/linuxcnc_g1_inverse_time_missing_f_error.ngc
Normal file
@@ -0,0 +1,3 @@
|
||||
G21 G90
|
||||
G93
|
||||
G1 X1
|
||||
2
tests/gcode/linuxcnc_g1_zero_feed_error.ngc
Normal file
2
tests/gcode/linuxcnc_g1_zero_feed_error.ngc
Normal file
@@ -0,0 +1,2 @@
|
||||
G21 G90
|
||||
G1 X1
|
||||
@@ -1,6 +1,7 @@
|
||||
G21 G90 G17
|
||||
G52 X1 Y2
|
||||
G52 Y3
|
||||
(Source basis: LinuxCNC src/emc/rs274ngc/interp_convert.cc convert_axis_offsets treats G52 offsets as sticky per-axis values, including U/V/W, and G92.2/G92.3 suspend and restore #5211-#5219.)
|
||||
G52 X1 Y2 U4 V5
|
||||
G52 Y3 V6
|
||||
G92.2
|
||||
G92.3
|
||||
G92.1
|
||||
|
||||
3
tests/gcode/linuxcnc_g53_non_g52_motion_error.ngc
Normal file
3
tests/gcode/linuxcnc_g53_non_g52_motion_error.ngc
Normal file
@@ -0,0 +1,3 @@
|
||||
G21 G90 G17
|
||||
F100
|
||||
G5.3 G1 X1
|
||||
3
tests/gcode/linuxcnc_g64_default_tolerances.ini
Normal file
3
tests/gcode/linuxcnc_g64_default_tolerances.ini
Normal file
@@ -0,0 +1,3 @@
|
||||
[RS274NGC]
|
||||
G64_DEFAULT_TOLERANCE = 0.07
|
||||
G64_DEFAULT_NAIVETOLERANCE = 0.04
|
||||
4
tests/gcode/linuxcnc_g64_default_tolerances.ngc
Normal file
4
tests/gcode/linuxcnc_g64_default_tolerances.ngc
Normal file
@@ -0,0 +1,4 @@
|
||||
G21 G90 G17
|
||||
(Source basis: LinuxCNC src/emc/rs274ngc/rs274ngc_pre.cc reads G64_DEFAULT_TOLERANCE and G64_DEFAULT_NAIVETOLERANCE for G64 without P/Q.)
|
||||
G64
|
||||
M30
|
||||
7
tests/gcode/linuxcnc_g92_disable_persistence_check.ngc
Normal file
7
tests/gcode/linuxcnc_g92_disable_persistence_check.ngc
Normal file
@@ -0,0 +1,7 @@
|
||||
G21 G90 G17
|
||||
F100
|
||||
(Source basis: LinuxCNC src/emc/rs274ngc/interp_convert.cc convert_stop clears persisted G92/G52 parameters on program end.)
|
||||
O10 if [[#5210 EQ 0] AND [#5211 EQ 0] AND [#5212 EQ 0] AND [#5213 EQ 0]]
|
||||
G1 X1
|
||||
O10 endif
|
||||
M30
|
||||
4
tests/gcode/linuxcnc_g92_disable_persistence_set.ngc
Normal file
4
tests/gcode/linuxcnc_g92_disable_persistence_set.ngc
Normal file
@@ -0,0 +1,4 @@
|
||||
G21 G90 G17
|
||||
(Source basis: LinuxCNC src/emc/rs274ngc/interp_convert.cc convert_stop clears #5210-#5219 when DISABLE_G92_PERSISTENCE is enabled.)
|
||||
G92 X4 Y5 Z6
|
||||
M30
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user