This commit is contained in:
PJarczak 2026-04-20 19:05:07 +02:00
parent 52a3d0e556
commit 4aa80f055a
5 changed files with 153 additions and 32 deletions

View file

@ -25,11 +25,16 @@ jobs:
uses: ./.github/workflows/build_linux_portable.yml
secrets: inherit
build_macos:
uses: ./.github/workflows/build_macos_bridge.yml
secrets: inherit
publish_release:
name: Publish release assets
needs:
- build_windows
- build_linux
- build_macos
if: ${{ github.event_name == 'push' || github.event_name == 'release' }}
runs-on: ubuntu-24.04
permissions:

View file

@ -88,6 +88,19 @@ std::string run_and_capture(const std::string& command, int* exit_code = nullptr
return trim_ascii(output);
}
std::filesystem::path runtime_dir()
{
const auto env_value = required_env("PJARCZAK_MAC_RUNTIME_DIR");
if (!env_value.empty())
return std::filesystem::path(env_value);
const auto home = required_env("HOME");
if (home.empty())
return {};
return std::filesystem::path(home) / "Library" / "Application Support" / "OrcaSlicer" / "macos-bridge" / "runtime";
}
std::string configured_instance_name(const std::filesystem::path& plugin_dir)
{
const auto env_value = required_env("PJARCZAK_MAC_LIMA_INSTANCE");
@ -96,24 +109,36 @@ std::string configured_instance_name(const std::filesystem::path& plugin_dir)
return read_text_file_trimmed(plugin_dir / mac_lima_instance_file_name());
}
std::string first_missing_runtime_file(const std::filesystem::path& plugin_dir)
std::string first_missing_runtime_file(const std::filesystem::path& plugin_dir,
const std::filesystem::path& runtime_dir_path)
{
const std::string required_files[] = {
host_executable_file_name(),
std::string("pjarczak_bambu_linux_host_abi1"),
std::string("pjarczak_bambu_linux_host_abi0"),
const std::string plugin_required_files[] = {
mac_host_wrapper_file_name(),
mac_runtime_install_script_file_name(),
mac_runtime_verify_script_file_name(),
mac_lima_instance_file_name(),
mac_lima_instance_file_name()
};
for (const std::string& name : plugin_required_files) {
if (!std::filesystem::exists(plugin_dir / std::filesystem::path(name)))
return name;
}
if (runtime_dir_path.empty())
return "macOS runtime directory is not resolvable";
const std::string runtime_required_files[] = {
host_executable_file_name(),
std::string("pjarczak_bambu_linux_host_abi1"),
std::string("pjarczak_bambu_linux_host_abi0"),
linux_network_library_name(),
linux_source_library_name(),
std::string("ca-certificates.crt"),
std::string("slicer_base64.cer")
};
for (const std::string& name : required_files) {
if (!std::filesystem::exists(plugin_dir / std::filesystem::path(name)))
for (const std::string& name : runtime_required_files) {
if (!std::filesystem::exists(runtime_dir_path / std::filesystem::path(name)))
return name;
}
@ -177,7 +202,8 @@ std::string launch_preflight_error()
if (plugin_dir.empty())
return "bridge launcher could not resolve plugin directory";
const auto missing_file = first_missing_runtime_file(plugin_dir);
const std::filesystem::path runtime_dir_path = runtime_dir();
const auto missing_file = first_missing_runtime_file(plugin_dir, runtime_dir_path);
if (!missing_file.empty())
return "required macOS runtime file missing: " + missing_file;
@ -198,7 +224,8 @@ LaunchSpec build_default_launch_spec()
if (plugin_dir.empty())
return error_launch_spec("bridge launcher could not resolve plugin directory");
const auto missing_file = first_missing_runtime_file(plugin_dir);
const std::filesystem::path runtime_dir_path = runtime_dir();
const auto missing_file = first_missing_runtime_file(plugin_dir, runtime_dir_path);
if (!missing_file.empty())
return error_launch_spec("required macOS runtime file missing: " + missing_file);
@ -211,16 +238,17 @@ LaunchSpec build_default_launch_spec()
return error_launch_spec(reason.empty() ? std::string("macOS Lima runtime is not ready") : reason);
const std::filesystem::path wrapper_path = plugin_dir / mac_host_wrapper_file_name();
const std::filesystem::path host_path = plugin_dir / host_executable_file_name();
const std::filesystem::path host_path = runtime_dir_path / host_executable_file_name();
LaunchSpec spec;
spec.description = "macOS via Lima linux guest";
spec.argv = {wrapper_path.string(), host_path.string()};
spec.env = {
{"PJARCZAK_BAMBU_PLUGIN_DIR", plugin_dir.string()},
{"PJARCZAK_BAMBU_NETWORK_SO", (plugin_dir / linux_network_library_name()).string()},
{"PJARCZAK_BAMBU_SOURCE_SO", (plugin_dir / linux_source_library_name()).string()},
{"PJARCZAK_BAMBU_PLUGIN_DIR", runtime_dir_path.string()},
{"PJARCZAK_BAMBU_NETWORK_SO", (runtime_dir_path / linux_network_library_name()).string()},
{"PJARCZAK_BAMBU_SOURCE_SO", (runtime_dir_path / linux_source_library_name()).string()},
{"PJARCZAK_BAMBU_REQUIRE_LINUX_GUEST", "1"},
{"PJARCZAK_MAC_RUNTIME_DIR", runtime_dir_path.string()},
{"PJARCZAK_MAC_LIMA_INSTANCE", instance}
};
return spec;

View file

@ -7,9 +7,14 @@ if [ -z "$HOST_PATH" ]; then
exit 127
fi
runtime_dir_default() {
printf '%s
' "$HOME/Library/Application Support/OrcaSlicer/macos-bridge/runtime"
}
PLUGIN_DIR="${PJARCZAK_BAMBU_PLUGIN_DIR:-}"
if [ -z "$PLUGIN_DIR" ]; then
PLUGIN_DIR=$(cd "$(dirname "$HOST_PATH")" && pwd)
PLUGIN_DIR=$(runtime_dir_default)
fi
trim_file() {

View file

@ -42,19 +42,21 @@ fi
APP_SUPPORT_DIR="$HOME/Library/Application Support/OrcaSlicer/macos-bridge"
LOCAL_LIMA_ROOT="$APP_SUPPORT_DIR/lima"
LOCAL_LIMA_BIN="$LOCAL_LIMA_ROOT/bin"
mkdir -p "$APP_SUPPORT_DIR" "$LOCAL_LIMA_ROOT"
RUNTIME_DIR="${PJARCZAK_MAC_RUNTIME_DIR:-$APP_SUPPORT_DIR/runtime}"
mkdir -p "$APP_SUPPORT_DIR" "$LOCAL_LIMA_ROOT" "$RUNTIME_DIR"
trim_file() {
local path="$1"
if [[ ! -f "$path" ]]; then
return 1
fi
LC_ALL=C tr -d '\r' < "$path" | head -n 1 | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'
LC_ALL=C tr -d ' ' < "$path" | head -n 1 | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'
}
find_limactl() {
if [[ -n "${PJARCZAK_LIMACTL:-}" && -x "${PJARCZAK_LIMACTL}" ]]; then
printf '%s\n' "$PJARCZAK_LIMACTL"
printf '%s
' "$PJARCZAK_LIMACTL"
return 0
fi
if command -v limactl >/dev/null 2>&1; then
@ -62,12 +64,14 @@ find_limactl() {
return 0
fi
if [[ -x "$LOCAL_LIMA_BIN/limactl" ]]; then
printf '%s\n' "$LOCAL_LIMA_BIN/limactl"
printf '%s
' "$LOCAL_LIMA_BIN/limactl"
return 0
fi
for candidate in /opt/homebrew/bin/limactl /usr/local/bin/limactl; do
if [[ -x "$candidate" ]]; then
printf '%s\n' "$candidate"
printf '%s
' "$candidate"
return 0
fi
done
@ -76,7 +80,7 @@ find_limactl() {
install_lima_binary_locally() {
local version
version=$(curl -fsSL https://api.github.com/repos/lima-vm/lima/releases/latest | sed -n 's/.*"tag_name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -n 1)
version=$(curl -fsSL https://api.github.com/repos/lima-vm/lima/releases/latest | sed -n 's/.*"tag_name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*//p' | head -n 1)
if [[ -z "$version" ]]; then
echo "failed to resolve latest Lima version from GitHub API" >&2
return 1
@ -144,6 +148,37 @@ maybe_install_rosetta() {
/usr/sbin/softwareupdate --install-rosetta --agree-to-license >/dev/null 2>&1 || true
}
copy_runtime_payload() {
local src_dir="$1"
local dst_dir="$2"
local file
local required_files=(
libbambu_networking.so
libBambuSource.so
pjarczak_bambu_linux_host
pjarczak_bambu_linux_host_abi1
pjarczak_bambu_linux_host_abi0
ca-certificates.crt
slicer_base64.cer
)
for file in "${required_files[@]}"; do
if [[ ! -f "$src_dir/$file" ]]; then
echo "missing required runtime payload file: $file" >&2
exit 1
fi
cp -f "$src_dir/$file" "$dst_dir/$file"
done
for file in liblive555.so libagora_rtc_sdk.so libagora-fdkaac.so; do
if [[ -f "$src_dir/$file" ]]; then
cp -f "$src_dir/$file" "$dst_dir/$file"
fi
done
chmod 755 "$dst_dir/pjarczak_bambu_linux_host" "$dst_dir/pjarczak_bambu_linux_host_abi1" "$dst_dir/pjarczak_bambu_linux_host_abi0"
}
INSTANCE="${PJARCZAK_MAC_LIMA_INSTANCE:-}"
if [[ -z "$INSTANCE" ]]; then
INSTANCE=$(trim_file "$PLUGIN_DIR/pjarczak_lima_instance.txt" || true)
@ -154,6 +189,7 @@ fi
ensure_lima_installed
maybe_install_rosetta
copy_runtime_payload "$PLUGIN_DIR" "$RUNTIME_DIR"
START_ARGS=(start "--name=${INSTANCE}" --mount-writable)
MACOS_MAJOR=$(sw_vers -productVersion | awk -F. '{print $1}')
@ -174,4 +210,5 @@ fi
"$LIMACTL" start-at-login "$INSTANCE" --enabled >/dev/null 2>&1 || true
"$LIMACTL" shell "$INSTANCE" -- /usr/bin/env true >/dev/null
printf 'runtime installed\n'
printf 'runtime installed
'

View file

@ -39,31 +39,37 @@ if [[ -z "$PLUGIN_DIR" ]]; then
exit 2
fi
APP_SUPPORT_DIR="$HOME/Library/Application Support/OrcaSlicer/macos-bridge"
RUNTIME_DIR="${PJARCZAK_MAC_RUNTIME_DIR:-$APP_SUPPORT_DIR/runtime}"
trim_file() {
local path="$1"
if [[ ! -f "$path" ]]; then
return 1
fi
LC_ALL=C tr -d '\r' < "$path" | head -n 1 | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'
LC_ALL=C tr -d ' ' < "$path" | head -n 1 | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'
}
find_limactl() {
if [[ -n "${PJARCZAK_LIMACTL:-}" && -x "${PJARCZAK_LIMACTL}" ]]; then
printf '%s\n' "$PJARCZAK_LIMACTL"
printf '%s
' "$PJARCZAK_LIMACTL"
return 0
fi
if command -v limactl >/dev/null 2>&1; then
command -v limactl
return 0
fi
local local_bin="$HOME/Library/Application Support/OrcaSlicer/macos-bridge/lima/bin/limactl"
local local_bin="$APP_SUPPORT_DIR/lima/bin/limactl"
if [[ -x "$local_bin" ]]; then
printf '%s\n' "$local_bin"
printf '%s
' "$local_bin"
return 0
fi
for candidate in /opt/homebrew/bin/limactl /usr/local/bin/limactl; do
if [[ -x "$candidate" ]]; then
printf '%s\n' "$candidate"
printf '%s
' "$candidate"
return 0
fi
done
@ -79,6 +85,27 @@ require_file() {
fi
}
compare_required_file() {
local src="$1"
local dst="$2"
local label="$3"
if [[ ! -f "$src" || ! -f "$dst" ]]; then
echo "runtime payload file missing: $label" >&2
exit 1
fi
if ! cmp -s "$src" "$dst"; then
echo "runtime payload out of date: $label" >&2
exit 1
fi
}
mkdir -p "$APP_SUPPORT_DIR"
require_file "$PLUGIN_DIR/install_runtime_macos.sh" "install_runtime_macos.sh"
require_file "$PLUGIN_DIR/verify_runtime_macos.sh" "verify_runtime_macos.sh"
require_file "$PLUGIN_DIR/pjarczak_lima_instance.txt" "pjarczak_lima_instance.txt"
require_file "$PLUGIN_DIR/pjarczak-bambu-linux-host-wrapper" "pjarczak-bambu-linux-host-wrapper"
if [[ "$ALLOW_MISSING_LINUX_PLUGIN" -eq 0 ]]; then
require_file "$PLUGIN_DIR/libbambu_networking.so" "libbambu_networking.so"
require_file "$PLUGIN_DIR/libBambuSource.so" "libBambuSource.so"
@ -86,13 +113,31 @@ fi
require_file "$PLUGIN_DIR/pjarczak_bambu_linux_host" "pjarczak_bambu_linux_host"
require_file "$PLUGIN_DIR/pjarczak_bambu_linux_host_abi1" "pjarczak_bambu_linux_host_abi1"
require_file "$PLUGIN_DIR/pjarczak_bambu_linux_host_abi0" "pjarczak_bambu_linux_host_abi0"
require_file "$PLUGIN_DIR/pjarczak-bambu-linux-host-wrapper" "pjarczak-bambu-linux-host-wrapper"
require_file "$PLUGIN_DIR/install_runtime_macos.sh" "install_runtime_macos.sh"
require_file "$PLUGIN_DIR/verify_runtime_macos.sh" "verify_runtime_macos.sh"
require_file "$PLUGIN_DIR/pjarczak_lima_instance.txt" "pjarczak_lima_instance.txt"
require_file "$PLUGIN_DIR/ca-certificates.crt" "ca-certificates.crt"
require_file "$PLUGIN_DIR/slicer_base64.cer" "slicer_base64.cer"
require_file "$RUNTIME_DIR/libbambu_networking.so" "runtime/libbambu_networking.so"
require_file "$RUNTIME_DIR/libBambuSource.so" "runtime/libBambuSource.so"
require_file "$RUNTIME_DIR/pjarczak_bambu_linux_host" "runtime/pjarczak_bambu_linux_host"
require_file "$RUNTIME_DIR/pjarczak_bambu_linux_host_abi1" "runtime/pjarczak_bambu_linux_host_abi1"
require_file "$RUNTIME_DIR/pjarczak_bambu_linux_host_abi0" "runtime/pjarczak_bambu_linux_host_abi0"
require_file "$RUNTIME_DIR/ca-certificates.crt" "runtime/ca-certificates.crt"
require_file "$RUNTIME_DIR/slicer_base64.cer" "runtime/slicer_base64.cer"
compare_required_file "$PLUGIN_DIR/libbambu_networking.so" "$RUNTIME_DIR/libbambu_networking.so" "libbambu_networking.so"
compare_required_file "$PLUGIN_DIR/libBambuSource.so" "$RUNTIME_DIR/libBambuSource.so" "libBambuSource.so"
compare_required_file "$PLUGIN_DIR/pjarczak_bambu_linux_host" "$RUNTIME_DIR/pjarczak_bambu_linux_host" "pjarczak_bambu_linux_host"
compare_required_file "$PLUGIN_DIR/pjarczak_bambu_linux_host_abi1" "$RUNTIME_DIR/pjarczak_bambu_linux_host_abi1" "pjarczak_bambu_linux_host_abi1"
compare_required_file "$PLUGIN_DIR/pjarczak_bambu_linux_host_abi0" "$RUNTIME_DIR/pjarczak_bambu_linux_host_abi0" "pjarczak_bambu_linux_host_abi0"
compare_required_file "$PLUGIN_DIR/ca-certificates.crt" "$RUNTIME_DIR/ca-certificates.crt" "ca-certificates.crt"
compare_required_file "$PLUGIN_DIR/slicer_base64.cer" "$RUNTIME_DIR/slicer_base64.cer" "slicer_base64.cer"
for optional_file in liblive555.so libagora_rtc_sdk.so libagora-fdkaac.so; do
if [[ -f "$PLUGIN_DIR/$optional_file" ]]; then
compare_required_file "$PLUGIN_DIR/$optional_file" "$RUNTIME_DIR/$optional_file" "$optional_file"
fi
done
LIMACTL=$(find_limactl || true)
if [[ -z "$LIMACTL" ]]; then
echo "limactl not found" >&2
@ -113,4 +158,5 @@ if ! "$LIMACTL" shell "$INSTANCE" -- /usr/bin/env true >/dev/null 2>&1; then
exit 1
fi
printf 'runtime ok\n'
printf 'runtime ok
'