This commit is contained in:
PJarczak 2026-04-04 17:48:56 +02:00
parent 05aa464989
commit bf40630719
18 changed files with 438 additions and 90 deletions

3
.gitignore vendored
View file

@ -45,4 +45,5 @@ test.js
.clangd
internal_docs/
*.flatpak
/flatpak-repo/
/flatpak-repo/
/.idea/

8
.idea/.gitignore generated vendored
View file

@ -1,8 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

2
.idea/OrcaSlicer.iml generated
View file

@ -1,2 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module classpath="CMake" type="CPP_MODULE" version="4" />

View file

@ -1,7 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<clangFormatSettings>
<option name="ENABLED" value="true" />
</clangFormatSettings>
</code_scheme>
</component>

View file

@ -1,5 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

4
.idea/misc.xml generated
View file

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
</project>

2
.idea/modules.xml generated
View file

@ -2,7 +2,7 @@
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/OrcaSlicer.iml" filepath="$PROJECT_DIR$/.idea/OrcaSlicer.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/OrcaSlicer-bambulab.iml" filepath="$PROJECT_DIR$/.idea/OrcaSlicer-bambulab.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml generated
View file

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

View file

@ -44,3 +44,49 @@ if (UNIX AND NOT APPLE)
RUNTIME DESTINATION "."
)
endif()
if (APPLE)
set(PJARCZAK_MAC_WRAPPER_SCRIPT_SOURCE ${CMAKE_SOURCE_DIR}/tools/pjarczak_bambu_macos_linux_wrapper/pjarczak_bambu_macos_linux_wrapper.sh)
add_custom_command(TARGET pjarczak_bambu_networking_bridge POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${PJARCZAK_MAC_WRAPPER_SCRIPT_SOURCE}
${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/pjarczak_bambu_macos_linux_wrapper.sh
)
install(FILES ${PJARCZAK_MAC_WRAPPER_SCRIPT_SOURCE}
DESTINATION "."
RENAME pjarczak_bambu_macos_linux_wrapper.sh
)
endif()
if (WIN32)
set(PJARCZAK_WSL_HELPER_SOURCE ${CMAKE_SOURCE_DIR}/tools/pjarczak_bambu_runtime/wsl/pjarczak_wsl_run_host.sh)
set(PJARCZAK_WSL_INSTALLER_SOURCE ${CMAKE_SOURCE_DIR}/tools/pjarczak_bambu_runtime/wsl/install_runtime.ps1)
set(PJARCZAK_WSL_INSTALLER_CMD_SOURCE ${CMAKE_SOURCE_DIR}/tools/pjarczak_bambu_runtime/wsl/install_runtime.cmd)
set(PJARCZAK_WSL_VERIFY_SOURCE ${CMAKE_SOURCE_DIR}/tools/pjarczak_bambu_runtime/wsl/verify_runtime.ps1)
set(PJARCZAK_RUNTIME_README_SOURCE ${CMAKE_SOURCE_DIR}/tools/pjarczak_bambu_runtime/README_runtime_bridge.txt)
add_custom_command(TARGET pjarczak_bambu_networking_bridge POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${PJARCZAK_WSL_HELPER_SOURCE}
${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/pjarczak_wsl_run_host.sh
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${PJARCZAK_WSL_INSTALLER_SOURCE}
${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/install_runtime.ps1
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${PJARCZAK_WSL_INSTALLER_CMD_SOURCE}
${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/install_runtime.cmd
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${PJARCZAK_WSL_VERIFY_SOURCE}
${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/verify_runtime.ps1
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${PJARCZAK_RUNTIME_README_SOURCE}
${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/README_runtime_bridge.txt
)
install(FILES
${PJARCZAK_WSL_HELPER_SOURCE}
${PJARCZAK_WSL_INSTALLER_SOURCE}
${PJARCZAK_WSL_INSTALLER_CMD_SOURCE}
${PJARCZAK_WSL_VERIFY_SOURCE}
${PJARCZAK_RUNTIME_README_SOURCE}
DESTINATION "."
)
endif()

View file

@ -3,6 +3,7 @@
#include <array>
#include <cstdint>
#include <cctype>
#include <fstream>
#include <sstream>
#include <iomanip>
@ -39,7 +40,7 @@ bool expected_machine_matches(std::uint16_t machine)
{
#if defined(__x86_64__) || defined(_M_X64)
return machine == EM_X86_64;
#elif defined(__aarch64__)
#elif defined(__aarch64__) || defined(_M_ARM64)
return machine == EM_AARCH64;
#else
(void)machine;
@ -60,6 +61,17 @@ std::string env_or(const char* name, const char* fallback)
return fallback;
}
bool env_flag_enabled(const char* name)
{
const char* v = std::getenv(name);
if (!v || !*v)
return false;
std::string s(v);
for (char& ch : s)
ch = static_cast<char>(std::tolower(static_cast<unsigned char>(ch)));
return s == "1" || s == "true" || s == "yes" || s == "on";
}
boost::filesystem::path process_dir_path()
{
try {
@ -83,16 +95,26 @@ const nlohmann::json* find_manifest_entry(const nlohmann::json& root, const std:
return nullptr;
}
}
} // namespace
bool enabled()
{
if (env_flag_enabled("PJARCZAK_DISABLE_LINUX_BRIDGE"))
return false;
if (env_flag_enabled("PJARCZAK_FORCE_LINUX_BRIDGE"))
return true;
#if defined(_MSC_VER) || defined(_WIN32)
return true;
#elif defined(__WXMAC__) || defined(__APPLE__)
return true;
#else
return false;
#endif
}
bool source_module_is_network_module()
{
return true;
return enabled();
}
bool should_force_linux_plugin_payload(const std::string& plugin_name)
@ -354,4 +376,4 @@ std::vector<std::string> ota_copy_extensions()
return {".so", ".json"};
}
}
} // namespace Slic3r::PJarczakLinuxBridge

View file

@ -7,18 +7,38 @@ namespace Slic3r::PJarczakLinuxBridge {
namespace {
const char* env_host_cmd()
const char* env_value(const char* name)
{
return std::getenv("PJARCZAK_LINUX_HOST_CMD");
return std::getenv(name);
}
std::string wrapper_executable_name()
std::string env_or(const char* name, const char* fallback)
{
return "pjarczak-bambu-linux-host-wrapper";
if (const char* v = env_value(name); v && *v)
return v;
return fallback;
}
std::string shell_quote(const std::string& value)
{
std::string out = "'";
for (char ch : value) {
if (ch == '\'')
out += "'\\''";
else
out += ch;
}
out += "'";
return out;
}
std::string wrapper_script_name()
{
return "pjarczak_bambu_macos_linux_wrapper.sh";
}
} // namespace
std::string host_executable_name()
{
return "pjarczak_bambu_linux_host";
@ -32,15 +52,31 @@ std::string host_pipe_hint()
LaunchSpec build_default_launch_spec()
{
LaunchSpec spec;
if (const char* cmd = env_host_cmd(); cmd && *cmd) {
spec.description = "mac via PJARCZAK_LINUX_HOST_CMD";
if (const char* cmd = env_value("PJARCZAK_MAC_LINUX_WRAPPER_CMD"); cmd && *cmd) {
spec.description = "mac via PJARCZAK_MAC_LINUX_WRAPPER_CMD";
spec.argv = {"/bin/sh", "-lc", cmd};
return spec;
}
spec.description = "mac via bundled linux wrapper";
spec.argv = {sibling_binary_path(wrapper_executable_name()), sibling_binary_path(host_executable_name())};
const std::string wrapper = sibling_binary_path(wrapper_script_name());
const std::string host = sibling_binary_path(host_executable_name());
const std::string runtime_dir_default = sibling_binary_path("pjarczak_bambu_linux_host.runtime");
const std::string runtime_dir = env_or("PJARCZAK_MAC_RUNTIME_DIR", runtime_dir_default.c_str());
const std::string plugin_dir = env_or("PJARCZAK_BAMBU_PLUGIN_DIR", "");
std::string cmd;
cmd += "exec ";
cmd += shell_quote(wrapper);
cmd += " ";
cmd += shell_quote(host);
cmd += " ";
cmd += shell_quote(runtime_dir);
cmd += " ";
cmd += shell_quote(plugin_dir);
spec.description = "mac via wrapper script";
spec.argv = {"/bin/sh", "-lc", cmd};
return spec;
}
}
} // namespace Slic3r::PJarczakLinuxBridge

View file

@ -15,9 +15,11 @@ const char* env_value(const char* name)
return std::getenv(name);
}
const char* env_host_cmd()
std::string env_or(const char* name, const char* fallback)
{
return env_value("PJARCZAK_LINUX_HOST_CMD");
if (const char* v = env_value(name); v && *v)
return v;
return fallback;
}
std::string shell_quote(const std::string& value)
@ -43,6 +45,31 @@ std::string to_wsl_path(std::string path)
return path;
}
std::string host_path_in_distro()
{
return env_or("PJARCZAK_WSL_HOST_PATH", "/opt/pjarczak/bin/pjarczak_bambu_linux_host");
}
std::string runtime_dir_in_distro()
{
return env_or("PJARCZAK_WSL_RUNTIME_DIR", "/opt/pjarczak/runtime");
}
std::string wsl_distro_name()
{
return env_or("PJARCZAK_WSL_DISTRO", "PJARCZAK-BAMBU");
}
std::string wsl_user_name()
{
return env_or("PJARCZAK_WSL_USER", "root");
}
std::string wsl_shell_path()
{
return env_or("PJARCZAK_WSL_SHELL", "/bin/sh");
}
void append_shell_export(std::string& script, const char* name, const std::string& value)
{
if (value.empty())
@ -62,14 +89,10 @@ void append_shell_path_export(std::string& script, const char* name)
append_shell_export(script, name, to_wsl_path(value));
}
std::string host_runtime_dir_name()
{
return "pjarczak_bambu_linux_host.runtime";
}
std::string build_shell_prefix()
{
std::string script = "set -eu;";
append_shell_path_export(script, "PJARCZAK_BAMBU_PLUGIN_DIR");
append_shell_path_export(script, "PJARCZAK_BAMBU_NETWORK_SO");
append_shell_path_export(script, "PJARCZAK_BAMBU_SOURCE_SO");
@ -78,15 +101,36 @@ std::string build_shell_prefix()
if (const char* version = env_value("PJARCZAK_EXPECTED_BAMBU_NETWORK_VERSION"); version && *version)
append_shell_export(script, "PJARCZAK_EXPECTED_BAMBU_NETWORK_VERSION", version);
const std::string runtime_path = to_wsl_path(sibling_binary_path(host_runtime_dir_name()));
script += "export LD_LIBRARY_PATH=";
script += shell_quote(runtime_path);
script += "${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}};";
script += "RUNTIME_DIR=";
script += shell_quote(runtime_dir_in_distro());
script += ";";
script += "HOST=";
script += shell_quote(host_path_in_distro());
script += ";";
script += "PLUGIN_DIR=${PJARCZAK_BAMBU_PLUGIN_DIR:-};";
script += "if [ -z \"${PJARCZAK_BAMBU_NETWORK_SO:-}\" ] && [ -n \"$PLUGIN_DIR\" ]; then export PJARCZAK_BAMBU_NETWORK_SO=\"$PLUGIN_DIR/libbambu_networking.so\"; fi;";
script += "if [ -z \"${PJARCZAK_BAMBU_SOURCE_SO:-}\" ] && [ -n \"$PLUGIN_DIR\" ]; then export PJARCZAK_BAMBU_SOURCE_SO=\"$PLUGIN_DIR/libBambuSource.so\"; fi;";
script += "if [ -z \"${PJARCZAK_BAMBU_LIVE555_SO:-}\" ] && [ -n \"$PLUGIN_DIR\" ]; then export PJARCZAK_BAMBU_LIVE555_SO=\"$PLUGIN_DIR/liblive555.so\"; fi;";
script += "LIB_DIR=\"$RUNTIME_DIR\";";
script += "if [ -n \"${PJARCZAK_BAMBU_NETWORK_SO:-}\" ]; then LIB_DIR=$(dirname \"$PJARCZAK_BAMBU_NETWORK_SO\"); fi;";
script += "export LD_LIBRARY_PATH=\"$LIB_DIR:$RUNTIME_DIR${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}\";";
script += "[ -x \"$HOST\" ] || chmod +x \"$HOST\" || true;";
script += "[ -x \"$HOST\" ] || { echo \"missing linux host: $HOST\" 1>&2; exit 127; };";
script += "if [ -n \"${PJARCZAK_BAMBU_NETWORK_SO:-}\" ] && [ ! -f \"$PJARCZAK_BAMBU_NETWORK_SO\" ]; then echo \"missing libbambu_networking.so: $PJARCZAK_BAMBU_NETWORK_SO\" 1>&2; exit 127; fi;";
script += "if [ -n \"${PJARCZAK_BAMBU_SOURCE_SO:-}\" ] && [ ! -f \"$PJARCZAK_BAMBU_SOURCE_SO\" ]; then echo \"missing libBambuSource.so: $PJARCZAK_BAMBU_SOURCE_SO\" 1>&2; exit 127; fi;";
script += "if [ -n \"${PJARCZAK_BAMBU_LIVE555_SO:-}\" ] && [ ! -f \"$PJARCZAK_BAMBU_LIVE555_SO\" ]; then echo \"missing liblive555.so: $PJARCZAK_BAMBU_LIVE555_SO\" 1>&2; exit 127; fi;";
return script;
}
std::string build_default_shell_script()
{
std::string script = build_shell_prefix();
script += "exec \"$HOST\";";
return script;
}
} // namespace
std::string host_executable_name()
{
return "pjarczak_bambu_linux_host";
@ -100,26 +144,30 @@ std::string host_pipe_hint()
LaunchSpec build_default_launch_spec()
{
LaunchSpec spec;
std::string script = build_shell_prefix();
if (const char* cmd = env_host_cmd(); cmd && *cmd) {
if (const char* cmd = env_value("PJARCZAK_LINUX_HOST_CMD"); cmd && *cmd) {
spec.description = "windows via PJARCZAK_LINUX_HOST_CMD";
std::string script = build_shell_prefix();
script += cmd;
spec.argv = {"wsl.exe", "--", "bash", "-lc", script};
spec.argv = {
"wsl.exe",
"--distribution", wsl_distro_name(),
"--user", wsl_user_name(),
"--exec", wsl_shell_path(),
"-lc", script
};
return spec;
}
const std::string host_path = to_wsl_path(sibling_binary_path(host_executable_name()));
script += "HOST=";
script += shell_quote(host_path);
script += ";";
script += "[ -x \"$HOST\" ] || chmod +x \"$HOST\" || true;";
script += "exec \"$HOST\";";
spec.description = "windows via WSL";
spec.argv = {"wsl.exe", "--", "bash", "-lc", script};
spec.description = "windows via WSL distro=" + wsl_distro_name() + " user=" + wsl_user_name();
spec.argv = {
"wsl.exe",
"--distribution", wsl_distro_name(),
"--user", wsl_user_name(),
"--exec", wsl_shell_path(),
"-lc", build_default_shell_script()
};
return spec;
}
}
} // namespace Slic3r::PJarczakLinuxBridge

View file

@ -21,17 +21,40 @@ RpcClient::~RpcClient()
stop_locked();
}
void RpcClient::append_stderr_line(const std::string& line)
{
std::lock_guard<std::mutex> lock(m_stderr_mutex);
if (!m_stderr_tail.empty())
m_stderr_tail += "\n";
m_stderr_tail += line;
constexpr std::size_t max_tail = 8192;
if (m_stderr_tail.size() > max_tail)
m_stderr_tail.erase(0, m_stderr_tail.size() - max_tail);
}
std::string RpcClient::stderr_summary() const
{
std::lock_guard<std::mutex> lock(m_stderr_mutex);
return m_stderr_tail;
}
bool RpcClient::start_locked()
{
if (m_proc && m_proc->child.running())
return true;
auto spec = build_default_launch_spec();
try {
auto spec = build_default_launch_spec();
if (spec.argv.empty()) {
m_last_error = "empty launch spec";
return false;
}
{
std::lock_guard<std::mutex> lock(m_stderr_mutex);
m_stderr_tail.clear();
}
bp::environment env = boost::this_process::environment();
for (const auto& kv : spec.env)
env[kv.first] = kv.second;
@ -44,21 +67,24 @@ bool RpcClient::start_locked()
if (!exe_path.is_absolute())
exe_path = bp::search_path(spec.argv[0]);
if (exe_path.empty()) {
m_last_error = "bridge host executable not found: " + spec.argv[0];
m_last_error = "bridge host executable not found for " + spec.description + ": " + spec.argv[0];
return false;
}
auto proc = std::make_unique<Proc>();
proc->child = bp::child(exe_path, bp::args(args), bp::std_in < proc->in, bp::std_out > proc->out, env);
proc->child = bp::child(exe_path, bp::args(args), bp::std_in < proc->in, bp::std_out > proc->out, bp::std_err > proc->err, env);
m_proc = std::move(proc);
m_reader_stop = false;
if (m_reader.joinable())
m_reader.join();
if (m_stderr_reader.joinable())
m_stderr_reader.join();
m_reader = std::thread([this] { reader_loop(); });
m_stderr_reader = std::thread([this] { stderr_reader_loop(); });
m_last_error.clear();
return true;
} catch (const std::exception& e) {
m_last_error = e.what();
m_last_error = "bridge host start failed (" + spec.description + "): " + e.what();
m_proc.reset();
return false;
}
@ -75,6 +101,8 @@ void RpcClient::stop_locked()
}
if (m_reader.joinable())
m_reader.join();
if (m_stderr_reader.joinable())
m_stderr_reader.join();
m_proc.reset();
}
@ -90,26 +118,53 @@ bool RpcClient::is_started() const
return m_proc && m_proc->child.running();
}
void RpcClient::reader_loop()
void RpcClient::stderr_reader_loop()
{
while (!m_reader_stop) {
std::string line;
for (;;) {
Proc* proc = nullptr;
{
std::lock_guard<std::mutex> lock(m_state_mutex);
if (!m_proc)
break;
if (!std::getline(m_proc->out, line)) {
m_last_error = "bridge host closed stdout";
auto pending = m_pending;
m_pending.clear();
for (auto& it : pending) {
std::lock_guard<std::mutex> plock(it.second->mutex);
it.second->payload = {{"ok", false}, {"error", m_last_error}};
it.second->ready = true;
it.second->cv.notify_all();
}
proc = m_proc.get();
}
std::string line;
if (!std::getline(proc->err, line))
break;
if (!line.empty())
append_stderr_line(line);
}
}
void RpcClient::reader_loop()
{
for (;;) {
Proc* proc = nullptr;
{
std::lock_guard<std::mutex> lock(m_state_mutex);
if (!m_proc)
break;
proc = m_proc.get();
}
std::string line;
if (!std::getline(proc->out, line)) {
std::string error = "bridge host closed stdout";
const std::string stderr = stderr_summary();
if (!stderr.empty())
error += "; stderr: " + stderr;
std::lock_guard<std::mutex> lock(m_state_mutex);
m_last_error = error;
auto pending = m_pending;
m_pending.clear();
for (auto& it : pending) {
std::lock_guard<std::mutex> plock(it.second->mutex);
it.second->payload = {{"ok", false}, {"error", m_last_error}};
it.second->ready = true;
it.second->cv.notify_all();
}
break;
}
RpcFrame reply;
@ -209,4 +264,4 @@ std::string RpcClient::last_error() const
return m_last_error;
}
}
} // namespace Slic3r::PJarczakLinuxBridge

View file

@ -33,6 +33,7 @@ private:
struct Proc {
boost::process::opstream in;
boost::process::ipstream out;
boost::process::ipstream err;
boost::process::child child;
};
@ -47,15 +48,21 @@ private:
bool start_locked();
void stop_locked();
void reader_loop();
void stderr_reader_loop();
void append_stderr_line(const std::string& line);
std::string stderr_summary() const;
mutable std::mutex m_state_mutex;
std::mutex m_write_mutex;
std::mutex m_stderr_mutex;
std::unique_ptr<Proc> m_proc;
std::thread m_reader;
std::thread m_stderr_reader;
int m_next_id{1};
std::string m_last_error;
std::map<int, std::shared_ptr<Pending>> m_pending;
bool m_reader_stop{false};
std::string m_stderr_tail;
};
}

View file

@ -0,0 +1,30 @@
#!/bin/sh
set -eu
HOST_PATH="${1:-}"
RUNTIME_DIR="${2:-}"
PLUGIN_DIR="${3:-}"
if [ -n "${PJARCZAK_MAC_LINUX_WRAPPER_CMD:-}" ]; then
exec /bin/sh -lc "$PJARCZAK_MAC_LINUX_WRAPPER_CMD"
fi
if [ -n "${PJARCZAK_MAC_DOCKER_IMAGE:-}" ]; then
exec docker run --rm -i \
-e PJARCZAK_BAMBU_PLUGIN_DIR=/runtime/plugin \
-e PJARCZAK_BAMBU_NETWORK_SO=/runtime/plugin/libbambu_networking.so \
-e PJARCZAK_BAMBU_SOURCE_SO=/runtime/plugin/libBambuSource.so \
-e PJARCZAK_BAMBU_LIVE555_SO=/runtime/plugin/liblive555.so \
-e PJARCZAK_EXPECTED_BAMBU_NETWORK_VERSION="${PJARCZAK_EXPECTED_BAMBU_NETWORK_VERSION:-}" \
-v "$RUNTIME_DIR:/runtime/host:ro" \
-v "$PLUGIN_DIR:/runtime/plugin:ro" \
"$PJARCZAK_MAC_DOCKER_IMAGE" /runtime/host/pjarczak_bambu_linux_host
fi
if [ -n "${PJARCZAK_MAC_LIMA_INSTANCE:-}" ]; then
exec limactl shell "$PJARCZAK_MAC_LIMA_INSTANCE" -- /bin/sh -lc \
"export PJARCZAK_BAMBU_PLUGIN_DIR=$(printf %s \"$PLUGIN_DIR\"); export PJARCZAK_BAMBU_NETWORK_SO=$(printf %s \"$PLUGIN_DIR/libbambu_networking.so\"); export PJARCZAK_BAMBU_SOURCE_SO=$(printf %s \"$PLUGIN_DIR/libBambuSource.so\"); export PJARCZAK_BAMBU_LIVE555_SO=$(printf %s \"$PLUGIN_DIR/liblive555.so\"); exec $(printf %s \"$HOST_PATH\")"
fi
echo "No macOS Linux wrapper configured. Set PJARCZAK_MAC_LINUX_WRAPPER_CMD, PJARCZAK_MAC_DOCKER_IMAGE or PJARCZAK_MAC_LIMA_INSTANCE." >&2
exit 127

View file

@ -0,0 +1,35 @@
param(
[Parameter(Mandatory = $true)][string]$OutputDir,
[Parameter(Mandatory = $true)][string]$RootFs,
[Parameter(Mandatory = $true)][string]$LinuxHostBinary,
[string]$RuntimeDir = ""
)
$ErrorActionPreference = 'Stop'
$scriptDir = Split-Path -Parent $PSCommandPath
$toolsRoot = [System.IO.Path]::GetFullPath((Join-Path $scriptDir '..'))
$wslRoot = Join-Path $toolsRoot 'wsl'
if (-not (Test-Path $RootFs)) { throw "RootFs not found: $RootFs" }
if (-not (Test-Path $LinuxHostBinary)) { throw "LinuxHostBinary not found: $LinuxHostBinary" }
if ($RuntimeDir -and -not (Test-Path $RuntimeDir)) { throw "RuntimeDir not found: $RuntimeDir" }
New-Item -ItemType Directory -Force -Path $OutputDir | Out-Null
New-Item -ItemType Directory -Force -Path (Join-Path $OutputDir 'rootfs') | Out-Null
New-Item -ItemType Directory -Force -Path (Join-Path $OutputDir 'linux-runtime') | Out-Null
Copy-Item -Force (Join-Path $wslRoot 'install_runtime.ps1') (Join-Path $OutputDir 'install_runtime.ps1')
Copy-Item -Force (Join-Path $wslRoot 'install_runtime.cmd') (Join-Path $OutputDir 'install_runtime.cmd')
Copy-Item -Force (Join-Path $wslRoot 'verify_runtime.ps1') (Join-Path $OutputDir 'verify_runtime.ps1')
Copy-Item -Force (Join-Path $toolsRoot 'README_runtime_bridge.txt') (Join-Path $OutputDir 'README_runtime_bridge.txt')
Copy-Item -Force $RootFs (Join-Path $OutputDir 'rootfs\pjarczak-bambu-rootfs.tar')
Copy-Item -Force $LinuxHostBinary (Join-Path $OutputDir 'linux-runtime\pjarczak_bambu_linux_host')
if ($RuntimeDir) {
New-Item -ItemType Directory -Force -Path (Join-Path $OutputDir 'linux-runtime\runtime') | Out-Null
Copy-Item -Recurse -Force (Join-Path $RuntimeDir '*') (Join-Path $OutputDir 'linux-runtime\runtime')
}
Write-Host 'Bundle created:'
Write-Host $OutputDir

View file

@ -0,0 +1,25 @@
#!/bin/sh
set -eu
HOST="${1:-${PJARCZAK_WSL_HOST_PATH:-/opt/pjarczak/bin/pjarczak_bambu_linux_host}}"
RUNTIME_DIR="${2:-${PJARCZAK_WSL_RUNTIME_DIR:-/opt/pjarczak/runtime}}"
PLUGIN_DIR="${PJARCZAK_BAMBU_PLUGIN_DIR:-}"
if [ -z "${PJARCZAK_BAMBU_NETWORK_SO:-}" ] && [ -n "$PLUGIN_DIR" ]; then
export PJARCZAK_BAMBU_NETWORK_SO="$PLUGIN_DIR/libbambu_networking.so"
fi
if [ -z "${PJARCZAK_BAMBU_SOURCE_SO:-}" ] && [ -n "$PLUGIN_DIR" ]; then
export PJARCZAK_BAMBU_SOURCE_SO="$PLUGIN_DIR/libBambuSource.so"
fi
if [ -z "${PJARCZAK_BAMBU_LIVE555_SO:-}" ] && [ -n "$PLUGIN_DIR" ]; then
export PJARCZAK_BAMBU_LIVE555_SO="$PLUGIN_DIR/liblive555.so"
fi
LIB_DIR="$RUNTIME_DIR"
if [ -n "${PJARCZAK_BAMBU_NETWORK_SO:-}" ]; then
LIB_DIR="$(dirname "$PJARCZAK_BAMBU_NETWORK_SO")"
fi
export LD_LIBRARY_PATH="$LIB_DIR:$RUNTIME_DIR${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}"
[ -x "$HOST" ] || chmod +x "$HOST" || true
exec "$HOST"

View file

@ -0,0 +1,75 @@
param(
[string]$Distro = $(if ($env:PJARCZAK_WSL_DISTRO) { $env:PJARCZAK_WSL_DISTRO } else { 'PJARCZAK-BAMBU' })
)
$ErrorActionPreference = 'Stop'
function Find-WslExe {
foreach ($candidate in @((Join-Path $env:WINDIR 'System32\wsl.exe'), (Join-Path $env:WINDIR 'Sysnative\wsl.exe'))) {
if (Test-Path $candidate) {
return $candidate
}
}
$cmd = Get-Command wsl.exe -ErrorAction SilentlyContinue
if ($cmd) {
return $cmd.Source
}
throw 'wsl.exe not found'
}
function Step([string]$Name, [scriptblock]$Block) {
Write-Host ('[' + $Name + ']')
$global:LASTEXITCODE = 0
& $Block
if ($LASTEXITCODE -ne 0) {
throw "$Name failed with exit code $LASTEXITCODE"
}
Write-Host ''
}
function Step-WslLddStrict([string]$Name, [string]$CommandText) {
Step $Name {
$output = & $WslExe --distribution $Distro --user root --exec /bin/sh -lc $CommandText 2>&1
$exitCode = $LASTEXITCODE
$text = ($output | Out-String)
$text = $text.TrimEnd()
if (-not [string]::IsNullOrWhiteSpace($text)) {
Write-Host $text
}
if ($exitCode -ne 0) {
throw "$Name failed with exit code $exitCode"
}
if ($text -match '(?m)\bnot found\b') {
throw "$Name reported missing shared libraries"
}
}
}
$WslExe = Find-WslExe
Step 'env' {
Write-Host ('PJARCZAK_WSL_DISTRO=' + $env:PJARCZAK_WSL_DISTRO)
Write-Host ('PJARCZAK_WSL_USER=' + $env:PJARCZAK_WSL_USER)
Write-Host ('PJARCZAK_WSL_HOST_PATH=' + $env:PJARCZAK_WSL_HOST_PATH)
Write-Host ('PJARCZAK_WSL_RUNTIME_DIR=' + $env:PJARCZAK_WSL_RUNTIME_DIR)
}
Step 'wsl-status' {
& $WslExe --status
}
Step 'wsl-list' {
& $WslExe -l -v
}
Step 'host-check' {
& $WslExe --distribution $Distro --user root --exec /bin/sh -lc 'set -eu; test -x /opt/pjarczak/bin/pjarczak_bambu_linux_host; echo HOST_OK'
}
Step 'runtime-check' {
& $WslExe --distribution $Distro --user root --exec /bin/sh -lc 'set -eu; ls -la /opt/pjarczak/bin; ls -la /opt/pjarczak/runtime || true'
}
Step-WslLddStrict 'ldd' 'set -eu; LD_LIBRARY_PATH=/opt/pjarczak/runtime ldd /opt/pjarczak/bin/pjarczak_bambu_linux_host'
Write-Host 'Verify finished.'