Skip to content

Fix Windows natives: separate audio/GLFW DLLs + macos-x86_64 cross-link - #11

Closed
MateuszKubuszok wants to merge 54 commits into
masterfrom
fix/windows-natives-and-macos-x86
Closed

Fix Windows natives: separate audio/GLFW DLLs + macos-x86_64 cross-link#11
MateuszKubuszok wants to merge 54 commits into
masterfrom
fix/windows-natives-and-macos-x86

Conversation

@MateuszKubuszok

@MateuszKubuszok MateuszKubuszok commented Jun 23, 2026

Copy link
Copy Markdown
Member

Problem

The published pnm-provider-sge-desktop JAR was missing the Windows
sge_audio.dll / glfw3.dll. The old build merged the C libs into
sge_native_ops.dll on Windows-cross, but a Rust cdylib only re-exports
#[no_mangle] Rust symbols — the C audio/GLFW symbols were swallowed and
exported nowhere, and the extra C code destabilised the cdylib's load
(UnsatisfiedLinkError: sge_native_ops on the Windows JVM).

Changes

This branch also carries the prior macos-x86_64 -arch cross-link fix,
the ANGLE Windows naming fix, and the GLFW _GLFW_BUILD_DLL export
(commit 1fc9b2d). This commit completes the Windows audio/GLFW fix:

  • build.rs: drop the merge_into_cdylib path. Windows-cross now
    builds separate sge_audio.dll / glfw3.dll via the existing
    build_*_shared lld-link path, like every other platform.
    sge_native_ops.dll stays a clean Rust-only cdylib. Merged helpers are
    retained but #[allow(dead_code)].
  • build.rs: name the Windows GLFW DLL glfw3.dll (was glfw.dll)
    so the artifact-collection step and JVM loader pick it up — a latent
    mismatch that the merge path had been bypassing.
  • sge_audio_bridge.c: add SGE_AUDIO_API
    (__declspec(dllexport) on Windows, no-op elsewhere) on all 41 public
    sge_audio_* functions so sge_audio.dll actually exports them.
    Mirrors GLFW's _GLFW_BUILD_DLL.
  • ci.yml: assert the Windows DLLs are present in the desktop
    provider JAR — the verification gap that let the regression ship.

Verification

  • Host build: cargo build --release produces real
    libsge_audio.dylib (41 exported sge_audio_* symbols) +
    libglfw.dylib; sge_native_ops stays clean. clippy + rustfmt clean.
  • Windows cross-build validated by this PR's CI (cargo-xwin).

Builds SGE Rust native libraries and packages them as fat JARs
with native/<platform>/ layout for consumption via sbt-multi-arch-release
NativeLibBundlePlugin.

Five provider artifacts:
- scala-native-sge-ops-provider: sge_native_ops.a, sge_audio.a, glfw3.a,
freetype.a for Scala Native static linking (6 desktop platforms)
- panama-sge-ops-provider: .dylib/.so/.dll for JVM Panama FFM runtime
loading (6 desktop platforms)
- android-sge-ops-provider: .so for Android JNI (3 ABIs)
- scala-native-angle-provider: EGL + GLESv2 for Scala Native
- panama-angle-provider: EGL + GLESv2 for JVM Panama

Rust source from sge/sge-deps/native-components/ with vendored GLFW
and miniaudio (git submodules). Cross-compilation via cargo-zigbuild
(Linux), cargo-xwin (Windows), native cargo (macOS), NDK (Android).

CI validates JAR contents — fails fast if expected native files are
missing for any platform.
Rust workspace decomposition:
- Monolithic sge_native_ops crate → 3 independent crates:
  core/ → libsge_native_ops (ETC1, buffer_ops, audio, gdx2d)
  freetype/ → libsge_freetype (FreeType font rasterization)
  physics/ → libsge_physics (Rapier2D 2D physics)
- Removed dead JNI bridge (Android uses PanamaPort, not JNI)

Test coverage (0 → 88 tests):
- buffer_ops: 36 tests (copy, transforms, vertex find/compare)
- etc1: 22 tests (codec, PKM header, encode/decode roundtrip)
- gdx2d: 5 tests (PNG decode, invalid data, null safety)
- freetype: 5 tests (library lifecycle, stroker, null safety)
- physics: 10 tests (world lifecycle, gravity sim, raycast, body ops)

Provider JARs restructured (5 → 11):
- Renamed *-sge-ops-* → *-sge-core-* (no more freetype in core)
- Added: scala-native/panama/android providers for freetype + physics
- Windows companion .lib stubs embedded in core provider
- Linux libobjc.a stub embedded in core provider
- Updated cross-all.sh and cross-android.sh for workspace builds
- CI validates all 11 provider JARs
…ertia, AABB queries (ISS-457)

- Collision filtering: set/get collision_groups and solver_groups for colliders
- Revolute joint: enable_limits, set/get_limits, is_limit_enabled, enable_motor, set/get_motor_speed, set_max_motor_torque, get_angle
- Prismatic joint: enable_limits, set/get_limits, enable_motor, set/get_motor_speed, set_max_motor_force, get_translation
- Body mass properties: get_mass, get_inertia, get_local_center_of_mass, recompute_mass_properties
- AABB queries: query_aabb returns collider handles within bounding box
- Rename all 11 provider directories and artifacts to follow
  sn-provider-*/pnm-provider-* naming convention
- Consolidate ops providers: sn-provider-sge, pnm-provider-sge-desktop,
  pnm-provider-sge-android (was scala-native-sge-ops, panama-sge-ops,
  android-sge-ops)
- sn-provider-sge and pnm-provider-sge-desktop depend transitively on
  their respective angle providers
- Replace native-bundle.json with sn-provider.json (new format with
  binary field, flags-groups, provider-schema-version)
- Add pnm-provider.json manifests for all Panama providers (desktop
  and android) — previously had no manifests
- Use multiarch-core Platform model in build.sbt instead of hand-written
  platform strings
- Add SNAPSHOT publishing from PR builds
- Update CI JAR verification and README
…imesh, heightfield, joint getters, spring joint, shape cast, ray cast all, point projection, solver params
…, collider getters, trimesh, heightfield, spring joint, shape cast, solver params)
- Add sn-provider-sge-physics3d, pnm-provider-sge-physics3d-desktop,
  pnm-provider-sge-physics3d-android provider projects to build.sbt
- Add sge_phys_intersect_shape FFI function for shape overlap queries
Add 92 new C ABI functions covering:
- Body: torque impulse, reset forces/torques, type query, per-axis
  translation/rotation locking, world/local COM, inertia, velocity at point
- Collider: all property getters, enable/disable, position (world + relative),
  shape type, AABB, parent body, mass, contact skin, active events,
  collision types, collision/solver groups
- Shapes: heightfield (3D grid)
- Joints: revolute (3D axis+anchor), prismatic (3D axis), motor (6-DOF),
  spring — all with limits, motors, and getters
- Queries: AABB, point, ray cast all, project point, cast shape, intersect shape
- Contact detail queries (7 floats per 3D contact point)
- Intersection events, solver parameters
…D + 3D)

- Buffer ContactForceEvent during step, add poll_contact_force_events FFI
- Add collider contact_force_event_threshold get/set
- Implement SgePhysicsHooks with one-way platform support via
  Rapier's update_as_oneway_platform helper
- Add collider active_hooks flags and set/get_one_way_direction FFI
- All existing tests pass (16 in 2D, 5 in 3D)
The @link("objc") annotation on ObjCRuntime in SGE core causes the
Scala Native linker to require objc.lib on Windows. Linux already had
a libobjc.a stub; Windows was missing the equivalent. On macOS the
system libobjc is used directly.

Generate objc.lib stubs for windows-x86_64 and windows-aarch64 using
zig cc (same approach as the Linux stubs), include them in the
sn-provider-sge JAR, and verify their presence in CI.
Three bugs in Windows ANGLE packaging:

1. build.sbt: allow set had "GLESv2.dll" but archive contains
   "libGLESv2.dll" (lib prefix) — DLL was silently excluded from JAR

2. download-angle.sh: never copied .dll.lib import libraries from the
   ANGLE archive. Windows MSVC linker needs these to resolve GL symbols.
   Now copies libEGL.dll.lib → EGL.lib, libGLESv2.dll.lib → GLESv2.lib

3. EGL.lib and GLESv2.lib were in sn-provider-sge core JAR as Rust
   companion stubs (no GL symbols), masking the missing ANGLE imports.
   Moved to sn-provider-sge-angle where they belong.

Without this fix, Scala Native linking on Windows fails with
"unresolved external symbol glCullFace" etc. because the linker
finds the empty Rust companion stub instead of the ANGLE import lib.
GLFW on Windows needs gdi32, shell32, user32 (DragAcceptFiles,
CreateDIBSection, ChoosePixelFormat etc. from Win32 API). miniaudio
needs ole32 and winmm. These are auto-linked by MSVC but Scala Native
uses clang++ which requires explicit -l flags.

Without this, Scala Native linking on Windows fails with 17 unresolved
externals from GLFW's win32_window.o and win32_monitor.o.
Documents licenses for GLFW (zlib), miniaudio (Unlicense/MIT-0),
ANGLE (BSD-3), and Rust crate dependencies linked at build time.
Configure [workspace.lints.clippy] to establish a sensible lint
policy for this FFI-heavy C ABI codebase:

- Allow missing_safety_doc, too_many_arguments, unnecessary_cast
  (inherent to C ABI libraries with no Rust callers)
- Allow pedantic cast lints that are pure noise for FFI code
  (cast_sign_loss, cast_possible_truncation, ptr_cast_constness, etc.)
- Enable useful pedantic lints as warnings
  (manual_range_contains, needless_pass_by_value, redundant_closure)

All 4 member crates opt in via [lints] workspace = true.
- build.rs: remove needless borrows on format!() and array literals
- etc1.rs: use RangeInclusive::contains and iterator enumerate
- physics3d: remove useless .into() conversions (Vec3 -> Vec3),
  simplify convex_hull call, replace index loops with slice::fill
Add rustfmt.toml (edition 2021) and apply cargo fmt --all to
normalize all source files to standard Rust formatting.
Add a new 'lint' job that runs in parallel with build-and-package.
Runs cargo clippy --workspace -- -D warnings and cargo fmt --check
to catch regressions before the full cross-compilation build.
MateuszKubuszok and others added 24 commits May 17, 2026 13:28
- Bump sbt-kubuszok from 0.1.0 to 0.2.0
- Add mimaSettings (mimaPreviousArtifacts, mimaFailOnNoPrevious,
  packageDoc/publishArtifact := false) to all modules
- Move packageDoc setting from ThisBuild into mimaSettings
- Sort provider modules alphabetically within each category
- Sort root project aggregation alphabetically by category
- Use .settings(publishSettings) without splat (consistent with sge)
- Add noPublishSettings + mimaSettings to root project
- project/plugins.sbt: multiarch-core 0.1.2 -> 0.3.0, sbt-kubuszok 0.2.0 -> 0.2.3
- project/build.properties: sbt.version 1.12.11 -> 2.0.0
- build.sbt: packageBin mappings are now keyed by xsbti.HashedVirtualFileRef
  in sbt 2.0; convert each native File via fileConverter.toVirtualFile
- build.sbt: drop sbt-welcome usage (logo/usefulTasks); the plugin is no
  longer bundled by sbt-kubuszok 0.2.3 on sbt 2.0

Resource-only build; packageBin verified to still emit native/<classifier>/<file>
mappings intact.
sbt 2.0 writes packageBin output to target/out/jvm/u/<name>/<name>-<ver>.jar
at the build root, not providers/<name>/target/*.jar as in sbt 1.x. The
verify step's hardcoded sbt-1.x globs found nothing and failed.

Replace each 'ls providers/<name>/target/*.jar' with a layout-robust
'find target/out/jvm/u/<name>' lookup that excludes sources/javadoc jars.
Native build paths (native-components/target/cross/...) are unchanged.
Two native-provider packaging defects surfaced by sge's
sgeValidateNativeLibs gate (ISS-484) and Windows JVM tests:

1. ANGLE Windows DLL naming. SGE/multiarch load ANGLE by the logical
   names "EGL"/"GLESv2", which NativeLibLoader maps to EGL.dll/GLESv2.dll
   on Windows (no "lib" prefix, unlike System.mapLibraryName on
   macOS/Linux). The upstream archives ship libEGL.dll/libGLESv2.dll, and
   the pnm-provider packaged/promised those prefixed names — so the JVM
   could never resolve them at runtime and the gate reported
   GLESv2.dll absent. download-angle.sh now stages both names side by side
   (libEGL.dll/libGLESv2.dll for the sn-provider, EGL.dll/GLESv2.dll for
   the pnm-provider); the pnm-angle manifest + packaging now reference the
   unprefixed Windows names.

2. macos-x86_64 audio/glfw 16 KB stubs. build_audio_bridge_shared and
   build_glfw_shared invoked the cc compiler for the final dylib link
   without carrying cc_tool.args() — dropping the -arch x86_64 flag on
   cross builds. Linking x86_64 objects with the host (arm64) default
   produced non-functional ~16 KB stub dylibs. The link step now forwards
   the compiler's own args so it targets the same arch as the archive.

3. Windows glfw export. Defined _GLFW_BUILD_DLL on the Windows shared-DLL
   path so GLFWAPI resolves to __declspec(dllexport); MSVC/lld-link export
   nothing by default, so without it glfw3.dll exposes no glfw* symbols.

Note: the Windows audio bridge (sge_audio_*) still needs an export
mechanism, and the merge-into-sge_native_ops.dll strategy on Windows
should be revisited — see report. These are not verifiable without a
Windows cross-compile and are left for CI.
The published pnm-provider-sge-desktop JAR was missing the Windows
sge_audio.dll / glfw3.dll, and merging the C libs into sge_native_ops.dll
destabilised that cdylib's load (UnsatisfiedLinkError: sge_native_ops on
the Windows JVM).

A Rust cdylib only re-exports #[no_mangle] Rust symbols, so audio/GLFW
objects linked into sge_native_ops.dll were swallowed and exported
nowhere. Fix by building separate DLLs on Windows-cross like every other
platform, and exporting the C symbols those DLLs need:

- build.rs: drop the merge_into_cdylib path (Windows-cross now uses the
  existing build_audio_bridge_shared / build_glfw_shared lld-link path).
  Keep sge_native_ops a clean Rust-only cdylib. The merged helpers are
  retained but #[allow(dead_code)].
- build.rs: name the Windows GLFW DLL glfw3.dll (was glfw.dll) so the
  artifact-collection step and JVM loader actually pick it up. This
  mismatch was latent while the merge path bypassed build_glfw_shared.
- sge_audio_bridge.c: add SGE_AUDIO_API (__declspec(dllexport) on Windows,
  no-op elsewhere) and apply it to all 41 public sge_audio_* functions so
  sge_audio.dll exports them — mirrors GLFW's _GLFW_BUILD_DLL fix.
- ci.yml: assert the Windows DLLs (sge_native_ops.dll, sge_audio.dll,
  glfw3.dll) are present in the desktop provider JAR — the gap that let
  the missing-DLL regression ship undetected.

Host build re-confirmed: real libsge_audio.dylib (41 exports) +
libglfw.dylib produced; clippy + rustfmt clean.
CI's first run linked windows-x86_64 fine but failed windows-aarch64 with
lld-link: undefined symbol: _initterm (EC symbol) (and the rest of the CRT
startup/onexit family, all "EC symbol"). /machine:arm64x produces a hybrid
ARM64X image that additionally requires the ARM64EC-flavoured CRT, but the
xwin crt/ucrt/vcruntime import libs we pass are the pure-ARM64 set, so the
EC symbols were left undefined.

We want a plain ARM64 DLL: switch both lld-link sites (sge_audio.dll and
glfw3.dll) to /machine:arm64. The libpaths already point at the arm64 import
libs, so this is now consistent.

This path was never exercised before because Windows-cross used to merge the
C libs into sge_native_ops.dll instead of building separate DLLs.
After switching windows-aarch64 to /machine:arm64, the link still crashed:
lld::coff::ImportFile::parse() SIGSEGV while parsing the ARM64 Windows SDK
import libs. The crash backtrace showed rust-lld (rustup's bundled lld) was
used — the lld_link_command() helper only probed /opt/homebrew/opt/lld/bin/lld,
which doesn't exist on the CI runner, so it fell back to `lld-link` on PATH,
which resolved to the older, crashing rust-lld.

Probe the real LLVM lld-link from Homebrew's `llvm`/`lld` formulae explicitly
(/opt/homebrew/opt/llvm/bin/lld-link first — that's what CI's `brew install
llvm` provides and adds to PATH), covering both Apple-silicon and Intel
prefixes, and only fall back to PATH `lld-link` last. The newer lld parses the
arm64 import libs without crashing.
Iteration 3 still crashed in rust-lld: the explicit /opt/homebrew/opt/llvm/bin
probe didn't match on the runner and build.rs fell back to PATH `lld-link`,
which resolves to rustup's rust-lld (it crashes on the ARM64 import libs).

Make it deterministic:
- CI/release: resolve the LLVM prefix with `brew --prefix llvm`, ls the
  lld-link to fail loudly if absent, and export SGE_LLD_LINK to its absolute
  path.
- build.rs: honor SGE_LLD_LINK first; also scan versioned llvm@N kegs under
  both Homebrew Cellars as extra fallbacks before the last-resort PATH lookup.
Iteration 4 failed at the install step: ls /opt/homebrew/opt/llvm/bin/lld-link
"No such file or directory". Homebrew's `llvm` formula does not include the lld
driver/symlinks; lld-link comes from the separate `lld` formula.

Install both `llvm` and `lld`, add each prefix to PATH, and point SGE_LLD_LINK
at `$(brew --prefix lld)/bin/lld-link`. build.rs already lists that path among
its candidates and honors SGE_LLD_LINK first.
With the real Homebrew lld-link, windows-x86_64 links cleanly, but
windows-aarch64 now fails: "kernel32.lib(KERNEL32.dll): machine type arm64ec
conflicts with arm64". cargo-xwin's arm64 Windows SDK import libs are
ARM64EC-flavoured, so forcing /machine:arm64 conflicts.

Build a hybrid ARM64X image instead (both lld-link sites): ARM64X accepts our
arm64 object archive plus the arm64ec imports and is loadable by native ARM64
Windows processes. The earlier arm64x EC-symbol failure was rust-lld-specific;
the real lld resolves the EC CRT from the same libs.

Also add a CI diagnostic dumping the xwin arm64 lib layout / kernel32.lib
machine type for ground truth if this needs further tuning.
ARM64X with bare lld-link still left the DLL CRT startup undefined
(_initterm / _onexit / terminate "EC symbol"s): those objects are pulled by
the CRT-entry logic that clang-cl's /LD adds, which a raw lld-link invocation
does not.

Replace both Windows-cross link blocks (sge_audio.dll, glfw3.dll) with a
clang-cl /LD link driven by the xwin-wrapped compiler `cc` returns. clang-cl
selects the correct target machine from its baked-in --target=<triple> and
links the DLL CRT startup — including the ARM64EC CRT — so we no longer
hand-pick /machine or the SDK libpaths. Whole-archive + extra system import
libs are passed after -link.

lld_link_command() is retained (#[allow(dead_code)]) for reference.
…build

The clang-cl /LD approach failed even for windows-x86_64 ("no input files",
and it would not inherit cargo-xwin's winsysroot anyway — xwin wraps the
linker, not the cc-crate compiler args). Restore the lld-link path that DID
link windows-x86_64 successfully and reached the arm64 EC-CRT stage.

The earlier diagnostic ran BEFORE the first cargo-xwin build, so the xwin SDK
cache was still empty (blank ls). Move it after the build with if: always()
and dump the real dir tree + per-arch kernel32.lib machine type, so the next
iteration has ground truth on whether a pure-arm64 (non-EC) SDK lib variant
exists for the windows-aarch64 link.
The post-build diagnostic revealed the cargo-xwin SDK cache layout:
  - per-arch lib dirs are named aarch64 / x86_64 (NOT arm64) — our libpaths
    pointed at a nonexistent .../arm64 dir, so they were silent no-ops and lld
    only found libs via xwin's injected LIB env (the arm64ec set).
  - the aarch64 SDK import libs are ARM64EC-flavoured.

Factor both Windows-cross links into windows_cross_lld_link() and fix all three:
  - arch dir -> aarch64 / x86_64 (matches the cache).
  - /machine:arm64ec for aarch64 (matches the arm64ec import libs; /machine:arm64
    conflicted, /machine:arm64x left the EC CRT unresolved). arm64ec is
    x64-ABI-compatible and loadable in ARM64 Windows processes.
  - add msvcrt.lib so the DLL CRT startup (_initterm/_onexit/terminate/...)
    resolves — those were the undefined "EC symbol"s.

windows-x86_64 keeps /machine:x64 + x86_64 dirs (unchanged, already linked OK).
Hand-picking lld-link CRT libs hit a dead end: x64 linked with
kernel32/ucrt/vcruntime, but the aarch64 (arm64ec) image then left the DLL CRT
startup _initterm/_onexit undefined, and adding msvcrt.lib pulled in unresolved
dllimport CRT data (__argc/_commode/_daylight/...), breaking x64 too.

Drive the DLL link through clang-cl /LD (the xwin-wrapped compiler), which
selects the target machine and links the full DLL CRT itself. The static archive
is passed as a positional input (so clang-cl has an input file — the prior
"no input files" failure) and re-listed under /wholearchive: so every
sge_audio_*/glfw* export survives. cc carries clang-cl's --target/winsysroot.

Emit the resolved link command as a cargo:warning for diagnosability.
The diagnostic showed the clang-cl invocation was correct (target, imsvc
includes, /LD, /Fe, -link, /wholearchive) yet still "no input files":
clang-cl's driver only recognises .lib/.obj as linker inputs and silently
ignores a Unix .a archive.

Copy the built lib<name>.a to <name>.lib and pass that as both the positional
input and the /wholearchive target.
The .lib alone still produced "no input files": clang-cl /LD is a
compile-and-link mode and needs a translation unit, not just libraries.

Write a trivial <stem>_dllmain.c (one anchor symbol) as the compile input,
keep the archive copied to .lib and whole-archived. clang-cl compiles the dummy
and links our exports + the full DLL CRT it pulls in for the target — fixing the
arm64ec EC-CRT problem without hand-picking CRT libs.
clang-cl parses any arg starting with '/' as an MSVC option, so the
absolute /Users/.../dllmain.c was read as the /U option and the driver
reported 'no input files'. Run clang-cl with the dummy source's directory
as cwd and pass just the bare filename; the .c extension makes it a
compile input. /LD, /Fe:, /link and /wholearchive: stay absolute.
…externals)

The Windows desktop provider built glfw3.dll but shipped no real import
library for it: scripts/cross-all.sh fabricated glfw3.lib by COPYING
sge_native_ops.lib (a stub with the wrong exports). So Scala Native's
@link("glfw3") link on Windows failed with LNK2019 unresolved external
symbol glfwInit (etc.) -> LNK1120 48 unresolved externals (sge
Native FFI IT windows-x86_64).

- build.rs (windows_cross_lld_link): pass /implib:<release_dir>/glfw3.dll.lib
  to the clang-cl /LD link so lld-link emits a genuine import library with
  the real GLFW exports, next to glfw3.dll (mirrors cargo's
  sge_native_ops.dll.lib).
- cross-all.sh: collect glfw3.dll.lib and rename to glfw3.lib (the name
  @link("glfw3") resolves on Windows); drop glfw3/glfw from the bogus
  companion-stub list so the stub can no longer shadow the real lib.

build.sbt sn-provider-sge mapping already globs glfw3.lib and CI verify_jar
already asserts native/<win>/glfw3.lib, so packaging is unchanged.
…IT link)

The glfw3.lib fix dropped the Windows Native FFI IT link errors 48 -> 27,
revealing two more import-lib gaps of the same kind:

1. sge_audio: AudioOpsNative's @link("sge_audio") had 25 LNK2019
   unresolved (sge_audio_play_sound, ...). build_audio_bridge_shared links
   sge_audio.dll via windows_cross_lld_link, which already emits
   sge_audio.dll.lib now (the /implib: added for glfw applies to it too) —
   but cross-all.sh still fabricated sge_audio.lib as a sge_native_ops.lib
   stub. Collect sge_audio.dll.lib -> sge_audio.lib and drop sge_audio from
   the bogus-stub list (mirrors the glfw3 fix). Already in the
   sn-provider-sge JAR mapping + verify_jar.

2. glfw_platform_stubs.c: glfwGetCocoaWindow / glfwGetX11Window are
   referenced by WindowingOpsNative.getNativeWindowHandle on every platform
   (Scala Native needs every @extern resolvable), but on Windows the stubs
   were compiled into glfw3.dll WITHOUT being exported, so glfw3.lib lacked
   them -> 2 LNK2019. Export the stubs from the DLL via __declspec(dllexport)
   under _GLFW_BUILD_DLL (mirrors GLFW's own GLFWAPI). Empty on ELF/Mach-O,
   which already export globals by default.
…der-sge

With the real import libs in place the Windows Native FFI IT now LINKS,
but the binary exits 0xC0000135 STATUS_DLL_NOT_FOUND at startup: on Windows
sge_native_ops/sge_audio/glfw3 are linked via import libraries that
reference the matching DLLs, so those DLLs must be present at run time. The
multiarch NativeProviderPlugin copies every .dll it extracts next to the
linked executable (no rpath on Windows) — but the sn-provider-sge mapping
shipped only the .lib/.a link artifacts, so the runtime DLLs were never
extracted/copied (only the ANGLE provider's EGL.dll/GLESv2.dll were).

Add sge_native_ops.dll / sge_audio.dll / glfw3.dll to the sn-provider-sge
mapping (they already exist in the windows-* cross dirs via cross-all.sh;
no-op for linux/macos). Now the plugin copies them next to the exe and the
FFI validation binary starts.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant