Objective-C package can't find header file

We are trying to support SPM in our pure Objective-C SDK (framework target in Xcode) but when it is included in a project, Xcode can't find an internal header file. I created a test project: GitHub - rabc/spm_objc_test

When it is included in the project using Xcode SPM management, the build gives the error 'MyPrivateClass.h' file not found that is imported in MyPublicClass.h (the error is the same when it is imported in *m file). I tried using cSettings(it is in another branch in the same repo), but no luck.

What am I missing?

I made it work without altering your directory structure by changing the following:

diff --git a/MyTest/MyPublicClass.h b/MyTest/MyPublicClass.h
index 09a33ba..4a82b63 100644
--- a/MyTest/MyPublicClass.h
+++ b/MyTest/MyPublicClass.h
@@ -7,7 +7,11 @@
 //
 
 #import <Foundation/Foundation.h>
+#ifdef SWIFT_PACKAGE
+#import "Internals/MyPrivateClass.h"
+#else
 #import "MyPrivateClass.h"
+#endif
 
 NS_ASSUME_NONNULL_BEGIN
 
diff --git a/MyTestSDK/MyTestSDK.h b/MyTestSDK/MyTestSDK.h
index 19de043..462c8c5 100644
--- a/MyTestSDK/MyTestSDK.h
+++ b/MyTestSDK/MyTestSDK.h
@@ -16,5 +16,8 @@ FOUNDATION_EXPORT const unsigned char MyTestSDKVersionString[];
 
 // In this header, you should import all the public headers of your framework using statements like #import <MyTestSDK/PublicHeader.h>
 
-
+#ifdef SWIFT_PACKAGE
+#import "../MyTest/MyPublicClass.h"
+#else
 #import <MyTestSDK/MyPublicClass.h>
+#endif
diff --git a/Package.swift b/Package.swift
index 49141eb..a226201 100644
--- a/Package.swift
+++ b/Package.swift
@@ -10,6 +10,12 @@ let package = Package(
         .library(name: "MyTestSDK",  targets: ["Core"])
     ],
     targets: [
-        .target(name: "Core", path: "MyTest", publicHeadersPath: "MyTestSDK")
+        .target(name: "Core", path: "", sources: ["MyTest"], publicHeadersPath: "MyTestSDK"),
+        .target(
+          name: "SampleClient",
+          dependencies: ["Core"],
+          path: "SampleClient",
+          cSettings: [.define("SWIFT_PACKAGE")]
+        )
     ]
 )
diff --git a/SampleClient/main.swift b/SampleClient/main.swift
new file mode 100644
index 0000000..512b47b
--- /dev/null
+++ b/SampleClient/main.swift
@@ -0,0 +1,3 @@
+import Core
+
+print(MyPublicClass())

However, unless you have a very good reason not to, it will probably be more convenient to rearrange the files so that SwiftPM and any other build systems you need to support can use the same import paths without any #ifdef statements.

Woah, indeed now it works. Thanks!

Indeed, it is not convenient at all. I will see what we are going to do. Thanks for the help!

This was a really helpful post. I am curious though - can you elaborate on how you might rearrange the files to be able to use the same import paths for say both CocoaPods and SPM integrations in the example above?

CocoaPods appears to permit a copying phase, where the headers are copied into the build product in a different arrangement than they exist in source. SwiftPM does not permit this. The trick is to make sure the headers in the source directories are arranged the same way they eventually will be after CocoaPods copies them. Then the same relative paths can be used both when pointing at the source directory with SwiftPM and when pointing at the product directory with CocoaPods.

In the above example, this could be accomplished either by putting MyPrivateClass.h directly at the publicHeadersPath for SwiftPM, or by teaching CocoaPods to copy it into an Internals subdirectory of the product. Having done one of those two things, you would no longer have to wrap the imports in #if, because both tools could use the same import with the same relative path.

1 Like

We solved making imports the same for CocoaPods and SwiftPM in Firebase by moving public headers from Public to a subdirectory like Public/{podName}. Then CocoaPods and SwiftPM clients can reference the headers the same way. See the example at firebase-ios-sdk/FirebaseCore/Sources/Public/FirebaseCore at master · firebase/firebase-ios-sdk · GitHub and others in the repo along with the podspecs and Package.swift.