2

I am trying to use a legacy framework as a Swift package. This framework has an umbrella header which imports UIKit via #import <UIKit/UIKit.h>, so the swift source files do not explicitly import UIKit. Building via SPM fails with error messages like: error: cannot find type 'UIFont' in scope. If I change the source files to explicitly import UIKit, these errors go away, but it seems there should be a Swift Package Manager equivalent to allowing a wider scope import.

See this PR for the specific project and my current workaround: https://github.com/i-schuetz/SwiftCharts/pull/419

pschwamb
  • 809
  • 6
  • 11

1 Answers1

4

The Swift package needs to have a Swift source file that re-exports UIKit

@_exported import UIKit

You only need one of these per target in your package that you want to act as an umbrella.

If the legacy framework isn't yours, you can create your own Swift package whose library target declares a dependency on the framework and which re-exports the framework and UIKit, even if all it has in it is a single file with the @_exported import statements. Then to use it in your project, you'd import your wrapper package instead of the original framework package.

I think you can also do it with a module map, but I'd need to do some research on exactly how.

Chip Jarred
  • 2,600
  • 7
  • 12
  • Thanks for the quick response. This sounds like it would work, but relies on a non-standardized swift feature. The module map option would maybe be more standard, but I couldn't get that to work. – pschwamb Apr 07 '21 at 19:37
  • Yeah I tried the module map once before too and failed, then came across `@_exported`. Although the underscore does indicate that it's not "official", it or something like it is needed, so I expect that it will become standard, or a feature will be provided to state the equivalent in the `Package.swift` itself. Anyway, since you only need it in one place, if it does break you only have one place you need to go to fix it. – Chip Jarred Apr 07 '21 at 19:39
  • I think this is a useful answer, so I upvoted it, but I think it's a bit of a hack, doing something similar, but not identical (i.e. re-exporting vs framework wide import), and using a non-standard Swift feature. Seems there there should be a supported way to do framework wide import in a Swift framework since it is a very common practice in Objective-C frameworks. – pschwamb Apr 24 '21 at 15:20
  • Thanks for upvoting it. Maybe someone who knows (or has the time to research) how to do it with module maps will be able to provide a more satisfactory answer. Unfortunately whatever the module map solution is, it's not as simple as @_exported, because as I mentioned before, I tried that approach and never quite got it right, whereas @_exported worked immediately and did exactly what I needed. – Chip Jarred Apr 26 '21 at 03:14