ashvardanian / ashvardanian/NumKong
SwiftPM: header-only CNumKong target breaks transitive linking in Xcode 16+
- Dominant language
- C
- Stars
- 1.9k
- Forks
- 130
- Avg merge
- 18h 28m
- Merged PRs (30d)
- 3
Description
## Problem
`CNumKong` is declared as a regular SwiftPM target with `path: "include"` and no `.c` sources — i.e. header-only:
```swift
.target(
name: "CNumKong",
path: "include",
publicHeadersPath: ".",
cSettings: [...]
)
```
This is technically a valid SwiftPM declaration and `swift build` succeeds in isolation. But when `CNumKong` is pulled **transitively** (e.g. via `CNumKongDispatch` from USearch into an iOS/macOS app target), the link step fails:
```
error: missing required object file: CNumKong.o
```
This is the long-standing SwiftPM bug [swiftlang/swift-package-manager#5706](https://github.com/swiftlang/swift-package-manager/issues/5706) — open since October 2022. PR [#6006](https://github.com/swiftlang/swift-package-manager/pull/6006) partially addressed it on the CLI side, but Xcode 16+ still trips on transitive linking.
## Why this hits NumKong specifically
NumKong's actual implementation (`c/numkong.c`, `c/dispatch_*.c`) lives in `CNumKongDispatch`, not in `CNumKong`. The current `CNumKong` target is purely a **module facade** — it exposes headers and the existing `include/module.modulemap` (with the `CNumKongCore` / `CNumKongKernels` / `CNumKongCapabilities` / `CNumKong` umbrella hierarchy), but has no compilable code. So `CNumKong` is structurally header-only by design — which is exactly what trips the SwiftPM bug.
## Reproduction
USearch declares `.package(url: "https://github.com/ashvardanian/NumKong", from: "7.5.0")` and depends on the `CNumKongDispatch` product. Any iOS/macOS app pulling USearch via SwiftPM in Xcode 16+ fails at link time on the missing `CNumKong.o`.
## Two viable approaches
### Merge `CNumKong` into `CNumKongDispatch`
One C target with `path: "c"` + `publicHeadersPath: "../include"` (or move headers into `c/include/`). Matches your previous comment «CNumKong should be the shared library with runtime dynamic dispatch baked in» literally.
- ✅ Structurally cleanest; aligns with stated intent; eliminates the «module facade vs implementation» split.
- ⚠️ Larger structural change; affects paths referenced by CMake / `build.rs` / `setup.py`.
### Substantive shim source in `CNumKong` (this PR)
A single new C file (`include/cnumkong_module.c`) with one real exported symbol and an explanatory comment. Same pattern as [`apple/swift-system`'s `Sources/CSystem/shims.c`](https://github.com/apple/swift-system/blob/main/Sources/CSystem/shims.c).
- ✅ Smallest diff — one new file, no paths changed, no other build systems touched.
- ⚠️ One synthetic file in `include/`.
## Question
Sending a PR for the **shim approach** in #354 as the smallest viable change. Functionally equivalent to swift-system's shim. Happy to rebase as the merge approach if you'd prefer the structural fix.
For context: my earlier PR #352 used `_dummy.c`, which you correctly rejected as ad-hoc. The new PR uses a real exported symbol (`nk_cnumkong_module_loaded`) with an explanatory comment — same shape as swift-system's shim.
Contributor guide
Research direction
Start with the CNumKong target declaration and include/module.modulemap, then compare its header-only layout with CNumKongDispatch and the shim pattern referenced from apple/swift-system. Review PR #354 and reproduce the transitive-linking failure through USearch in an Xcode 16+ iOS or macOS app; done means the missing CNumKong.o error no longer occurs.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c, swift
- Domain
- build-system, mobile-dev
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 38/100