Compare commits

...

6 Commits

Author SHA1 Message Date
cnc
40a63c76f7 高效率推进 LinuxCNC 源码对齐流程
说明:集中 LinuxCNC 源码清单与 wasm/native probe 的路径解析,补强 manifest、shim、source-link 检查,并保持 LinuxCNC 源码后端对齐验证流程可复用。

验证:./test-native.sh;./test-linuxcnc-source-link.sh;./test-all-native.sh;wasm source/probe 相关脚本。
2026-05-27 11:14:06 +08:00
cnc
ce2f3f3769 Harden LinuxCNC wasm and native probe workflows 2026-05-26 17:00:58 +08:00
cnc
86734622d7 对齐 LinuxCNC NURBS 事件行号 2026-05-24 22:02:46 +08:00
cnc
dd4b7d9314 覆盖 LinuxCNC G6.2 XZ NURBS 映射 2026-05-24 21:55:45 +08:00
cnc
efc92d0380 修正 LinuxCNC NURBS 平面映射 2026-05-24 21:52:21 +08:00
cnc
b4861fd618 对齐 LinuxCNC 解释器行为覆盖 2026-05-24 21:47:29 +08:00
176 changed files with 17939 additions and 1016 deletions

152
analyze-linuxcnc-wasm-blockers.sh Executable file
View File

@@ -0,0 +1,152 @@
#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$0")"
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
manifest=${1:-linuxcnc-rs274-wasm-source-files.txt}
if [[ ! -f "$manifest" ]]; then
echo "missing manifest: $manifest" >&2
exit 1
fi
if [[ ! -d "$linuxcnc_root" ]]; then
echo "missing LinuxCNC root: $linuxcnc_root" >&2
exit 1
fi
python_blockers=()
core_python_sources=()
dlopen_blockers=()
core_dlopen_sources=()
tooldata_blockers=()
core_tooldata_sources=()
shimmed_tooldata_users=()
core_tooldata_users=()
native_backend_blockers=()
native_fs_blockers=()
core_native_fs_sources=()
core_count=0
blocked_count=0
blocked_replacements=()
core_source_list=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_wasm_blocker_core_sources.XXXXXX.txt")
blocked_source_list=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_wasm_blocker_blocked_sources.XXXXXX.txt")
trap 'rm -f "$core_source_list" "$blocked_source_list"' EXIT
blocked_replacement_for() {
case "$1" in
src/emc/tooldata/tooldata_mmap.cc)
./list-linuxcnc-wasm-safe-shims.sh tooldata_mmap_backend.cc
;;
*)
return 1
;;
esac
}
./list-linuxcnc-wasm-manifest-sources.sh "$manifest" core > "$core_source_list"
./list-linuxcnc-wasm-manifest-sources.sh "$manifest" blocked > "$blocked_source_list"
core_count=$(wc -l < "$core_source_list")
blocked_count=$(wc -l < "$blocked_source_list")
scan_source() {
local group=$1
local path=$2
full_path="$linuxcnc_root/$path"
if [[ "$group" == "blocked" ]]; then
if ! replacement=$(blocked_replacement_for "$path"); then
echo "missing blocked replacement mapping: $path" >&2
exit 1
fi
if [[ ! -f "$replacement" ]]; then
echo "missing blocked replacement source: $replacement" >&2
exit 1
fi
blocked_replacements+=("$path -> $replacement")
fi
if [[ "$path" == src/emc/tooldata/* ]]; then
if [[ "$group" == "blocked" ]]; then
tooldata_blockers+=("$path")
else
core_tooldata_sources+=("$path")
fi
fi
if [[ "$path" == "src/emc/tooldata/tooldata_mmap.cc" ]]; then
native_backend_blockers+=("$path")
fi
if grep -Eq 'Python\.h|boost/python|pythonplugin|PyObject|PyInit_' "$full_path"; then
if [[ "$group" == "blocked" ]]; then
python_blockers+=("$path")
else
core_python_sources+=("$path")
fi
fi
if grep -Eq 'dlopen|dlsym|RTLD_' "$full_path"; then
if [[ "$group" == "blocked" ]]; then
dlopen_blockers+=("$path")
else
core_dlopen_sources+=("$path")
fi
fi
if grep -Eq 'mkstemp|mkstemps|dirent\.h|opendir|readdir|unistd\.h' "$full_path"; then
if [[ "$group" == "blocked" ]]; then
native_fs_blockers+=("$path")
else
core_native_fs_sources+=("$path")
fi
fi
if [[ "$path" != src/emc/tooldata/* ]] && grep -Eq 'tooldata/tooldata.hh|tooldata_' "$full_path"; then
if [[ "$group" == "blocked" ]]; then
shimmed_tooldata_users+=("$path")
else
core_tooldata_users+=("$path")
fi
fi
}
while IFS= read -r path; do
[[ -z "$path" ]] && continue
scan_source core "$path"
done < "$core_source_list"
while IFS= read -r path; do
[[ -z "$path" ]] && continue
scan_source blocked "$path"
done < "$blocked_source_list"
print_group() {
local title=$1
shift
echo "[$title]"
if [[ $# -eq 0 ]]; then
echo "(none)"
else
printf '%s\n' "$@" | LC_ALL=C sort -u
fi
echo
}
echo "[manifest]"
echo "core=$core_count"
echo "blocked=$blocked_count"
echo
print_group "python" "${python_blockers[@]}"
print_group "dlopen" "${dlopen_blockers[@]}"
print_group "tooldata" "${tooldata_blockers[@]}"
print_group "tooldata-users" "${shimmed_tooldata_users[@]}"
print_group "native-backend" "${native_backend_blockers[@]}"
print_group "native-fs" "${native_fs_blockers[@]}"
print_group "blocked-replacements" "${blocked_replacements[@]}"
print_group "core-python-shimmed" "${core_python_sources[@]}"
print_group "core-dlopen-shimmed" "${core_dlopen_sources[@]}"
print_group "core-tooldata-shimmed" "${core_tooldata_sources[@]}"
print_group "core-tooldata-users-shimmed" "${core_tooldata_users[@]}"
print_group "core-native-fs-shimmed" "${core_native_fs_sources[@]}"

View File

@@ -3,12 +3,97 @@ set -euo pipefail
cd "$(dirname "$0")"
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
manifest=${1:-linuxcnc-rs274-wasm-source-files.txt}
if [[ ! -f "$manifest" ]]; then
echo "missing manifest: $manifest" >&2
exit 1
fi
if [[ ! -d "$linuxcnc_root" ]]; then
echo "missing LinuxCNC root: $linuxcnc_root" >&2
exit 1
fi
manifest=$(cd "$(dirname "$manifest")" && pwd)/$(basename "$manifest")
linuxcnc_root=$(cd "$linuxcnc_root" && pwd)
default_manifest="$PWD/linuxcnc-rs274-wasm-source-files.txt"
# This script writes fixed build and public artifact paths, so serialize it.
exec 9>"${TMPDIR:-/tmp}/cnc_sim_build_wasm.lock"
flock 9
manifest_core_count=0
manifest_blocked_count=0
manifest_core_sources=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_wasm_manifest_core.XXXXXX.txt")
manifest_blocked_sources=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_wasm_manifest_blocked.XXXXXX.txt")
trap 'rm -f "$manifest_core_sources" "$manifest_blocked_sources"' EXIT
LINUXCNC_ROOT="$linuxcnc_root" ./list-linuxcnc-wasm-manifest-sources.sh "$manifest" core > "$manifest_core_sources"
LINUXCNC_ROOT="$linuxcnc_root" ./list-linuxcnc-wasm-manifest-sources.sh "$manifest" blocked > "$manifest_blocked_sources"
manifest_core_count=$(wc -l < "$manifest_core_sources")
manifest_blocked_count=$(wc -l < "$manifest_blocked_sources")
if [[ "$manifest_core_count" -eq 0 || "$manifest_blocked_count" -eq 0 ]]; then
echo "unexpected wasm manifest partition: core=$manifest_core_count blocked=$manifest_blocked_count" >&2
exit 1
fi
if [[ "$manifest" == "$default_manifest" ]] && [[ "$manifest_core_count" -ne 25 || "$manifest_blocked_count" -ne 1 ]]; then
echo "unexpected wasm manifest partition: core=$manifest_core_count blocked=$manifest_blocked_count" >&2
exit 1
fi
echo "LinuxCNC wasm blocker scan"
./test-linuxcnc-wasm-blockers.sh "$manifest"
echo "LinuxCNC wasm-safe source syntax probe"
./test-linuxcnc-wasm-source-syntax.sh "$manifest"
echo "LinuxCNC wasm-safe source object probe"
./test-linuxcnc-wasm-source-objects.sh "$manifest"
echo "LinuxCNC wasm-safe CMake probe target"
./test-linuxcnc-wasm-cmake-safe-probe.sh "$manifest"
echo "LinuxCNC wasm tooldata shim link probe"
./test-linuxcnc-wasm-tooldata-link.sh
echo "LinuxCNC wasm tooldata_common link probe"
./test-linuxcnc-wasm-tooldata-common-link.sh
echo "LinuxCNC wasm tooldata_mmap symbol probe"
./test-linuxcnc-wasm-tooldata-mmap-symbols.sh
echo "LinuxCNC wasm tooldata runtime symbol probe"
./test-linuxcnc-wasm-tooldata-runtime-symbols.sh
echo "LinuxCNC wasm interp_base link probe"
./test-linuxcnc-wasm-interp-base-link.sh
echo "LinuxCNC wasm interp_find link probe"
./test-linuxcnc-wasm-interp-find-link.sh
echo "LinuxCNC wasm python_plugin link probe"
./test-linuxcnc-wasm-python-plugin-link.sh
echo "LinuxCNC wasm rs274ngc_pre object probe"
./test-linuxcnc-wasm-rs274ngc-pre-object.sh
echo "LinuxCNC wasm rs274ngc_pre link blocker scan"
./test-linuxcnc-wasm-rs274ngc-pre-link-blockers.sh "$manifest"
echo "LinuxCNC wasm rs274ngc_pre link probe"
./test-linuxcnc-wasm-rs274ngc-pre-link.sh "$manifest"
if ! command -v emcmake >/dev/null 2>&1; then
echo "Emscripten is required. Install/activate emsdk so emcmake and emcc are in PATH." >&2
exit 1
fi
emcmake cmake -S core -B build/wasm -DCMAKE_BUILD_TYPE=Release
emcmake cmake -S core -B build/wasm \
-DCMAKE_BUILD_TYPE=Release \
-DCNC_SIM_LINUXCNC_ROOT="$linuxcnc_root" \
-DCNC_SIM_LINUXCNC_WASM_SOURCE_MANIFEST="$manifest" \
-DCNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE=ON
cmake --build build/wasm
mkdir -p web/public

View File

@@ -3,7 +3,13 @@ project(cnc_sim_wasm_core LANGUAGES CXX)
option(CNC_SIM_ENABLE_LINUXCNC_BRIDGE "Build the experimental LinuxCNC canon bridge" OFF)
option(CNC_SIM_ENABLE_LINUXCNC_RS274_BACKEND "Build the native LinuxCNC librs274 backend" OFF)
option(CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE "Compile the browser-safe subset of LinuxCNC rs274 sources" OFF)
set(CNC_SIM_LINUXCNC_ROOT "" CACHE PATH "LinuxCNC source root for the experimental bridge")
set(CNC_SIM_LINUXCNC_WASM_SOURCE_MANIFEST
"${CMAKE_CURRENT_SOURCE_DIR}/../linuxcnc-rs274-wasm-source-files.txt"
CACHE FILEPATH
"Manifest that partitions LinuxCNC rs274 sources into wasm-safe core and blocked groups"
)
set(cnc_sim_core_sources
src/canon_event_sink.cpp
@@ -28,6 +34,137 @@ if(CNC_SIM_ENABLE_LINUXCNC_RS274_BACKEND)
)
endif()
if(CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE)
if(NOT CNC_SIM_LINUXCNC_ROOT)
message(FATAL_ERROR "Set CNC_SIM_LINUXCNC_ROOT to the LinuxCNC source root")
endif()
get_filename_component(CNC_SIM_LINUXCNC_ROOT_ABS
"${CNC_SIM_LINUXCNC_ROOT}"
ABSOLUTE
BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/.."
)
if(NOT IS_DIRECTORY "${CNC_SIM_LINUXCNC_ROOT_ABS}")
message(FATAL_ERROR "LinuxCNC source root does not exist: ${CNC_SIM_LINUXCNC_ROOT_ABS}")
endif()
if(NOT EXISTS "${CNC_SIM_LINUXCNC_WASM_SOURCE_MANIFEST}")
message(FATAL_ERROR "Missing LinuxCNC wasm source manifest: ${CNC_SIM_LINUXCNC_WASM_SOURCE_MANIFEST}")
endif()
if(IS_DIRECTORY "${CNC_SIM_LINUXCNC_WASM_SOURCE_MANIFEST}")
message(FATAL_ERROR "LinuxCNC wasm source manifest is not a file: ${CNC_SIM_LINUXCNC_WASM_SOURCE_MANIFEST}")
endif()
set(linuxcnc_wasm_safe_probe_sources)
set(linuxcnc_wasm_blocked_sources)
file(STRINGS "${CNC_SIM_LINUXCNC_WASM_SOURCE_MANIFEST}" linuxcnc_wasm_manifest_lines)
foreach(manifest_line IN LISTS linuxcnc_wasm_manifest_lines)
string(STRIP "${manifest_line}" manifest_line)
if(manifest_line STREQUAL "" OR manifest_line MATCHES "^#")
continue()
endif()
if(NOT manifest_line MATCHES "^([^:]+):([^:]+):(.*)$")
message(FATAL_ERROR "Bad LinuxCNC wasm source manifest line: ${manifest_line}")
endif()
set(manifest_group "${CMAKE_MATCH_1}")
set(manifest_path "${CMAKE_MATCH_2}")
if(NOT manifest_group STREQUAL "core" AND NOT manifest_group STREQUAL "blocked")
message(FATAL_ERROR "Unknown LinuxCNC wasm source manifest group: ${manifest_group}")
endif()
set(manifest_source "${CNC_SIM_LINUXCNC_ROOT_ABS}/${manifest_path}")
if(NOT EXISTS "${manifest_source}")
message(FATAL_ERROR "LinuxCNC wasm manifest source does not exist: ${manifest_source}")
endif()
if(IS_DIRECTORY "${manifest_source}")
message(FATAL_ERROR "LinuxCNC wasm manifest source is not a file: ${manifest_source}")
endif()
if(manifest_group STREQUAL "core")
list(APPEND linuxcnc_wasm_safe_probe_sources "${manifest_source}")
else()
list(APPEND linuxcnc_wasm_blocked_sources "${manifest_source}")
endif()
endforeach()
list(LENGTH linuxcnc_wasm_safe_probe_sources linuxcnc_wasm_safe_probe_source_count)
list(LENGTH linuxcnc_wasm_blocked_sources linuxcnc_wasm_blocked_source_count)
if(linuxcnc_wasm_safe_probe_source_count EQUAL 0)
message(FATAL_ERROR "LinuxCNC wasm source manifest has no core entries")
endif()
if(linuxcnc_wasm_blocked_source_count EQUAL 0)
message(FATAL_ERROR "LinuxCNC wasm source manifest has no blocked entries")
endif()
message(STATUS "LinuxCNC wasm-safe core sources: ${linuxcnc_wasm_safe_probe_source_count}")
message(STATUS "LinuxCNC wasm blocked sources: ${linuxcnc_wasm_blocked_source_count}")
set(linuxcnc_wasm_safe_probe_shims
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims/dlfcn.cc
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims/emc_status_shim.cc
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims/gettext_shim.cc
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims/linuxcnc_runtime_shim.cc
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims/python_c_api_shim.cc
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims/rtapi_compat.cc
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims/tooldata/tooldata_mmap_backend.cc
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims/tooldata/tooldata_runtime_stubs.cc
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims/pythonplugin/python_plugin.cc
)
add_library(linuxcnc_rs274_wasm_safe_probe_objects OBJECT
${linuxcnc_wasm_safe_probe_shims}
${linuxcnc_wasm_safe_probe_sources}
)
target_compile_features(linuxcnc_rs274_wasm_safe_probe_objects PUBLIC cxx_std_20)
target_compile_definitions(linuxcnc_rs274_wasm_safe_probe_objects PRIVATE ULAPI)
target_compile_options(linuxcnc_rs274_wasm_safe_probe_objects PRIVATE -include wctype.h)
target_include_directories(linuxcnc_rs274_wasm_safe_probe_objects
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/src
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims
${CNC_SIM_LINUXCNC_ROOT_ABS}/src
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc/nml_intf
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc/rs274ngc
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc/motion
${CNC_SIM_LINUXCNC_ROOT_ABS}/include
)
set(linuxcnc_rs274_wasm_safe_probe_project_sources
${CMAKE_CURRENT_SOURCE_DIR}/src/canon_event_sink.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_canon_bridge.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_tooldata_fixture.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/rtcp_kinematics.cpp
)
add_executable(linuxcnc_rs274_wasm_safe_probe EXCLUDE_FROM_ALL
$<TARGET_OBJECTS:linuxcnc_rs274_wasm_safe_probe_objects>
${linuxcnc_rs274_wasm_safe_probe_project_sources}
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims/rs274ngc_pre_probe_main.cc
)
target_compile_features(linuxcnc_rs274_wasm_safe_probe PRIVATE cxx_std_20)
target_compile_definitions(linuxcnc_rs274_wasm_safe_probe PRIVATE ULAPI)
target_compile_options(linuxcnc_rs274_wasm_safe_probe PRIVATE -include wctype.h)
target_include_directories(linuxcnc_rs274_wasm_safe_probe
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/src
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims
${CNC_SIM_LINUXCNC_ROOT_ABS}/src
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc/nml_intf
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc/rs274ngc
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc/motion
${CNC_SIM_LINUXCNC_ROOT_ABS}/include
)
target_link_libraries(linuxcnc_rs274_wasm_safe_probe PRIVATE fmt)
if(linuxcnc_wasm_blocked_sources)
add_custom_target(linuxcnc_rs274_wasm_blocked_sources
SOURCES ${linuxcnc_wasm_blocked_sources}
)
endif()
endif()
add_library(cnc_sim_objects OBJECT
${cnc_sim_core_sources}
)
@@ -106,6 +243,11 @@ if(NOT EMSCRIPTEN)
target_link_libraries(rtcp_kinematics_smoke PRIVATE cnc_sim_core)
target_include_directories(rtcp_kinematics_smoke PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
add_executable(linuxcnc_gees_table_smoke
tests/linuxcnc_gees_table_smoke.cpp
)
target_include_directories(linuxcnc_gees_table_smoke PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
add_executable(simulator_gcode_controls_smoke
tests/simulator_gcode_controls_smoke.cpp
)

View File

@@ -1,7 +1,23 @@
#include "canon_event_sink.h"
#include <cmath>
#include "rtcp_kinematics.h"
namespace {
void rotate_xy(double *x, double *y, double degrees) {
const double radians = degrees * std::acos(-1.0) / 180.0;
const double c = std::cos(radians);
const double s = std::sin(radians);
const double nx = *x * c - *y * s;
const double ny = *x * s + *y * c;
*x = nx;
*y = ny;
}
} // namespace
void CanonEventSink::reset() {
position_ = {};
plane_ = 17;
@@ -14,6 +30,7 @@ void CanonEventSink::reset() {
probe_position_ = {};
probe_tripped_ = false;
tool_length_offset_ = {};
xy_rotation_degrees_ = 0.0;
callback_status_ = 0;
kinematics_type_ = 1;
feed_override_ = false;
@@ -22,6 +39,8 @@ void CanonEventSink::reset() {
feed_hold_ = false;
mist_on_ = false;
flood_on_ = false;
has_pending_motion_start_ = false;
pending_motion_start_ = {};
}
void CanonEventSink::set_callback(CncSimEventCallback callback, void *user_data) {
@@ -38,6 +57,10 @@ bool CanonEventSink::callback_aborted() const {
return callback_status_ != 0;
}
void CanonEventSink::set_block_delete(bool enabled) {
block_delete_ = enabled;
}
void CanonEventSink::configure_rtcp(bool enabled, double tool_length) {
rtcp_enabled_ = enabled;
default_rtcp_tool_length_ = tool_length;
@@ -62,6 +85,26 @@ void CanonEventSink::set_tool_length_offset(const CncSimPose &offset) {
tool_length_offset_ = offset;
}
void CanonEventSink::apply_tool_length_offset(const CncSimPose &offset) {
if (!has_pending_motion_start_) {
pending_motion_start_ = position_;
has_pending_motion_start_ = true;
}
double dx = tool_length_offset_.x - offset.x;
double dy = tool_length_offset_.y - offset.y;
rotate_xy(&dx, &dy, -xy_rotation_degrees_);
position_.x += dx;
position_.y += dy;
position_.z += tool_length_offset_.z - offset.z;
position_.a += tool_length_offset_.a - offset.a;
position_.b += tool_length_offset_.b - offset.b;
position_.c += tool_length_offset_.c - offset.c;
position_.u += tool_length_offset_.u - offset.u;
position_.v += tool_length_offset_.v - offset.v;
position_.w += tool_length_offset_.w - offset.w;
tool_length_offset_ = offset;
}
void CanonEventSink::set_rtcp_state(bool enabled, int h_code, int line) {
rtcp_enabled_ = enabled;
rtcp_h_code_ = enabled ? h_code : 0;
@@ -99,6 +142,7 @@ void CanonEventSink::set_g92_offset(const CncSimPose &offset, int line) {
}
void CanonEventSink::set_xy_rotation(double angle_degrees, int line) {
xy_rotation_degrees_ = angle_degrees;
CncSimEvent event = base_event(CNC_SIM_EVENT_SET_XY_ROTATION, line);
event.feed = angle_degrees;
emit(event);
@@ -138,8 +182,13 @@ void CanonEventSink::set_feed_mode(int spindle, int mode, int line) {
}
void CanonEventSink::set_spindle_speed(double spindle, int line) {
spindle_ = spindle;
set_spindle_speed(0, spindle, line);
}
void CanonEventSink::set_spindle_speed(int spindle, double speed, int line) {
spindle_ = speed;
CncSimEvent event = base_event(CNC_SIM_EVENT_SET_SPINDLE, line);
event.tool = spindle;
event.spindle = spindle_;
event.reserved = spindle_direction_;
emit(event);
@@ -229,16 +278,26 @@ void CanonEventSink::set_override_control(int control, bool enabled, int spindle
}
void CanonEventSink::start_spindle(int direction, int line) {
start_spindle(0, direction, line);
}
void CanonEventSink::start_spindle(int spindle, int direction, int line) {
spindle_direction_ = direction < 0 ? 2 : 1;
CncSimEvent event = base_event(CNC_SIM_EVENT_SET_SPINDLE, line);
event.tool = spindle;
event.spindle = spindle_;
event.reserved = spindle_direction_;
emit(event);
}
void CanonEventSink::stop_spindle(int line) {
stop_spindle(0, line);
}
void CanonEventSink::stop_spindle(int spindle, int line) {
spindle_direction_ = 0;
CncSimEvent event = base_event(CNC_SIM_EVENT_SET_SPINDLE, line);
event.tool = spindle;
event.spindle = 0.0;
event.reserved = spindle_direction_;
emit(event);
@@ -256,41 +315,45 @@ void CanonEventSink::change_tool(int line) {
void CanonEventSink::straight_traverse(int line, const CncSimPose &end) {
CncSimEvent event = base_event(CNC_SIM_EVENT_RAPID, line);
event.start = position_;
event.start = has_pending_motion_start_ ? pending_motion_start_ : position_;
event.end = end;
emit(event);
emit_rtcp_pivot(line, position_, end);
emit_rtcp_pivot(line, event.start, end);
has_pending_motion_start_ = false;
position_ = end;
}
void CanonEventSink::straight_feed(int line, const CncSimPose &end) {
CncSimEvent event = base_event(CNC_SIM_EVENT_LINEAR_FEED, line);
event.start = position_;
event.start = has_pending_motion_start_ ? pending_motion_start_ : position_;
event.end = end;
emit(event);
emit_rtcp_pivot(line, position_, end);
emit_rtcp_pivot(line, event.start, end);
has_pending_motion_start_ = false;
position_ = end;
}
void CanonEventSink::arc_feed(int line, const CncSimPose &end, const CncSimPose &center, int turns) {
CncSimEvent event = base_event(CNC_SIM_EVENT_ARC_FEED, line);
event.start = position_;
event.start = has_pending_motion_start_ ? pending_motion_start_ : position_;
event.end = end;
event.center = center;
event.arc_turns = turns;
emit(event);
emit_rtcp_pivot(line, position_, end);
emit_rtcp_pivot(line, event.start, end);
has_pending_motion_start_ = false;
position_ = end;
}
void CanonEventSink::straight_probe(int line, const CncSimPose &end, int probe_type) {
CncSimEvent event = base_event(CNC_SIM_EVENT_PROBE, line);
event.start = position_;
event.start = has_pending_motion_start_ ? pending_motion_start_ : position_;
event.end = end;
event.reserved = probe_type;
emit(event);
probe_position_ = end;
probe_tripped_ = (probe_type & 2) == 0;
has_pending_motion_start_ = false;
position_ = end;
}
@@ -397,6 +460,10 @@ bool CanonEventSink::flood_on() const {
return flood_on_;
}
bool CanonEventSink::block_delete() const {
return block_delete_;
}
void CanonEventSink::set_mist_on(bool enabled) {
mist_on_ = enabled;
}

View File

@@ -10,9 +10,11 @@ public:
void set_callback(CncSimEventCallback callback, void *user_data);
void clear_callback_status();
bool callback_aborted() const;
void set_block_delete(bool enabled);
void configure_rtcp(bool enabled, double tool_length);
void set_tool_length(int h_code, double tool_length);
void set_tool_length_offset(const CncSimPose &offset);
void apply_tool_length_offset(const CncSimPose &offset);
void set_rtcp_state(bool enabled, int h_code, int line);
void switch_kinematics(int kinematics_type, bool rtcp_enabled, int line);
void set_g5x_offset(int index, const CncSimPose &offset, int line);
@@ -25,6 +27,7 @@ public:
void set_feed_rate(double feed, int line);
void set_feed_mode(int spindle, int mode, int line);
void set_spindle_speed(double spindle, int line);
void set_spindle_speed(int spindle, double speed, int line);
void set_spindle_mode(int spindle, double mode, int line);
void set_speed_feed_sync(int spindle, double feed_per_revolution, bool velocity_mode, bool enabled, int line);
void orient_spindle(int spindle, double orientation, int mode, int line);
@@ -34,7 +37,9 @@ public:
void wait_input(int index, int input_type, int wait_type, double timeout, int line);
void set_override_control(int control, bool enabled, int spindle, int line);
void start_spindle(int direction, int line);
void start_spindle(int spindle, int direction, int line);
void stop_spindle(int line);
void stop_spindle(int spindle, int line);
void select_tool(int tool);
void change_tool(int line);
void straight_traverse(int line, const CncSimPose &end);
@@ -66,6 +71,7 @@ public:
bool feed_hold() const;
bool mist_on() const;
bool flood_on() const;
bool block_delete() const;
void set_mist_on(bool enabled);
void set_flood_on(bool enabled);
@@ -92,6 +98,7 @@ private:
double rtcp_tool_length_ = 0.0;
int rtcp_h_code_ = 0;
CncSimPose tool_length_offset_{};
double xy_rotation_degrees_ = 0.0;
int kinematics_type_ = 1;
bool feed_override_ = false;
bool speed_override_ = false;
@@ -99,5 +106,8 @@ private:
bool feed_hold_ = false;
bool mist_on_ = false;
bool flood_on_ = false;
bool block_delete_ = false;
std::unordered_map<int, double> tool_lengths_;
bool has_pending_motion_start_ = false;
CncSimPose pending_motion_start_{};
};

View File

@@ -152,6 +152,11 @@ int apply_config(CncSimHandle *handle, const std::string &json) {
if (has_rtcp_enabled || has_tool_length) {
handle->sink.configure_rtcp(rtcp_enabled, tool_length);
}
bool block_delete = false;
if (contains_bool_value(compact, "blockdelete", &block_delete) ||
contains_bool_value(compact, "block_delete", &block_delete)) {
handle->sink.set_block_delete(block_delete);
}
apply_tool_length_table(handle->sink, compact);
return 0;
}

View File

@@ -50,6 +50,12 @@ int plane_to_g_code(CANON_PLANE plane) {
return 18;
case CANON_PLANE::YZ:
return 19;
case CANON_PLANE::UV:
return 171;
case CANON_PLANE::UW:
return 181;
case CANON_PLANE::VW:
return 191;
default:
return 17;
}
@@ -73,6 +79,12 @@ CANON_PLANE g_code_to_plane(int plane) {
return CANON_PLANE::XZ;
case 19:
return CANON_PLANE::YZ;
case 171:
return CANON_PLANE::UV;
case 181:
return CANON_PLANE::UW;
case 191:
return CANON_PLANE::VW;
case 17:
default:
return CANON_PLANE::XY;
@@ -84,6 +96,27 @@ const CncSimPose &current_position() {
return active_sink ? active_sink->position() : zero;
}
template <typename NurbsPoint>
CncSimPose nurbs_plane_point_to_pose(const NurbsPoint &point, CANON_PLANE plane) {
CncSimPose end = current_position();
switch (plane) {
case CANON_PLANE::YZ:
end.y = point.NURBS_X;
end.z = point.NURBS_Y;
break;
case CANON_PLANE::XZ:
end.x = point.NURBS_Y;
end.z = point.NURBS_X;
break;
case CANON_PLANE::XY:
default:
end.x = point.NURBS_X;
end.y = point.NURBS_Y;
break;
}
return end;
}
void trace_call(const char *name) {
if (std::getenv("CNC_SIM_TRACE_CANON")) {
std::fprintf(stderr, "canon:%s\n", name);
@@ -373,27 +406,21 @@ void STOP_SPEED_FEED_SYNCH() {
}
}
void NURBS_G5_FEED(int lineno, const std::vector<NURBS_CONTROL_POINT> &points, unsigned int, CANON_PLANE) {
void NURBS_G5_FEED(int lineno, const std::vector<NURBS_CONTROL_POINT> &points, unsigned int, CANON_PLANE plane) {
if (!active_sink) {
return;
}
for (const auto &point : points) {
CncSimPose end = active_sink->position();
end.x = point.NURBS_X;
end.y = point.NURBS_Y;
active_sink->straight_feed(lineno, end);
active_sink->straight_feed(event_line(lineno), nurbs_plane_point_to_pose(point, plane));
}
}
void NURBS_G6_FEED(int lineno, const std::vector<NURBS_G6_CONTROL_POINT> &points, unsigned int, double, int, CANON_PLANE) {
void NURBS_G6_FEED(int lineno, const std::vector<NURBS_G6_CONTROL_POINT> &points, unsigned int, double, int, CANON_PLANE plane) {
if (!active_sink) {
return;
}
for (const auto &point : points) {
CncSimPose end = active_sink->position();
end.x = point.NURBS_X;
end.y = point.NURBS_Y;
active_sink->straight_feed(lineno, end);
active_sink->straight_feed(event_line(lineno), nurbs_plane_point_to_pose(point, plane));
}
}

View File

@@ -77,8 +77,12 @@ bool write_temp_program(const char *program,
size_t program_len,
std::string *path,
std::string *error) {
char tmpl[] = "/tmp/cnc_sim_api_XXXXXX.ngc";
const int fd = mkstemps(tmpl, 4);
const char *tmpdir = std::getenv("TMPDIR");
std::string tmpl = std::string(tmpdir ? tmpdir : "/tmp") + "/cnc_sim_api_XXXXXX.ngc";
std::vector<char> tmpl_buffer(tmpl.begin(), tmpl.end());
tmpl_buffer.push_back('\0');
const int fd = mkstemps(tmpl_buffer.data(), 4);
if (fd < 0) {
if (error) {
*error = "failed to create temporary ngc file";
@@ -100,13 +104,13 @@ bool write_temp_program(const char *program,
ok = false;
}
if (!ok) {
unlink(tmpl);
unlink(tmpl_buffer.data());
if (error) {
*error = "failed to write temporary ngc file";
}
return false;
}
*path = tmpl;
*path = tmpl_buffer.data();
return true;
}
@@ -185,6 +189,7 @@ int parse_linuxcnc_rs274_backend(CanonEventSink &sink,
cnc_sim_linuxcnc_set_canon_sink(nullptr);
return -1;
}
SET_BLOCK_DELETE(sink.block_delete());
if (file_mode_enabled()) {
std::string temp_path;

View File

@@ -2,6 +2,8 @@
#include "emc/tooldata/tooldata.hh"
#include <cstdlib>
void cnc_sim_init_minimal_linuxcnc_tooldata() {
static bool created = false;
if (!created) {
@@ -22,5 +24,29 @@ void cnc_sim_init_minimal_linuxcnc_tooldata() {
tool.diameter = 6.0;
tool.offset.tran.z = 12.5;
tooldata_put(tool, 1);
tooldata_last_index_set(1);
CANON_TOOL_TABLE thread_tool = tooldata_entry_init();
thread_tool.toolno = 4;
thread_tool.pocketno = 4;
thread_tool.diameter = 1.0;
thread_tool.offset.tran.z = 0.7;
tooldata_put(thread_tool, 4);
if (const char *spindle_tool = std::getenv("CNC_SIM_TOOL_IN_SPINDLE")) {
const int tool_id = std::atoi(spindle_tool);
if (tool_id == 1) {
CANON_TOOL_TABLE spindle_tooldata = tool;
spindle_tooldata.pocketno = 0;
spindle_tooldata.frontangle = 12.0;
spindle_tooldata.backangle = 34.0;
spindle_tooldata.orientation = 5;
tooldata_put(spindle_tooldata, 0);
} else if (tool_id == 4) {
CANON_TOOL_TABLE spindle_tooldata = thread_tool;
spindle_tooldata.pocketno = 0;
tooldata_put(spindle_tooldata, 0);
}
}
tooldata_last_index_set(4);
}

File diff suppressed because it is too large Load Diff

View File

@@ -3,6 +3,7 @@
#include "canon_event_sink.h"
#include <cstddef>
#include <unordered_map>
#include <string>
class SmokeGcodeParser {
@@ -12,14 +13,37 @@ public:
int parse(const char *program, size_t program_len, std::string *error);
private:
struct SmokeToolTableEntry {
CncSimPose offset{};
double diameter = 0.0;
double frontangle = 0.0;
double backangle = 0.0;
double orientation = 0.0;
};
CanonEventSink &sink_;
bool absolute_ = true;
bool arc_absolute_ = false;
bool lathe_diameter_mode_ = false;
bool cutter_comp_on_ = false;
bool cutter_comp_exit_pending_ = false;
bool cutter_comp_has_prev_vector_ = false;
bool cutter_comp_has_prev_prev_vector_ = false;
double cutter_comp_radius_ = 0.0;
int spindle_tool_id_ = 0;
CncSimPose cutter_comp_prev_vector_{};
CncSimPose cutter_comp_prev_prev_vector_{};
int cutter_comp_mode_ = 40;
bool spindle_css_mode_ = false;
bool tool_selected_ = false;
bool nurbs_g5_collecting_ = false;
int nurbs_g5_control_points_ = 0;
int nurbs_g5_order_ = 3;
bool nurbs_g6_collecting_ = false;
int feed_mode_ = 0;
int canned_cycle_ = 0;
bool canned_return_to_initial_ = false;
bool g92_applied_ = false;
bool canned_has_r_ = false;
bool canned_has_z_ = false;
bool canned_has_p_ = false;
@@ -36,6 +60,9 @@ private:
double canned_i_ = 0.0;
double canned_j_ = 0.0;
double canned_k_ = 0.0;
double m66_result_ = 0.0;
double oword_return_value_ = 0.0;
bool oword_value_returned_ = false;
int selected_tool_id_ = 0;
std::unordered_map<int, SmokeToolTableEntry> tool_table_;
};

View File

@@ -443,6 +443,37 @@ int main() {
ok &= expect(saw_g432_h_tool_length, "expected LinuxCNC G43.2 H tool-table additive event");
ok &= expect(saw_g49_dynamic_tool_length_clear, "expected LinuxCNC G49 dynamic tool length clear event");
const char g49_tool_offset_parameter_program[] =
"G21 G90 G17\n"
"G43.2 H1\n"
"O10 if [#<_tool_offset> EQ 1]\n"
"G1 X1 F100\n"
"O10 endif\n"
"G49\n"
"O10 if [#<_tool_offset> EQ 0]\n"
"G1 X2 F100\n"
"O10 endif\n"
"M30\n";
events.clear();
ok &= expect(cnc_sim_parse_program(sim,
g49_tool_offset_parameter_program,
sizeof(g49_tool_offset_parameter_program) - 1) == 0,
cnc_sim_last_error(sim));
bool saw_g49_tool_offset_parameter_before = false;
bool saw_g49_tool_offset_parameter_after = false;
for (const auto &event : events) {
saw_g49_tool_offset_parameter_before = saw_g49_tool_offset_parameter_before ||
(event.type == CNC_SIM_EVENT_LINEAR_FEED &&
event.line == 4 &&
near(event.end.x, 1.0));
saw_g49_tool_offset_parameter_after = saw_g49_tool_offset_parameter_after ||
(event.type == CNC_SIM_EVENT_LINEAR_FEED &&
event.line == 8 &&
near(event.end.x, 2.0));
}
ok &= expect(saw_g49_tool_offset_parameter_before && saw_g49_tool_offset_parameter_after,
"expected LinuxCNC G49 to clear the applied tool offset parameter before the next motion");
const char spindle_program[] =
"G21 G90 G17\n"
"S1200 M3\n"
@@ -1200,6 +1231,47 @@ int main() {
ok &= expect(saw_g52_restore, "expected LinuxCNC G52/G92 shared offset to restore with G92.3");
ok &= expect(saw_g52_end_line, "expected LinuxCNC G52 program end line number");
const char block_delete_program[] =
"G21 G90 G17 F100\n"
" /N10 G1 X5\n"
"G1 X2\n"
"M30\n";
const char block_delete_on_config[] = "{\"backend\":\"linuxcnc-rs274\",\"blockDelete\":true}";
events.clear();
ok &= expect(cnc_sim_load_config_json(sim, block_delete_on_config, sizeof(block_delete_on_config) - 1) == 0,
cnc_sim_last_error(sim));
ok &= expect(cnc_sim_parse_program(sim, block_delete_program, sizeof(block_delete_program) - 1) == 0,
cnc_sim_last_error(sim));
bool saw_block_delete_skipped_line = false;
bool saw_block_delete_followup_line = false;
for (const auto &event : events) {
saw_block_delete_skipped_line = saw_block_delete_skipped_line ||
(event.type == CNC_SIM_EVENT_LINEAR_FEED &&
event.line == 2 &&
event.end.x == 5.0);
saw_block_delete_followup_line = saw_block_delete_followup_line ||
(event.type == CNC_SIM_EVENT_LINEAR_FEED &&
event.line == 3 &&
event.end.x == 2.0);
}
ok &= expect(!saw_block_delete_skipped_line, "expected LinuxCNC block-delete line to be skipped");
ok &= expect(saw_block_delete_followup_line, "expected LinuxCNC block-delete followup line to execute");
const char block_delete_off_config[] = "{\"backend\":\"linuxcnc-rs274\",\"blockDelete\":false}";
events.clear();
ok &= expect(cnc_sim_load_config_json(sim, block_delete_off_config, sizeof(block_delete_off_config) - 1) == 0,
cnc_sim_last_error(sim));
ok &= expect(cnc_sim_parse_program(sim, block_delete_program, sizeof(block_delete_program) - 1) == 0,
cnc_sim_last_error(sim));
bool saw_block_delete_disabled_line = false;
for (const auto &event : events) {
saw_block_delete_disabled_line = saw_block_delete_disabled_line ||
(event.type == CNC_SIM_EVENT_LINEAR_FEED &&
event.line == 2 &&
event.end.x == 5.0);
}
ok &= expect(saw_block_delete_disabled_line, "expected LinuxCNC disabled block-delete line to execute");
cnc_sim_destroy(sim);
int abort_count = 0;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -63,5 +63,13 @@ int main() {
const CncSimPose roundtrip = rtcp_tool_tip_from_pivot(pivot, 123.4);
ok &= expect_pose_near(roundtrip, tip, "RTCP pivot/tool-tip roundtrip");
tip = {};
tip.a = 90.0;
tip.b = 90.0;
const RtcpVector vector = rtcp_tool_vector_from_pose(tip, 10.0);
ok &= expect_near(vector.x, 0.0, "A90 B90 tool vector x");
ok &= expect_near(vector.y, 10.0, "A90 B90 tool vector y");
ok &= expect_near(vector.z, 0.0, "A90 B90 tool vector z");
return ok ? 0 : 1;
}

View File

@@ -128,6 +128,11 @@ bool trace_enabled() {
return std::getenv("CNC_SIM_TRACE_RS274") != nullptr;
}
bool block_delete_enabled() {
const char *value = std::getenv("CNC_SIM_BLOCK_DELETE");
return value && std::string(value) != "0" && std::string(value) != "false";
}
bool execute_line(InterpBase *interp,
CanonEventSink &sink,
const std::string &line,
@@ -251,6 +256,7 @@ int main(int argc, char **argv) {
cnc_sim_init_minimal_linuxcnc_tooldata();
CanonEventSink sink;
sink.set_block_delete(block_delete_enabled());
bool first = true;
sink.set_callback(print_event, &first);
cnc_sim_linuxcnc_set_canon_sink(&sink);
@@ -271,6 +277,7 @@ int main(int argc, char **argv) {
if (trace_enabled()) {
std::cerr << "rs274:init done\n";
}
SET_BLOCK_DELETE(sink.block_delete());
bool ok = true;
if (use_file_mode) {

View File

@@ -0,0 +1,4 @@
#pragma once
#include "boost/python/object.hpp"

View File

@@ -0,0 +1,4 @@
#pragma once
#include "boost/python/object.hpp"

View File

@@ -0,0 +1,4 @@
#pragma once
#include "boost/python/object.hpp"

View File

@@ -0,0 +1,4 @@
#pragma once
#include "boost/python/object.hpp"

View File

@@ -0,0 +1,211 @@
#pragma once
#include <string>
extern "C" {
struct _typeobject {
const char *tp_name;
};
using PyTypeObject = _typeobject;
struct _object {
PyTypeObject *ob_type;
};
using PyObject = _object;
struct _inittab {
const char *name;
PyObject *(*initfunc)(void);
};
int Py_IsInitialized(void);
PyObject *PyErr_Occurred(void);
void PyErr_Clear(void);
int PyErr_ExceptionMatches(PyObject *);
int PyCallable_Check(PyObject *);
void PyErr_Fetch(PyObject **, PyObject **, PyObject **);
void PyErr_NormalizeException(PyObject **, PyObject **, PyObject **);
void PyErr_Print(void);
int PyUnicode_Check(PyObject *);
int PyLong_Check(PyObject *);
int PyFloat_Check(PyObject *);
int PyGen_Check(PyObject *);
PyObject *PyObject_Str(PyObject *);
const char *PyUnicode_AsUTF8(PyObject *);
void Py_DecRef(PyObject *);
extern PyObject *PyExc_KeyError;
extern PyObject *PyExc_StopIteration;
extern PyObject *_Py_NoneStructPtr;
#define Py_None (_Py_NoneStructPtr)
#define Py_TYPE(ob) ((ob)->ob_type)
#define Py_XDECREF(ob) \
do { \
if (ob) { \
Py_DecRef(ob); \
} \
} while (0)
}
namespace boost {
template <typename T>
const T &cref(const T &value) {
return value;
}
namespace python {
class error_already_set {};
class object {
public:
object() = default;
template <typename T>
object(const T &) {
}
~object() = default;
class attr_proxy {
public:
template <typename T>
attr_proxy &operator=(const T &) {
return *this;
}
operator object() const {
return object();
}
};
attr_proxy attr(const char *) const {
return {};
}
object operator[](const char *) const {
return {};
}
object operator[](const std::string &) const {
return {};
}
object operator[](int) const {
return {};
}
PyObject *ptr() const {
return nullptr;
}
template <typename... Args>
object operator()(Args &&...) const {
return {};
}
};
inline object getattr(const object &, const char *) {
return {};
}
class list : public object {
public:
template <typename T>
void append(const T &) {
}
};
class dict : public object {
public:
list keys() const {
return {};
}
};
class tuple : public object {
public:
tuple() = default;
tuple(const list &) {
}
};
class scope {
public:
explicit scope(const object &) {
}
object::attr_proxy attr(const char *) const {
return {};
}
};
template <typename T>
struct extract {
explicit extract(const object &) {
}
operator T() const {
return T();
}
};
inline object import(const char *) {
return {};
}
inline int len(const list &) {
return 0;
}
inline void handle_exception() {
}
template <typename T>
struct borrowed_result {
explicit borrowed_result(T *) {
}
};
template <typename T>
struct allow_null_result {
explicit allow_null_result(T *) {
}
};
template <typename T>
borrowed_result<T> borrowed(T *value) {
return borrowed_result<T>(value);
}
template <typename T>
allow_null_result<T> allow_null(T *value) {
return allow_null_result<T>(value);
}
template <typename T = void>
class handle {
public:
template <typename U>
explicit handle(const U &) {
}
explicit operator bool() const {
return false;
}
};
class str : public object {
public:
template <typename T>
explicit str(const T &) {
}
object join(const object &) const {
return {};
}
};
} // namespace python
} // namespace boost

View File

@@ -0,0 +1,10 @@
#pragma once
namespace boost {
namespace python {
class object;
} // namespace python
} // namespace boost

View File

@@ -0,0 +1,4 @@
#pragma once
#include "boost/python/object.hpp"

View File

@@ -0,0 +1,3 @@
#pragma once
#include "boost/python/object.hpp"

View File

@@ -0,0 +1,3 @@
#pragma once
#include "boost/python/object.hpp"

30
core/wasm_shims/dlfcn.cc Normal file
View File

@@ -0,0 +1,30 @@
#include "dlfcn.h"
#include <cstring>
namespace {
thread_local char last_error[128] = "dynamic loading is unavailable in wasm-safe probe";
} // namespace
extern "C" {
void *dlopen(const char *, int) {
return nullptr;
}
void *dlsym(void *, const char *) {
return nullptr;
}
char *dlerror(void) {
return last_error;
}
int dlclose(void *) {
return 0;
}
} // extern "C"

18
core/wasm_shims/dlfcn.h Normal file
View File

@@ -0,0 +1,18 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#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);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,4 @@
#include "nml_intf/emc_nml.hh"
EMC_STAT *emcStatus = nullptr;

View File

@@ -0,0 +1,6 @@
#include <cstddef>
extern "C" char *gettext(const char *msgid) {
return const_cast<char *>(msgid ? msgid : "");
}

View File

@@ -0,0 +1,7 @@
#include "interp_base.hh"
int main() {
InterpBase *interp = interp_from_shlib("nonexistent-interpreter.so");
return interp == nullptr ? 0 : 1;
}

View File

@@ -0,0 +1,40 @@
#include "tooldata/tooldata.hh"
#include "rs274ngc/rs274ngc_interp.hh"
int main() {
if (tool_mmap_creator(nullptr, 1) != 0) {
return 7;
}
tooldata_reset();
CANON_TOOL_TABLE spindle = tooldata_entry_init();
spindle.toolno = 0;
spindle.pocketno = 0;
if (tooldata_put(spindle, 0) != IDX_OK) {
return 1;
}
CANON_TOOL_TABLE tool = tooldata_entry_init();
tool.toolno = 7;
tool.pocketno = 12;
if (tooldata_put(tool, 12) != IDX_NEW) {
return 2;
}
int idx = -1;
int pocket = -1;
auto *interp = reinterpret_cast<Interp *>(0x1);
if (interp->find_tool_index(nullptr, 7, &idx) != INTERP_OK) {
return 3;
}
if (idx != 12) {
return 4;
}
if (interp->find_tool_pocket(nullptr, 7, &pocket) != INTERP_OK) {
return 5;
}
if (pocket != 12) {
return 6;
}
return 0;
}

View File

@@ -0,0 +1,7 @@
#include "rs274ngc/rs274ngc_interp.hh"
#include <cstdarg>
void Interp::setError(const char *, ...) {
}

View File

@@ -0,0 +1,72 @@
#include "boost/python/object.hpp"
#include "hal.h"
int _task = 0;
extern "C" PyObject *PyInit_interpreter(void) {
return nullptr;
}
extern "C" PyObject *PyInit_emccanon(void) {
return nullptr;
}
extern "C" {
struct _inittab builtin_modules[] = {
{"interpreter", PyInit_interpreter},
{"emccanon", PyInit_emccanon},
{nullptr, nullptr},
};
}
extern "C" int hal_init(const char *) {
return 1;
}
extern "C" int hal_ready(int) {
return 0;
}
extern "C" int hal_get_pin_value_by_name(const char *,
hal_type_t *type,
hal_data_u **data,
bool *connected) {
if (type) {
*type = HAL_TYPE_UNINITIALIZED;
}
if (data) {
*data = nullptr;
}
if (connected) {
*connected = false;
}
return -1;
}
extern "C" int hal_get_signal_value_by_name(const char *,
hal_type_t *type,
hal_data_u **data,
bool *has_writers) {
if (type) {
*type = HAL_TYPE_UNINITIALIZED;
}
if (data) {
*data = nullptr;
}
if (has_writers) {
*has_writers = false;
}
return -1;
}
extern "C" int hal_get_param_value_by_name(const char *,
hal_type_t *type,
hal_data_u **data) {
if (type) {
*type = HAL_TYPE_UNINITIALIZED;
}
if (data) {
*data = nullptr;
}
return -1;
}

View File

@@ -0,0 +1,76 @@
#include "boost/python/object.hpp"
extern "C" {
static PyTypeObject none_type = {"NoneType"};
static PyObject none_object = {&none_type};
PyObject *PyExc_KeyError = reinterpret_cast<PyObject *>(1);
PyObject *PyExc_StopIteration = reinterpret_cast<PyObject *>(2);
PyObject *_Py_NoneStructPtr = &none_object;
int Py_IsInitialized(void) {
return 1;
}
PyObject *PyErr_Occurred(void) {
return nullptr;
}
void PyErr_Clear(void) {
}
int PyErr_ExceptionMatches(PyObject *) {
return 0;
}
int PyCallable_Check(PyObject *) {
return 0;
}
void PyErr_Fetch(PyObject **exc, PyObject **val, PyObject **tb) {
if (exc) {
*exc = nullptr;
}
if (val) {
*val = nullptr;
}
if (tb) {
*tb = nullptr;
}
}
void PyErr_NormalizeException(PyObject **, PyObject **, PyObject **) {
}
void PyErr_Print(void) {
}
int PyUnicode_Check(PyObject *) {
return 0;
}
int PyLong_Check(PyObject *) {
return 0;
}
int PyFloat_Check(PyObject *) {
return 0;
}
int PyGen_Check(PyObject *) {
return 0;
}
PyObject *PyObject_Str(PyObject *) {
return &none_object;
}
const char *PyUnicode_AsUTF8(PyObject *) {
return "";
}
void Py_DecRef(PyObject *) {
}
}

View File

@@ -0,0 +1,50 @@
#include "pythonplugin/python_plugin.hh"
__attribute__((weak)) std::string handle_pyerror() {
return "python disabled in wasm-safe probe";
}
PythonPlugin *python_plugin = nullptr;
PythonPlugin *PythonPlugin::instantiate(struct _inittab *) {
static PythonPlugin plugin;
python_plugin = &plugin;
python_plugin->status = PLUGIN_OK;
return python_plugin;
}
int PythonPlugin::configure(const char *, const char *) {
status = PLUGIN_OK;
return status;
}
bool PythonPlugin::is_callable(const char *, const char *) {
return false;
}
int PythonPlugin::call(const char *,
const char *,
boost::python::object,
boost::python::object,
boost::python::object &retval) {
retval = boost::python::object();
status = PLUGIN_NO_CALLABLE;
return status;
}
int PythonPlugin::run_string(const char *, boost::python::object &retval, bool) {
retval = boost::python::object();
status = PLUGIN_OK;
return status;
}
int PythonPlugin::call_method(boost::python::object, boost::python::object &retval) {
retval = boost::python::object();
status = PLUGIN_OK;
return status;
}
int PythonPlugin::initialize() {
status = PLUGIN_OK;
return status;
}

View File

@@ -0,0 +1,60 @@
#pragma once
#include <string>
#include <vector>
#include <sys/types.h>
#include "boost/python/object.hpp"
extern std::string handle_pyerror();
enum pp_status {
PLUGIN_NO_SECTION = -1,
PLUGIN_NO_INIFILE = -2,
PLUGIN_BAD_INIFILE = -3,
PLUGIN_NO_TOPLEVEL = -4,
PLUGIN_BAD_PATH = -5,
PLUGIN_STAT_FAILED = -6,
PLUGIN_INITTAB_FAILED = -7,
PLUGIN_PYTHON_ALREADY_INITIALIZED = -8,
PLUGIN_EXCEPTION_DURING_PATH_PREPEND = -9,
PLUGIN_EXCEPTION_DURING_PATH_APPEND = -10,
PLUGIN_INIT_EXCEPTION = -11,
PLUGIN_PYTHON_NOT_INITIALIZED = -12,
PLUGIN_PATH_TOO_LONG = -13,
PLUGIN_OK = 0,
PLUGIN_NO_CALLABLE = 1,
PLUGIN_EXCEPTION = 2
};
class PythonPlugin {
public:
static PythonPlugin *instantiate(struct _inittab *inittab = nullptr);
int configure(const char *iniFilename = nullptr, const char *section = nullptr);
bool is_callable(const char *module, const char *funcname);
int call(const char *module,
const char *callable,
boost::python::object tupleargs,
boost::python::object kwargs,
boost::python::object &retval);
int run_string(const char *cmd, boost::python::object &retval, bool as_file = false);
int call_method(boost::python::object method, boost::python::object &retval);
int plugin_status() { return status; }
bool usable() { return status >= PLUGIN_OK; }
int initialize();
const std::string &last_exception() { return exception_msg; }
const std::string &last_errmsg() { return error_msg; }
boost::python::object main_namespace;
private:
PythonPlugin() = default;
int status = PLUGIN_OK;
std::string exception_msg;
std::string error_msg;
int log_level = 0;
};
extern PythonPlugin *python_plugin;

View File

@@ -0,0 +1,23 @@
#include "pythonplugin/python_plugin.hh"
int main() {
auto *plugin = PythonPlugin::instantiate(nullptr);
if (!plugin) {
return 1;
}
if (!plugin->usable()) {
return 2;
}
boost::python::object retval;
if (plugin->run_string("noop", retval, false) != PLUGIN_OK) {
return 3;
}
if (plugin->is_callable(nullptr, "noop")) {
return 4;
}
if (handle_pyerror().empty()) {
return 5;
}
return 0;
}

View File

@@ -0,0 +1,33 @@
#include "canon_event_sink.h"
#include "linuxcnc_canon_bridge.h"
#include "linuxcnc_tooldata_fixture.h"
#include "rs274ngc_interp.hh"
#include <cmath>
int main() {
cnc_sim_init_minimal_linuxcnc_tooldata();
CanonEventSink sink;
cnc_sim_linuxcnc_set_canon_sink(&sink);
Interp interp;
if (interp.init() != INTERP_OK) {
return 1;
}
if (interp.sequence_number() != 0) {
return 2;
}
const double start_x = sink.position().x;
cnc_sim_linuxcnc_set_current_line(1);
const int read_rc = interp.read("G91 G0 X1");
if (read_rc != INTERP_OK) {
return 3;
}
const int execute_rc = interp.execute();
if (execute_rc != INTERP_OK && execute_rc != INTERP_EXECUTE_FINISH) {
return 4;
}
return std::fabs(sink.position().x - (start_x + 1.0)) < 1e-9 ? 0 : 5;
}

View File

@@ -0,0 +1,11 @@
#include <cstdarg>
#include <cstdio>
extern "C" int rtapi_snprintf(char *buf, unsigned long size, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
const int rc = std::vsnprintf(buf, static_cast<std::size_t>(size), fmt, ap);
va_end(ap);
return rc;
}

View File

@@ -0,0 +1,58 @@
#pragma once
#include "nml_intf/canon.hh"
#include "nml_intf/emc_nml.hh"
extern "C" {
typedef enum {
IDX_OK = 0,
IDX_NEW,
IDX_FAIL,
} toolidx_t;
typedef enum {
DB_NOTUSED = 0,
DB_ACTIVE,
} tooldb_t;
typedef enum {
SPINDLE_LOAD,
SPINDLE_UNLOAD,
TOOL_OFFSET,
} tool_notify_t;
struct CANON_TOOL_TABLE tooldata_entry_init(void);
toolidx_t tooldata_put(struct CANON_TOOL_TABLE tdata, int idx);
toolidx_t tooldata_get(CANON_TOOL_TABLE *pdata, int idx);
void tooldata_init(bool random_tool_changer);
void tooldata_reset(void);
void tooldata_last_index_set(int idx);
int tooldata_last_index_get(void);
int tooldata_find_index_for_tool(int toolno);
void tooldata_format_toolline(int idx,
bool ignore_zero_values,
CANON_TOOL_TABLE tdata,
char formatted_line[CANON_TOOL_ENTRY_LEN]);
void tooldata_add_init(int nonrandom_start_idx);
int tooldata_read_entry(const char *input_line);
void tooldata_set_db(tooldb_t mode);
int tooldata_load(const char *filename);
int tooldata_save(const char *filename);
int tool_mmap_creator(EMC_TOOL_STAT const *ptr, int random_toolchanger);
int tool_mmap_user(void);
void tool_mmap_close(void);
bool tool_mmap_is_random_toolchanger(void);
int tool_nml_register(CANON_TOOL_TABLE *tblptr);
int tooldata_db_init(char progname_plus_args[], int random_toolchanger);
int tooldata_db_notify(tool_notify_t ntype,
int toolno,
int pocketno,
CANON_TOOL_TABLE tdata);
int tooldata_db_getall(void);
} // extern "C"

View File

@@ -0,0 +1,101 @@
#include "tooldata.hh"
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <unistd.h>
namespace {
std::string make_temp_template(const char *name) {
const char *tmpdir = std::getenv("TMPDIR");
std::string tmpl = std::string(tmpdir ? tmpdir : "/tmp") + "/" + name;
return tmpl;
}
} // namespace
int main() {
if (tool_mmap_user() != -1) {
return 11;
}
if (tool_mmap_creator(nullptr, 1) != 0) {
return 12;
}
if (tool_mmap_user() != 0) {
return 13;
}
if (!tool_mmap_is_random_toolchanger()) {
return 14;
}
tooldata_init(true);
tooldata_reset();
tooldata_add_init(0);
if (tooldata_read_entry("T7 P12 Z3.5 D8 ;probe\n") != 12) {
return 1;
}
CANON_TOOL_TABLE loaded = tooldata_entry_init();
if (tooldata_get(&loaded, 12) != IDX_OK) {
return 2;
}
if (loaded.toolno != 7 || loaded.pocketno != 12 ||
loaded.offset.tran.z != 3.5 || loaded.diameter != 8.0 ||
std::strcmp(loaded.comment, "probe") != 0) {
return 3;
}
char line[CANON_TOOL_ENTRY_LEN] = {};
tooldata_format_toolline(12, true, loaded, line);
if (!std::strstr(line, "T7") || !std::strstr(line, "P12") ||
!std::strstr(line, "D+8.000000") || !std::strstr(line, ";probe")) {
return 4;
}
std::string path_template = make_temp_template("cnc_tooldata_common_probe_XXXXXX");
std::vector<char> path(path_template.begin(), path_template.end());
path.push_back('\0');
const int fd = mkstemp(path.data());
if (fd < 0) {
return 5;
}
close(fd);
if (tooldata_save(path.data()) != 0) {
std::remove(path.data());
return 6;
}
tooldata_reset();
if (tooldata_find_index_for_tool(7) != -1) {
std::remove(path.data());
return 7;
}
if (tooldata_load(path.data()) != 0) {
std::remove(path.data());
return 8;
}
std::remove(path.data());
if (tooldata_get(&loaded, 12) != IDX_OK || loaded.toolno != 7 ||
loaded.pocketno != 12 || loaded.offset.tran.z != 3.5 ||
loaded.diameter != 8.0) {
return 9;
}
tooldata_set_db(DB_ACTIVE);
if (tooldata_load(path.data()) != -1) {
return 10;
}
tool_mmap_close();
if (tool_mmap_user() != -1) {
return 15;
}
return 0;
}

View File

@@ -0,0 +1,127 @@
#include "tooldata.hh"
#include <cstdlib>
#include <cstdio>
#include <unistd.h>
namespace {
CANON_TOOL_TABLE tool_table[CANON_POCKETS_MAX];
EMC_TOOL_STAT const *toolstat = nullptr;
int last_index = 0;
bool mmap_created = false;
bool mmap_random_toolchanger = false;
bool mmap_creator_called = false;
} // namespace
extern "C" {
toolidx_t tooldata_put(CANON_TOOL_TABLE tdata, int idx) {
if (!mmap_created) {
return IDX_FAIL;
}
if (idx < 0 || idx >= CANON_POCKETS_MAX) {
return IDX_FAIL;
}
const toolidx_t result = idx > last_index ? IDX_NEW : IDX_OK;
tool_table[idx] = tdata;
if (idx > last_index) {
last_index = idx;
}
if (idx == 0 && toolstat) {
*(CANON_TOOL_TABLE *)(&toolstat->toolTableCurrent) = tdata;
}
return result;
}
toolidx_t tooldata_get(CANON_TOOL_TABLE *pdata, int idx) {
if (!mmap_created) {
std::fprintf(stderr, "%5d tooldata_get() not mmapped BYE\n", getpid());
std::exit(EXIT_FAILURE);
}
if (!pdata || idx < 0 || idx >= CANON_POCKETS_MAX) {
return IDX_FAIL;
}
*pdata = tool_table[idx];
return IDX_OK;
}
void tooldata_reset(void) {
if (!mmap_created) {
return;
}
const CANON_TOOL_TABLE empty = tooldata_entry_init();
for (int idx = 0; idx < CANON_POCKETS_MAX; ++idx) {
tool_table[idx] = empty;
}
}
void tooldata_last_index_set(int idx) {
if (!mmap_created) {
return;
}
if (idx < 0 || idx >= CANON_POCKETS_MAX) {
idx = 0;
}
last_index = idx;
}
int tooldata_last_index_get(void) {
if (!mmap_created) {
return -1;
}
return last_index;
}
int tooldata_find_index_for_tool(int toolno) {
if (!mmap_created || toolno == -1) {
return -1;
}
if (!mmap_random_toolchanger && toolno == 0) {
return 0;
}
int found = -1;
for (int idx = 0; idx <= last_index && idx < CANON_POCKETS_MAX; ++idx) {
if (tool_table[idx].toolno == toolno) {
found = idx;
if (idx != 0) {
break;
}
}
}
return found;
}
int tool_mmap_creator(EMC_TOOL_STAT const *ptr, int random_toolchanger) {
if (mmap_creator_called) {
std::fprintf(stderr, "Error: tool_mmap_creator already called BYE\n");
std::exit(EXIT_FAILURE);
}
toolstat = ptr;
mmap_creator_called = true;
mmap_created = true;
mmap_random_toolchanger = random_toolchanger;
last_index = 0;
return 0;
}
int tool_mmap_user(void) {
return mmap_created ? 0 : -1;
}
void tool_mmap_close(void) {
mmap_created = false;
mmap_random_toolchanger = false;
toolstat = nullptr;
last_index = 0;
}
bool tool_mmap_is_random_toolchanger(void) {
return mmap_random_toolchanger;
}
} // extern "C"

View File

@@ -0,0 +1,340 @@
#include "tooldata/tooldata.hh"
#include <fcntl.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <sys/wait.h>
#include <unistd.h>
#include <vector>
namespace {
std::string make_temp_path(const char *name) {
const char *tmpdir = std::getenv("TMPDIR");
return std::string(tmpdir ? tmpdir : "/tmp") + "/" + name;
}
class ScopedTempWorkdir {
public:
explicit ScopedTempWorkdir(const char *name_template) {
cwd_fd_ = open(".", O_RDONLY);
if (cwd_fd_ < 0) {
return;
}
std::string path_template = make_temp_path(name_template);
dir_buffer_.assign(path_template.begin(), path_template.end());
dir_buffer_.push_back('\0');
dir_ = mkdtemp(dir_buffer_.data());
if (!dir_) {
return;
}
if (chdir(dir_) != 0) {
dir_ = nullptr;
return;
}
ok_ = true;
}
~ScopedTempWorkdir() {
if (cwd_fd_ >= 0) {
if (ok_) {
fchdir(cwd_fd_);
}
close(cwd_fd_);
}
if (dir_) {
rmdir(dir_);
}
}
bool ok() const {
return ok_;
}
private:
int cwd_fd_ = -1;
std::vector<char> dir_buffer_;
char *dir_ = nullptr;
bool ok_ = false;
};
} // namespace
int main() {
const pid_t creator_child = fork();
if (creator_child < 0) {
return 41;
}
if (creator_child == 0) {
if (tool_mmap_creator(nullptr, 1) != 0) {
_exit(42);
}
tool_mmap_creator(nullptr, 0);
_exit(43);
}
int creator_status = 0;
if (waitpid(creator_child, &creator_status, 0) != creator_child) {
return 44;
}
if (!WIFEXITED(creator_status) || WEXITSTATUS(creator_status) == 0) {
return 45;
}
if (tool_mmap_user() != -1) {
return 25;
}
CANON_TOOL_TABLE uncreated_tool = tooldata_entry_init();
if (tooldata_put(uncreated_tool, 0) != IDX_FAIL) {
return 27;
}
const pid_t get_child = fork();
if (get_child < 0) {
return 46;
}
if (get_child == 0) {
tooldata_get(&uncreated_tool, 0);
_exit(47);
}
int get_status = 0;
if (waitpid(get_child, &get_status, 0) != get_child) {
return 48;
}
if (!WIFEXITED(get_status) || WEXITSTATUS(get_status) == 0) {
return 38;
}
if (tooldata_last_index_get() != -1) {
return 40;
}
if (tooldata_db_getall() != -1) {
return 28;
}
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(
missing_db_program_with_arg_string.begin(),
missing_db_program_with_arg_string.end());
missing_db_program_with_arg.push_back('\0');
if (tooldata_db_init(missing_db_program_with_arg.data(), 1) != -1) {
return 55;
}
const auto separator = missing_db_program_with_arg_string.find(' ');
if (separator == std::string::npos || missing_db_program_with_arg[separator] != 0) {
return 56;
}
std::string missing_db_program_string = make_temp_path("cnc_tooldata_probe_missing_db_program");
std::vector<char> missing_db_program(
missing_db_program_string.begin(),
missing_db_program_string.end());
missing_db_program.push_back('\0');
if (tooldata_db_init(missing_db_program.data(), 1) != -1) {
return 31;
}
char too_many_db_args[] = "/bin/true a b c d e f g h i";
if (tooldata_db_init(too_many_db_args, 1) != -1) {
return 32;
}
char non_db_program[] = "/bin/true";
if (tooldata_db_init(non_db_program, 1) != -1) {
return 33;
}
if (tool_nml_register(nullptr) != -1) {
return 29;
}
alignas(EMC_TOOL_STAT) unsigned char toolstat_storage[sizeof(EMC_TOOL_STAT)] = {};
auto *toolstat = reinterpret_cast<EMC_TOOL_STAT *>(toolstat_storage);
if (tool_mmap_creator(toolstat, 1) != 0) {
return 15;
}
if (tool_mmap_user() != 0) {
return 26;
}
if (!tool_mmap_is_random_toolchanger()) {
return 16;
}
tooldata_set_db(DB_ACTIVE);
const std::string unavailable_db_path = make_temp_path("cnc_tooldata_probe_db_unavailable.tbl");
if (tooldata_load(unavailable_db_path.c_str()) != -1) {
return 30;
}
tooldata_set_db(DB_ACTIVE);
tooldata_init(false);
if (tooldata_save(nullptr) != 0) {
return 34;
}
tooldata_set_db(DB_NOTUSED);
tooldata_init(true);
tooldata_reset();
CANON_TOOL_TABLE spindle = tooldata_entry_init();
spindle.toolno = 0;
spindle.pocketno = 0;
if (tooldata_put(spindle, 0) != IDX_OK) {
return 1;
}
if (toolstat->toolTableCurrent.toolno != 0 || toolstat->toolTableCurrent.pocketno != 0) {
return 49;
}
CANON_TOOL_TABLE tool = tooldata_entry_init();
tool.toolno = 7;
tool.pocketno = 12;
tool.offset.tran.z = 3.5;
tool.diameter = 8.0;
std::strncpy(tool.comment, "probe", CANON_TOOL_COMMENT_SIZE - 1);
if (tooldata_put(tool, 12) != IDX_NEW) {
return 2;
}
CANON_TOOL_TABLE loaded = tooldata_entry_init();
if (tooldata_get(&loaded, 12) != IDX_OK) {
return 3;
}
if (loaded.toolno != 7 || loaded.pocketno != 12 || loaded.offset.tran.z != 3.5 || loaded.diameter != 8.0) {
return 4;
}
char db_spindle_line[CANON_TOOL_ENTRY_LEN] = {};
{
ScopedTempWorkdir db_spindle_workdir("cnc_tooldata_probe_workdir.XXXXXX");
if (!db_spindle_workdir.ok()) {
return 35;
}
std::remove("./db_spindle.tbl");
tooldata_set_db(DB_ACTIVE);
if (tooldata_save(nullptr) != 0) {
return 36;
}
FILE *db_spindle_fp = std::fopen("./db_spindle.tbl", "r");
if (!db_spindle_fp) {
return 37;
}
std::fread(db_spindle_line, 1, sizeof(db_spindle_line) - 1, db_spindle_fp);
std::fclose(db_spindle_fp);
std::remove("./db_spindle.tbl");
tooldata_set_db(DB_NOTUSED);
}
if (!std::strstr(db_spindle_line, "T0") || std::strstr(db_spindle_line, "T7")) {
return 38;
}
if (tooldata_find_index_for_tool(7) != 12) {
return 5;
}
if (tooldata_find_index_for_tool(0) != 0) {
return 6;
}
if (tooldata_find_index_for_tool(-1) != -1) {
return 17;
}
tooldata_init(false);
if (tooldata_find_index_for_tool(0) != 0) {
return 18;
}
tooldata_init(true);
tooldata_last_index_set(12);
if (tooldata_last_index_get() != 12) {
return 7;
}
if (tooldata_put(tool, -1) != IDX_FAIL) {
return 50;
}
if (tooldata_put(tool, CANON_POCKETS_MAX) != IDX_FAIL) {
return 51;
}
if (tooldata_last_index_get() != 12) {
return 52;
}
if (tooldata_get(&loaded, -1) != IDX_FAIL) {
return 53;
}
if (tooldata_get(&loaded, CANON_POCKETS_MAX) != IDX_FAIL) {
return 54;
}
tooldata_last_index_set(CANON_POCKETS_MAX);
if (tooldata_last_index_get() != 0) {
return 24;
}
tooldata_last_index_set(12);
char line[CANON_TOOL_ENTRY_LEN] = {};
tooldata_format_toolline(12, true, loaded, line);
if (!std::strstr(line, "T7") || !std::strstr(line, "P12") || !std::strstr(line, "D+8.000000")) {
return 8;
}
std::string path_template = make_temp_path("cnc_tooldata_probe_XXXXXX");
std::vector<char> path(path_template.begin(), path_template.end());
path.push_back('\0');
const int fd = mkstemp(path.data());
if (fd < 0) {
return 9;
}
close(fd);
tooldata_last_index_set(0);
if (tooldata_save(path.data()) != 0) {
std::remove(path.data());
return 10;
}
tooldata_reset();
if (tooldata_find_index_for_tool(7) != -1) {
std::remove(path.data());
return 11;
}
if (tooldata_load(path.data()) != 0) {
std::remove(path.data());
return 12;
}
std::remove(path.data());
CANON_TOOL_TABLE reloaded = tooldata_entry_init();
if (tooldata_get(&reloaded, 12) != IDX_OK) {
return 13;
}
if (reloaded.toolno != 7 || reloaded.pocketno != 12 ||
reloaded.offset.tran.z != 3.5 || reloaded.diameter != 8.0) {
return 14;
}
tooldata_init(false);
std::string nonrandom_path_template = make_temp_path("cnc_tooldata_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 19;
}
FILE *nonrandom_fp = fdopen(nonrandom_fd, "w");
if (!nonrandom_fp) {
close(nonrandom_fd);
std::remove(nonrandom_path.data());
return 20;
}
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 21;
}
std::remove(nonrandom_path.data());
CANON_TOOL_TABLE nonrandom_spindle = tooldata_entry_init();
if (tooldata_get(&nonrandom_spindle, 0) != IDX_OK) {
return 22;
}
if (nonrandom_spindle.toolno != -1 || nonrandom_spindle.pocketno != 5 ||
nonrandom_spindle.offset.tran.z != 4.25) {
return 23;
}
tool_mmap_close();
if (tool_mmap_user() != -1) {
return 39;
}
return 0;
}

View File

@@ -0,0 +1,47 @@
#include "tooldata.hh"
#include <cstring>
#include <unistd.h>
namespace {
constexpr int MAX_DB_PROGRAM_ARGS = 10;
bool db_live = false;
} // namespace
extern "C" {
int tool_nml_register(CANON_TOOL_TABLE *tblptr) {
return tblptr ? 0 : -1;
}
int tooldata_db_init(char progname_plus_args[], int) {
if (!progname_plus_args) {
return -1;
}
char *saveptr = nullptr;
char *program = strtok_r(progname_plus_args, " ", &saveptr);
int argc = 0;
for (char *token = program; token; token = strtok_r(nullptr, " ", &saveptr)) {
++argc;
if (argc >= MAX_DB_PROGRAM_ARGS) {
return -1;
}
}
if (!program || access(program, X_OK) != 0) {
return -1;
}
return -1;
}
int tooldata_db_notify(tool_notify_t, int, int, CANON_TOOL_TABLE) {
return 0;
}
int tooldata_db_getall(void) {
return db_live ? 0 : -1;
}
} // extern "C"

View File

@@ -11,8 +11,8 @@ The browser calls only `cnc_sim_*` functions from `core/include/cnc_sim_api.h`.
Test:
```bash
g++ -std=c++17 -I core/include core/src/cnc_sim_api.cpp core/tests/cnc_sim_api_smoke.cpp -o /tmp/cnc_sim_api_smoke
/tmp/cnc_sim_api_smoke
g++ -std=c++17 -I core/include core/src/cnc_sim_api.cpp core/tests/cnc_sim_api_smoke.cpp -o ./cnc_sim_api_smoke
./cnc_sim_api_smoke
```
## Step 1: Temporary event parser
@@ -102,8 +102,8 @@ Before porting `rs274ngc` sources to wasm, use the already-built native LinuxCNC
This builds `core/tools/linuxcnc_rs274_dump.cpp`, links LinuxCNC `librs274`, and writes:
- `/tmp/cnc_sim_linuxcnc_basic_motion.json`
- `/tmp/cnc_sim_linuxcnc_basic_mill.json`
- run-local output files under a per-run temporary `build_dir/outputs/`
- example files: `cnc_sim_linuxcnc_basic_motion.json`, `cnc_sim_linuxcnc_basic_mill.json`
This is a native-only stepping stone. Once stable, the same event sink is used by the wasm build.

View File

@@ -43,6 +43,7 @@ These are the first group to keep compiling while we peel away native-only depen
- `interp_remap.cc`
- `interp_setup.cc`
- `interp_write.cc`
- `inifile.cc`
- `modal_state.cc`
- `nurbs_additional_functions.cc`
- `rs274ngc_pre.cc`
@@ -64,7 +65,7 @@ These are not needed for the browser simulator ABI and should not be part of the
- Python/Boost.Python remap and named parameter hooks.
- `dlopen`/`dlsym` interpreter loading in `interp_base.cc`.
- mmap-backed `tooldata_mmap.cc`.
- native mmap/filesystem storage in `tooldata_mmap.cc`.
- persistent parameter file writes.
- dynamic INI/HAL queries.
@@ -92,7 +93,9 @@ The next boundary is linking. Expected link risks:
- `PythonPlugin` and Boost.Python symbols from remap/named parameter paths.
- Python module initialization symbols if the source backend reuses the existing builtin module setup.
- `tooldata_*` implementations, currently mmap-backed in native LinuxCNC and unsuitable for wasm.
- `tooldata_mmap.cc` native mmap/filesystem storage. `tooldata_common.cc` now
remains in the wasm-safe core and links against browser-safe tooldata backend
shims.
- dynamic loader code in `interp_base.cc`.
- parameter file persistence in `rs274ngc_pre.cc`.
@@ -112,13 +115,26 @@ and libraries for the dependencies that have not been replaced yet:
- `libpyplugin` for Python remap and named-parameter hooks.
- `liblinuxcncini` and `liblinuxcnchal` for INI/HAL named parameter paths.
- `liblinuxcnc-uspace-posix` for `rtapi_*` user-space helpers.
- `libtooldata` for the current mmap-backed native tool table.
- `libtooldata` for the native source-link runner. The wasm-safe source probes
instead compile LinuxCNC `tooldata_common.cc` with `tooldata_mmap_backend.cc`
and `tooldata_runtime_stubs.cc`.
This is not wasm-ready yet, but it proves the simulator can own and compile the
RS274 interpreter core sources directly. The next source-port boundary is to
replace each support dependency with browser-safe shims instead of pulling in
the LinuxCNC task, motion, HAL, and Python runtime layers.
The wasm-safe source manifest is `linuxcnc-rs274-wasm-source-files.txt`. The
`rs274ngc_pre` wasm link and undefined-symbol probes read their LinuxCNC source
list from that manifest so `inifile.cc`, `tooldata_common.cc`, and the
interpreter sources stay on one source of truth.
When `CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE=ON`, CMake also exposes
`linuxcnc_rs274_wasm_safe_probe_objects` and the `EXCLUDE_FROM_ALL`
`linuxcnc_rs274_wasm_safe_probe` executable. The executable mirrors the
`rs274ngc_pre` shell link probe and is built only when explicitly requested, so
the normal browser wasm artifact does not accidentally link the probe runtime.
The native runner used by this probe now recognizes simulator-owned control
lines before handing code to LinuxCNC: `M428`, `M429`, `M430`, `G43.4`,
`G43.5`, and `G49`. This keeps the direct runner aligned with the public

View File

@@ -0,0 +1,28 @@
# LinuxCNC rs274 source subset for browser-safe source-link probing.
# Format: group:path:note
core:src/emc/rs274ngc/interp_arc.cc:arc geometry and canonical arc conversion
core:src/emc/rs274ngc/interp_array.cc:block array initialization
core:src/emc/rs274ngc/interp_base.cc:base interpreter interface; compile-safe with wasm dlfcn shim, runtime replacement still required
core:src/emc/rs274ngc/interp_check.cc:error text and block checks
core:src/emc/rs274ngc/interp_convert.cc:block-to-canon conversion
core:src/emc/rs274ngc/interp_cycles.cc:canned cycles
core:src/emc/rs274ngc/interp_execute.cc:execute parsed blocks
core:src/emc/rs274ngc/interp_find.cc:geometry and tool lookup helpers; still depends on tooldata declarations
core:src/emc/rs274ngc/interp_g7x.cc:lathe roughing cycles
core:src/emc/rs274ngc/interp_inspection.cc:inspection helpers
core:src/emc/rs274ngc/interp_internal.cc:internal setup and utility logic
core:src/emc/rs274ngc/interp_inverse.cc:inverse time/feed helpers
core:src/emc/rs274ngc/interp_queue.cc:canonical command queue
core:src/emc/rs274ngc/interp_read.cc:line lexer/parser
core:src/emc/rs274ngc/interp_setup.cc:setup initialization helpers; satisfied by wasm Boost.Python shim
core:src/emc/rs274ngc/interp_write.cc:modal state writers
core:src/emc/rs274ngc/modal_state.cc:state tag modal representation
core:src/emc/rs274ngc/nurbs_additional_functions.cc:NURBS helpers
core:src/emc/rs274ngc/interp_namedparams.cc:Python named-parameter hooks satisfied by wasm Boost.Python/Python C API shims
core:src/emc/rs274ngc/interp_o_word.cc:O-word control flow and directory traversal; compile-safe with wasm shims
core:src/emc/rs274ngc/interp_python.cc:Python remap support satisfied by wasm Python plugin shim
core:src/emc/rs274ngc/interp_remap.cc:Python remap support satisfied by wasm Python plugin shim
core:src/emc/rs274ngc/rs274ngc_pre.cc:Interp implementation covered by rs274ngc_pre link probe
core:src/emc/tooldata/tooldata_common.cc:shared tool table parser/format logic linked with wasm-safe mmap backend
core:src/emc/ini/inifile.cc:INI reader needed by rs274ngc_pre source-link probe
blocked:src/emc/tooldata/tooldata_mmap.cc:native mmap implementation

44
list-cnc-sim-core-sources.sh Executable file
View File

@@ -0,0 +1,44 @@
#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$0")"
filter=${1:-}
awk '
/set\(cnc_sim_core_sources/ {
in_list = 1
next
}
in_list && /^[[:space:]]*\)/ {
exit
}
in_list {
line = $0
sub(/^[[:space:]]*/, "", line)
sub(/[[:space:]]*$/, "", line)
if (line == "") {
next
}
print "core/" line
}
' core/CMakeLists.txt | while IFS= read -r source; do
if [[ ! -f "$source" ]]; then
echo "missing cnc sim core source: $source" >&2
exit 1
fi
if [[ -n "$filter" && "$(basename "$source")" != "$filter" ]]; then
continue
fi
printf '%s\n' "$source"
done | {
found=0
while IFS= read -r source; do
found=1
printf '%s\n' "$source"
done
if [[ -n "$filter" && "$found" -eq 0 ]]; then
echo "missing cnc sim core source in CMake list: $filter" >&2
exit 1
fi
}

View File

@@ -0,0 +1,30 @@
#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$0")"
filter=${1:-}
sources=(
core/src/canon_event_sink.cpp
core/src/linuxcnc_canon_bridge.cpp
core/src/rtcp_kinematics.cpp
)
found=0
for source in "${sources[@]}"; do
if [[ ! -f "$source" ]]; then
echo "missing LinuxCNC bridge smoke project source: $source" >&2
exit 1
fi
if [[ -n "$filter" && "$(basename "$source")" != "$filter" ]]; then
continue
fi
found=1
printf '%s\n' "$source"
done
if [[ -n "$filter" && "$found" -eq 0 ]]; then
echo "missing LinuxCNC bridge smoke project source in list: $filter" >&2
exit 1
fi

View File

@@ -0,0 +1,53 @@
#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$0")"
filter=${1:-}
awk '
/set\(cnc_sim_core_sources/ {
in_core = 1
next
}
in_core && /^[[:space:]]*\)/ {
in_core = 0
next
}
/list\(APPEND cnc_sim_core_sources/ {
in_backend_sources = 1
next
}
in_backend_sources && /^[[:space:]]*\)/ {
in_backend_sources = 0
next
}
in_core || in_backend_sources {
line = $0
sub(/^[[:space:]]*/, "", line)
sub(/[[:space:]]*$/, "", line)
if (line == "") {
next
}
print "core/" line
}
' core/CMakeLists.txt | while IFS= read -r source; do
if [[ ! -f "$source" ]]; then
echo "missing LinuxCNC rs274 API project source: $source" >&2
exit 1
fi
if [[ -n "$filter" && "$(basename "$source")" != "$filter" ]]; then
continue
fi
printf '%s\n' "$source"
done | {
found=0
while IFS= read -r source; do
found=1
printf '%s\n' "$source"
done
if [[ -n "$filter" && "$found" -eq 0 ]]; then
echo "missing LinuxCNC rs274 API project source in CMake list: $filter" >&2
exit 1
fi
}

View File

@@ -0,0 +1,33 @@
#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$0")"
filter=${1:-}
sources=(
core/src/canon_event_sink.cpp
core/src/linuxcnc_canon_bridge.cpp
core/src/linuxcnc_tooldata_fixture.cpp
core/src/rtcp_kinematics.cpp
core/src/simulator_gcode_controls.cpp
core/tools/linuxcnc_rs274_dump.cpp
)
found=0
for source in "${sources[@]}"; do
if [[ ! -f "$source" ]]; then
echo "missing LinuxCNC rs274 dump project source: $source" >&2
exit 1
fi
if [[ -n "$filter" && "$(basename "$source")" != "$filter" ]]; then
continue
fi
found=1
printf '%s\n' "$source"
done
if [[ -n "$filter" && "$found" -eq 0 ]]; then
echo "missing LinuxCNC rs274 dump project source in list: $filter" >&2
exit 1
fi

25
list-linuxcnc-source-files.sh Executable file
View File

@@ -0,0 +1,25 @@
#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$0")"
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
if [[ ! -d "$linuxcnc_root" ]]; then
echo "missing LinuxCNC root: $linuxcnc_root" >&2
exit 1
fi
if [[ "$#" -eq 0 ]]; then
echo "usage: $0 <linuxcnc-relative-source>..." >&2
exit 1
fi
for source in "$@"; do
full_source="$linuxcnc_root/$source"
if [[ ! -f "$full_source" ]]; then
echo "missing LinuxCNC source: $source" >&2
exit 1
fi
printf '%s\n' "$full_source"
done

View File

@@ -0,0 +1,72 @@
#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$0")"
manifest=${1:-linuxcnc-rs274-source-files.txt}
filter_group=${2:-core}
output_mode=${3:-relative}
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
if [[ ! -f "$manifest" ]]; then
echo "missing manifest: $manifest" >&2
exit 1
fi
if [[ ! -d "$linuxcnc_root" ]]; then
echo "missing LinuxCNC root: $linuxcnc_root" >&2
exit 1
fi
case "$filter_group" in
core|binding|tooldata|all)
;;
*)
echo "unknown manifest source filter: $filter_group" >&2
exit 1
;;
esac
case "$output_mode" in
relative|full)
;;
*)
echo "unknown manifest source output mode: $output_mode" >&2
exit 1
;;
esac
seen_sources=()
while IFS=: read -r group path note; do
case "$group" in
""|\#*)
continue
;;
core|binding|tooldata)
;;
*)
echo "unknown manifest group: $group" >&2
exit 1
;;
esac
if [[ ! -f "$linuxcnc_root/$path" ]]; then
echo "missing manifest file: $path" >&2
exit 1
fi
if [[ "$group" == "core" ]]; then
if printf '%s\n' "${seen_sources[@]}" | grep -Fx -- "$path" >/dev/null; then
echo "duplicate manifest source: $path" >&2
exit 1
fi
seen_sources+=("$path")
fi
if [[ "$filter_group" == "all" || "$filter_group" == "$group" ]]; then
if [[ "$output_mode" == "full" ]]; then
printf '%s\n' "$linuxcnc_root/$path"
else
printf '%s\n' "$path"
fi
fi
done < "$manifest"

View File

@@ -0,0 +1,45 @@
#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$0")"
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
filter=${1:-}
if [[ ! -d "$linuxcnc_root" ]]; then
echo "missing LinuxCNC root: $linuxcnc_root" >&2
exit 1
fi
objects=(
src/objects/emc/rs274ngc/interpmodule.o
src/objects/emc/rs274ngc/canonmodule.o
src/objects/emc/rs274ngc/pyarrays.o
src/objects/emc/rs274ngc/pyblock.o
src/objects/emc/rs274ngc/pyemctypes.o
src/objects/emc/rs274ngc/pyinterp1.o
src/objects/emc/rs274ngc/pyparamclass.o
src/objects/emc/nml_intf/emcops.o
src/objects/emc/sai/dummyemcstat.o
src/objects/libnml/nml/stat_msg.o
)
found=0
for object in "${objects[@]}"; do
full_object="$linuxcnc_root/$object"
if [[ ! -f "$full_object" ]]; then
echo "missing LinuxCNC support object: $full_object" >&2
echo "build LinuxCNC first or set LINUXCNC_ROOT to a built tree" >&2
exit 1
fi
if [[ -n "$filter" && "$(basename "$object")" != "$filter" ]]; then
continue
fi
found=1
printf '%s\n' "$full_object"
done
if [[ -n "$filter" && "$found" -eq 0 ]]; then
echo "missing LinuxCNC support object in list: $filter" >&2
exit 1
fi

View File

@@ -0,0 +1,70 @@
#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$0")"
manifest=${1:-linuxcnc-rs274-wasm-source-files.txt}
filter_group=${2:-core}
output_mode=${3:-relative}
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
if [[ ! -f "$manifest" ]]; then
echo "missing manifest: $manifest" >&2
exit 1
fi
if [[ ! -d "$linuxcnc_root" ]]; then
echo "missing LinuxCNC root: $linuxcnc_root" >&2
exit 1
fi
case "$filter_group" in
core|blocked|all)
;;
*)
echo "unknown manifest source filter: $filter_group" >&2
exit 1
;;
esac
case "$output_mode" in
relative|full)
;;
*)
echo "unknown manifest source output mode: $output_mode" >&2
exit 1
;;
esac
seen_sources=()
while IFS=: read -r group path note; do
case "$group" in
""|\#*)
continue
;;
core|blocked)
;;
*)
echo "unknown manifest group: $group" >&2
exit 1
;;
esac
if [[ ! -f "$linuxcnc_root/$path" ]]; then
echo "missing manifest source: $path" >&2
exit 1
fi
if printf '%s\n' "${seen_sources[@]}" | grep -Fx -- "$path" >/dev/null; then
echo "duplicate manifest source: $path" >&2
exit 1
fi
seen_sources+=("$path")
if [[ "$filter_group" == "all" || "$filter_group" == "$group" ]]; then
if [[ "$output_mode" == "full" ]]; then
printf '%s\n' "$linuxcnc_root/$path"
else
printf '%s\n' "$path"
fi
fi
done < "$manifest"

View File

@@ -0,0 +1,45 @@
#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$0")"
filter=${1:-}
awk '
/set\(linuxcnc_rs274_wasm_safe_probe_project_sources/ {
in_list = 1
next
}
in_list && /^[[:space:]]*\)/ {
exit
}
in_list {
line = $0
sub(/^[[:space:]]*/, "", line)
sub(/[[:space:]]*$/, "", line)
if (line == "") {
next
}
sub(/^\$\{CMAKE_CURRENT_SOURCE_DIR\}\//, "core/", line)
print line
}
' core/CMakeLists.txt | while IFS= read -r source; do
if [[ ! -f "$source" ]]; then
echo "missing wasm-safe project source: $source" >&2
exit 1
fi
if [[ -n "$filter" && "$(basename "$source")" != "$filter" ]]; then
continue
fi
printf '%s\n' "$source"
done | {
found=0
while IFS= read -r source; do
found=1
printf '%s\n' "$source"
done
if [[ -n "$filter" && "$found" -eq 0 ]]; then
echo "missing wasm-safe project source in CMake list: $filter" >&2
exit 1
fi
}

View File

@@ -0,0 +1,45 @@
#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$0")"
filter=${1:-}
awk '
/set\(linuxcnc_wasm_safe_probe_shims/ {
in_list = 1
next
}
in_list && /^[[:space:]]*\)/ {
exit
}
in_list {
line = $0
sub(/^[[:space:]]*/, "", line)
sub(/[[:space:]]*$/, "", line)
if (line == "") {
next
}
sub(/^\$\{CMAKE_CURRENT_SOURCE_DIR\}\//, "core/", line)
print line
}
' core/CMakeLists.txt | while IFS= read -r source; do
if [[ ! -f "$source" ]]; then
echo "missing wasm-safe shim source: $source" >&2
exit 1
fi
if [[ -n "$filter" && "$(basename "$source")" != "$filter" ]]; then
continue
fi
printf '%s\n' "$source"
done | {
found=0
while IFS= read -r source; do
found=1
printf '%s\n' "$source"
done
if [[ -n "$filter" && "$found" -eq 0 ]]; then
echo "missing wasm-safe shim in CMake list: $filter" >&2
exit 1
fi
}

View File

@@ -16,8 +16,8 @@
5187 0.000000
5188 0.000000
5189 0.000000
5210 0.000000
5211 0.000000
5210 1.000000
5211 -1.000000
5212 0.000000
5213 0.000000
5214 0.000000
@@ -27,8 +27,8 @@
5218 0.000000
5219 0.000000
5220 1.000000
5221 0.000000
5222 0.000000
5221 0.015192
5222 -1.041888
5223 0.000000
5224 0.000000
5225 0.000000
@@ -36,7 +36,7 @@
5227 0.000000
5228 0.000000
5229 0.000000
5230 0.000000
5230 30.000000
5241 0.000000
5242 0.000000
5243 0.000000

119
rs274ngc.var.bak Normal file
View File

@@ -0,0 +1,119 @@
5161 0.000000
5162 0.000000
5163 0.000000
5164 0.000000
5165 0.000000
5166 0.000000
5167 0.000000
5168 0.000000
5169 0.000000
5181 0.000000
5182 0.000000
5183 0.000000
5184 0.000000
5185 0.000000
5186 0.000000
5187 0.000000
5188 0.000000
5189 0.000000
5210 1.000000
5211 -1.000000
5212 0.000000
5213 0.000000
5214 0.000000
5215 0.000000
5216 0.000000
5217 0.000000
5218 0.000000
5219 0.000000
5220 1.000000
5221 0.015192
5222 -1.041888
5223 0.000000
5224 0.000000
5225 0.000000
5226 0.000000
5227 0.000000
5228 0.000000
5229 0.000000
5230 30.000000
5241 0.000000
5242 0.000000
5243 0.000000
5244 0.000000
5245 0.000000
5246 0.000000
5247 0.000000
5248 0.000000
5249 0.000000
5250 0.000000
5261 0.000000
5262 0.000000
5263 0.000000
5264 0.000000
5265 0.000000
5266 0.000000
5267 0.000000
5268 0.000000
5269 0.000000
5270 0.000000
5281 0.000000
5282 0.000000
5283 0.000000
5284 0.000000
5285 0.000000
5286 0.000000
5287 0.000000
5288 0.000000
5289 0.000000
5290 0.000000
5301 0.000000
5302 0.000000
5303 0.000000
5304 0.000000
5305 0.000000
5306 0.000000
5307 0.000000
5308 0.000000
5309 0.000000
5310 0.000000
5321 0.000000
5322 0.000000
5323 0.000000
5324 0.000000
5325 0.000000
5326 0.000000
5327 0.000000
5328 0.000000
5329 0.000000
5330 0.000000
5341 0.000000
5342 0.000000
5343 0.000000
5344 0.000000
5345 0.000000
5346 0.000000
5347 0.000000
5348 0.000000
5349 0.000000
5350 0.000000
5361 0.000000
5362 0.000000
5363 0.000000
5364 0.000000
5365 0.000000
5366 0.000000
5367 0.000000
5368 0.000000
5369 0.000000
5370 0.000000
5381 0.000000
5382 0.000000
5383 0.000000
5384 0.000000
5385 0.000000
5386 0.000000
5387 0.000000
5388 0.000000
5389 0.000000
5390 0.000000

View File

@@ -3,10 +3,250 @@ set -euo pipefail
cd "$(dirname "$0")"
manifest=${1:-linuxcnc-rs274-source-files.txt}
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
missing_root=/tmp/does-not-exist-linuxcnc
missing_root_log=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_native_missing_root.XXXXXX.log")
grep -F 'exec 9>"${TMPDIR:-/tmp}/cnc_sim_rs274_source_link.lock"' test-linuxcnc-source-link.sh >/dev/null
grep -F "flock 9" test-linuxcnc-source-link.sh >/dev/null
grep -F "missing LinuxCNC support object:" list-linuxcnc-source-support-objects.sh >/dev/null
grep -F "build LinuxCNC first or set LINUXCNC_ROOT to a built tree" list-linuxcnc-source-support-objects.sh >/dev/null
grep -F 'exec 9>"${TMPDIR:-/tmp}/cnc_sim_linuxcnc_rs274_native.lock"' test-linuxcnc-rs274-native.sh >/dev/null
grep -F "flock 9" test-linuxcnc-rs274-native.sh >/dev/null
grep -F "CNC_SIM_ENABLE_LINUXCNC_RS274_BACKEND is native-only; it links LinuxCNC librs274" core/CMakeLists.txt >/dev/null
grep -F "Set CNC_SIM_LINUXCNC_ROOT to the LinuxCNC source root" core/CMakeLists.txt >/dev/null
grep -F "find_package(Python3 REQUIRED COMPONENTS Development)" core/CMakeLists.txt >/dev/null
grep -F "target_compile_definitions(cnc_sim_objects" core/CMakeLists.txt >/dev/null
grep -F "CNC_SIM_ENABLE_LINUXCNC_RS274_BACKEND" core/CMakeLists.txt >/dev/null
grep -F 'target_link_directories(cnc_sim_core' core/CMakeLists.txt >/dev/null
grep -F "add_executable(cnc_sim_api_linuxcnc_rs274_smoke" core/CMakeLists.txt >/dev/null
grep -F "target_link_libraries(cnc_sim_core" core/CMakeLists.txt >/dev/null
grep -F "rs274" core/CMakeLists.txt >/dev/null
grep -F "tooldata" core/CMakeLists.txt >/dev/null
grep -F "Python3::Python" core/CMakeLists.txt >/dev/null
grep -F '"-Wl,-rpath,${CNC_SIM_LINUXCNC_ROOT}/lib"' core/CMakeLists.txt >/dev/null
grep -F "add_library(cnc_sim_linuxcnc_canon_bridge STATIC" core/CMakeLists.txt >/dev/null
grep -F "target_link_libraries(cnc_sim_linuxcnc_canon_bridge PRIVATE cnc_sim_core tooldata)" core/CMakeLists.txt >/dev/null
grep -F './list-linuxcnc-rs274-dump-project-sources.sh > "$project_source_list"' test-linuxcnc-source-link.sh >/dev/null
grep -F './list-linuxcnc-rs274-dump-project-sources.sh > "$project_source_list"' test-linuxcnc-rs274-native.sh >/dev/null
grep -F './list-linuxcnc-rs274-api-project-sources.sh > "$project_source_list"' test-linuxcnc-api-native.sh >/dev/null
grep -F './list-cnc-sim-core-sources.sh > "$core_source_list"' test-native.sh >/dev/null
grep -F './list-linuxcnc-bridge-smoke-project-sources.sh > "$project_source_list"' test-linuxcnc-bridge-native.sh >/dev/null
grep -F 'LINUXCNC_ROOT="$linuxcnc_root" ./list-linuxcnc-source-support-objects.sh > "$support_object_list"' test-linuxcnc-source-link.sh >/dev/null
for script in \
test-linuxcnc-source-syntax.sh \
test-linuxcnc-source-objects.sh \
test-linuxcnc-source-link.sh \
test-linuxcnc-bridge-native.sh \
test-linuxcnc-rs274-native.sh \
test-linuxcnc-api-native.sh; do
if LINUXCNC_ROOT="$missing_root" "./$script" >"$missing_root_log" 2>&1; then
echo "$script accepted missing LinuxCNC root: $missing_root" >&2
exit 1
fi
if ! grep -F "missing LinuxCNC root: $missing_root" "$missing_root_log" >/dev/null; then
echo "$script did not report missing LinuxCNC root clearly" >&2
sed -n '1,20p' "$missing_root_log" >&2
exit 1
fi
done
rm -f "$missing_root_log"
missing_manifest=${TMPDIR:-/tmp}/cnc_sim_missing_native_manifest.txt
missing_manifest_log=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_missing_native_manifest.XXXXXX.log")
rm -f "$missing_manifest"
for script in \
list-linuxcnc-source-manifest-sources.sh \
test-linuxcnc-source-syntax.sh \
test-linuxcnc-source-objects.sh \
test-linuxcnc-source-link.sh; do
if "./$script" "$missing_manifest" >"$missing_manifest_log" 2>&1; then
echo "$script accepted missing manifest: $missing_manifest" >&2
exit 1
fi
if ! grep -F "missing manifest: $missing_manifest" "$missing_manifest_log" >/dev/null; then
echo "$script did not report missing manifest clearly" >&2
sed -n '1,20p' "$missing_manifest_log" >&2
exit 1
fi
done
rm -f "$missing_manifest_log"
unknown_group_manifest=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_native_unknown_manifest_group.XXXXXX.txt")
unknown_group_log=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_native_unknown_manifest_group.XXXXXX.log")
printf 'bogus:src/emc/rs274ngc/interp_arc.cc:test unknown group\n' >"$unknown_group_manifest"
for script in \
list-linuxcnc-source-manifest-sources.sh \
test-linuxcnc-source-syntax.sh \
test-linuxcnc-source-objects.sh \
test-linuxcnc-source-link.sh; do
if "./$script" "$unknown_group_manifest" >"$unknown_group_log" 2>&1; then
echo "$script accepted unknown manifest group" >&2
exit 1
fi
if ! grep -F "unknown manifest group: bogus" "$unknown_group_log" >/dev/null; then
echo "$script did not report unknown manifest group clearly" >&2
sed -n '1,20p' "$unknown_group_log" >&2
exit 1
fi
done
rm -f "$unknown_group_manifest" "$unknown_group_log"
duplicate_manifest=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_native_duplicate_manifest.XXXXXX.txt")
duplicate_log=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_native_duplicate_manifest.XXXXXX.log")
printf 'core:src/emc/rs274ngc/interp_arc.cc:test duplicate source\ncore:src/emc/rs274ngc/interp_arc.cc:test duplicate source\n' >"$duplicate_manifest"
for script in \
list-linuxcnc-source-manifest-sources.sh \
test-linuxcnc-source-syntax.sh \
test-linuxcnc-source-objects.sh \
test-linuxcnc-source-link.sh; do
if "./$script" "$duplicate_manifest" >"$duplicate_log" 2>&1; then
echo "$script accepted duplicate manifest source" >&2
exit 1
fi
if ! grep -F "duplicate manifest source: src/emc/rs274ngc/interp_arc.cc" "$duplicate_log" >/dev/null; then
echo "$script did not report duplicate manifest source clearly" >&2
sed -n '1,20p' "$duplicate_log" >&2
exit 1
fi
done
rm -f "$duplicate_manifest" "$duplicate_log"
./list-linuxcnc-source-manifest-sources.sh "$manifest" core >/dev/null
grep -Fx "src/emc/rs274ngc/interp_arc.cc" \
< <(./list-linuxcnc-source-manifest-sources.sh "$manifest" core) >/dev/null
grep -Fx "src/emc/rs274ngc/interpmodule.cc" \
< <(./list-linuxcnc-source-manifest-sources.sh "$manifest" binding) >/dev/null
grep -Fx "src/emc/tooldata/tooldata_common.cc" \
< <(./list-linuxcnc-source-manifest-sources.sh "$manifest" tooldata) >/dev/null
unknown_filter_log=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_native_unknown_manifest_filter.XXXXXX.log")
if ./list-linuxcnc-source-manifest-sources.sh "$manifest" bogus >"$unknown_filter_log" 2>&1; then
echo "native manifest source lister accepted unknown filter" >&2
exit 1
fi
if ! grep -F "unknown manifest source filter: bogus" "$unknown_filter_log" >/dev/null; then
echo "native manifest source lister did not report unknown filter clearly" >&2
sed -n '1,20p' "$unknown_filter_log" >&2
exit 1
fi
rm -f "$unknown_filter_log"
unknown_output_log=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_native_unknown_manifest_output.XXXXXX.log")
if ./list-linuxcnc-source-manifest-sources.sh "$manifest" core bogus >"$unknown_output_log" 2>&1; then
echo "native manifest source lister accepted unknown output mode" >&2
exit 1
fi
if ! grep -F "unknown manifest source output mode: bogus" "$unknown_output_log" >/dev/null; then
echo "native manifest source lister did not report unknown output mode clearly" >&2
sed -n '1,20p' "$unknown_output_log" >&2
exit 1
fi
rm -f "$unknown_output_log"
grep -Fx "$linuxcnc_root/src/emc/rs274ngc/interp_arc.cc" \
< <(LINUXCNC_ROOT="$linuxcnc_root" ./list-linuxcnc-source-manifest-sources.sh "$manifest" core full) >/dev/null
./list-linuxcnc-rs274-dump-project-sources.sh >/dev/null
grep -Fx "core/tools/linuxcnc_rs274_dump.cpp" \
< <(./list-linuxcnc-rs274-dump-project-sources.sh linuxcnc_rs274_dump.cpp) >/dev/null
missing_dump_source_log=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_missing_rs274_dump_project_source.XXXXXX.log")
if ./list-linuxcnc-rs274-dump-project-sources.sh does_not_exist.cc >"$missing_dump_source_log" 2>&1; then
echo "rs274 dump project source lister accepted missing source filter" >&2
exit 1
fi
if ! grep -F "missing LinuxCNC rs274 dump project source in list: does_not_exist.cc" "$missing_dump_source_log" >/dev/null; then
echo "rs274 dump project source lister did not report missing source filter clearly" >&2
sed -n '1,20p' "$missing_dump_source_log" >&2
exit 1
fi
rm -f "$missing_dump_source_log"
./list-linuxcnc-rs274-api-project-sources.sh >/dev/null
grep -Fx "core/src/linuxcnc_rs274_backend.cpp" \
< <(./list-linuxcnc-rs274-api-project-sources.sh linuxcnc_rs274_backend.cpp) >/dev/null
missing_api_source_log=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_missing_rs274_api_project_source.XXXXXX.log")
if ./list-linuxcnc-rs274-api-project-sources.sh does_not_exist.cc >"$missing_api_source_log" 2>&1; then
echo "rs274 API project source lister accepted missing source filter" >&2
exit 1
fi
if ! grep -F "missing LinuxCNC rs274 API project source in CMake list: does_not_exist.cc" "$missing_api_source_log" >/dev/null; then
echo "rs274 API project source lister did not report missing source filter clearly" >&2
sed -n '1,20p' "$missing_api_source_log" >&2
exit 1
fi
rm -f "$missing_api_source_log"
./list-cnc-sim-core-sources.sh >/dev/null
grep -Fx "core/src/smoke_gcode_parser.cpp" \
< <(./list-cnc-sim-core-sources.sh smoke_gcode_parser.cpp) >/dev/null
missing_core_source_log=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_missing_core_source.XXXXXX.log")
if ./list-cnc-sim-core-sources.sh does_not_exist.cc >"$missing_core_source_log" 2>&1; then
echo "cnc sim core source lister accepted missing source filter" >&2
exit 1
fi
if ! grep -F "missing cnc sim core source in CMake list: does_not_exist.cc" "$missing_core_source_log" >/dev/null; then
echo "cnc sim core source lister did not report missing source filter clearly" >&2
sed -n '1,20p' "$missing_core_source_log" >&2
exit 1
fi
rm -f "$missing_core_source_log"
./list-linuxcnc-bridge-smoke-project-sources.sh >/dev/null
grep -Fx "core/src/linuxcnc_canon_bridge.cpp" \
< <(./list-linuxcnc-bridge-smoke-project-sources.sh linuxcnc_canon_bridge.cpp) >/dev/null
missing_bridge_source_log=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_missing_bridge_smoke_project_source.XXXXXX.log")
if ./list-linuxcnc-bridge-smoke-project-sources.sh does_not_exist.cc >"$missing_bridge_source_log" 2>&1; then
echo "LinuxCNC bridge smoke project source lister accepted missing source filter" >&2
exit 1
fi
if ! grep -F "missing LinuxCNC bridge smoke project source in list: does_not_exist.cc" "$missing_bridge_source_log" >/dev/null; then
echo "LinuxCNC bridge smoke project source lister did not report missing source filter clearly" >&2
sed -n '1,20p' "$missing_bridge_source_log" >&2
exit 1
fi
rm -f "$missing_bridge_source_log"
LINUXCNC_ROOT="$linuxcnc_root" ./list-linuxcnc-source-support-objects.sh >/dev/null
grep -F "/src/objects/emc/rs274ngc/interpmodule.o" \
< <(LINUXCNC_ROOT="$linuxcnc_root" ./list-linuxcnc-source-support-objects.sh interpmodule.o) >/dev/null
missing_support_object_log=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_missing_linuxcnc_support_object.XXXXXX.log")
if LINUXCNC_ROOT="$missing_root" ./list-linuxcnc-source-support-objects.sh >"$missing_support_object_log" 2>&1; then
echo "LinuxCNC support object lister accepted missing LinuxCNC root: $missing_root" >&2
exit 1
fi
if ! grep -F "missing LinuxCNC root: $missing_root" "$missing_support_object_log" >/dev/null; then
echo "LinuxCNC support object lister did not report missing LinuxCNC root clearly" >&2
sed -n '1,20p' "$missing_support_object_log" >&2
exit 1
fi
if LINUXCNC_ROOT="$linuxcnc_root" ./list-linuxcnc-source-support-objects.sh does_not_exist.o >"$missing_support_object_log" 2>&1; then
echo "LinuxCNC support object lister accepted missing object filter" >&2
exit 1
fi
if ! grep -F "missing LinuxCNC support object in list: does_not_exist.o" "$missing_support_object_log" >/dev/null; then
echo "LinuxCNC support object lister did not report missing object filter clearly" >&2
sed -n '1,20p' "$missing_support_object_log" >&2
exit 1
fi
rm -f "$missing_support_object_log"
missing_source_manifest=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_native_syntax_missing_source_manifest.XXXXXX.txt")
missing_source_log=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_native_syntax_missing_source.XXXXXX.log")
printf 'core:src/emc/rs274ngc/does_not_exist.cc:test missing source\n' >"$missing_source_manifest"
if ./test-linuxcnc-source-syntax.sh "$missing_source_manifest" >"$missing_source_log" 2>&1; then
echo "test-linuxcnc-source-syntax.sh accepted missing manifest file" >&2
exit 1
fi
if ! grep -F "missing manifest file: src/emc/rs274ngc/does_not_exist.cc" "$missing_source_log" >/dev/null; then
echo "test-linuxcnc-source-syntax.sh did not report missing manifest file clearly" >&2
sed -n '1,20p' "$missing_source_log" >&2
exit 1
fi
rm -f "$missing_source_manifest" "$missing_source_log"
./test-native.sh
./test-linuxcnc-source-syntax.sh
./test-linuxcnc-source-objects.sh
./test-linuxcnc-source-link.sh
./test-linuxcnc-source-syntax.sh "$manifest"
./test-linuxcnc-source-objects.sh "$manifest"
./test-linuxcnc-source-link.sh "$manifest"
./test-linuxcnc-bridge-native.sh
./test-linuxcnc-rs274-native.sh
./test-linuxcnc-api-native.sh

View File

@@ -5,11 +5,21 @@ cd "$(dirname "$0")"
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
cxx=${CXX:-g++}
build_dir=${TMPDIR:-/tmp}/cnc_sim_native
mkdir -p "$build_dir"
build_dir=$(mktemp -d "${TMPDIR:-/tmp}/cnc_sim_native.XXXXXX")
if [[ ! -d "$linuxcnc_root" ]]; then
echo "missing LinuxCNC root: $linuxcnc_root" >&2
exit 1
fi
trap 'rm -rf "$build_dir"' EXIT
var_file="$build_dir/rs274ngc-api.var"
cp "$linuxcnc_root/tests/halui/jogging/sim.var" "$var_file"
project_source_list="$build_dir/linuxcnc_rs274_api_project_sources.txt"
./list-linuxcnc-rs274-api-project-sources.sh > "$project_source_list"
mapfile -t project_sources < "$project_source_list"
"$cxx" -std=c++17 \
-DCNC_SIM_ENABLE_LINUXCNC_RS274_BACKEND \
$(python3.13-config --includes 2>/dev/null || python3-config --includes) \
@@ -21,15 +31,7 @@ cp "$linuxcnc_root/tests/halui/jogging/sim.var" "$var_file"
-I "$linuxcnc_root/src/emc/rs274ngc" \
-I "$linuxcnc_root/src/emc/motion" \
-I "$linuxcnc_root/include" \
core/src/canon_event_sink.cpp \
core/src/cnc_sim_api.cpp \
core/src/gcode_backend.cpp \
core/src/linuxcnc_canon_bridge.cpp \
core/src/linuxcnc_rs274_backend.cpp \
core/src/linuxcnc_tooldata_fixture.cpp \
core/src/rtcp_kinematics.cpp \
core/src/simulator_gcode_controls.cpp \
core/src/smoke_gcode_parser.cpp \
"${project_sources[@]}" \
core/tests/cnc_sim_api_linuxcnc_rs274_smoke.cpp \
-L "$linuxcnc_root/lib" \
-Wl,-rpath,"$linuxcnc_root/lib" \

View File

@@ -5,8 +5,17 @@ cd "$(dirname "$0")"
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
cxx=${CXX:-g++}
build_dir=${TMPDIR:-/tmp}/cnc_sim_native
mkdir -p "$build_dir"
build_dir=$(mktemp -d "${TMPDIR:-/tmp}/cnc_sim_native.XXXXXX")
if [[ ! -d "$linuxcnc_root" ]]; then
echo "missing LinuxCNC root: $linuxcnc_root" >&2
exit 1
fi
trap 'rm -rf "$build_dir"' EXIT
project_source_list="$build_dir/linuxcnc_bridge_smoke_project_sources.txt"
./list-linuxcnc-bridge-smoke-project-sources.sh > "$project_source_list"
mapfile -t project_sources < "$project_source_list"
"$cxx" -std=c++17 \
-I core/include \
@@ -17,9 +26,7 @@ mkdir -p "$build_dir"
-I "$linuxcnc_root/src/emc/motion" \
-I "$linuxcnc_root/src" \
-I "$linuxcnc_root/include" \
core/src/canon_event_sink.cpp \
core/src/linuxcnc_canon_bridge.cpp \
core/src/rtcp_kinematics.cpp \
"${project_sources[@]}" \
core/tests/linuxcnc_canon_bridge_smoke.cpp \
-L "$linuxcnc_root/lib" \
-Wl,-rpath,"$linuxcnc_root/lib" \

View File

@@ -5,14 +5,30 @@ cd "$(dirname "$0")"
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
cxx=${CXX:-g++}
build_dir=${TMPDIR:-/tmp}/cnc_sim_native
mkdir -p "$build_dir"
build_dir=$(mktemp -d "${TMPDIR:-/tmp}/cnc_sim_native.XXXXXX")
if [[ ! -d "$linuxcnc_root" ]]; then
echo "missing LinuxCNC root: $linuxcnc_root" >&2
exit 1
fi
trap 'rm -rf "$build_dir"' EXIT
# The LinuxCNC rs274 backend path can bus-error when two dumps run concurrently.
exec 9>"${TMPDIR:-/tmp}/cnc_sim_linuxcnc_rs274_native.lock"
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"
output_dir="$build_dir/outputs"
mkdir -p "$output_dir"
cp "$linuxcnc_root/tests/halui/jogging/sim.var" "$base_var_file"
cp "$base_var_file" "$var_file"
project_source_list="$build_dir/linuxcnc_rs274_dump_project_sources.txt"
./list-linuxcnc-rs274-dump-project-sources.sh > "$project_source_list"
mapfile -t project_sources < "$project_source_list"
"$cxx" -std=c++17 \
$(python3.13-config --includes 2>/dev/null || python3-config --includes) \
-I core/include \
@@ -23,12 +39,7 @@ cp "$base_var_file" "$var_file"
-I "$linuxcnc_root/src/emc/rs274ngc" \
-I "$linuxcnc_root/src/emc/motion" \
-I "$linuxcnc_root/include" \
core/src/canon_event_sink.cpp \
core/src/linuxcnc_canon_bridge.cpp \
core/src/linuxcnc_tooldata_fixture.cpp \
core/src/rtcp_kinematics.cpp \
core/src/simulator_gcode_controls.cpp \
core/tools/linuxcnc_rs274_dump.cpp \
"${project_sources[@]}" \
-L "$linuxcnc_root/lib" \
-Wl,-rpath,"$linuxcnc_root/lib" \
-lrs274 \
@@ -36,62 +47,65 @@ cp "$base_var_file" "$var_file"
-lpython3.13 \
-o "$build_dir/linuxcnc_rs274_dump"
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_basic_motion.ngc >/tmp/cnc_sim_linuxcnc_basic_motion.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/basic_mill.ngc >/tmp/cnc_sim_linuxcnc_basic_mill.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_rtcp_controls.ngc >/tmp/cnc_sim_linuxcnc_rtcp_controls.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_spindle_direction.ngc >/tmp/cnc_sim_linuxcnc_spindle_direction.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_spindle_modes.ngc >/tmp/cnc_sim_linuxcnc_spindle_modes.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_spindle_orient.ngc >/tmp/cnc_sim_linuxcnc_spindle_orient.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_io_controls.ngc >/tmp/cnc_sim_linuxcnc_io_controls.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_override_controls.ngc >/tmp/cnc_sim_linuxcnc_override_controls.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_modal_state.ngc >/tmp/cnc_sim_linuxcnc_modal_state.json
CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_modal_autorestore.ngc >/tmp/cnc_sim_linuxcnc_modal_autorestore.json
if CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_modal_invalidate.ngc >/tmp/cnc_sim_linuxcnc_modal_invalidate.json 2>/tmp/cnc_sim_linuxcnc_modal_invalidate.err; then
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_basic_motion.ngc >"$output_dir/cnc_sim_linuxcnc_basic_motion.json"
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/basic_mill.ngc >"$output_dir/cnc_sim_linuxcnc_basic_mill.json"
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_rtcp_controls.ngc >"$output_dir/cnc_sim_linuxcnc_rtcp_controls.json"
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_spindle_direction.ngc >"$output_dir/cnc_sim_linuxcnc_spindle_direction.json"
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_spindle_modes.ngc >"$output_dir/cnc_sim_linuxcnc_spindle_modes.json"
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_spindle_orient.ngc >"$output_dir/cnc_sim_linuxcnc_spindle_orient.json"
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_io_controls.ngc >"$output_dir/cnc_sim_linuxcnc_io_controls.json"
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_override_controls.ngc >"$output_dir/cnc_sim_linuxcnc_override_controls.json"
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_modal_state.ngc >"$output_dir/cnc_sim_linuxcnc_modal_state.json"
CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_modal_autorestore.ngc >"$output_dir/cnc_sim_linuxcnc_modal_autorestore.json"
if CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_modal_invalidate.ngc >"$output_dir/cnc_sim_linuxcnc_modal_invalidate.json" 2>"$output_dir/cnc_sim_linuxcnc_modal_invalidate.err"; then
echo "expected linuxcnc_modal_invalidate.ngc to fail" >&2
exit 1
fi
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_threading_sync.ngc >/tmp/cnc_sim_linuxcnc_threading_sync.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_threading_cycle.ngc >/tmp/cnc_sim_linuxcnc_threading_cycle.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_tool_number.ngc >/tmp/cnc_sim_linuxcnc_tool_number.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_program_stops.ngc >/tmp/cnc_sim_linuxcnc_program_stops.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_coolant.ngc >/tmp/cnc_sim_linuxcnc_coolant.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_feed_modes.ngc >/tmp/cnc_sim_linuxcnc_feed_modes.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_motion_modes.ngc >/tmp/cnc_sim_linuxcnc_motion_modes.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_tool_length.ngc >/tmp/cnc_sim_linuxcnc_tool_length.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_dynamic_tool_length.ngc >/tmp/cnc_sim_linuxcnc_dynamic_tool_length.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_canned_cycle.ngc >/tmp/cnc_sim_linuxcnc_canned_cycle.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_canned_cycles_extended.ngc >/tmp/cnc_sim_linuxcnc_canned_cycles_extended.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_canned_cycle_planes.ngc >/tmp/cnc_sim_linuxcnc_canned_cycle_planes.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_arc_planes.ngc >/tmp/cnc_sim_linuxcnc_arc_planes.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_arc_distance_modes.ngc >/tmp/cnc_sim_linuxcnc_arc_distance_modes.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_predefined_positions.ngc >/tmp/cnc_sim_linuxcnc_predefined_positions.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_machine_coordinates.ngc >/tmp/cnc_sim_linuxcnc_machine_coordinates.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_cutter_comp.ngc >/tmp/cnc_sim_linuxcnc_cutter_comp.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_comments.ngc >/tmp/cnc_sim_linuxcnc_comments.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_probe_no_error.ngc >/tmp/cnc_sim_linuxcnc_probe_no_error.json
CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/smoke_oword_subprogram.ngc >/tmp/cnc_sim_linuxcnc_oword_subprogram.json
CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_named_oword_subprogram.ngc >/tmp/cnc_sim_linuxcnc_named_oword_subprogram.json
CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_oword_control_flow.ngc >/tmp/cnc_sim_linuxcnc_oword_control_flow.json
CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_named_parameter_exists.ngc >/tmp/cnc_sim_linuxcnc_named_parameter_exists.json
CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_indexed_parameters.ngc >/tmp/cnc_sim_linuxcnc_indexed_parameters.json
CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_named_parameter_normalization.ngc >/tmp/cnc_sim_linuxcnc_named_parameter_normalization.json
INI_FILE_NAME="$ini_named_parameter_file" CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_ini_named_parameter.ngc >/tmp/cnc_sim_linuxcnc_ini_named_parameter.json
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"
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_tool_number.ngc >"$output_dir/cnc_sim_linuxcnc_tool_number.json"
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_program_stops.ngc >"$output_dir/cnc_sim_linuxcnc_program_stops.json"
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"
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"
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"
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_canned_cycles_extended.ngc >"$output_dir/cnc_sim_linuxcnc_canned_cycles_extended.json"
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_canned_cycle_planes.ngc >"$output_dir/cnc_sim_linuxcnc_canned_cycle_planes.json"
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_arc_planes.ngc >"$output_dir/cnc_sim_linuxcnc_arc_planes.json"
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_arc_distance_modes.ngc >"$output_dir/cnc_sim_linuxcnc_arc_distance_modes.json"
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_predefined_positions.ngc >"$output_dir/cnc_sim_linuxcnc_predefined_positions.json"
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"
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_comments.ngc >"$output_dir/cnc_sim_linuxcnc_comments.json"
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_probe_no_error.ngc >"$output_dir/cnc_sim_linuxcnc_probe_no_error.json"
CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/smoke_oword_subprogram.ngc >"$output_dir/cnc_sim_linuxcnc_oword_subprogram.json"
CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_named_oword_subprogram.ngc >"$output_dir/cnc_sim_linuxcnc_named_oword_subprogram.json"
CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_oword_control_flow.ngc >"$output_dir/cnc_sim_linuxcnc_oword_control_flow.json"
CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_named_parameter_exists.ngc >"$output_dir/cnc_sim_linuxcnc_named_parameter_exists.json"
CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_indexed_parameters.ngc >"$output_dir/cnc_sim_linuxcnc_indexed_parameters.json"
CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_named_parameter_normalization.ngc >"$output_dir/cnc_sim_linuxcnc_named_parameter_normalization.json"
INI_FILE_NAME="$ini_named_parameter_file" CNC_SIM_RS274_FILE_MODE=1 CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_ini_named_parameter.ngc >"$output_dir/cnc_sim_linuxcnc_ini_named_parameter.json"
cp "$base_var_file" "$var_file"
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_coordinate_offsets.ngc >/tmp/cnc_sim_linuxcnc_coordinate_offsets.json
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"
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_coordinate_l20.ngc >/tmp/cnc_sim_linuxcnc_coordinate_l20.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_coordinate_l20.ngc >"$output_dir/cnc_sim_linuxcnc_coordinate_l20.json"
cp "$base_var_file" "$var_file"
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_coordinate_p0.ngc >/tmp/cnc_sim_linuxcnc_coordinate_p0.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_coordinate_p0.ngc >"$output_dir/cnc_sim_linuxcnc_coordinate_p0.json"
cp "$base_var_file" "$var_file"
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_coordinate_select_all.ngc >/tmp/cnc_sim_linuxcnc_coordinate_select_all.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_coordinate_select_all.ngc >"$output_dir/cnc_sim_linuxcnc_coordinate_select_all.json"
cp "$base_var_file" "$var_file"
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_g92_restore.ngc >/tmp/cnc_sim_linuxcnc_g92_restore.json
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_g92_restore.ngc >"$output_dir/cnc_sim_linuxcnc_g92_restore.json"
cp "$base_var_file" "$var_file"
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_g52_offset.ngc >/tmp/cnc_sim_linuxcnc_g52_offset.json
python3 - <<'PY'
CNC_SIM_RS274_VAR="$var_file" "$build_dir/linuxcnc_rs274_dump" tests/gcode/linuxcnc_g52_offset.ngc >"$output_dir/cnc_sim_linuxcnc_g52_offset.json"
CNC_SIM_RS274_NATIVE_OUTPUT_DIR="$output_dir" python3 - <<'PY'
import json
import os
from pathlib import Path
OUTPUT_DIR = Path(os.environ["CNC_SIM_RS274_NATIVE_OUTPUT_DIR"])
def check(path, required):
events = json.loads(Path(path).read_text())
types = [event["type"] for event in events]
@@ -103,11 +117,14 @@ def check(path, required):
raise SystemExit(f"{path}: unexpected final XY position")
return events
required_motion = {"set-units", "set-plane", "set-spindle", "rapid", "set-feed", "linear-feed", "arc-feed", "dwell", "program-end"}
check("/tmp/cnc_sim_linuxcnc_basic_motion.json", required_motion)
check("/tmp/cnc_sim_linuxcnc_basic_mill.json", required_motion | {"tool-change"})
def load(name):
return json.loads((OUTPUT_DIR / name).read_text())
controls = json.loads(Path("/tmp/cnc_sim_linuxcnc_rtcp_controls.json").read_text())
required_motion = {"set-units", "set-plane", "set-spindle", "rapid", "set-feed", "linear-feed", "arc-feed", "dwell", "program-end"}
check(OUTPUT_DIR / "cnc_sim_linuxcnc_basic_motion.json", required_motion)
check(OUTPUT_DIR / "cnc_sim_linuxcnc_basic_mill.json", required_motion | {"tool-change"})
controls = load("cnc_sim_linuxcnc_rtcp_controls.json")
kin = [event for event in controls if event["type"] == "kinematics-switch"]
if [(event["reserved"], event["feed"]) for event in kin] != [(1, 1), (0, 0), (2, 1)]:
raise SystemExit("unexpected kinematics switch sequence")
@@ -115,7 +132,7 @@ rtcp = [event for event in controls if event["type"] == "rtcp-state"]
if [(event["line"], event["tool"], event["feed"]) for event in rtcp] != [(3, 0, 0), (4, 7, 1)]:
raise SystemExit("unexpected RTCP state sequence")
spindle = json.loads(Path("/tmp/cnc_sim_linuxcnc_spindle_direction.json").read_text())
spindle = load("cnc_sim_linuxcnc_spindle_direction.json")
spindle_states = [
(event["line"], event["spindle"], event["reserved"])
for event in spindle
@@ -128,7 +145,7 @@ if (3, 1200, 2) not in spindle_states:
if (4, 0, 0) not in spindle_states:
raise SystemExit("missing M5 stopped spindle state")
spindle_modes = json.loads(Path("/tmp/cnc_sim_linuxcnc_spindle_modes.json").read_text())
spindle_modes = load("cnc_sim_linuxcnc_spindle_modes.json")
spindle_mode_states = [
(event["line"], event["reserved"], event["feed"], event["tool"])
for event in spindle_modes
@@ -142,7 +159,7 @@ expected_spindle_mode_states = [
if spindle_mode_states != expected_spindle_mode_states:
raise SystemExit(f"unexpected G96/G97 spindle mode states: {spindle_mode_states!r}")
spindle_orient = json.loads(Path("/tmp/cnc_sim_linuxcnc_spindle_orient.json").read_text())
spindle_orient = load("cnc_sim_linuxcnc_spindle_orient.json")
if not any(
event["type"] == "comment" and
event["line"] == 2 and
@@ -163,7 +180,7 @@ if not any(
):
raise SystemExit("missing M19 spindle orient wait state")
io_controls = json.loads(Path("/tmp/cnc_sim_linuxcnc_io_controls.json").read_text())
io_controls = load("cnc_sim_linuxcnc_io_controls.json")
io_states = [
(event["line"], event["reserved"], event["tool"], event["feed"], event["arcTurns"], event["dwellSeconds"])
for event in io_controls
@@ -182,7 +199,7 @@ expected_io_states = [
if io_states != expected_io_states:
raise SystemExit(f"unexpected M62-M68 I/O states: {io_states!r}")
override_controls = json.loads(Path("/tmp/cnc_sim_linuxcnc_override_controls.json").read_text())
override_controls = load("cnc_sim_linuxcnc_override_controls.json")
override_states = [
(event["line"], event["reserved"], event["tool"], event["feed"])
for event in override_controls
@@ -206,7 +223,7 @@ expected_override_states = [
if override_states != expected_override_states:
raise SystemExit(f"unexpected M48-M53 override states: {override_states!r}")
modal_state = json.loads(Path("/tmp/cnc_sim_linuxcnc_modal_state.json").read_text())
modal_state = load("cnc_sim_linuxcnc_modal_state.json")
if not any(
event["type"] == "rapid" and
event["line"] == 7 and
@@ -226,7 +243,7 @@ if not any(
):
raise SystemExit("missing M72 restored XY plane arc")
modal_autorestore = json.loads(Path("/tmp/cnc_sim_linuxcnc_modal_autorestore.json").read_text())
modal_autorestore = load("cnc_sim_linuxcnc_modal_autorestore.json")
if not any(
event["type"] == "rapid" and
event["line"] == 9 and
@@ -243,7 +260,7 @@ if not any(
):
raise SystemExit("missing M73 autorestored incremental caller move")
threading_sync = json.loads(Path("/tmp/cnc_sim_linuxcnc_threading_sync.json").read_text())
threading_sync = load("cnc_sim_linuxcnc_threading_sync.json")
sync_states = [
(event["line"], event["reserved"], event["feed"], event["tool"])
for event in threading_sync
@@ -263,7 +280,7 @@ if not any(
):
raise SystemExit("missing G33.1 rigid tap motion line")
threading_cycle = json.loads(Path("/tmp/cnc_sim_linuxcnc_threading_cycle.json").read_text())
threading_cycle = load("cnc_sim_linuxcnc_threading_cycle.json")
if not any(
event["type"] == "comment" and
event["line"] == 4 and
@@ -282,7 +299,7 @@ if not any(
if not any(event["type"] == "program-end" and event["line"] == 5 for event in threading_cycle):
raise SystemExit("missing G76 program end line number")
tool_number = json.loads(Path("/tmp/cnc_sim_linuxcnc_tool_number.json").read_text())
tool_number = load("cnc_sim_linuxcnc_tool_number.json")
if not any(
event["type"] == "tool-change" and
event["line"] == 2 and
@@ -291,7 +308,7 @@ if not any(
):
raise SystemExit("missing M61 Q1 tool-number event line")
stops = json.loads(Path("/tmp/cnc_sim_linuxcnc_program_stops.json").read_text())
stops = load("cnc_sim_linuxcnc_program_stops.json")
stop_states = [
(event["line"], event["reserved"])
for event in stops
@@ -301,7 +318,7 @@ for expected in [(2, 1), (3, 2), (4, 3), (4, 1), (5, 0)]:
if expected not in stop_states:
raise SystemExit(f"missing program stop state {expected!r}")
coolant = json.loads(Path("/tmp/cnc_sim_linuxcnc_coolant.json").read_text())
coolant = load("cnc_sim_linuxcnc_coolant.json")
coolant_states = [
(event["line"], event["reserved"])
for event in coolant
@@ -311,7 +328,7 @@ for expected in [(2, 11), (3, 21), (4, 10), (4, 20)]:
if expected not in coolant_states:
raise SystemExit(f"missing coolant state {expected!r}")
feed_modes = json.loads(Path("/tmp/cnc_sim_linuxcnc_feed_modes.json").read_text())
feed_modes = load("cnc_sim_linuxcnc_feed_modes.json")
feed_mode_comments = [
(event["line"], event["reserved"])
for event in feed_modes
@@ -329,7 +346,7 @@ for expected in [(3, 0), (4, 0)]:
if expected not in feed_mode_events:
raise SystemExit(f"missing feed mode event {expected!r}")
motion_modes = json.loads(Path("/tmp/cnc_sim_linuxcnc_motion_modes.json").read_text())
motion_modes = load("cnc_sim_linuxcnc_motion_modes.json")
motion_mode_states = [
(event["line"], event["reserved"], event["feed"])
for event in motion_modes
@@ -339,7 +356,7 @@ 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}")
tool_length = json.loads(Path("/tmp/cnc_sim_linuxcnc_tool_length.json").read_text())
tool_length = load("cnc_sim_linuxcnc_tool_length.json")
if not any(
event["type"] == "comment" and
event["line"] == 2 and
@@ -357,7 +374,7 @@ if not any(
):
raise SystemExit("missing G49 tool length clear event")
dynamic_tool_length = json.loads(Path("/tmp/cnc_sim_linuxcnc_dynamic_tool_length.json").read_text())
dynamic_tool_length = load("cnc_sim_linuxcnc_dynamic_tool_length.json")
dynamic_offsets = [
(event["line"], event["start"]["x"], event["start"]["z"])
for event in dynamic_tool_length
@@ -367,7 +384,7 @@ expected_dynamic_offsets = [(2, 1, 2), (3, 1.25, 2.5), (4, 1.25, 15), (5, 0, 0)]
if dynamic_offsets != expected_dynamic_offsets:
raise SystemExit(f"unexpected G43.1/G43.2 tool length offsets: {dynamic_offsets!r}")
cycle = json.loads(Path("/tmp/cnc_sim_linuxcnc_canned_cycle.json").read_text())
cycle = load("cnc_sim_linuxcnc_canned_cycle.json")
motions = [event for event in cycle if event["type"] in {"rapid", "linear-feed"}]
expected_cycle = [
("rapid", 0, 0, 5),
@@ -380,7 +397,7 @@ actual_cycle = [(event["type"], event["end"]["x"], event["end"]["y"], event["end
if actual_cycle != expected_cycle:
raise SystemExit(f"unexpected G81/G80 expansion: {actual_cycle!r}")
cycle_planes = json.loads(Path("/tmp/cnc_sim_linuxcnc_canned_cycle_planes.json").read_text())
cycle_planes = load("cnc_sim_linuxcnc_canned_cycle_planes.json")
if not any(
event["type"] == "linear-feed" and
event["line"] == 4 and
@@ -526,7 +543,7 @@ expected_plane_g87_sequence = [
if plane_g87_sequence != expected_plane_g87_sequence:
raise SystemExit(f"unexpected G19 G87 plane sequence: {plane_g87_sequence!r}")
extended_cycle = json.loads(Path("/tmp/cnc_sim_linuxcnc_canned_cycles_extended.json").read_text())
extended_cycle = load("cnc_sim_linuxcnc_canned_cycles_extended.json")
if not any(
event["type"] == "linear-feed" and
event["line"] == 3 and
@@ -653,7 +670,7 @@ expected_g87_sequence = [
if g87_sequence != expected_g87_sequence:
raise SystemExit(f"unexpected G87 back-boring sequence: {g87_sequence!r}")
arc_planes = json.loads(Path("/tmp/cnc_sim_linuxcnc_arc_planes.json").read_text())
arc_planes = load("cnc_sim_linuxcnc_arc_planes.json")
if not any(
event["type"] == "arc-feed" and
event["line"] == 5 and
@@ -683,7 +700,7 @@ if not any(
):
raise SystemExit("missing G19 YZ plane arc-feed mapping")
arc_distance = json.loads(Path("/tmp/cnc_sim_linuxcnc_arc_distance_modes.json").read_text())
arc_distance = load("cnc_sim_linuxcnc_arc_distance_modes.json")
arc_centers = [
(event["line"], event["center"]["x"], event["center"]["y"])
for event in arc_distance
@@ -693,7 +710,7 @@ expected_arc_centers = [(5, 5, 0), (7, 15, 0), (9, 25, 0)]
if arc_centers != expected_arc_centers:
raise SystemExit(f"unexpected G90.1/G91.1 arc centers: {arc_centers!r}")
predefined = json.loads(Path("/tmp/cnc_sim_linuxcnc_predefined_positions.json").read_text())
predefined = load("cnc_sim_linuxcnc_predefined_positions.json")
predefined_rapids = [
(
event["line"],
@@ -712,7 +729,7 @@ expected_predefined_rapids = [
if predefined_rapids != expected_predefined_rapids:
raise SystemExit(f"unexpected G28/G30 rapid sequence: {predefined_rapids!r}")
machine_coords = json.loads(Path("/tmp/cnc_sim_linuxcnc_machine_coordinates.json").read_text())
machine_coords = load("cnc_sim_linuxcnc_machine_coordinates.json")
machine_moves = [
(
event["type"], event["line"],
@@ -730,7 +747,7 @@ expected_machine_moves = [
if machine_moves != expected_machine_moves:
raise SystemExit(f"unexpected G53 machine-coordinate moves: {machine_moves!r}")
cutter_comp = json.loads(Path("/tmp/cnc_sim_linuxcnc_cutter_comp.json").read_text())
cutter_comp = load("cnc_sim_linuxcnc_cutter_comp.json")
cutter_comp_motions = [
event
for event in cutter_comp
@@ -758,11 +775,11 @@ actual_cutter_comp = [
if actual_cutter_comp != expected_cutter_comp:
raise SystemExit(f"unexpected cutter compensation path: {actual_cutter_comp!r}")
comments = json.loads(Path("/tmp/cnc_sim_linuxcnc_comments.json").read_text())
comments = load("cnc_sim_linuxcnc_comments.json")
if not any(event["type"] == "comment" and event["line"] == 2 for event in comments):
raise SystemExit("missing LinuxCNC comment line event")
probe = json.loads(Path("/tmp/cnc_sim_linuxcnc_probe_no_error.json").read_text())
probe = load("cnc_sim_linuxcnc_probe_no_error.json")
probe_events = [
(event["line"], event["reserved"], event["start"]["z"], event["end"]["z"])
for event in probe
@@ -787,7 +804,7 @@ if not any(
):
raise SystemExit("missing #5070 probe-tripped conditional motion")
oword = json.loads(Path("/tmp/cnc_sim_linuxcnc_oword_subprogram.json").read_text())
oword = load("cnc_sim_linuxcnc_oword_subprogram.json")
if not any(
event["type"] == "linear-feed" and
event["line"] == 8 and
@@ -812,7 +829,7 @@ if any(
):
raise SystemExit("LinuxCNC O-word return should skip remaining subprogram body")
named_oword = json.loads(Path("/tmp/cnc_sim_linuxcnc_named_oword_subprogram.json").read_text())
named_oword = load("cnc_sim_linuxcnc_named_oword_subprogram.json")
if not any(
event["type"] == "linear-feed" and
event["line"] == 9 and
@@ -845,7 +862,7 @@ if any(
):
raise SystemExit("LinuxCNC named O-word return should skip remaining subprogram body")
oword_flow = json.loads(Path("/tmp/cnc_sim_linuxcnc_oword_control_flow.json").read_text())
oword_flow = load("cnc_sim_linuxcnc_oword_control_flow.json")
if not any(event["type"] == "linear-feed" and event["line"] == 7 and event["end"]["x"] == 2 for event in oword_flow):
raise SystemExit("missing LinuxCNC O-word elseif branch motion")
if any(
@@ -910,7 +927,7 @@ if not any(
):
raise SystemExit("missing LinuxCNC O-word do/continue skipped-body counter motion")
exists = json.loads(Path("/tmp/cnc_sim_linuxcnc_named_parameter_exists.json").read_text())
exists = load("cnc_sim_linuxcnc_named_parameter_exists.json")
exists_moves = [
(event["line"], event["end"]["x"], event["end"]["y"])
for event in exists
@@ -920,7 +937,7 @@ expected_exists_moves = [(5, 1, 0), (8, 1, 1)]
if exists_moves != expected_exists_moves:
raise SystemExit(f"unexpected LinuxCNC EXISTS named parameter branch motions: {exists_moves!r}")
indexed = json.loads(Path("/tmp/cnc_sim_linuxcnc_indexed_parameters.json").read_text())
indexed = load("cnc_sim_linuxcnc_indexed_parameters.json")
indexed_moves = [
(
event["line"],
@@ -947,7 +964,7 @@ expected_indexed_moves = [
if indexed_moves != expected_indexed_moves:
raise SystemExit(f"unexpected LinuxCNC indexed/indirect parameter motions: {indexed_moves!r}")
normalized = json.loads(Path("/tmp/cnc_sim_linuxcnc_named_parameter_normalization.json").read_text())
normalized = load("cnc_sim_linuxcnc_named_parameter_normalization.json")
normalized_moves = [
(event["line"], event["end"]["x"], event["end"]["y"])
for event in normalized
@@ -957,7 +974,7 @@ expected_normalized_moves = [(4, 12, 0), (6, 12, 1)]
if normalized_moves != expected_normalized_moves:
raise SystemExit(f"unexpected LinuxCNC normalized named parameter motions: {normalized_moves!r}")
ini_named = json.loads(Path("/tmp/cnc_sim_linuxcnc_ini_named_parameter.json").read_text())
ini_named = load("cnc_sim_linuxcnc_ini_named_parameter.json")
ini_named_moves = [
(event["line"], event["end"]["x"], event["end"]["y"])
for event in ini_named
@@ -967,7 +984,7 @@ expected_ini_named_moves = [(3, 3.25, 0), (5, 3.25, 1)]
if ini_named_moves != expected_ini_named_moves:
raise SystemExit(f"unexpected LinuxCNC INI named parameter motions: {ini_named_moves!r}")
coords = json.loads(Path("/tmp/cnc_sim_linuxcnc_coordinate_offsets.json").read_text())
coords = load("cnc_sim_linuxcnc_coordinate_offsets.json")
g5x = [event for event in coords if event["type"] == "set-g5x-offset"]
g92 = [event for event in coords if event["type"] == "set-g92-offset"]
rot = [event for event in coords if event["type"] == "set-xy-rotation"]
@@ -993,7 +1010,7 @@ if not any(
if not any(event["type"] == "program-end" and event["line"] == 5 for event in coords):
raise SystemExit("missing coordinate program end line number")
l20 = json.loads(Path("/tmp/cnc_sim_linuxcnc_coordinate_l20.json").read_text())
l20 = load("cnc_sim_linuxcnc_coordinate_l20.json")
if not any(
event["type"] == "set-g5x-offset" and
event["line"] == 4 and
@@ -1007,7 +1024,7 @@ if not any(
if not any(event["type"] == "program-end" and event["line"] == 5 for event in l20):
raise SystemExit("missing G10 L20 program end line number")
p0 = json.loads(Path("/tmp/cnc_sim_linuxcnc_coordinate_p0.json").read_text())
p0 = load("cnc_sim_linuxcnc_coordinate_p0.json")
if not any(
event["type"] == "set-g5x-offset" and
event["line"] == 3 and
@@ -1021,7 +1038,7 @@ if not any(
if not any(event["type"] == "program-end" and event["line"] == 4 for event in p0):
raise SystemExit("missing G10 P0 program end line number")
select_all = json.loads(Path("/tmp/cnc_sim_linuxcnc_coordinate_select_all.json").read_text())
select_all = load("cnc_sim_linuxcnc_coordinate_select_all.json")
select_events = [
(event["line"], event["tool"], event["start"]["x"])
for event in select_all
@@ -1041,7 +1058,7 @@ expected_select_events = [
if select_events != expected_select_events:
raise SystemExit(f"unexpected G54-G59.3 selection events: {select_events!r}")
g92_restore = json.loads(Path("/tmp/cnc_sim_linuxcnc_g92_restore.json").read_text())
g92_restore = load("cnc_sim_linuxcnc_g92_restore.json")
g92_states = [
(event["line"], event["start"]["x"], event["start"]["y"], event["start"]["z"])
for event in g92_restore
@@ -1059,7 +1076,7 @@ if g92_states != expected_g92_states:
if not any(event["type"] == "program-end" and event["line"] == 7 for event in g92_restore):
raise SystemExit("missing G92 restore program end line number")
g52_offset = json.loads(Path("/tmp/cnc_sim_linuxcnc_g52_offset.json").read_text())
g52_offset = load("cnc_sim_linuxcnc_g52_offset.json")
g52_states = [
(event["line"], event["start"]["x"], event["start"]["y"], event["start"]["z"])
for event in g52_offset
@@ -1079,45 +1096,45 @@ if not any(event["type"] == "program-end" and event["line"] == 7 for event in g5
PY
echo "linuxcnc rs274 native smoke passed"
echo "dumped /tmp/cnc_sim_linuxcnc_basic_motion.json"
echo "dumped /tmp/cnc_sim_linuxcnc_basic_mill.json"
echo "dumped /tmp/cnc_sim_linuxcnc_rtcp_controls.json"
echo "dumped /tmp/cnc_sim_linuxcnc_spindle_direction.json"
echo "dumped /tmp/cnc_sim_linuxcnc_spindle_modes.json"
echo "dumped /tmp/cnc_sim_linuxcnc_spindle_orient.json"
echo "dumped /tmp/cnc_sim_linuxcnc_io_controls.json"
echo "dumped /tmp/cnc_sim_linuxcnc_override_controls.json"
echo "dumped /tmp/cnc_sim_linuxcnc_modal_state.json"
echo "dumped /tmp/cnc_sim_linuxcnc_modal_autorestore.json"
echo "dumped /tmp/cnc_sim_linuxcnc_threading_sync.json"
echo "dumped /tmp/cnc_sim_linuxcnc_threading_cycle.json"
echo "dumped /tmp/cnc_sim_linuxcnc_tool_number.json"
echo "dumped /tmp/cnc_sim_linuxcnc_program_stops.json"
echo "dumped /tmp/cnc_sim_linuxcnc_coolant.json"
echo "dumped /tmp/cnc_sim_linuxcnc_feed_modes.json"
echo "dumped /tmp/cnc_sim_linuxcnc_motion_modes.json"
echo "dumped /tmp/cnc_sim_linuxcnc_tool_length.json"
echo "dumped /tmp/cnc_sim_linuxcnc_dynamic_tool_length.json"
echo "dumped /tmp/cnc_sim_linuxcnc_canned_cycle.json"
echo "dumped /tmp/cnc_sim_linuxcnc_canned_cycles_extended.json"
echo "dumped /tmp/cnc_sim_linuxcnc_canned_cycle_planes.json"
echo "dumped /tmp/cnc_sim_linuxcnc_arc_planes.json"
echo "dumped /tmp/cnc_sim_linuxcnc_arc_distance_modes.json"
echo "dumped /tmp/cnc_sim_linuxcnc_predefined_positions.json"
echo "dumped /tmp/cnc_sim_linuxcnc_machine_coordinates.json"
echo "dumped /tmp/cnc_sim_linuxcnc_cutter_comp.json"
echo "dumped /tmp/cnc_sim_linuxcnc_comments.json"
echo "dumped /tmp/cnc_sim_linuxcnc_probe_no_error.json"
echo "dumped /tmp/cnc_sim_linuxcnc_oword_subprogram.json"
echo "dumped /tmp/cnc_sim_linuxcnc_named_oword_subprogram.json"
echo "dumped /tmp/cnc_sim_linuxcnc_oword_control_flow.json"
echo "dumped /tmp/cnc_sim_linuxcnc_named_parameter_exists.json"
echo "dumped /tmp/cnc_sim_linuxcnc_indexed_parameters.json"
echo "dumped /tmp/cnc_sim_linuxcnc_named_parameter_normalization.json"
echo "dumped /tmp/cnc_sim_linuxcnc_ini_named_parameter.json"
echo "dumped /tmp/cnc_sim_linuxcnc_coordinate_offsets.json"
echo "dumped /tmp/cnc_sim_linuxcnc_coordinate_l20.json"
echo "dumped /tmp/cnc_sim_linuxcnc_coordinate_p0.json"
echo "dumped /tmp/cnc_sim_linuxcnc_coordinate_select_all.json"
echo "dumped /tmp/cnc_sim_linuxcnc_g92_restore.json"
echo "dumped /tmp/cnc_sim_linuxcnc_g52_offset.json"
echo "dumped $output_dir/cnc_sim_linuxcnc_basic_motion.json"
echo "dumped $output_dir/cnc_sim_linuxcnc_basic_mill.json"
echo "dumped $output_dir/cnc_sim_linuxcnc_rtcp_controls.json"
echo "dumped $output_dir/cnc_sim_linuxcnc_spindle_direction.json"
echo "dumped $output_dir/cnc_sim_linuxcnc_spindle_modes.json"
echo "dumped $output_dir/cnc_sim_linuxcnc_spindle_orient.json"
echo "dumped $output_dir/cnc_sim_linuxcnc_io_controls.json"
echo "dumped $output_dir/cnc_sim_linuxcnc_override_controls.json"
echo "dumped $output_dir/cnc_sim_linuxcnc_modal_state.json"
echo "dumped $output_dir/cnc_sim_linuxcnc_modal_autorestore.json"
echo "dumped $output_dir/cnc_sim_linuxcnc_threading_sync.json"
echo "dumped $output_dir/cnc_sim_linuxcnc_threading_cycle.json"
echo "dumped $output_dir/cnc_sim_linuxcnc_tool_number.json"
echo "dumped $output_dir/cnc_sim_linuxcnc_program_stops.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_tool_length.json"
echo "dumped $output_dir/cnc_sim_linuxcnc_dynamic_tool_length.json"
echo "dumped $output_dir/cnc_sim_linuxcnc_canned_cycle.json"
echo "dumped $output_dir/cnc_sim_linuxcnc_canned_cycles_extended.json"
echo "dumped $output_dir/cnc_sim_linuxcnc_canned_cycle_planes.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_predefined_positions.json"
echo "dumped $output_dir/cnc_sim_linuxcnc_machine_coordinates.json"
echo "dumped $output_dir/cnc_sim_linuxcnc_cutter_comp.json"
echo "dumped $output_dir/cnc_sim_linuxcnc_comments.json"
echo "dumped $output_dir/cnc_sim_linuxcnc_probe_no_error.json"
echo "dumped $output_dir/cnc_sim_linuxcnc_oword_subprogram.json"
echo "dumped $output_dir/cnc_sim_linuxcnc_named_oword_subprogram.json"
echo "dumped $output_dir/cnc_sim_linuxcnc_oword_control_flow.json"
echo "dumped $output_dir/cnc_sim_linuxcnc_named_parameter_exists.json"
echo "dumped $output_dir/cnc_sim_linuxcnc_indexed_parameters.json"
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_coordinate_offsets.json"
echo "dumped $output_dir/cnc_sim_linuxcnc_coordinate_l20.json"
echo "dumped $output_dir/cnc_sim_linuxcnc_coordinate_p0.json"
echo "dumped $output_dir/cnc_sim_linuxcnc_coordinate_select_all.json"
echo "dumped $output_dir/cnc_sim_linuxcnc_g92_restore.json"
echo "dumped $output_dir/cnc_sim_linuxcnc_g52_offset.json"

File diff suppressed because it is too large Load Diff

View File

@@ -5,11 +5,21 @@ cd "$(dirname "$0")"
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
cxx=${CXX:-g++}
build_dir=${TMPDIR:-/tmp}/cnc_sim_rs274_objects
build_dir=$(mktemp -d "${TMPDIR:-/tmp}/cnc_sim_rs274_objects.XXXXXX")
python_includes=$(python3.13-config --includes 2>/dev/null || python3-config --includes)
manifest=${1:-linuxcnc-rs274-source-files.txt}
rm -rf "$build_dir"
mkdir -p "$build_dir"
if [[ ! -f "$manifest" ]]; then
echo "missing manifest: $manifest" >&2
exit 1
fi
if [[ ! -d "$linuxcnc_root" ]]; then
echo "missing LinuxCNC root: $linuxcnc_root" >&2
exit 1
fi
trap 'rm -rf "$build_dir"' EXIT
common_flags=(
-std=c++17
@@ -24,26 +34,17 @@ common_flags=(
)
sources=()
while IFS=: read -r group path note; do
case "$group" in
core)
sources+=("$path")
;;
""|\#*|binding|tooldata)
;;
*)
echo "unknown manifest group: $group" >&2
exit 1
;;
esac
done < linuxcnc-rs274-source-files.txt
source_list="$build_dir/linuxcnc_core_sources.txt"
LINUXCNC_ROOT="$linuxcnc_root" ./list-linuxcnc-source-manifest-sources.sh "$manifest" core full > "$source_list"
mapfile -t sources < "$source_list"
source_index=0
for source in "${sources[@]}"; do
obj="$build_dir/$(basename "$source" .cc).o"
obj="$build_dir/linuxcnc_${source_index}.o"
# shellcheck disable=SC2086
"$cxx" "${common_flags[@]}" $python_includes -c "$linuxcnc_root/$source" -o "$obj"
"$cxx" "${common_flags[@]}" $python_includes -c "$source" -o "$obj"
source_index=$((source_index + 1))
done
echo "linuxcnc rs274 source object build passed (${#sources[@]} objects)"
echo "built objects in $build_dir"

View File

@@ -6,16 +6,44 @@ cd "$(dirname "$0")"
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
cxx=${CXX:-g++}
python_includes=$(python3.13-config --includes 2>/dev/null || python3-config --includes)
manifest=${1:-linuxcnc-rs274-source-files.txt}
while IFS=: read -r group path note; do
case "$group" in
""|\#*) continue ;;
esac
if [[ ! -f "$linuxcnc_root/$path" ]]; then
echo "missing manifest file: $path" >&2
exit 1
fi
done < linuxcnc-rs274-source-files.txt
if [[ ! -f "$manifest" ]]; then
echo "missing manifest: $manifest" >&2
exit 1
fi
if [[ ! -d "$linuxcnc_root" ]]; then
echo "missing LinuxCNC root: $linuxcnc_root" >&2
exit 1
fi
source_list=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_linuxcnc_source_syntax_sources.XXXXXX.txt")
trap 'rm -f "$source_list"' EXIT
LINUXCNC_ROOT="$linuxcnc_root" ./list-linuxcnc-source-manifest-sources.sh "$manifest" all full > "$source_list"
missing_source_manifest=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_missing_rs274_manifest_source.XXXXXX.txt")
missing_source_log=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_missing_rs274_manifest_source.XXXXXX.log")
printf 'core:src/emc/rs274ngc/does_not_exist.cc:test missing source\n' >"$missing_source_manifest"
if ./test-linuxcnc-source-objects.sh "$missing_source_manifest" >"$missing_source_log" 2>&1; then
echo "linuxcnc source object probe accepted missing manifest file" >&2
exit 1
fi
if ! grep -F "missing manifest file: src/emc/rs274ngc/does_not_exist.cc" "$missing_source_log" >/dev/null; then
echo "linuxcnc source object probe did not report missing manifest file clearly" >&2
sed -n '1,20p' "$missing_source_log" >&2
exit 1
fi
if ./test-linuxcnc-source-link.sh "$missing_source_manifest" >"$missing_source_log" 2>&1; then
echo "linuxcnc source link probe accepted missing manifest file" >&2
exit 1
fi
if ! grep -F "missing manifest file: src/emc/rs274ngc/does_not_exist.cc" "$missing_source_log" >/dev/null; then
echo "linuxcnc source link probe did not report missing manifest file clearly" >&2
sed -n '1,20p' "$missing_source_log" >&2
exit 1
fi
rm -f "$missing_source_manifest" "$missing_source_log"
common_flags=(
-std=c++17
@@ -30,19 +58,10 @@ common_flags=(
-I "$linuxcnc_root/include"
)
probe_sources=(
src/emc/rs274ngc/interp_base.cc
src/emc/rs274ngc/modal_state.cc
src/emc/rs274ngc/interp_arc.cc
src/emc/rs274ngc/interp_find.cc
src/emc/rs274ngc/interp_read.cc
src/emc/rs274ngc/nurbs_additional_functions.cc
)
for source in "${probe_sources[@]}"; do
while IFS= read -r source; do
[[ -z "$source" ]] && continue
# shellcheck disable=SC2086
"$cxx" "${common_flags[@]}" $python_includes "$linuxcnc_root/$source"
done
"$cxx" "${common_flags[@]}" $python_includes "$source"
done < "$source_list"
echo "linuxcnc rs274 source syntax probe passed"

116
test-linuxcnc-wasm-blockers.sh Executable file
View File

@@ -0,0 +1,116 @@
#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$0")"
manifest=${1:-linuxcnc-rs274-wasm-source-files.txt}
missing_manifest=${TMPDIR:-/tmp}/cnc_sim_missing_wasm_blocker_manifest.txt
missing_manifest_log=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_missing_wasm_blocker_manifest.XXXXXX.log")
rm -f "$missing_manifest"
if ./analyze-linuxcnc-wasm-blockers.sh "$missing_manifest" >"$missing_manifest_log" 2>&1; then
echo "wasm blocker analyzer accepted missing manifest: $missing_manifest" >&2
exit 1
fi
if ! grep -F "missing manifest: $missing_manifest" "$missing_manifest_log" >/dev/null; then
echo "wasm blocker analyzer did not report missing manifest clearly" >&2
sed -n '1,20p' "$missing_manifest_log" >&2
exit 1
fi
rm -f "$missing_manifest_log"
missing_root=/tmp/does-not-exist-linuxcnc
missing_root_log=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_wasm_blocker_missing_root.XXXXXX.log")
if LINUXCNC_ROOT="$missing_root" ./analyze-linuxcnc-wasm-blockers.sh "$manifest" >"$missing_root_log" 2>&1; then
echo "wasm blocker analyzer accepted missing LinuxCNC root" >&2
exit 1
fi
if ! grep -F "missing LinuxCNC root: $missing_root" "$missing_root_log" >/dev/null; then
echo "wasm blocker analyzer did not report missing LinuxCNC root clearly" >&2
sed -n '1,20p' "$missing_root_log" >&2
exit 1
fi
rm -f "$missing_root_log"
output=$(./analyze-linuxcnc-wasm-blockers.sh "$manifest")
missing_source_manifest=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_missing_wasm_blocker_manifest_source.XXXXXX.txt")
missing_source_log=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_missing_wasm_blocker_manifest_source.XXXXXX.log")
printf 'blocked:src/emc/tooldata/does_not_exist.cc:test missing blocked source\n' >"$missing_source_manifest"
if ./analyze-linuxcnc-wasm-blockers.sh "$missing_source_manifest" >"$missing_source_log" 2>&1; then
echo "wasm blocker analyzer accepted missing manifest source" >&2
exit 1
fi
if ! grep -F "missing manifest source: src/emc/tooldata/does_not_exist.cc" "$missing_source_log" >/dev/null; then
echo "wasm blocker analyzer did not report missing manifest source clearly" >&2
sed -n '1,20p' "$missing_source_log" >&2
exit 1
fi
rm -f "$missing_source_manifest" "$missing_source_log"
duplicate_manifest=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_duplicate_wasm_blocker_manifest.XXXXXX.txt")
duplicate_manifest_log=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_duplicate_wasm_blocker_manifest.XXXXXX.log")
cat >"$duplicate_manifest" <<'EOF'
core:src/emc/rs274ngc/interp_arc.cc:duplicate core entry
core:src/emc/rs274ngc/interp_arc.cc:duplicate core entry
blocked:src/emc/tooldata/tooldata_mmap.cc:blocked entry
EOF
if ./analyze-linuxcnc-wasm-blockers.sh "$duplicate_manifest" >"$duplicate_manifest_log" 2>&1; then
echo "wasm blocker analyzer accepted duplicate manifest source" >&2
exit 1
fi
if ! grep -F "duplicate manifest source: src/emc/rs274ngc/interp_arc.cc" "$duplicate_manifest_log" >/dev/null; then
echo "wasm blocker analyzer did not report duplicate manifest source clearly" >&2
sed -n '1,20p' "$duplicate_manifest_log" >&2
exit 1
fi
rm -f "$duplicate_manifest" "$duplicate_manifest_log"
missing_replacement_manifest=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_missing_wasm_blocked_replacement.XXXXXX.txt")
missing_replacement_log=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_missing_wasm_blocked_replacement.XXXXXX.log")
cat >"$missing_replacement_manifest" <<'EOF'
core:src/emc/rs274ngc/interp_arc.cc:core entry
blocked:src/emc/tooldata/tooldata_db.cc:blocked entry without wasm replacement
EOF
if ./analyze-linuxcnc-wasm-blockers.sh "$missing_replacement_manifest" >"$missing_replacement_log" 2>&1; then
echo "wasm blocker analyzer accepted blocked source without replacement mapping" >&2
exit 1
fi
if ! grep -F "missing blocked replacement mapping: src/emc/tooldata/tooldata_db.cc" "$missing_replacement_log" >/dev/null; then
echo "wasm blocker analyzer did not report missing replacement mapping clearly" >&2
sed -n '1,20p' "$missing_replacement_log" >&2
exit 1
fi
rm -f "$missing_replacement_manifest" "$missing_replacement_log"
grep -F "[manifest]" <<<"$output" >/dev/null
grep -F "core=25" <<<"$(sed -n '/^\[manifest\]/,/^$/p' <<<"$output")" >/dev/null
grep -F "blocked=1" <<<"$(sed -n '/^\[manifest\]/,/^$/p' <<<"$output")" >/dev/null
grep -F "[python]" <<<"$output" >/dev/null
grep -F "(none)" <<<"$(sed -n '/^\[python\]/,/^$/p' <<<"$output")" >/dev/null
grep -F "[dlopen]" <<<"$output" >/dev/null
grep -F "(none)" <<<"$(sed -n '/^\[dlopen\]/,/^$/p' <<<"$output")" >/dev/null
grep -F "[tooldata]" <<<"$output" >/dev/null
grep -F "src/emc/tooldata/tooldata_mmap.cc" <<<"$output" >/dev/null
grep -F "[tooldata-users]" <<<"$output" >/dev/null
grep -F "(none)" <<<"$(sed -n '/^\[tooldata-users\]/,/^$/p' <<<"$output")" >/dev/null
grep -F "[native-backend]" <<<"$output" >/dev/null
grep -F "src/emc/tooldata/tooldata_mmap.cc" <<<"$(sed -n '/^\[native-backend\]/,/^$/p' <<<"$output")" >/dev/null
grep -F "[native-fs]" <<<"$output" >/dev/null
grep -F "src/emc/tooldata/tooldata_mmap.cc" <<<"$(sed -n '/^\[native-fs\]/,/^$/p' <<<"$output")" >/dev/null
grep -F "[blocked-replacements]" <<<"$output" >/dev/null
grep -F "src/emc/tooldata/tooldata_mmap.cc -> core/wasm_shims/tooldata/tooldata_mmap_backend.cc" \
<<<"$(sed -n '/^\[blocked-replacements\]/,/^$/p' <<<"$output")" >/dev/null
grep -F "[core-python-shimmed]" <<<"$output" >/dev/null
grep -F "src/emc/rs274ngc/interp_python.cc" <<<"$(sed -n '/^\[core-python-shimmed\]/,/^$/p' <<<"$output")" >/dev/null
grep -F "src/emc/rs274ngc/rs274ngc_pre.cc" <<<"$(sed -n '/^\[core-python-shimmed\]/,/^$/p' <<<"$output")" >/dev/null
grep -F "[core-dlopen-shimmed]" <<<"$output" >/dev/null
grep -F "src/emc/rs274ngc/interp_base.cc" <<<"$(sed -n '/^\[core-dlopen-shimmed\]/,/^$/p' <<<"$output")" >/dev/null
grep -F "[core-tooldata-shimmed]" <<<"$output" >/dev/null
grep -F "src/emc/tooldata/tooldata_common.cc" <<<"$(sed -n '/^\[core-tooldata-shimmed\]/,/^$/p' <<<"$output")" >/dev/null
grep -F "[core-tooldata-users-shimmed]" <<<"$output" >/dev/null
grep -F "src/emc/rs274ngc/interp_find.cc" <<<"$(sed -n '/^\[core-tooldata-users-shimmed\]/,/^$/p' <<<"$output")" >/dev/null
grep -F "[core-native-fs-shimmed]" <<<"$output" >/dev/null
grep -F "src/emc/rs274ngc/interp_o_word.cc" <<<"$(sed -n '/^\[core-native-fs-shimmed\]/,/^$/p' <<<"$output")" >/dev/null
echo "linuxcnc wasm blocker scan passed"

View File

@@ -0,0 +1,569 @@
#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$0")"
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
build_dir=$(mktemp -d "${TMPDIR:-/tmp}/cnc_sim_linuxcnc_wasm_cmake_safe_probe.XXXXXX")
manifest=${1:-linuxcnc-rs274-wasm-source-files.txt}
if [[ ! -f "$manifest" ]]; then
echo "missing manifest: $manifest" >&2
exit 1
fi
if [[ ! -d "$linuxcnc_root" ]]; then
echo "missing LinuxCNC root: $linuxcnc_root" >&2
exit 1
fi
trap 'rm -rf "$build_dir"' EXIT
missing_manifest=${TMPDIR:-/tmp}/cnc_sim_missing_build_wasm_manifest.txt
missing_manifest_log=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_missing_build_wasm_manifest.XXXXXX.log")
rm -f "$missing_manifest"
if ./build-wasm.sh "$missing_manifest" >"$missing_manifest_log" 2>&1; then
echo "build-wasm accepted missing manifest: $missing_manifest" >&2
exit 1
fi
if ! grep -F "missing manifest: $missing_manifest" "$missing_manifest_log" >/dev/null; then
echo "build-wasm did not report missing manifest clearly" >&2
sed -n '1,20p' "$missing_manifest_log" >&2
exit 1
fi
rm -f "$missing_manifest_log"
missing_root=/tmp/does-not-exist-linuxcnc
missing_root_log=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_build_wasm_missing_root.XXXXXX.log")
if LINUXCNC_ROOT="$missing_root" ./build-wasm.sh >"$missing_root_log" 2>&1; then
echo "build-wasm accepted missing LinuxCNC root: $missing_root" >&2
exit 1
fi
if ! grep -F "missing LinuxCNC root: $missing_root" "$missing_root_log" >/dev/null; then
echo "build-wasm did not report missing LinuxCNC root clearly" >&2
sed -n '1,20p' "$missing_root_log" >&2
exit 1
fi
grep -F 'exec 9>"${TMPDIR:-/tmp}/cnc_sim_build_wasm.lock"' build-wasm.sh >/dev/null
grep -F "flock 9" build-wasm.sh >/dev/null
grep -F -- './test-linuxcnc-wasm-blockers.sh "$manifest"' build-wasm.sh >/dev/null
grep -F -- './test-linuxcnc-wasm-source-syntax.sh "$manifest"' build-wasm.sh >/dev/null
grep -F -- './test-linuxcnc-wasm-source-objects.sh "$manifest"' build-wasm.sh >/dev/null
grep -F -- './test-linuxcnc-wasm-cmake-safe-probe.sh "$manifest"' build-wasm.sh >/dev/null
grep -F -- './test-linuxcnc-wasm-tooldata-link.sh' build-wasm.sh >/dev/null
grep -F -- './test-linuxcnc-wasm-tooldata-common-link.sh' build-wasm.sh >/dev/null
grep -F -- './test-linuxcnc-wasm-tooldata-mmap-symbols.sh' build-wasm.sh >/dev/null
grep -F -- './test-linuxcnc-wasm-tooldata-runtime-symbols.sh' build-wasm.sh >/dev/null
grep -F -- './test-linuxcnc-wasm-interp-base-link.sh' build-wasm.sh >/dev/null
grep -F -- './test-linuxcnc-wasm-interp-find-link.sh' build-wasm.sh >/dev/null
grep -F -- './test-linuxcnc-wasm-python-plugin-link.sh' build-wasm.sh >/dev/null
grep -F -- './test-linuxcnc-wasm-rs274ngc-pre-object.sh' build-wasm.sh >/dev/null
grep -F -- './test-linuxcnc-wasm-rs274ngc-pre-link-blockers.sh "$manifest"' build-wasm.sh >/dev/null
grep -F -- './test-linuxcnc-wasm-rs274ngc-pre-link.sh "$manifest"' build-wasm.sh >/dev/null
grep -F -- '-DCNC_SIM_LINUXCNC_WASM_SOURCE_MANIFEST="$manifest"' build-wasm.sh >/dev/null
grep -F -- 'if ! command -v emcmake >/dev/null 2>&1; then' build-wasm.sh >/dev/null
grep -F "Emscripten is required. Install/activate emsdk so emcmake and emcc are in PATH." build-wasm.sh >/dev/null
grep -F -- 'emcmake cmake -S core -B build/wasm \' build-wasm.sh >/dev/null
grep -F -- 'default_manifest="$PWD/linuxcnc-rs274-wasm-source-files.txt"' build-wasm.sh >/dev/null
grep -F -- 'LINUXCNC_ROOT="$linuxcnc_root" ./list-linuxcnc-wasm-manifest-sources.sh "$manifest" core > "$manifest_core_sources"' build-wasm.sh >/dev/null
grep -F -- 'LINUXCNC_ROOT="$linuxcnc_root" ./list-linuxcnc-wasm-manifest-sources.sh "$manifest" blocked > "$manifest_blocked_sources"' build-wasm.sh >/dev/null
grep -F -- 'if [[ "$manifest" == "$default_manifest" ]] && [[ "$manifest_core_count" -ne 25 || "$manifest_blocked_count" -ne 1 ]]; then' build-wasm.sh >/dev/null
./list-linuxcnc-wasm-safe-shims.sh >/dev/null
./list-linuxcnc-wasm-safe-project-sources.sh >/dev/null
./list-linuxcnc-wasm-manifest-sources.sh "$manifest" core >/dev/null
grep -Fx "src/emc/rs274ngc/interp_arc.cc" \
< <(./list-linuxcnc-wasm-manifest-sources.sh "$manifest" core) >/dev/null
grep -Fx "src/emc/tooldata/tooldata_mmap.cc" \
< <(./list-linuxcnc-wasm-manifest-sources.sh "$manifest" blocked) >/dev/null
unknown_manifest_filter_log=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_unknown_wasm_manifest_filter.XXXXXX.log")
if ./list-linuxcnc-wasm-manifest-sources.sh "$manifest" bogus >"$unknown_manifest_filter_log" 2>&1; then
echo "wasm manifest source lister accepted unknown filter" >&2
exit 1
fi
if ! grep -F "unknown manifest source filter: bogus" "$unknown_manifest_filter_log" >/dev/null; then
echo "wasm manifest source lister did not report unknown filter clearly" >&2
sed -n '1,20p' "$unknown_manifest_filter_log" >&2
exit 1
fi
rm -f "$unknown_manifest_filter_log"
unknown_manifest_output_log=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_unknown_wasm_manifest_output.XXXXXX.log")
if ./list-linuxcnc-wasm-manifest-sources.sh "$manifest" core bogus >"$unknown_manifest_output_log" 2>&1; then
echo "wasm manifest source lister accepted unknown output mode" >&2
exit 1
fi
if ! grep -F "unknown manifest source output mode: bogus" "$unknown_manifest_output_log" >/dev/null; then
echo "wasm manifest source lister did not report unknown output mode clearly" >&2
sed -n '1,20p' "$unknown_manifest_output_log" >&2
exit 1
fi
rm -f "$unknown_manifest_output_log"
grep -Fx "$linuxcnc_root/src/emc/rs274ngc/interp_arc.cc" \
< <(LINUXCNC_ROOT="$linuxcnc_root" ./list-linuxcnc-wasm-manifest-sources.sh "$manifest" core full) >/dev/null
grep -Fx "core/wasm_shims/dlfcn.cc" < <(./list-linuxcnc-wasm-safe-shims.sh dlfcn.cc) >/dev/null
grep -Fx "core/wasm_shims/pythonplugin/python_plugin.cc" \
< <(./list-linuxcnc-wasm-safe-shims.sh python_plugin.cc) >/dev/null
grep -Fx "core/wasm_shims/rtapi_compat.cc" \
< <(./list-linuxcnc-wasm-safe-shims.sh rtapi_compat.cc) >/dev/null
grep -Fx "core/wasm_shims/tooldata/tooldata_mmap_backend.cc" \
< <(./list-linuxcnc-wasm-safe-shims.sh tooldata_mmap_backend.cc) >/dev/null
grep -Fx "core/wasm_shims/tooldata/tooldata_runtime_stubs.cc" \
< <(./list-linuxcnc-wasm-safe-shims.sh tooldata_runtime_stubs.cc) >/dev/null
grep -Fx "core/src/linuxcnc_canon_bridge.cpp" \
< <(./list-linuxcnc-wasm-safe-project-sources.sh linuxcnc_canon_bridge.cpp) >/dev/null
missing_shim_log=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_missing_wasm_safe_shim.XXXXXX.log")
if ./list-linuxcnc-wasm-safe-shims.sh does_not_exist.cc >"$missing_shim_log" 2>&1; then
echo "wasm-safe shim lister accepted missing shim filter" >&2
exit 1
fi
if ! grep -F "missing wasm-safe shim in CMake list: does_not_exist.cc" "$missing_shim_log" >/dev/null; then
echo "wasm-safe shim lister did not report missing shim filter clearly" >&2
sed -n '1,20p' "$missing_shim_log" >&2
exit 1
fi
rm -f "$missing_shim_log"
missing_project_source_log=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_missing_wasm_safe_project_source.XXXXXX.log")
if ./list-linuxcnc-wasm-safe-project-sources.sh does_not_exist.cc >"$missing_project_source_log" 2>&1; then
echo "wasm-safe project source lister accepted missing source filter" >&2
exit 1
fi
if ! grep -F "missing wasm-safe project source in CMake list: does_not_exist.cc" "$missing_project_source_log" >/dev/null; then
echo "wasm-safe project source lister did not report missing source filter clearly" >&2
sed -n '1,20p' "$missing_project_source_log" >&2
exit 1
fi
rm -f "$missing_project_source_log"
rm -f "$missing_root_log"
missing_wasm_script_manifest=${TMPDIR:-/tmp}/cnc_sim_missing_wasm_script_manifest.txt
missing_wasm_script_manifest_log=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_missing_wasm_script_manifest.XXXXXX.log")
rm -f "$missing_wasm_script_manifest"
for script in \
list-linuxcnc-wasm-manifest-sources.sh \
test-linuxcnc-wasm-source-syntax.sh \
test-linuxcnc-wasm-source-objects.sh \
test-linuxcnc-wasm-rs274ngc-pre-link-blockers.sh \
test-linuxcnc-wasm-rs274ngc-pre-link.sh; do
if "./$script" "$missing_wasm_script_manifest" >"$missing_wasm_script_manifest_log" 2>&1; then
echo "$script accepted missing manifest: $missing_wasm_script_manifest" >&2
exit 1
fi
if ! grep -F "missing manifest: $missing_wasm_script_manifest" "$missing_wasm_script_manifest_log" >/dev/null; then
echo "$script did not report missing manifest clearly" >&2
sed -n '1,20p' "$missing_wasm_script_manifest_log" >&2
exit 1
fi
done
rm -f "$missing_wasm_script_manifest_log"
missing_root_scripts=(
test-linuxcnc-wasm-interp-base-link.sh
test-linuxcnc-wasm-interp-find-link.sh
test-linuxcnc-wasm-python-plugin-link.sh
test-linuxcnc-wasm-rs274ngc-pre-object.sh
test-linuxcnc-wasm-rs274ngc-pre-link-blockers.sh
test-linuxcnc-wasm-rs274ngc-pre-link.sh
test-linuxcnc-wasm-source-objects.sh
test-linuxcnc-wasm-source-syntax.sh
test-linuxcnc-wasm-tooldata-common-link.sh
test-linuxcnc-wasm-tooldata-link.sh
test-linuxcnc-wasm-tooldata-mmap-symbols.sh
test-linuxcnc-wasm-tooldata-runtime-symbols.sh
)
for script in "${missing_root_scripts[@]}"; do
if LINUXCNC_ROOT="$missing_root" "./$script" >"$missing_root_log" 2>&1; then
echo "$script accepted missing LinuxCNC root: $missing_root" >&2
exit 1
fi
if ! grep -F "missing LinuxCNC root: $missing_root" "$missing_root_log" >/dev/null; then
echo "$script did not report missing LinuxCNC root clearly" >&2
sed -n '1,20p' "$missing_root_log" >&2
exit 1
fi
done
rm -f "$missing_root_log"
missing_source_root=$(mktemp -d "${TMPDIR:-/tmp}/cnc_sim_missing_linuxcnc_source_root.XXXXXX")
missing_source_log=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_missing_linuxcnc_source.XXXXXX.log")
mkdir -p "$missing_source_root/src" "$missing_source_root/include"
fixed_source_scripts=(
"test-linuxcnc-wasm-interp-base-link.sh:src/emc/rs274ngc/interp_base.cc"
"test-linuxcnc-wasm-interp-find-link.sh:src/emc/tooldata/tooldata_common.cc"
"test-linuxcnc-wasm-rs274ngc-pre-object.sh:src/emc/rs274ngc/rs274ngc_pre.cc"
"test-linuxcnc-wasm-tooldata-common-link.sh:src/emc/tooldata/tooldata_common.cc"
"test-linuxcnc-wasm-tooldata-link.sh:src/emc/tooldata/tooldata_common.cc"
"test-linuxcnc-wasm-tooldata-mmap-symbols.sh:src/emc/tooldata/tooldata_mmap.cc"
"test-linuxcnc-wasm-tooldata-runtime-symbols.sh:src/emc/tooldata/tooldata_db.cc"
)
for script_and_path in "${fixed_source_scripts[@]}"; do
script=${script_and_path%%:*}
source_path=${script_and_path#*:}
if LINUXCNC_ROOT="$missing_source_root" "./$script" >"$missing_source_log" 2>&1; then
echo "$script accepted missing LinuxCNC source: $source_path" >&2
exit 1
fi
if ! grep -F "missing LinuxCNC source: $source_path" "$missing_source_log" >/dev/null; then
echo "$script did not report missing LinuxCNC source clearly" >&2
sed -n '1,20p' "$missing_source_log" >&2
exit 1
fi
done
rm -rf "$missing_source_root"
rm -f "$missing_source_log"
missing_interp_find_root=$(mktemp -d "${TMPDIR:-/tmp}/cnc_sim_missing_interp_find_source_root.XXXXXX")
missing_interp_find_log=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_missing_interp_find_source.XXXXXX.log")
mkdir -p "$missing_interp_find_root/src/emc/tooldata" "$missing_interp_find_root/src/emc/rs274ngc" "$missing_interp_find_root/include"
touch "$missing_interp_find_root/src/emc/tooldata/tooldata_common.cc"
if LINUXCNC_ROOT="$missing_interp_find_root" ./test-linuxcnc-wasm-interp-find-link.sh >"$missing_interp_find_log" 2>&1; then
echo "test-linuxcnc-wasm-interp-find-link.sh accepted missing LinuxCNC source: src/emc/rs274ngc/interp_find.cc" >&2
exit 1
fi
if ! grep -F "missing LinuxCNC source: src/emc/rs274ngc/interp_find.cc" "$missing_interp_find_log" >/dev/null; then
echo "test-linuxcnc-wasm-interp-find-link.sh did not report missing interp_find source clearly" >&2
sed -n '1,20p' "$missing_interp_find_log" >&2
exit 1
fi
rm -rf "$missing_interp_find_root"
rm -f "$missing_interp_find_log"
missing_tooldata_runtime_root=$(mktemp -d "${TMPDIR:-/tmp}/cnc_sim_missing_tooldata_runtime_source_root.XXXXXX")
missing_tooldata_runtime_log=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_missing_tooldata_runtime_source.XXXXXX.log")
mkdir -p "$missing_tooldata_runtime_root/src/emc/tooldata" "$missing_tooldata_runtime_root/include"
touch "$missing_tooldata_runtime_root/src/emc/tooldata/tooldata_db.cc"
if LINUXCNC_ROOT="$missing_tooldata_runtime_root" ./test-linuxcnc-wasm-tooldata-runtime-symbols.sh >"$missing_tooldata_runtime_log" 2>&1; then
echo "test-linuxcnc-wasm-tooldata-runtime-symbols.sh accepted missing LinuxCNC source: src/emc/tooldata/tooldata_nml.cc" >&2
exit 1
fi
if ! grep -F "missing LinuxCNC source: src/emc/tooldata/tooldata_nml.cc" "$missing_tooldata_runtime_log" >/dev/null; then
echo "test-linuxcnc-wasm-tooldata-runtime-symbols.sh did not report missing tooldata_nml source clearly" >&2
sed -n '1,20p' "$missing_tooldata_runtime_log" >&2
exit 1
fi
rm -rf "$missing_tooldata_runtime_root"
rm -f "$missing_tooldata_runtime_log"
unknown_group_manifest=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_unknown_wasm_manifest_group.XXXXXX.txt")
unknown_group_log=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_unknown_wasm_manifest_group.XXXXXX.log")
printf 'bogus:src/emc/rs274ngc/interp_arc.cc:test unknown group\n' >"$unknown_group_manifest"
if ./build-wasm.sh "$unknown_group_manifest" >"$unknown_group_log" 2>&1; then
echo "build-wasm accepted unknown manifest group" >&2
exit 1
fi
if ! grep -F "unknown manifest group: bogus" "$unknown_group_log" >/dev/null; then
echo "build-wasm did not report unknown manifest group clearly" >&2
sed -n '1,20p' "$unknown_group_log" >&2
exit 1
fi
for script in \
analyze-linuxcnc-wasm-blockers.sh \
test-linuxcnc-wasm-source-syntax.sh \
test-linuxcnc-wasm-source-objects.sh \
test-linuxcnc-wasm-rs274ngc-pre-link-blockers.sh \
test-linuxcnc-wasm-rs274ngc-pre-link.sh; do
if "./$script" "$unknown_group_manifest" >"$unknown_group_log" 2>&1; then
echo "$script accepted unknown manifest group" >&2
exit 1
fi
if ! grep -F "unknown manifest group: bogus" "$unknown_group_log" >/dev/null; then
echo "$script did not report unknown manifest group clearly" >&2
sed -n '1,20p' "$unknown_group_log" >&2
exit 1
fi
done
rm -f "$unknown_group_manifest" "$unknown_group_log"
blocker_scan_log=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_wasm_blocker_scan.XXXXXX.log")
./test-linuxcnc-wasm-rs274ngc-pre-link-blockers.sh >"$blocker_scan_log" 2>&1
blocker_report_file=$(awk '/^wrote / { print $2 }' "$blocker_scan_log")
if [[ -z "$blocker_report_file" || ! -f "$blocker_report_file" ]]; then
echo "wasm rs274ngc_pre blocker scan did not preserve its report file" >&2
sed -n '1,20p' "$blocker_scan_log" >&2
exit 1
fi
rm -f "$blocker_report_file" "$blocker_scan_log"
missing_source_manifest=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_missing_wasm_manifest_source.XXXXXX.txt")
missing_source_log=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_missing_wasm_manifest_source.XXXXXX.log")
printf 'core:src/emc/rs274ngc/does_not_exist.cc:test missing source\n' >"$missing_source_manifest"
if ./build-wasm.sh "$missing_source_manifest" >"$missing_source_log" 2>&1; then
echo "build-wasm accepted missing manifest source" >&2
exit 1
fi
if ! grep -F "missing manifest source: src/emc/rs274ngc/does_not_exist.cc" "$missing_source_log" >/dev/null; then
echo "build-wasm did not report missing manifest source clearly" >&2
sed -n '1,20p' "$missing_source_log" >&2
exit 1
fi
if ./test-linuxcnc-wasm-source-syntax.sh "$missing_source_manifest" >"$missing_source_log" 2>&1; then
echo "wasm source syntax probe accepted missing manifest source" >&2
exit 1
fi
if ! grep -F "missing manifest source: src/emc/rs274ngc/does_not_exist.cc" "$missing_source_log" >/dev/null; then
echo "wasm source syntax probe did not report missing manifest source clearly" >&2
sed -n '1,20p' "$missing_source_log" >&2
exit 1
fi
if ./test-linuxcnc-wasm-source-objects.sh "$missing_source_manifest" >"$missing_source_log" 2>&1; then
echo "wasm source object probe accepted missing manifest source" >&2
exit 1
fi
if ! grep -F "missing manifest source: src/emc/rs274ngc/does_not_exist.cc" "$missing_source_log" >/dev/null; then
echo "wasm source object probe did not report missing manifest source clearly" >&2
sed -n '1,20p' "$missing_source_log" >&2
exit 1
fi
if ./test-linuxcnc-wasm-rs274ngc-pre-link-blockers.sh "$missing_source_manifest" >"$missing_source_log" 2>&1; then
echo "wasm rs274ngc_pre blocker scan accepted missing manifest source" >&2
exit 1
fi
if ! grep -F "missing manifest source: src/emc/rs274ngc/does_not_exist.cc" "$missing_source_log" >/dev/null; then
echo "wasm rs274ngc_pre blocker scan did not report missing manifest source clearly" >&2
sed -n '1,20p' "$missing_source_log" >&2
exit 1
fi
if ./test-linuxcnc-wasm-rs274ngc-pre-link.sh "$missing_source_manifest" >"$missing_source_log" 2>&1; then
echo "wasm rs274ngc_pre link probe accepted missing manifest source" >&2
exit 1
fi
if ! grep -F "missing manifest source: src/emc/rs274ngc/does_not_exist.cc" "$missing_source_log" >/dev/null; then
echo "wasm rs274ngc_pre link probe did not report missing manifest source clearly" >&2
sed -n '1,20p' "$missing_source_log" >&2
exit 1
fi
rm -f "$missing_source_manifest" "$missing_source_log"
empty_partition_log=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_empty_wasm_manifest_partition.XXXXXX.log")
empty_core_manifest=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_empty_wasm_manifest_core.XXXXXX.txt")
empty_blocked_manifest=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_empty_wasm_manifest_blocked.XXXXXX.txt")
printf 'blocked:src/emc/tooldata/tooldata_mmap.cc:test empty core partition\n' >"$empty_core_manifest"
if ./build-wasm.sh "$empty_core_manifest" >"$empty_partition_log" 2>&1; then
echo "build-wasm accepted empty core manifest partition" >&2
exit 1
fi
if ! grep -F "unexpected wasm manifest partition: core=0 blocked=1" "$empty_partition_log" >/dev/null; then
echo "build-wasm did not report empty core manifest partition clearly" >&2
sed -n '1,20p' "$empty_partition_log" >&2
exit 1
fi
printf 'core:src/emc/rs274ngc/interp_arc.cc:test empty blocked partition\n' >"$empty_blocked_manifest"
if ./build-wasm.sh "$empty_blocked_manifest" >"$empty_partition_log" 2>&1; then
echo "build-wasm accepted empty blocked manifest partition" >&2
exit 1
fi
if ! grep -F "unexpected wasm manifest partition: core=1 blocked=0" "$empty_partition_log" >/dev/null; then
echo "build-wasm did not report empty blocked manifest partition clearly" >&2
sed -n '1,20p' "$empty_partition_log" >&2
exit 1
fi
rm -f "$empty_core_manifest" "$empty_blocked_manifest" "$empty_partition_log"
bad_default_manifest_dir=$(mktemp -d "${TMPDIR:-/tmp}/cnc_sim_bad_default_wasm_manifest.XXXXXX")
bad_default_manifest_log=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_bad_default_wasm_manifest.XXXXXX.log")
linuxcnc_root_abs=$(cd "$linuxcnc_root" && pwd)
cp build-wasm.sh "$bad_default_manifest_dir/build-wasm.sh"
cp list-linuxcnc-wasm-manifest-sources.sh "$bad_default_manifest_dir/list-linuxcnc-wasm-manifest-sources.sh"
printf 'core:src/emc/rs274ngc/interp_arc.cc:test bad default core count\nblocked:src/emc/tooldata/tooldata_mmap.cc:test bad default blocked count\n' \
>"$bad_default_manifest_dir/linuxcnc-rs274-wasm-source-files.txt"
if LINUXCNC_ROOT="$linuxcnc_root_abs" "$bad_default_manifest_dir/build-wasm.sh" >"$bad_default_manifest_log" 2>&1; then
echo "build-wasm accepted bad default wasm manifest partition" >&2
exit 1
fi
if ! grep -F "unexpected wasm manifest partition: core=1 blocked=1" "$bad_default_manifest_log" >/dev/null; then
echo "build-wasm did not enforce default wasm manifest partition for no-arg entry" >&2
sed -n '1,20p' "$bad_default_manifest_log" >&2
exit 1
fi
rm -rf "$bad_default_manifest_dir"
rm -f "$bad_default_manifest_log"
duplicate_manifest=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_duplicate_wasm_manifest.XXXXXX.txt")
duplicate_manifest_log=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_duplicate_wasm_manifest.XXXXXX.log")
cat >"$duplicate_manifest" <<'EOF'
core:src/emc/rs274ngc/interp_arc.cc:duplicate core entry
core:src/emc/rs274ngc/interp_arc.cc:duplicate core entry
blocked:src/emc/tooldata/tooldata_mmap.cc:blocked entry
EOF
if ./build-wasm.sh "$duplicate_manifest" >"$duplicate_manifest_log" 2>&1; then
echo "build-wasm accepted duplicate manifest source" >&2
exit 1
fi
if ! grep -F "duplicate manifest source: src/emc/rs274ngc/interp_arc.cc" "$duplicate_manifest_log" >/dev/null; then
echo "build-wasm did not report duplicate manifest source clearly" >&2
sed -n '1,20p' "$duplicate_manifest_log" >&2
exit 1
fi
rm -f "$duplicate_manifest" "$duplicate_manifest_log"
comment_manifest=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_comment_wasm_manifest.XXXXXX.txt")
comment_manifest_log=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_comment_wasm_manifest.XXXXXX.log")
cat >"$comment_manifest" <<'EOF'
# LinuxCNC rs274 source subset for browser-safe source-link probing.
# Format: group:path:note
core:src/emc/rs274ngc/interp_arc.cc:commented core entry
blocked:src/emc/tooldata/tooldata_mmap.cc:commented blocked entry
EOF
if ./build-wasm.sh "$comment_manifest" >"$comment_manifest_log" 2>&1; then
:
fi
if grep -F "duplicate manifest source" "$comment_manifest_log" >/dev/null; then
echo "build-wasm rejected commented manifest lines as duplicates" >&2
sed -n '1,20p' "$comment_manifest_log" >&2
exit 1
fi
rm -f "$comment_manifest" "$comment_manifest_log"
duplicate_source_manifest=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_duplicate_wasm_source_manifest.XXXXXX.txt")
duplicate_source_log=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_duplicate_wasm_source_manifest.XXXXXX.log")
cat >"$duplicate_source_manifest" <<'EOF'
core:src/emc/rs274ngc/interp_arc.cc:duplicate core entry
core:src/emc/rs274ngc/interp_arc.cc:duplicate core entry
blocked:src/emc/tooldata/tooldata_mmap.cc:blocked entry
EOF
if ./test-linuxcnc-wasm-source-objects.sh "$duplicate_source_manifest" >"$duplicate_source_log" 2>&1; then
echo "source object probe accepted duplicate manifest source" >&2
exit 1
fi
if ! grep -F "duplicate manifest source: src/emc/rs274ngc/interp_arc.cc" "$duplicate_source_log" >/dev/null; then
echo "source object probe did not report duplicate manifest source clearly" >&2
sed -n '1,20p' "$duplicate_source_log" >&2
exit 1
fi
rm -f "$duplicate_source_manifest" "$duplicate_source_log"
duplicate_syntax_manifest=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_duplicate_wasm_syntax_manifest.XXXXXX.txt")
duplicate_syntax_log=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_duplicate_wasm_syntax_manifest.XXXXXX.log")
cat >"$duplicate_syntax_manifest" <<'EOF'
core:src/emc/rs274ngc/interp_arc.cc:duplicate core entry
core:src/emc/rs274ngc/interp_arc.cc:duplicate core entry
blocked:src/emc/tooldata/tooldata_mmap.cc:blocked entry
EOF
if ./test-linuxcnc-wasm-source-syntax.sh "$duplicate_syntax_manifest" >"$duplicate_syntax_log" 2>&1; then
echo "syntax probe accepted duplicate manifest source" >&2
exit 1
fi
if ! grep -F "duplicate manifest source: src/emc/rs274ngc/interp_arc.cc" "$duplicate_syntax_log" >/dev/null; then
echo "syntax probe did not report duplicate manifest source clearly" >&2
sed -n '1,20p' "$duplicate_syntax_log" >&2
exit 1
fi
rm -f "$duplicate_syntax_manifest" "$duplicate_syntax_log"
duplicate_pre_blocker_manifest=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_duplicate_wasm_pre_blocker_manifest.XXXXXX.txt")
duplicate_pre_blocker_log=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_duplicate_wasm_pre_blocker_manifest.XXXXXX.log")
cat >"$duplicate_pre_blocker_manifest" <<'EOF'
core:src/emc/rs274ngc/interp_arc.cc:duplicate core entry
core:src/emc/rs274ngc/interp_arc.cc:duplicate core entry
blocked:src/emc/tooldata/tooldata_mmap.cc:blocked entry
EOF
if ./test-linuxcnc-wasm-rs274ngc-pre-link-blockers.sh "$duplicate_pre_blocker_manifest" >"$duplicate_pre_blocker_log" 2>&1; then
echo "rs274ngc_pre blocker scan accepted duplicate manifest source" >&2
exit 1
fi
if ! grep -F "duplicate manifest source: src/emc/rs274ngc/interp_arc.cc" "$duplicate_pre_blocker_log" >/dev/null; then
echo "rs274ngc_pre blocker scan did not report duplicate manifest source clearly" >&2
sed -n '1,20p' "$duplicate_pre_blocker_log" >&2
exit 1
fi
rm -f "$duplicate_pre_blocker_manifest" "$duplicate_pre_blocker_log"
duplicate_pre_link_manifest=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_duplicate_wasm_pre_link_manifest.XXXXXX.txt")
duplicate_pre_link_log=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_duplicate_wasm_pre_link_manifest.XXXXXX.log")
cat >"$duplicate_pre_link_manifest" <<'EOF'
core:src/emc/rs274ngc/interp_arc.cc:duplicate core entry
core:src/emc/rs274ngc/interp_arc.cc:duplicate core entry
blocked:src/emc/tooldata/tooldata_mmap.cc:blocked entry
EOF
if ./test-linuxcnc-wasm-rs274ngc-pre-link.sh "$duplicate_pre_link_manifest" >"$duplicate_pre_link_log" 2>&1; then
echo "rs274ngc_pre link probe accepted duplicate manifest source" >&2
exit 1
fi
if ! grep -F "duplicate manifest source: src/emc/rs274ngc/interp_arc.cc" "$duplicate_pre_link_log" >/dev/null; then
echo "rs274ngc_pre link probe did not report duplicate manifest source clearly" >&2
sed -n '1,20p' "$duplicate_pre_link_log" >&2
exit 1
fi
rm -f "$duplicate_pre_link_manifest" "$duplicate_pre_link_log"
linuxcnc_root=$(cd "$linuxcnc_root" && pwd)
default_manifest="$PWD/linuxcnc-rs274-wasm-source-files.txt"
manifest_core_count=0
manifest_blocked_count=0
manifest_core_sources="$build_dir/wasm_core_sources.txt"
manifest_blocked_sources="$build_dir/wasm_blocked_sources.txt"
./list-linuxcnc-wasm-manifest-sources.sh "$manifest" core > "$manifest_core_sources"
./list-linuxcnc-wasm-manifest-sources.sh "$manifest" blocked > "$manifest_blocked_sources"
manifest_core_count=$(wc -l < "$manifest_core_sources")
manifest_blocked_count=$(wc -l < "$manifest_blocked_sources")
required_shim_sources="$build_dir/wasm_safe_shim_sources.txt"
./list-linuxcnc-wasm-safe-shims.sh > "$required_shim_sources"
required_project_sources="$build_dir/wasm_safe_project_sources.txt"
./list-linuxcnc-wasm-safe-project-sources.sh > "$required_project_sources"
if [[ "$manifest" == "$default_manifest" ]] && [[ "$manifest_core_count" -ne 25 || "$manifest_blocked_count" -ne 1 ]]; then
echo "unexpected wasm manifest partition: core=$manifest_core_count blocked=$manifest_blocked_count" >&2
exit 1
fi
if [[ "$manifest_core_count" -eq 0 || "$manifest_blocked_count" -eq 0 ]]; then
echo "unexpected wasm manifest partition: core=$manifest_core_count blocked=$manifest_blocked_count" >&2
exit 1
fi
while IFS= read -r shim; do
[[ -z "$shim" ]] && continue
cmake_shim=${shim#core/}
if ! grep -F "$cmake_shim" core/CMakeLists.txt >/dev/null; then
echo "missing CMake wasm-safe shim: $cmake_shim" >&2
exit 1
fi
done < "$required_shim_sources"
while IFS= read -r source; do
[[ -z "$source" ]] && continue
cmake_source=${source#core/}
if ! grep -F "$cmake_source" core/CMakeLists.txt >/dev/null; then
echo "missing CMake wasm-safe project source: $cmake_source" >&2
exit 1
fi
done < "$required_project_sources"
grep -F "add_executable(linuxcnc_rs274_wasm_safe_probe EXCLUDE_FROM_ALL" core/CMakeLists.txt >/dev/null
grep -F "wasm_shims/rs274ngc_pre_probe_main.cc" core/CMakeLists.txt >/dev/null
grep -F "target_link_libraries(linuxcnc_rs274_wasm_safe_probe PRIVATE fmt)" core/CMakeLists.txt >/dev/null
grep -F "add_custom_target(linuxcnc_rs274_wasm_blocked_sources" core/CMakeLists.txt >/dev/null
grep -F "LinuxCNC source root does not exist" core/CMakeLists.txt >/dev/null
grep -F 'if(NOT IS_DIRECTORY "${CNC_SIM_LINUXCNC_ROOT_ABS}")' core/CMakeLists.txt >/dev/null
grep -F "Missing LinuxCNC wasm source manifest" core/CMakeLists.txt >/dev/null
grep -F 'if(NOT EXISTS "${CNC_SIM_LINUXCNC_WASM_SOURCE_MANIFEST}")' core/CMakeLists.txt >/dev/null
grep -F "LinuxCNC wasm source manifest is not a file" core/CMakeLists.txt >/dev/null
grep -F 'if(IS_DIRECTORY "${CNC_SIM_LINUXCNC_WASM_SOURCE_MANIFEST}")' core/CMakeLists.txt >/dev/null
grep -F "Bad LinuxCNC wasm source manifest line" core/CMakeLists.txt >/dev/null
grep -F "LinuxCNC wasm manifest source does not exist" core/CMakeLists.txt >/dev/null
grep -F 'if(NOT EXISTS "${manifest_source}")' core/CMakeLists.txt >/dev/null
grep -F "LinuxCNC wasm manifest source is not a file" core/CMakeLists.txt >/dev/null
grep -F 'if(IS_DIRECTORY "${manifest_source}")' core/CMakeLists.txt >/dev/null
awk '
/set\(manifest_source/ { manifest_source = NR }
/Unknown LinuxCNC wasm source manifest group/ { unknown_group = NR }
END { exit !(unknown_group && manifest_source && unknown_group < manifest_source) }
' core/CMakeLists.txt
grep -F "LinuxCNC wasm source manifest has no core entries" core/CMakeLists.txt >/dev/null
grep -F "LinuxCNC wasm source manifest has no blocked entries" core/CMakeLists.txt >/dev/null
if ! command -v cmake >/dev/null 2>&1; then
echo "cmake not found; skipping linuxcnc wasm-safe CMake probe target"
exit 0
fi
cmake -S core -B "$build_dir" \
-DCMAKE_BUILD_TYPE=Release \
-DCNC_SIM_LINUXCNC_ROOT="$linuxcnc_root" \
-DCNC_SIM_LINUXCNC_WASM_SOURCE_MANIFEST="$manifest" \
-DCNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE=ON
cmake --build "$build_dir" --target linuxcnc_rs274_wasm_safe_probe_objects
cmake --build "$build_dir" --target linuxcnc_rs274_wasm_safe_probe
"$build_dir/linuxcnc_rs274_wasm_safe_probe"
echo "linuxcnc wasm-safe CMake probe target passed"

View File

@@ -0,0 +1,39 @@
#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$0")"
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
cxx=${CXX:-g++}
build_dir=$(mktemp -d "${TMPDIR:-/tmp}/cnc_sim_linuxcnc_wasm_interp_base_link.XXXXXX")
if [[ ! -d "$linuxcnc_root" ]]; then
echo "missing LinuxCNC root: $linuxcnc_root" >&2
exit 1
fi
trap 'rm -rf "$build_dir"' EXIT
dlfcn_shim=$(./list-linuxcnc-wasm-safe-shims.sh dlfcn.cc)
interp_base_source=$(LINUXCNC_ROOT="$linuxcnc_root" ./list-linuxcnc-source-files.sh src/emc/rs274ngc/interp_base.cc)
common_flags=(
-std=c++17
-DULAPI
-I "$(pwd)/core/wasm_shims"
-I "$linuxcnc_root/src"
-I "$linuxcnc_root/src/emc"
-I "$linuxcnc_root/src/emc/nml_intf"
-I "$linuxcnc_root/src/emc/rs274ngc"
-I "$linuxcnc_root/src/emc/motion"
-I "$linuxcnc_root/include"
)
"$cxx" "${common_flags[@]}" \
"$dlfcn_shim" \
"$interp_base_source" \
core/wasm_shims/interp_base_probe_main.cc \
-o "$build_dir/interp_base_probe"
"$build_dir/interp_base_probe"
echo "linuxcnc wasm interp_base link probe passed"

View File

@@ -0,0 +1,74 @@
#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$0")"
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
cxx=${CXX:-g++}
build_dir=$(mktemp -d "${TMPDIR:-/tmp}/cnc_sim_linuxcnc_wasm_interp_find_link.XXXXXX")
if [[ ! -d "$linuxcnc_root" ]]; then
echo "missing LinuxCNC root: $linuxcnc_root" >&2
exit 1
fi
trap 'rm -rf "$build_dir"' EXIT
tooldata_mmap_backend_shim=$(./list-linuxcnc-wasm-safe-shims.sh tooldata_mmap_backend.cc)
tooldata_runtime_stubs_shim=$(./list-linuxcnc-wasm-safe-shims.sh tooldata_runtime_stubs.cc)
rtapi_compat_shim=$(./list-linuxcnc-wasm-safe-shims.sh rtapi_compat.cc)
readarray -t linuxcnc_sources < <(LINUXCNC_ROOT="$linuxcnc_root" ./list-linuxcnc-source-files.sh \
src/emc/tooldata/tooldata_common.cc \
src/emc/rs274ngc/interp_find.cc)
tooldata_common_source=${linuxcnc_sources[0]}
interp_find_source=${linuxcnc_sources[1]}
common_flags=(
-std=c++17
-DULAPI
-ffunction-sections
-fdata-sections
-I "$(pwd)/core/wasm_shims"
-I "$linuxcnc_root/src"
-I "$linuxcnc_root/src/emc"
-I "$linuxcnc_root/src/emc/nml_intf"
-I "$linuxcnc_root/src/emc/rs274ngc"
-I "$linuxcnc_root/src/emc/motion"
-I "$linuxcnc_root/include"
)
"$cxx" "${common_flags[@]}" \
-c "$tooldata_common_source" \
-o "$build_dir/tooldata_common.o"
"$cxx" "${common_flags[@]}" \
-c "$tooldata_mmap_backend_shim" \
-o "$build_dir/tooldata_mmap_backend.o"
"$cxx" "${common_flags[@]}" \
-c "$tooldata_runtime_stubs_shim" \
-o "$build_dir/tooldata_runtime_stubs.o"
"$cxx" "${common_flags[@]}" \
-c "$rtapi_compat_shim" \
-o "$build_dir/rtapi_compat.o"
"$cxx" "${common_flags[@]}" \
-c core/wasm_shims/interp_find_probe_stubs.cc \
-o "$build_dir/interp_find_probe_stubs.o"
"$cxx" "${common_flags[@]}" \
-c "$interp_find_source" \
-o "$build_dir/interp_find.o"
"$cxx" "${common_flags[@]}" \
-c core/wasm_shims/interp_find_probe_main.cc \
-o "$build_dir/interp_find_probe_main.o"
"$cxx" \
"$build_dir/tooldata_common.o" \
"$build_dir/tooldata_mmap_backend.o" \
"$build_dir/tooldata_runtime_stubs.o" \
"$build_dir/rtapi_compat.o" \
"$build_dir/interp_find_probe_stubs.o" \
"$build_dir/interp_find.o" \
"$build_dir/interp_find_probe_main.o" \
-Wl,--gc-sections \
-o "$build_dir/interp_find_probe"
"$build_dir/interp_find_probe"
echo "linuxcnc wasm interp_find link probe passed"

View File

@@ -0,0 +1,37 @@
#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$0")"
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
cxx=${CXX:-g++}
build_dir=$(mktemp -d "${TMPDIR:-/tmp}/cnc_sim_linuxcnc_wasm_python_plugin_link.XXXXXX")
if [[ ! -d "$linuxcnc_root" ]]; then
echo "missing LinuxCNC root: $linuxcnc_root" >&2
exit 1
fi
trap 'rm -rf "$build_dir"' EXIT
python_plugin_shim=$(./list-linuxcnc-wasm-safe-shims.sh python_plugin.cc)
common_flags=(
-std=c++17
-DULAPI
-I "$(pwd)/core/wasm_shims"
-I "$linuxcnc_root/src"
-I "$linuxcnc_root/src/emc"
-I "$linuxcnc_root/src/emc/nml_intf"
-I "$linuxcnc_root/src/emc/rs274ngc"
-I "$linuxcnc_root/src/emc/motion"
-I "$linuxcnc_root/include"
)
"$cxx" "${common_flags[@]}" \
"$python_plugin_shim" \
core/wasm_shims/pythonplugin/python_plugin_probe_main.cc \
-o "$build_dir/python_plugin_probe"
"$build_dir/python_plugin_probe"
echo "linuxcnc wasm python_plugin link probe passed"

View File

@@ -0,0 +1,142 @@
#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$0")"
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
cxx=${CXX:-g++}
build_dir=$(mktemp -d "${TMPDIR:-/tmp}/cnc_sim_linuxcnc_wasm_rs274ngc_pre_link_blockers.XXXXXX")
report_file=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_linuxcnc_wasm_rs274ngc_pre_undefined.XXXXXX.txt")
manifest=${1:-linuxcnc-rs274-wasm-source-files.txt}
if [[ ! -f "$manifest" ]]; then
echo "missing manifest: $manifest" >&2
exit 1
fi
if [[ ! -d "$linuxcnc_root" ]]; then
echo "missing LinuxCNC root: $linuxcnc_root" >&2
exit 1
fi
trap 'rm -rf "$build_dir"' EXIT
common_flags=(
-std=c++20
-DULAPI
-ffunction-sections
-fdata-sections
-include wctype.h
-I "$(pwd)/core/include"
-I "$(pwd)/core/wasm_shims"
-I "$linuxcnc_root/src"
-I "$linuxcnc_root/src/emc"
-I "$linuxcnc_root/src/emc/nml_intf"
-I "$linuxcnc_root/src/emc/rs274ngc"
-I "$linuxcnc_root/src/emc/motion"
-I "$linuxcnc_root/include"
)
shim_list="$build_dir/wasm_safe_shims.txt"
./list-linuxcnc-wasm-safe-shims.sh > "$shim_list"
mapfile -t shim_sources < "$shim_list"
project_source_list="$build_dir/wasm_safe_project_sources.txt"
./list-linuxcnc-wasm-safe-project-sources.sh > "$project_source_list"
mapfile -t project_sources < "$project_source_list"
linuxcnc_sources=()
source_list="$build_dir/wasm_core_sources.txt"
LINUXCNC_ROOT="$linuxcnc_root" ./list-linuxcnc-wasm-manifest-sources.sh "$manifest" core full > "$source_list"
mapfile -t linuxcnc_sources < "$source_list"
shim_index=0
for source in "${shim_sources[@]}"; do
obj="$build_dir/shim_${shim_index}.o"
"$cxx" "${common_flags[@]}" -c "$source" -o "$obj"
shim_index=$((shim_index + 1))
done
project_index=0
for source in "${project_sources[@]}"; do
obj="$build_dir/project_${project_index}.o"
"$cxx" "${common_flags[@]}" -c "$source" -o "$obj"
project_index=$((project_index + 1))
done
linuxcnc_index=0
for source in "${linuxcnc_sources[@]}"; do
obj="$build_dir/linuxcnc_${linuxcnc_index}.o"
"$cxx" "${common_flags[@]}" -c "$source" -o "$obj"
linuxcnc_index=$((linuxcnc_index + 1))
done
undefined_file="$build_dir/undefined.raw"
defined_file="$build_dir/defined.raw"
nm -u "$build_dir"/*.o \
| awk '{print $2}' \
| sed '/^$/d' \
| LC_ALL=C sort -u \
> "$undefined_file"
nm --defined-only "$build_dir"/*.o \
| awk '{print $3}' \
| sed '/^$/d' \
| LC_ALL=C sort -u \
> "$defined_file"
{
comm -23 "$undefined_file" "$defined_file" \
| grep -Ev '^(_GLOBAL_OFFSET_TABLE_|_Unwind_Resume)$' \
| grep -Ev '^(__assert_fail|__cxa_|__divdc3|__dso_handle|__errno_location|__gxx_personality_v0|__isoc23_|__muldc3|__stack_chk_fail)' \
| grep -Ev '^(abort|access|acos|asin|atan2|atof|atoi|basename|cabs|calloc|ceil|close|closedir|copysign|cos|cosl|exit|exp|fclose|fdatasync|fdopen|feof|fflush|fgetc|fgets|fileno|floor|fmod|fopen|fprintf|fputs|free|freelocale|fseek|fstat|ftell|fwrite|getcwd|getenv|getpid|gettimeofday|hypot|islower|isprint|isspace|isupper|isxdigit|link|localtime|log|lstat|malloc|memchr|memcmp|memcpy|memmove|memset|mkstemp|nearbyint|newlocale|open|opendir|perror|pow|printf|pthread_mutex_lock|pthread_mutex_unlock|putc|puts|read|readdir|realpath|realloc|remove|rename|setlocale|sin|sinl|snprintf|sprintf|sqrt|sscanf|stat|stderr|stdout|strcasecmp|strcat|strchr|strcmp|strcpy|strdup|strerror|strlen|strncasecmp|strncat|strncmp|strncpy|strrchr|strspn|strstr|strtod|strtok_r|strtol|strtoul|tan|tanl|tolower|toupper|towlower|unlink|uselocale|vfprintf|vsnprintf|wordexp|wordfree)$' \
| grep -Ev '^(_ZN3fmt|_ZSt|_ZNSt|_ZNKSt|_ZNKRSt|_ZNS|_ZTI|_ZTS|_ZTV|_Zdl|_Znwm|_Znam|_Zda|_ZdaPv|_ZdaPvm|_ZdlPvm|_ZTv|_ZTh)'
} > "$report_file" || true
if grep -F "_ZN6Interp13read_commentEPcPiP12block_structPd" "$report_file" >/dev/null; then
echo "unexpected unresolved read_comment after interp_read.cc" >&2
exit 1
fi
if grep -F "_ZN6Interp15find_tool_indexEP5setupiPi" "$report_file" >/dev/null; then
echo "unexpected unresolved find_tool_index after interp_find.cc" >&2
exit 1
fi
if grep -F "_ZN6Interp16find_named_paramEPKcPiPd" "$report_file" >/dev/null; then
echo "unexpected unresolved find_named_param after interp_namedparams.cc" >&2
exit 1
fi
if grep -Fx "emcStatus" "$report_file" >/dev/null; then
echo "unexpected unresolved emcStatus after shim" >&2
exit 1
fi
if grep -Fx "gettext" "$report_file" >/dev/null; then
echo "unexpected unresolved gettext after shim" >&2
exit 1
fi
if grep -Fx "_task" "$report_file" >/dev/null; then
echo "unexpected unresolved _task after runtime shim" >&2
exit 1
fi
if grep -Fx "builtin_modules" "$report_file" >/dev/null; then
echo "unexpected unresolved builtin_modules after runtime shim" >&2
exit 1
fi
for hal_symbol in \
hal_get_param_value_by_name \
hal_get_pin_value_by_name \
hal_get_signal_value_by_name \
hal_init \
hal_ready; do
if grep -Fx "$hal_symbol" "$report_file" >/dev/null; then
echo "unexpected unresolved $hal_symbol after runtime shim" >&2
exit 1
fi
done
if [[ -s "$report_file" ]]; then
echo "unexpected unresolved project symbols after rs274ngc_pre shim coverage:" >&2
sed -n '1,120p' "$report_file" >&2
exit 1
fi
echo "linuxcnc wasm rs274ngc_pre link blocker scan passed"
echo "wrote $report_file"

View File

@@ -0,0 +1,72 @@
#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$0")"
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
cxx=${CXX:-g++}
build_dir=$(mktemp -d "${TMPDIR:-/tmp}/cnc_sim_linuxcnc_wasm_rs274ngc_pre_link.XXXXXX")
manifest=${1:-linuxcnc-rs274-wasm-source-files.txt}
if [[ ! -f "$manifest" ]]; then
echo "missing manifest: $manifest" >&2
exit 1
fi
if [[ ! -d "$linuxcnc_root" ]]; then
echo "missing LinuxCNC root: $linuxcnc_root" >&2
exit 1
fi
trap 'rm -rf "$build_dir"' EXIT
common_flags=(
-std=c++20
-DULAPI
-ffunction-sections
-fdata-sections
-I "$(pwd)/core/src"
-include wctype.h
-I "$(pwd)/core/include"
-I "$(pwd)/core/wasm_shims"
-I "$linuxcnc_root/src"
-I "$linuxcnc_root/src/emc"
-I "$linuxcnc_root/src/emc/nml_intf"
-I "$linuxcnc_root/src/emc/rs274ngc"
-I "$linuxcnc_root/src/emc/motion"
-I "$linuxcnc_root/include"
)
shim_list="$build_dir/wasm_safe_shims.txt"
./list-linuxcnc-wasm-safe-shims.sh > "$shim_list"
mapfile -t sources < "$shim_list"
project_source_list="$build_dir/wasm_safe_project_sources.txt"
./list-linuxcnc-wasm-safe-project-sources.sh > "$project_source_list"
mapfile -t project_sources < "$project_source_list"
sources+=("${project_sources[@]}")
source_list="$build_dir/wasm_core_sources.txt"
LINUXCNC_ROOT="$linuxcnc_root" ./list-linuxcnc-wasm-manifest-sources.sh "$manifest" core full > "$source_list"
mapfile -t linuxcnc_sources < "$source_list"
for source in "${linuxcnc_sources[@]}"; do
sources+=("$source")
done
sources+=(core/wasm_shims/rs274ngc_pre_probe_main.cc)
objects=()
object_index=0
for source in "${sources[@]}"; do
obj="$build_dir/source_${object_index}.o"
"$cxx" "${common_flags[@]}" -c "$source" -o "$obj"
objects+=("$obj")
object_index=$((object_index + 1))
done
"$cxx" "${objects[@]}" \
-Wl,--gc-sections \
-lfmt \
-o "$build_dir/rs274ngc_pre_probe"
"$build_dir/rs274ngc_pre_probe"
echo "linuxcnc wasm rs274ngc_pre link probe passed"

View File

@@ -0,0 +1,33 @@
#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$0")"
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
cxx=${CXX:-g++}
build_dir=$(mktemp -d "${TMPDIR:-/tmp}/cnc_sim_linuxcnc_wasm_rs274ngc_pre_object.XXXXXX")
if [[ ! -d "$linuxcnc_root" ]]; then
echo "missing LinuxCNC root: $linuxcnc_root" >&2
exit 1
fi
trap 'rm -rf "$build_dir"' EXIT
rs274ngc_pre_source=$(LINUXCNC_ROOT="$linuxcnc_root" ./list-linuxcnc-source-files.sh src/emc/rs274ngc/rs274ngc_pre.cc)
common_flags=(
-std=c++17
-DULAPI
-I "$(pwd)/core/wasm_shims"
-I "$linuxcnc_root/src"
-I "$linuxcnc_root/src/emc"
-I "$linuxcnc_root/src/emc/nml_intf"
-I "$linuxcnc_root/src/emc/rs274ngc"
-I "$linuxcnc_root/src/emc/motion"
-I "$linuxcnc_root/include"
)
"$cxx" "${common_flags[@]}" \
-c "$rs274ngc_pre_source" \
-o "$build_dir/rs274ngc_pre.o"
echo "linuxcnc wasm rs274ngc_pre object probe passed"

View File

@@ -0,0 +1,59 @@
#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$0")"
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
manifest=${1:-linuxcnc-rs274-wasm-source-files.txt}
cxx=${CXX:-g++}
build_dir=$(mktemp -d "${TMPDIR:-/tmp}/cnc_sim_linuxcnc_wasm_safe_probe.XXXXXX")
if [[ ! -f "$manifest" ]]; then
echo "missing manifest: $manifest" >&2
exit 1
fi
if [[ ! -d "$linuxcnc_root" ]]; then
echo "missing LinuxCNC root: $linuxcnc_root" >&2
exit 1
fi
trap 'rm -rf "$build_dir"' EXIT
shim_list="$build_dir/wasm_safe_shims.txt"
./list-linuxcnc-wasm-safe-shims.sh > "$shim_list"
mapfile -t shim_sources < "$shim_list"
common_flags=(
-std=c++20
-DULAPI
-include wctype.h
-I "$(pwd)/core/include"
-I "$(pwd)/core/src"
-I "$(pwd)/core/wasm_shims"
-I "$linuxcnc_root/src"
-I "$linuxcnc_root/src/emc"
-I "$linuxcnc_root/src/emc/nml_intf"
-I "$linuxcnc_root/src/emc/rs274ngc"
-I "$linuxcnc_root/src/emc/motion"
-I "$linuxcnc_root/include"
)
source_list="$build_dir/wasm_core_sources.txt"
LINUXCNC_ROOT="$linuxcnc_root" ./list-linuxcnc-wasm-manifest-sources.sh "$manifest" core full > "$source_list"
mapfile -t sources < "$source_list"
shim_index=0
for source in "${shim_sources[@]}"; do
obj="$build_dir/shim_${shim_index}.o"
"$cxx" "${common_flags[@]}" -c "$source" -o "$obj"
shim_index=$((shim_index + 1))
done
source_index=0
for source in "${sources[@]}"; do
obj="$build_dir/linuxcnc_${source_index}.o"
"$cxx" "${common_flags[@]}" -c "$source" -o "$obj"
source_index=$((source_index + 1))
done
echo "linuxcnc wasm-safe source object probe passed (${#sources[@]} linuxcnc objects + ${#shim_sources[@]} shims)"

View File

@@ -0,0 +1,45 @@
#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$0")"
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
manifest=${1:-linuxcnc-rs274-wasm-source-files.txt}
cxx=${CXX:-g++}
if [[ ! -f "$manifest" ]]; then
echo "missing manifest: $manifest" >&2
exit 1
fi
if [[ ! -d "$linuxcnc_root" ]]; then
echo "missing LinuxCNC root: $linuxcnc_root" >&2
exit 1
fi
common_flags=(
-std=c++20
-DULAPI
-fsyntax-only
-include wctype.h
-I "$(pwd)/core/include"
-I "$(pwd)/core/src"
-I "$(pwd)/core/wasm_shims"
-I "$linuxcnc_root/src"
-I "$linuxcnc_root/src/emc"
-I "$linuxcnc_root/src/emc/nml_intf"
-I "$linuxcnc_root/src/emc/rs274ngc"
-I "$linuxcnc_root/src/emc/motion"
-I "$linuxcnc_root/include"
)
source_list=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_linuxcnc_wasm_source_syntax_sources.XXXXXX.txt")
trap 'rm -f "$source_list"' EXIT
LINUXCNC_ROOT="$linuxcnc_root" ./list-linuxcnc-wasm-manifest-sources.sh "$manifest" core full > "$source_list"
mapfile -t sources < "$source_list"
for source in "${sources[@]}"; do
"$cxx" "${common_flags[@]}" "$source"
done
echo "linuxcnc wasm-safe source syntax probe passed (${#sources[@]} files)"

View File

@@ -0,0 +1,41 @@
#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$0")"
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
cxx=${CXX:-g++}
build_dir=$(mktemp -d "${TMPDIR:-/tmp}/cnc_sim_linuxcnc_wasm_tooldata_common_link.XXXXXX")
if [[ ! -d "$linuxcnc_root" ]]; then
echo "missing LinuxCNC root: $linuxcnc_root" >&2
exit 1
fi
trap 'rm -rf "$build_dir"' EXIT
tooldata_mmap_backend_shim=$(./list-linuxcnc-wasm-safe-shims.sh tooldata_mmap_backend.cc)
tooldata_runtime_stubs_shim=$(./list-linuxcnc-wasm-safe-shims.sh tooldata_runtime_stubs.cc)
tooldata_common_source=$(LINUXCNC_ROOT="$linuxcnc_root" ./list-linuxcnc-source-files.sh src/emc/tooldata/tooldata_common.cc)
common_flags=(
-std=c++17
-DULAPI
-I "$linuxcnc_root/src/emc/tooldata"
-I "$linuxcnc_root/src"
-I "$linuxcnc_root/src/emc"
-I "$linuxcnc_root/src/emc/nml_intf"
-I "$linuxcnc_root/src/emc/rs274ngc"
-I "$linuxcnc_root/src/emc/motion"
-I "$linuxcnc_root/include"
)
"$cxx" "${common_flags[@]}" \
"$tooldata_common_source" \
"$tooldata_mmap_backend_shim" \
"$tooldata_runtime_stubs_shim" \
core/wasm_shims/tooldata/tooldata_common_probe_main.cc \
-o "$build_dir/tooldata_common_probe"
"$build_dir/tooldata_common_probe"
echo "linuxcnc wasm tooldata_common link probe passed"

View File

@@ -0,0 +1,41 @@
#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$0")"
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
cxx=${CXX:-g++}
build_dir=$(mktemp -d "${TMPDIR:-/tmp}/cnc_sim_linuxcnc_wasm_tooldata_link.XXXXXX")
if [[ ! -d "$linuxcnc_root" ]]; then
echo "missing LinuxCNC root: $linuxcnc_root" >&2
exit 1
fi
trap 'rm -rf "$build_dir"' EXIT
tooldata_mmap_backend_shim=$(./list-linuxcnc-wasm-safe-shims.sh tooldata_mmap_backend.cc)
tooldata_runtime_stubs_shim=$(./list-linuxcnc-wasm-safe-shims.sh tooldata_runtime_stubs.cc)
tooldata_common_source=$(LINUXCNC_ROOT="$linuxcnc_root" ./list-linuxcnc-source-files.sh src/emc/tooldata/tooldata_common.cc)
common_flags=(
-std=c++17
-DULAPI
-I "$(pwd)/core/wasm_shims"
-I "$linuxcnc_root/src"
-I "$linuxcnc_root/src/emc"
-I "$linuxcnc_root/src/emc/nml_intf"
-I "$linuxcnc_root/src/emc/rs274ngc"
-I "$linuxcnc_root/src/emc/motion"
-I "$linuxcnc_root/include"
)
"$cxx" "${common_flags[@]}" \
"$tooldata_common_source" \
"$tooldata_mmap_backend_shim" \
"$tooldata_runtime_stubs_shim" \
core/wasm_shims/tooldata/tooldata_probe_main.cc \
-o "$build_dir/tooldata_probe"
"$build_dir/tooldata_probe"
echo "linuxcnc wasm tooldata shim link probe passed"

View File

@@ -0,0 +1,66 @@
#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$0")"
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
cxx=${CXX:-g++}
build_dir=$(mktemp -d "${TMPDIR:-/tmp}/cnc_sim_linuxcnc_wasm_tooldata_mmap_symbols.XXXXXX")
if [[ ! -d "$linuxcnc_root" ]]; then
echo "missing LinuxCNC root: $linuxcnc_root" >&2
exit 1
fi
trap 'rm -rf "$build_dir"' EXIT
tooldata_mmap_backend_shim=$(./list-linuxcnc-wasm-safe-shims.sh tooldata_mmap_backend.cc)
tooldata_mmap_source=$(LINUXCNC_ROOT="$linuxcnc_root" ./list-linuxcnc-source-files.sh src/emc/tooldata/tooldata_mmap.cc)
common_flags=(
-std=c++17
-DULAPI
-I "$(pwd)/core/wasm_shims"
-I "$linuxcnc_root/src"
-I "$linuxcnc_root/src/emc"
-I "$linuxcnc_root/src/emc/nml_intf"
-I "$linuxcnc_root/src/emc/rs274ngc"
-I "$linuxcnc_root/src/emc/motion"
-I "$linuxcnc_root/include"
)
"$cxx" "${common_flags[@]}" \
-c "$tooldata_mmap_backend_shim" \
-o "$build_dir/tooldata_mmap_backend.o"
"$cxx" "${common_flags[@]}" \
-c "$tooldata_mmap_source" \
-o "$build_dir/linuxcnc_tooldata_mmap.o"
nm --defined-only "$build_dir/tooldata_mmap_backend.o" \
| awk '$2 ~ /^[A-Z]$/ {print $3}' \
| LC_ALL=C sort -u \
> "$build_dir/backend.exports"
nm --defined-only "$build_dir/linuxcnc_tooldata_mmap.o" \
| awk '$2 ~ /^[A-Z]$/ {print $3}' \
| LC_ALL=C sort -u \
> "$build_dir/linuxcnc.exports"
if ! comm -23 "$build_dir/linuxcnc.exports" "$build_dir/backend.exports" > "$build_dir/missing.exports"; then
exit 1
fi
if [[ -s "$build_dir/missing.exports" ]]; then
echo "missing wasm tooldata mmap backend exports from LinuxCNC tooldata_mmap.cc:" >&2
cat "$build_dir/missing.exports" >&2
exit 1
fi
comm -13 "$build_dir/linuxcnc.exports" "$build_dir/backend.exports" > "$build_dir/unexpected.exports"
if [[ -s "$build_dir/unexpected.exports" ]]; then
echo "unexpected wasm tooldata mmap backend exports beyond LinuxCNC tooldata_mmap.cc:" >&2
cat "$build_dir/unexpected.exports" >&2
exit 1
fi
echo "linuxcnc wasm tooldata_mmap symbol probe passed"

View File

@@ -0,0 +1,84 @@
#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$0")"
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
cxx=${CXX:-g++}
build_dir=$(mktemp -d "${TMPDIR:-/tmp}/cnc_sim_linuxcnc_wasm_tooldata_runtime_symbols.XXXXXX")
if [[ ! -d "$linuxcnc_root" ]]; then
echo "missing LinuxCNC root: $linuxcnc_root" >&2
exit 1
fi
trap 'rm -rf "$build_dir"' EXIT
tooldata_mmap_backend_shim=$(./list-linuxcnc-wasm-safe-shims.sh tooldata_mmap_backend.cc)
tooldata_runtime_stubs_shim=$(./list-linuxcnc-wasm-safe-shims.sh tooldata_runtime_stubs.cc)
readarray -t linuxcnc_sources < <(LINUXCNC_ROOT="$linuxcnc_root" ./list-linuxcnc-source-files.sh \
src/emc/tooldata/tooldata_db.cc \
src/emc/tooldata/tooldata_nml.cc)
tooldata_db_source=${linuxcnc_sources[0]}
tooldata_nml_source=${linuxcnc_sources[1]}
common_flags=(
-std=c++17
-DULAPI
-I "$(pwd)/core/wasm_shims"
-I "$linuxcnc_root/src"
-I "$linuxcnc_root/src/emc"
-I "$linuxcnc_root/src/emc/nml_intf"
-I "$linuxcnc_root/src/emc/rs274ngc"
-I "$linuxcnc_root/src/emc/motion"
-I "$linuxcnc_root/include"
)
"$cxx" "${common_flags[@]}" \
-c "$tooldata_runtime_stubs_shim" \
-o "$build_dir/tooldata_runtime_stubs.o"
"$cxx" "${common_flags[@]}" \
-c "$tooldata_mmap_backend_shim" \
-o "$build_dir/tooldata_mmap_backend.o"
"$cxx" "${common_flags[@]}" \
-c "$tooldata_db_source" \
-o "$build_dir/linuxcnc_tooldata_db.o"
"$cxx" "${common_flags[@]}" \
-c "$tooldata_nml_source" \
-o "$build_dir/linuxcnc_tooldata_nml.o"
nm --defined-only "$build_dir/tooldata_runtime_stubs.o" \
| awk '$2 ~ /^[A-Z]$/ {print $3}' \
| LC_ALL=C sort -u \
> "$build_dir/runtime.exports"
nm --defined-only "$build_dir/tooldata_mmap_backend.o" \
| awk '$2 ~ /^[A-Z]$/ {print $3}' \
| LC_ALL=C sort -u \
> "$build_dir/backend.exports"
nm --defined-only "$build_dir"/linuxcnc_tooldata_*.o \
| awk '$2 ~ /^[A-Z]$/ {print $3}' \
| LC_ALL=C sort -u \
> "$build_dir/linuxcnc-runtime.exports"
comm -23 "$build_dir/linuxcnc-runtime.exports" "$build_dir/backend.exports" \
> "$build_dir/expected.exports"
comm -23 "$build_dir/expected.exports" "$build_dir/runtime.exports" > "$build_dir/missing.exports"
if [[ -s "$build_dir/missing.exports" ]]; then
echo "missing wasm tooldata runtime stub exports from LinuxCNC runtime sources:" >&2
cat "$build_dir/missing.exports" >&2
exit 1
fi
comm -13 "$build_dir/expected.exports" "$build_dir/runtime.exports" > "$build_dir/unexpected.exports"
if [[ -s "$build_dir/unexpected.exports" ]]; then
echo "unexpected wasm tooldata runtime stub exports beyond LinuxCNC runtime sources:" >&2
cat "$build_dir/unexpected.exports" >&2
exit 1
fi
echo "linuxcnc wasm tooldata runtime symbol probe passed"

View File

@@ -4,58 +4,58 @@ set -euo pipefail
cd "$(dirname "$0")"
cxx=${CXX:-g++}
build_dir=${TMPDIR:-/tmp}/cnc_sim_native
mkdir -p "$build_dir"
build_dir=$(mktemp -d "${TMPDIR:-/tmp}/cnc_sim_native.XXXXXX")
trap 'rm -rf "$build_dir"' EXIT
core_source_list="$build_dir/cnc_sim_core_sources.txt"
./list-cnc-sim-core-sources.sh > "$core_source_list"
mapfile -t core_sources < "$core_source_list"
"$cxx" -std=c++17 -I core/include -I core/src \
core/src/canon_event_sink.cpp \
core/src/rtcp_kinematics.cpp \
"${core_sources[@]}" \
core/tests/canon_event_sink_smoke.cpp \
-o "$build_dir/canon_event_sink_smoke"
"$cxx" -std=c++17 -I core/include -I core/src \
core/src/rtcp_kinematics.cpp \
"${core_sources[@]}" \
core/tests/rtcp_kinematics_smoke.cpp \
-o "$build_dir/rtcp_kinematics_smoke"
"$cxx" -std=c++17 -I core/include -I core/src \
core/src/canon_event_sink.cpp \
core/src/rtcp_kinematics.cpp \
core/src/simulator_gcode_controls.cpp \
core/tests/linuxcnc_gees_table_smoke.cpp \
-o "$build_dir/linuxcnc_gees_table_smoke"
"$cxx" -std=c++17 -I core/include -I core/src \
"${core_sources[@]}" \
core/tests/simulator_gcode_controls_smoke.cpp \
-o "$build_dir/simulator_gcode_controls_smoke"
"$cxx" -std=c++17 -I core/include -I core/src \
core/src/canon_event_sink.cpp \
core/src/cnc_sim_api.cpp \
core/src/gcode_backend.cpp \
core/src/rtcp_kinematics.cpp \
core/src/simulator_gcode_controls.cpp \
core/src/smoke_gcode_parser.cpp \
"${core_sources[@]}" \
core/tests/cnc_sim_api_smoke.cpp \
-o "$build_dir/cnc_sim_api_smoke"
"$cxx" -std=c++17 -I core/include -I core/src \
core/src/canon_event_sink.cpp \
core/src/cnc_sim_api.cpp \
core/src/gcode_backend.cpp \
core/src/rtcp_kinematics.cpp \
core/src/simulator_gcode_controls.cpp \
core/src/smoke_gcode_parser.cpp \
"${core_sources[@]}" \
core/tools/cnc_sim_dump.cpp \
-o "$build_dir/cnc_sim_dump"
"$build_dir/canon_event_sink_smoke"
"$build_dir/rtcp_kinematics_smoke"
"$build_dir/linuxcnc_gees_table_smoke"
"$build_dir/simulator_gcode_controls_smoke"
"$build_dir/cnc_sim_api_smoke"
"$build_dir/cnc_sim_dump" tests/gcode/basic_mill.ngc >/tmp/cnc_sim_basic_mill.json
"$build_dir/cnc_sim_dump" tests/gcode/incremental_and_r_arc.ngc >/tmp/cnc_sim_incremental_and_r_arc.json
"$build_dir/cnc_sim_dump" tests/gcode/smoke_subprogram_m98.ngc >/tmp/cnc_sim_smoke_subprogram_m98.json
"$build_dir/cnc_sim_dump" tests/gcode/smoke_oword_subprogram.ngc >/tmp/cnc_sim_smoke_oword_subprogram.json
basic_mill_json="$build_dir/cnc_sim_basic_mill.json"
incremental_arc_json="$build_dir/cnc_sim_incremental_and_r_arc.json"
subprogram_m98_json="$build_dir/cnc_sim_smoke_subprogram_m98.json"
oword_subprogram_json="$build_dir/cnc_sim_smoke_oword_subprogram.json"
"$build_dir/cnc_sim_dump" tests/gcode/basic_mill.ngc >"$basic_mill_json"
"$build_dir/cnc_sim_dump" tests/gcode/incremental_and_r_arc.ngc >"$incremental_arc_json"
"$build_dir/cnc_sim_dump" tests/gcode/smoke_subprogram_m98.ngc >"$subprogram_m98_json"
"$build_dir/cnc_sim_dump" tests/gcode/smoke_oword_subprogram.ngc >"$oword_subprogram_json"
echo "native tests passed"
echo "dumped /tmp/cnc_sim_basic_mill.json"
echo "dumped /tmp/cnc_sim_incremental_and_r_arc.json"
echo "dumped /tmp/cnc_sim_smoke_subprogram_m98.json"
echo "dumped /tmp/cnc_sim_smoke_oword_subprogram.json"
echo "dumped $basic_mill_json"
echo "dumped $incremental_arc_json"
echo "dumped $subprogram_m98_json"
echo "dumped $oword_subprogram_json"

View File

@@ -0,0 +1,9 @@
#42 = 0
#<named> = 4711
O100 while [#42 LT 100]
O200 if [#42 EQ 20]
(abort, MixedCase param42=#42 named=#<named>)
O200 endif
#42 = [#42 + 1]
O100 endwhile
M2

View File

@@ -0,0 +1,4 @@
G21
F1
G0 X0 Y0 Z0
G2 X50.00 Y0 I[25.00 - [0.0101 * SQRT[2]]]

View File

@@ -0,0 +1,5 @@
G20
F1
G0 X0 Y0 Z0
G2 X5.000 Y0 I[2.500 - [0.00099 * SQRT[2]]]
M2

View File

@@ -0,0 +1,4 @@
G21 G90 G17 F100
/N10 G1 X5
G1 X2
M30

View File

@@ -0,0 +1,18 @@
O<inner> sub
O10 if [#<_call_level> EQ 2 AND #<_remap_level> EQ 0]
G1 Z1
O10 endif
O<inner> endsub
O<outer> sub
O20 if [#<_call_level> EQ 1 AND #<_remap_level> EQ 0]
G1 Y1
O20 endif
O<inner> call
O<outer> endsub
G21 G90
F100
O30 if [#<_call_level> EQ 0 AND #<_remap_level> EQ 0]
G1 X1
O30 endif
O<outer> call
M30

View File

@@ -0,0 +1,2 @@
G21 G90 G17
G81 X1 A10 Z-1 R1

View File

@@ -0,0 +1,2 @@
G21 G90 G17
G81 X1 B10 Z-1 R1

View File

@@ -0,0 +1,2 @@
G21 G90 G17
G81 X1 C10 Z-1 R1

View File

@@ -0,0 +1,3 @@
G21 G90 G18
F100
G81 X1 Z-1 R1

View File

@@ -0,0 +1,3 @@
G21 G90 G18
F100
G81 X1 Y2 Z-1 R1

View File

@@ -0,0 +1,3 @@
G21 G90 G19
F100
G81 Y1 Z-1 R1

View File

@@ -0,0 +1,3 @@
G21 G90 G19
F100
G81 X2 Y1 Z-1 R1

View File

@@ -0,0 +1,3 @@
G21 G90 G17
F100
G73 X1 Z-1 R1

View File

@@ -0,0 +1,3 @@
G21 G90 G17
F100
G73 X1 Z-1 R1 Q0

View File

@@ -0,0 +1,4 @@
G21 G90 G17
F100
S100 M3
G74 X1 Z-1 R1

View File

@@ -0,0 +1,3 @@
G21 G90 G17
F100
G74 X1 Z-1 R1

View File

@@ -0,0 +1,3 @@
G21 G90 G17
F100
G82 X1 Z-1 R1

View File

@@ -0,0 +1,3 @@
G21 G90 G17
F100
G83 X1 Z-1 R1

View File

@@ -0,0 +1,3 @@
G21 G90 G17
F100
G83 X1 Z-1 R1 Q0

Some files were not shown because too many files have changed in this diff Show More