Skip to content

FFI symbols emitted as undefined values in caller IR (compile fails for any importer) #1

@proggeramlug

Description

@proggeramlug

@perryts/storekit FFI symbols emitted as undefined values in caller IR

Severity: blocker — prevents any app importing @perryts/storekit from compiling.
Perry version: 0.5.782 (also seen on 0.5.783).
Package version: @perryts/storekit@0.1.1.

What happens

perry compile against any TS module that imports symbols from @perryts/storekit fails during LLVM IR generation:

Error compiling module 'app/src/lib/payments.ts' with --backend llvm: clang -c failed.
.../perry_llvm_*.ll:5360:23: error: use of undefined value '@js_storekit_get_jws'
   %r144 = call double @js_storekit_get_jws()
                       ^
1 error generated.
⚠ 1 module(s) failed to compile — linking with empty stubs

The error happens at IR validation — Perry's IR generator emits call double @js_storekit_get_jws() but never emits the matching declare external directive for the symbol. Linking can't recover because the calling module is then stubbed out (empty _perry_init_*), which cascades into every public function in the caller (purchasePlan, restorePurchases, setOnSubscriptionChange, …) being unresolved.

What works

Verbose output (perry compile -vv) shows Perry does see and build the package:

Native library: @perryts/storekit (6 FFI functions)
[0] app/node_modules/@perryts/storekit/src/index.ts
...
Building native library: @perryts/storekit ...
Linking native library: .../node_modules/@perryts/storekit/crate-ios/target/release/libperry_storekit.a

So the manifest is parsed, the crate gets built (via cargo build --release), and the static lib is staged for linking. The bug is specifically in IR generation for callers of the library.

What we suspect

Local file: dependencies that follow the older manifest format work fine. For example, the same app imports from perry-searchbird-apple-auth (no abiVersion field, unscoped name) and the FFI declarations are emitted correctly. The differences vs @perryts/storekit:

  • Scoped npm name (@perryts/... vs unscoped perry-searchbird-...)
  • Has perry.nativeLibrary.abiVersion: "0.5" in package.json (the manifest-v1 spec docs/native-libraries/manifest-v1.md)

We didn't isolate which difference triggers the bug, but we'd guess one of:

  1. The IR-gen lookup keys symbols by the package directory name and chokes on the @scope/name path component.
  2. The manifest-v1 code path skips the FFI declaration emission step that the legacy path runs.

Repro

mkdir repro && cd repro && npm init -y
npm install @perryts/storekit
cat > main.ts <<'EOF'
import { js_storekit_start_listener } from "@perryts/storekit";
js_storekit_start_listener();
EOF
perry compile main.ts

Expected: links cleanly.
Actual: error: use of undefined value '@js_storekit_start_listener'.

Workaround

Revert to a pre-built local fork of storekit (unscoped name, no abiVersion in manifest). Painful for downstream apps, especially since the official package was meant to close #537.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions