Public headers not found

Hello,

I have an open source Objective C framework, which I'd like to provide using Swift Package Manager as well.

Normally, I have public headers set in the Xcode project, which, when the framework is built, are copied under the framework bundle, and are discovered when linked with by Xcode.

I can't, however get it to work with SwiftPM.

I created a modulemap for my framework (there are more public headers than just the umbrella header):

framework module LNPopupController {
	umbrella header "LNPopupController.h"
	export *
	module * { export * }
}

and I define the library like so in the Package.swift:

let package = Package(
	name: "LNPopupController",
	platforms: [
		.iOS(.v12),
		.macOS(.v10_15)
	],
	products: [
		// Products define the executables and libraries a package produces, and make them visible to other packages.
		.library(
			name: "LNPopupController",
			type: .dynamic,
			targets: ["LNPopupController"]),
	],
	dependencies: [
		// Dependencies declare other packages that this package depends on.
		// .package(url: /* package url */, from: "1.0.0"),
	],
	targets: [
		// Targets are the basic building blocks of a package. A target can define a module or a test suite.
		// Targets can depend on other targets in this package, and on products in packages this package depends on.
		.target(
			name: "LNPopupController",
			dependencies: [],
			path: "LNPopupController",
			publicHeadersPath: ".",
			cSettings: [
				.headerSearchPath("."),
				.headerSearchPath("Private"),
			]),
	]
)

When added as a project dependency in Xcode, the framework compiles just fine, but when the dependent target attempts to import LNPopupController, an error is thrown: umbrella header 'LNPopupController.h' not found

Looking at the build folder, indeed, I see that Xcode has built a binary, but has not copied the public headers.

Any way to specify which headers are public, and make the build system copy them for import?

My attempts to play with SPM are here: https://github.com/LeoNatan/LNPopupController/tree/SPM

Thanks!

When I tried using your library from that branch, simply deleting the custom module map made the import successful. Is there a problem with the one automatically generated by SwiftPM?

Thank you for your reply. If I remove the modulemap, attempting to import the framework fails with

No such module 'LNPopupController'

Did it actually fail, or did it just fail during indexing because the underlying module hadn’t been assembled yet? I see that error while I’m looking at the code from the point when I add the package until the next time I tell the project to build. But the actual build succeeds, and it also causes the indexing error to vanish because from that point on the underlying module is complete and available. I can make the error reappear temporarily by cleaning the build folder, but then triggering an actual build resolves the error again. It’s not the greatest UI experience from Xcode, but your package seems to be working just fine.

Nope, it fails for me.

(In case there is a misunderstanding, I don't mean building the package itself, I mean adding it as a dependency in a demo project, and trying to build the demo project.)

Did you just add as a dependency, or did you also import the framework and try to use any of its symbols?

Thanks

Here is an Objective-C framework that I was able to restructure to be compatible with SPM, tested with both Xcode 12b3 and swift package: GitHub - Kentzo/ShortcutRecorder at develop

That’s what I did. With Xcode 11.6. I’m very confused as to why we are seeing different results.

Yes.

@Kentzo Thanks, I'll try to study it and see if I can adapt my project with the same approach. I did try having symbolic links to my headers in a include/ folder, but that didn't work either before.

@Kentzo Cheers, I adapted the same structure as yours (using soft links) and it works now. Thanks!

1 Like