Swift wraps C lib; important enum symbols missing via SwiftPM

I'm trying to move a functioning Xcode project to SwiftPM. The original project builds the C library as a static library, then my Swift library statically links to that, and everything is okay. When someone uses the Swift library, all of the symbols that were original C enums are available in the Swift application using the Swift library.

This isn't working for me when I try to migrate this to a pure SwiftPM package. None of the original symbols are present.

Here is my Package.swift:

// swift-tools-version:5.3
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "SwLibTidy",
    products: [

        .library(
            name: "CLibTidy",
            targets: ["CLibTidy"]),

        .library(
            name: "SwLibTidy",
            targets: ["SwLibTidy"]),
        
        .executable(
            name: "Console",
            targets: ["Console"]),
    ],
    
    dependencies: [],
    
    targets: [

        .target(
            name: "CLibTidy"
            , dependencies: []
            , path: "Sources/CLibTidy"
            , exclude: ["version.txt"]
            , cSettings: [
                .define("LIBTIDY_VERSION", to: #""1.2.3""#, nil),
                .define("RELEASE_DATE", to: #""2021/07/12""#, nil)
            ]
        ),
        
        .target(
            name: "SwLibTidy",
            dependencies: ["CLibTidy"],
            path: "Sources/SwLibTidy"
        ),
        
        .target(
            name: "Console",
            dependencies: ["SwLibTidy"],
            path: "Sources/Console"
        ),
        
//        .testTarget(
//            name: "SwLibTidyTests",
//            dependencies: ["CLibTidy", "SwLibTidy"]
//        ),
    ]
)

Basically, I build CLibTidy using vendored source code. I've manually created module.modulemap for now, but it's fine, because when I build SwLibTidy, it has access to everything that I've declared in the module.modulemap, including the critical tidyenum.h.

SwLibTidy builds fine, and I can use everything I defined in my .swift files, and everything brought in via the modulemap is fine.

When I try to run tests or my simple console test app, none of values that were originally enums are visible, i.e., "Cannot find 'whatever' in scope." Sample main.swift file exhibiting this:

import Foundation
import SwLibTidy
let i = tidyOptGetInt( tdoc, TidyAccessibilityCheckLevel )

If I "Jump to Definition" of the import SwLibTidy file, the fake Swift header-like file indeed doesn't show my missing enums. If do the same to the import CLibTidy in my SwLibTidy.swift file, I can see where all of my enums have been properly brought in as a combination of struct plus public vars.

But why aren't these definitions being exposed by my SwLibTidy? Why does it work in a non-SwiftPM project when I build a static lib from the C code first? And most importantly, is there anything I can do to make this work?

Heavily stripped Github sample of my non-working package

I'd like to keep this self contained, and let SwiftPM run the C-compiler, rather than refactor this to use a system library, or try binary targets. Basically, plug and play for anyone who would include it.

Any suggestions? Many thanks in advance!

Does using @_exported import CLibTidy in the SwLibTidy module help?

That does seem to help!

It looks like it introduces a lot of conflicts between Bool types, but that's not SwiftPM's or Swift's fault, I suppose.

I wish I'd asked this question early this morning instead of struggling with it all day! On the other hand, I seem to know a lot more about SPM as a result ;-)

Thanks.

Terms of Service

Privacy Policy

Cookie Policy