|
| 1 | +#!/usr/bin/env python3 |
| 2 | +import os |
| 3 | +import subprocess |
| 4 | +import shutil |
| 5 | +import sys |
| 6 | +from pathlib import Path |
| 7 | + |
| 8 | +print("=== Building Rust FFI Libraries for All Platforms ===") |
| 9 | + |
| 10 | +# Get the directory where this script is located |
| 11 | +SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__)) |
| 12 | +os.chdir(SCRIPT_DIR) |
| 13 | + |
| 14 | +# Projects to build: (relative path, crate name, base lib name without prefixes) |
| 15 | +CRATES = [ |
| 16 | + ("optimizationsandtweaks_pathfinding", "optimizationsandtweaks_pathfinding"), |
| 17 | + ("optimizationsandtweaks_blocksupdates", "optimizationsandtweaks_blocksupdates"), |
| 18 | + ("optimizationsandtweaks_shared", "optimizationsandtweaks_shared"), |
| 19 | +] |
| 20 | + |
| 21 | +# Destination base directory (relative to repo root, where this script sits) |
| 22 | +DEST_BASE = os.path.abspath("src/main/resources/assets/optimizationsandtweaks/natives") |
| 23 | + |
| 24 | +# Setup osxcross PATH if available |
| 25 | +OSXCROSS_PATH = os.path.expanduser("~/osxcross/target/bin") |
| 26 | +if os.path.isdir(OSXCROSS_PATH): |
| 27 | + os.environ["PATH"] = f"{OSXCROSS_PATH}:{os.environ.get('PATH', '')}" |
| 28 | + print(f"\u2713 osxcross found at {OSXCROSS_PATH}") |
| 29 | + |
| 30 | + |
| 31 | +def run(cmd, check=True, cwd=None): |
| 32 | + print(f"$ {' '.join(cmd)}") |
| 33 | + subprocess.run(cmd, check=check, cwd=cwd) |
| 34 | + |
| 35 | + |
| 36 | +def check_target(target): |
| 37 | + result = subprocess.run(["rustup", "target", "list"], capture_output=True, text=True) |
| 38 | + if f"{target} (installed)" not in result.stdout: |
| 39 | + print(f"Installing target {target}...") |
| 40 | + run(["rustup", "target", "add", target]) |
| 41 | + |
| 42 | + |
| 43 | +def ensure_dirs(): |
| 44 | + for os_dir in ("linux", "windows", "macos"): |
| 45 | + d = os.path.join(DEST_BASE, os_dir) |
| 46 | + os.makedirs(d, exist_ok=True) |
| 47 | + |
| 48 | + |
| 49 | +def build_crate_for_target(crate_dir, crate_name, target, os_dir, lib_base): |
| 50 | + print(f"\n=== Building {crate_name} for {target} ===") |
| 51 | + run(["cargo", "build", "--release", "--target", target], cwd=crate_dir) |
| 52 | + |
| 53 | + dest_dir = os.path.join(DEST_BASE, os_dir) |
| 54 | + os.makedirs(dest_dir, exist_ok=True) |
| 55 | + |
| 56 | + # Expected filenames per platform |
| 57 | + if os_dir == "windows": |
| 58 | + lib_name = f"{lib_base}.dll" |
| 59 | + src_path = os.path.join(crate_dir, "target", target, "release", lib_name) |
| 60 | + elif os_dir == "macos": |
| 61 | + lib_name = f"lib{lib_base}.dylib" |
| 62 | + src_path = os.path.join(crate_dir, "target", target, "release", lib_name) |
| 63 | + else: # linux |
| 64 | + lib_name = f"lib{lib_base}.so" |
| 65 | + src_path = os.path.join(crate_dir, "target", target, "release", lib_name) |
| 66 | + |
| 67 | + if not os.path.isfile(src_path): |
| 68 | + print(f"\u2717 Warning: Library not found at {src_path}") |
| 69 | + return None |
| 70 | + |
| 71 | + dest_path = os.path.join(dest_dir, lib_name) |
| 72 | + shutil.copy2(src_path, dest_path) |
| 73 | + print(f"\u2713 Copied {lib_name} to {dest_path}") |
| 74 | + return dest_path |
| 75 | + |
| 76 | + |
| 77 | +# Prepare |
| 78 | +ensure_dirs() |
| 79 | + |
| 80 | +# Linux x86_64 |
| 81 | +check_target("x86_64-unknown-linux-gnu") |
| 82 | +for crate_rel, crate_name in CRATES: |
| 83 | + crate_dir = os.path.join(SCRIPT_DIR, crate_rel) |
| 84 | + build_crate_for_target(crate_dir, crate_name, "x86_64-unknown-linux-gnu", "linux", crate_name) |
| 85 | + |
| 86 | +# Windows x86_64 |
| 87 | +check_target("x86_64-pc-windows-gnu") |
| 88 | +if shutil.which("x86_64-w64-mingw32-gcc"): |
| 89 | + for crate_rel, crate_name in CRATES: |
| 90 | + crate_dir = os.path.join(SCRIPT_DIR, crate_rel) |
| 91 | + build_crate_for_target(crate_dir, crate_name, "x86_64-pc-windows-gnu", "windows", crate_name) |
| 92 | +else: |
| 93 | + print("\u26a0 Warning: MinGW-w64 not found. Skipping Windows build.\n Install with: sudo apt-get install mingw-w64") |
| 94 | + |
| 95 | +# macOS - Build both architectures and create universal binaries per crate |
| 96 | +macos_x86_ok = shutil.which("x86_64-apple-darwin23.5-clang") is not None or sys.platform == "darwin" |
| 97 | +macos_arm_ok = shutil.which("aarch64-apple-darwin23.5-clang") is not None or sys.platform == "darwin" |
| 98 | + |
| 99 | +if macos_x86_ok: |
| 100 | + check_target("x86_64-apple-darwin") |
| 101 | +if macos_arm_ok: |
| 102 | + check_target("aarch64-apple-darwin") |
| 103 | + |
| 104 | +for crate_rel, crate_name in CRATES: |
| 105 | + crate_dir = os.path.join(SCRIPT_DIR, crate_rel) |
| 106 | + x86_lib = None |
| 107 | + arm_lib = None |
| 108 | + |
| 109 | + if macos_x86_ok: |
| 110 | + run(["cargo", "build", "--release", "--target", "x86_64-apple-darwin"], cwd=crate_dir) |
| 111 | + x86_lib = os.path.join(crate_dir, "target", "x86_64-apple-darwin", "release", f"lib{crate_name}.dylib") |
| 112 | + if not os.path.isfile(x86_lib): |
| 113 | + print(f"\u26a0 Warning: macOS x86_64 lib missing for {crate_name}: {x86_lib}") |
| 114 | + x86_lib = None |
| 115 | + |
| 116 | + if macos_arm_ok: |
| 117 | + run(["cargo", "build", "--release", "--target", "aarch64-apple-darwin"], cwd=crate_dir) |
| 118 | + arm_lib = os.path.join(crate_dir, "target", "aarch64-apple-darwin", "release", f"lib{crate_name}.dylib") |
| 119 | + if not os.path.isfile(arm_lib): |
| 120 | + print(f"\u26a0 Warning: macOS ARM64 lib missing for {crate_name}: {arm_lib}") |
| 121 | + arm_lib = None |
| 122 | + |
| 123 | + dest_dir = os.path.join(DEST_BASE, "macos") |
| 124 | + os.makedirs(dest_dir, exist_ok=True) |
| 125 | + universal_lib = os.path.join(dest_dir, f"lib{crate_name}.dylib") |
| 126 | + |
| 127 | + if x86_lib and arm_lib: |
| 128 | + print(f"\n=== Creating macOS Universal Binary for {crate_name} ===") |
| 129 | + if shutil.which("lipo"): |
| 130 | + run(["lipo", "-create", "-output", universal_lib, x86_lib, arm_lib]) |
| 131 | + print(f"\u2713 Created universal binary at {universal_lib}") |
| 132 | + else: |
| 133 | + print("\u26a0 Warning: 'lipo' not found. Copying ARM64 version only.") |
| 134 | + shutil.copy2(arm_lib, universal_lib) |
| 135 | + print(f"\u2713 Copied ARM64 library to {universal_lib}") |
| 136 | + elif x86_lib: |
| 137 | + shutil.copy2(x86_lib, universal_lib) |
| 138 | + print(f"\u2713 Copied x86_64 library to {universal_lib}") |
| 139 | + elif arm_lib: |
| 140 | + shutil.copy2(arm_lib, universal_lib) |
| 141 | + print(f"\u2713 Copied ARM64 library to {universal_lib}") |
| 142 | + |
| 143 | +print("\n=== Build Complete ===") |
| 144 | +print(f"Native libraries have been copied to:\n {DEST_BASE}/linux/\n {DEST_BASE}/windows/\n {DEST_BASE}/macos/") |
0 commit comments