Skip to content

Latest commit

 

History

History
102 lines (84 loc) · 4.56 KB

README.md

File metadata and controls

102 lines (84 loc) · 4.56 KB

MyPackage

Minimal complication error example.

I'm in the process of migrating an iOS app to use the latest version of a storage SDK. The previous SDK provided a model abstraction similar to CoreData, which leverages the dynamic nature of Objective-C. Since I have access to the Obj-C model source code, I'm using composition to implement the model storage functionality, along with many of the support classes, in Swift. This results in a mixed source package that is similar to the following...

let package = Package(
    name: "MyPackage",
    products: [
        // Products define the executables and libraries a package produces, and make them visible to other packages.
        .library(
            name: "MyPackage",
            targets: ["MyPackage"]),
        .library(
            name: "MyPackageObjC",
            targets: ["MyPackageObjC"]),
        .library(
            name: "MyPackageSwift",
            targets: ["MyPackageSwift"]),
    ],
    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: "MyPackage",
            dependencies: ["MyPackageSwift","MyPackageObjC"]),
        .target(
            name: "MyPackageObjC",
            dependencies: ["MyPackageSwift"]),
        .target(
            name: "MyPackageSwift",
            dependencies: []),
        .testTarget(
            name: "MyPackageTests",
            dependencies: ["MyPackage"]),
    ]
)

And a file system layout that looks like....

.
├── Package.swift
    ├── README.md
    ├── Sources
    │   ├── MyPackage
    │   │   └── Export.swift
    │   ├── MyPackageObjC
    │   │   ├── MyObject.m
    │   │   ├── NameGenerator+LastName.m
    │   │   └── include
    │   │       ├── MyObject.h
    │   │       └── NameGenerator+LastName.h
    │   └── MyPackageSwift
    │       └── MyPackage.swift
    └── Tests
        ├── LinuxMain.swift
        └── MyPackageTests
            ├── MyPackageTests.swift
            └── XCTestManifests.swift

Since the Swift target cannot depend on the Obj-C target, I've added categories in Obj-C to implement interactions with the model class. For example, since my Swift model factory class cannot import the Obj-C model class, I've implemented the method that creates the model from a underlying document as an Obj-C category on the Swift class. This works well when I build the MyPackageObjC target, and I can use the resulting package in Obj-C code in my app. However, this fails when I try to import the MyPackageObjC target in Swift. I created the MyPackage target that depends on both the Obj-C and Swift targets a means to factor the iOS app out of the equation. Export.swift uses @_exported import MyPackage to replicate what happens in the iOS app.

From the file NameGenerator+LastName.h in my minimal test project....

@import MyPackageSwift; <- error when building 'MyPackage' 

@interface NameGenerator (LastName)

- (NSString*)generateLastName;

@end

Here's a high level output of the error...

<module-includes>:1:9: note: in file included from <module-includes>:1:
#import "/Users/scott/Desktop/MyPackage/Sources/MyPackageObjC/include/NameGenerator+LastName.h"
        ^
/Users/scott/Desktop/MyPackage/Sources/MyPackageObjC/include/NameGenerator+LastName.h:2:9: error: module 'MyPackageSwift' not found
@import MyPackageSwift;
        ^
/Users/scott/Desktop/MyPackage/Sources/MyPackage/Export.swift:2:19: error: could not build Objective-C module 'MyPackageObjC'
@_exported import MyPackageObjC

After digging a bit deeper, I discovered that adding @import MyPackageSwift to any header in the Obj-C target causes this error when building the MyPackage target. But it works fine when building the Obj-C MyPackageObjC target.

Since this seems to work conditionally, is there any additional package compiler configuration entries I can use to resolve this?

What seems odd here is that the Obj-C target builds successfully earlier in the process. It's almost as if the Swift compiler is trying to compile the Obj-C header file through a traversal of @_exported import MyPackageObjC in the MyPackage Export.swift file. Does this only "work" for Swift targets?