https://github.com/mnmly/libigl-xcframework-builder
macOS xcframework builder for libigl (header-only). Consumed by mnmly/SwiftIGL.
https://github.com/mnmly/libigl-xcframework-builder
libigl macos swift-package-manager xcframework
Last synced: 4 days ago
JSON representation
macOS xcframework builder for libigl (header-only). Consumed by mnmly/SwiftIGL.
- Host: GitHub
- URL: https://github.com/mnmly/libigl-xcframework-builder
- Owner: mnmly
- Created: 2026-05-16T19:15:08.000Z (about 1 month ago)
- Default Branch: main
- Last Pushed: 2026-05-16T19:20:53.000Z (about 1 month ago)
- Last Synced: 2026-05-16T21:34:03.293Z (about 1 month ago)
- Topics: libigl, macos, swift-package-manager, xcframework
- Language: Shell
- Size: 9.77 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# libigl-xcframework-builder
Standalone builder that produces a header-only `igl.xcframework` for macOS
(arm64) from a tagged libigl release, bundled with a pinned Eigen.
libigl is header-only by default; this builder skips libigl's CMake and just
stages the `include/igl/` + `Eigen/` trees into a library-form xcframework
(stub static archive + `Headers/`). Library-form (vs. framework-form) is
deliberate so that `` and `` both resolve in consumer
C++ TUs.
Sibling project to `pdal-xcframework-builder`. Output is consumed by
`SwiftIGL` (Swift Package).
## Prerequisites
- macOS with Xcode command-line tools (`xcodebuild`, `clang`, `ar`)
- `cmake`, `git`
- (optional) `gh` for `make release`
## One-time setup
```sh
cp config.sh.example config.sh
$EDITOR config.sh # set SWIFT_PACKAGE_FRAMEWORKS_DIR if mirroring locally
```
## Build
```sh
make LIBIGL_VERSION=2.5.0
```
Or directly:
```sh
./build.sh 2.5.0
```
Phases (numbered in `build.sh`):
1. **Fetch libigl** — shallow clone at tag `v` (falls back to
``) into `work/libigl-/libigl-src`.
2. **Fetch Eigen** — shallow clone Eigen at `EIGEN_VERSION` (default `3.4.0`,
matching libigl's pinned FetchContent tag).
3. **Stage `include/`** — copy `include/igl/`, `Eigen/`, and
`unsupported/` into `stage/include/`. License files are copied to
`stage/include/.licenses/`.
4. **Stub static archive** — compile a single no-op `.c`, archive into
`libigl_stub.a`. xcframeworks need a real Mach-O attached to headers.
5. **xcframework** — `xcodebuild -create-xcframework -library libigl_stub.a
-headers stage/include -output output/igl.xcframework`.
6. **Codesign (optional)** — only when `CODESIGN_IDENTITY` is set.
7. **Mirror (optional)** — copy into `SWIFT_PACKAGE_FRAMEWORKS_DIR` so
SwiftIGL can pick it up via path-based binaryTarget during development.
8. **Zip + checksum** — `ditto` zip and `swift package compute-checksum`.
`RELEASE=1 ./build.sh ` (or `make release`) additionally creates a
GitHub release via `gh` if `GH_RELEASE_REPO` is set.
## Bump-version workflow
Releases are published to `mnmly/SwiftIGL` (configurable via
`GH_RELEASE_REPO` in `config.sh`). To ship a new libigl version:
```sh
# Build, mirror to SwiftIGL/Frameworks (for local iteration), zip,
# and gh release create with the zip attached.
make LIBIGL_VERSION=2.6.0 release
```
The release notes generated by phase 9 include the exact
`.binaryTarget(url:, checksum:)` snippet — paste it into
`mnmly/SwiftIGL/Package.swift`, commit, push.
The build refuses to overwrite an existing tag — bump `LIBIGL_VERSION`,
or delete the prior release first. If Eigen's pin moved in upstream
`libigl/cmake/recipes/external/eigen.cmake`, bump `EIGEN_VERSION` in
`config.sh` alongside.
## Layout produced
```
igl.xcframework/
├── Info.plist
└── macos-arm64/
├── libigl_stub.a
└── Headers/
├── igl/ # libigl headers
├── Eigen/ # Eigen core
├── unsupported/ # Eigen unsupported (optional)
└── .licenses/
```
## Consumer wiring (SwiftIGL)
```swift
.binaryTarget(
name: "igl",
path: "Frameworks/igl.xcframework" // or url: + checksum: for releases
),
.target(
name: "CxxIGL",
dependencies: ["igl"],
cxxSettings: [.headerSearchPath("include")]
),
```
C++ TUs in `CxxIGL` can then `#include ` and
`#include `.
## Why no framework module map
libigl exposes 600+ headers, each of which is its own translation unit when
`LIBIGL_USE_STATIC_LIBRARY=OFF` (the default). A Clang umbrella module that
sweeps all of them in is both slow and prone to template-instantiation
explosions. Library-form xcframeworks expose headers via plain
`-I`, which is what we want — consumers include only what they use.
## Out of scope
- iOS / Catalyst / x86_64 (untested).
- libigl `copyleft/` and `restricted/` modules (CGAL, comiso, embree,
matlab, mosek, predicates). They have non-trivial external deps; add as a
v2 if needed.
- `LIBIGL_USE_STATIC_LIBRARY=ON` precompiled-instantiations build. Currently
we ship pure headers — slower app builds, but no template-coverage gaps.