Swift Package and xcframework target for C library: where to include the header?

I am refactoring a project to use SPM. Previously in the “bridging header” I had a
#include <abc/abc.h>
which exposed the C static library in abc.xcframework to swift and worked very well.
Now I have the abc.xcframework as a binaryTarget in the SPM Package.swift, but there is no bridging header in a Swift Package and so the library is not found, it’s not getting included anywhere. Neither my swift package or the tests will compile.
Does anyone know how I can solve that? I've been trying to make a module as a target dependencies but it still won't find the structs etc declared in the abc.h


1 Like

If I understand what you're attempting to do, you are trying to import a C Header and use it in Swift code in your Swift Package. If this is indeed the case then what you need to do is create a separate target in your Package.swift file that includes the C Header and then include that in the target that contains your Swift code.

I've done this in one of my projects which you can find here. The CHalf target is the one that imports the C Header that I created whereas Half is the target that contains all of the Swift sources.

Hope this helps,

It sounds like the OP has a binaryTarget not a C target like you do in Half.

I was able to get this working without a module map by including an intermediate "dummy" C target. My swift target depends on a C target that has bridge.c and include/bridge.h and then the dummy C target depends on the binaryTarget that represents my xcframework.

Here is a look at the directory structure:

FooSwift on main [+?] via 🐦 v5.4.2 
❯ tree
├── Libs
│   └── FooRust.xcframework
│       ├── Info.plist
│       ├── ios-arm64
│       │   ├── Headers
│       │   │   └── libfoo.h
│       │   └── libfoo-ios.a
│       ├── ios-arm64_x86_64-maccatalyst
│       │   ├── Headers
│       │   │   └── libfoo.h
│       │   └── libfoo-ios-macabi.a
│       ├── ios-arm64_x86_64-simulator
│       │   ├── Headers
│       │   │   └── libfoo.h
│       │   └── libfoo-ios-sim.a
│       └── macos-arm64_x86_64
│           ├── Headers
│           │   └── libfoo.h
│           └── libfoo-macos.a
├── Package.swift
├── README.md
├── Sources
│   ├── C
│   │   ├── bridge.c
│   │   └── include
│   │       └── bridge.h
│   └── FooSwift
│       └── Foo.swift
└── Tests
    ├── LinuxMain.swift
    └── Foo-Tests
        ├── Foo_Tests.swift
        └── XCTestManifests.swift

16 directories, 18 files

and here's the package manifest:

FooSwift on main [+?] via 🐦 v5.4.2 
❯ cat Package.swift 
// swift-tools-version:5.4

import PackageDescription

let package = Package(
    name: "FooSwift",
    platforms: [
    products: [
            name: "FooSwift",
            targets: ["FooSwift"]),
    targets: [
            name: "FooSwift",
            dependencies: ["C"],
            path: "Sources/FooSwift",
            sources: ["Uno.swift"]),
            name: "C",
            dependencies: ["FooStatic"],
            path: "Sources/C"),
            name: "FooStatic",
            path: "Libs/FooRust.xcframework"),
            name: "Foo-Tests",
            dependencies: ["FooSwift"]),

You treat the intermediate C target as your "bridge" and in bridge.h you simply:

#include "libfoo.h"

My bridge.c file is essentially empty:

include "bridge.h"

void __dummy() {}
1 Like

Thanks, this worked a treat. Was stuck initially but got it working after adding

import CTargetName

statements in the Swift Target that depends on CTargetName

Terms of Service

Privacy Policy

Cookie Policy