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

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
.
β”œβ”€β”€ LICENSE
β”œβ”€β”€ 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: [
        .iOS(SupportedPlatform.IOSVersion.v14),
        .macOS(SupportedPlatform.MacOSVersion.v11),
    ],
    products: [
        .library(
            name: "FooSwift",
            targets: ["FooSwift"]),
    ],
    targets: [
        .target(
            name: "FooSwift",
            dependencies: ["C"],
            path: "Sources/FooSwift",
            sources: ["Uno.swift"]),
        .target(
            name: "C",
            dependencies: ["FooStatic"],
            path: "Sources/C"),
        .binaryTarget(
            name: "FooStatic",
            path: "Libs/FooRust.xcframework"),
        .testTarget(
            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() {}
3 Likes