How can I include my dependent framework's objects to my framework

swift
module
dependency

(Erhan) #1

I have an XCWorkspace that contains separate framework projects, project structure as follows

AFramework project (static framework project, AFramework project links BFramework and adds it to its target dependencies)

BFramework project (static framework project, contains public BClass.swift file)

AFramework project can access BClass.swift file as expected but I also want to expose BClass.swift file to the outside of AFramework, assume that an application project links just AFramework and on that app I want to access to BClass.swift file, what should I do to achieve that, using custom module map can be useful?

Here is the screenshot from the demo app, the app just links AFramework and tries to access to BClass.swift file, but that file is not accessible.

Additional Info: I use New Build System which is enabled by default in XCode 10.1

Thanks in advance for your help


iOS include third-party static library in Swift dynamic framework
(Jeremy David Giesbrecht) #2

There is no officially supported solution yet, but there is an incomplete, unofficial one which is already sufficient for most cases:

@_exported import BFramework

You can read about the remaining issues in this thread:


(Erhan) #3

Thanks for response @SDGGiesbrecht but even if I use @_exported import, it still fails

This is what Xcode says after applying your suggestion

"Missing required module 'BFramework' "

I've just exported import BFramework in AClass.swift file


(Jeremy David Giesbrecht) #4

In case it was not clear, @_exported only exports the interface; it does not assimilate the entire binary with the implementation. (You can @_exported import Foundation or other OS libraries too.)

The error probably means Xcode didn’t know it needed to build your BFramework and put it in the products directory so that there is something to link against in the first place.

If your top‐level project is a manual Xcode set‐up (as opposed to the package manager), you need to add all dependencies to the “Embedded Binaries” and “Linked Frameworks and Libraries” under MyProject → “Targets” → MyTarget → “General”.

If you are vending your framework to other users, you will have to tell them to set this part up.

(With the package manager and swift package generate-xcodeproj, all this is automatic.)


(Erhan) #5

Thanks for the clarification @SDGGiesbrecht about @_exported attribute.
As you guess my top-level project is a manual Xcode set-up (I don't use Cocoapods or any other dependency manager), I use an xcworkspace and add my framework projects to that workspace but unfortunately I can share only AFramework with the user (BFramework should be hidden from user in my case), that means I still need to embed BFramework binary to the AFramework.

By the way, Mach-O type is "Static Library" for both A and B Frameworks and I don't see “Embedded Binaries” configuration for framework target on XCode 10.1, there might be a restriction for framework targets, are you familiar with that?

So there might be any other option to achieve my needs, for example using a module map can be useful for me or do you have any other suggestion?


(Jeremy David Giesbrecht) #6

Given those circumstances, I do not really know what the answer might be.

I have found some other threads for you which may be related:

https://forums.developer.apple.com/thread/28948

https://forums.developer.apple.com/thread/105062

https://forums.developer.apple.com/thread/87729


(Jordan Rose) #7

I'd expect this to work as long as BFramework is in your search paths when you build the app. However, I can't exactly recommend it; because you're using static libraries, you may end up with two copies of BFramework being linked into the final app.

There's no way to say "AFramework automatically includes BFramework's interface" right now. It can only say "go find BFramework when you import AFramework".


(Erhan) #8

Thanks for the answer @jrose let me give some more details about my project set-up and scenario.

First of all, I create my framework projects as following, File-> New Project-> Cocoa Touch Framework. After project creation, I manually change MacO type to "Static Library" in build settings for both framework targets (A and B ).

AFramework and BFramework projects are inside a workspace called Test.xcworkspace, and my Test App project is not included in Test.xcworkspace.(It is a separate project and it is on the different location)

On the other hand, AFramework links BFramework and adds it to its target dependencies.

For Test.xcworkspace and Test App Project - build system set as legacy on Xcode (not new build system - also Xcode version is 10.1)

With above setup, When I build AFramework project, I can see that AFramework's executable file contains also BFramework's object file as seen below.(Btw, This does not happen when I use New Build System.)

After that, I manually add just A.framework to the Test app project, also I delete all of the files on Derived Data folder in Test.xcworkspace, I import AFramework to the test app project and call any method from both A and B frameworks, when I build the Test App Project it fails as below.(Missing required module BFramework)

But If I don't delete Derived Data folder in Test.xcworkspace It does not fails, strangely XCode finds BFramework from Derived Data folder in Test.xcworkspace project, Is that so strange also for you @jrose?

On the other hand, the same set-up with ObjC works properly even If I delete all files from Derived Data. For this case, I just add public header files from B to A target and set that headers file as public and it works.

So the question is why AFramework cannot find BFamework even if it contains all object files from B when I use Swift (Note that ObjC works properly for that case) and is there any wrong usage in my set-up or there might be any other linker flag that I have to use?

Thanks for help​ in advance


(Jordan Rose) #9

For this case, I just add public header files from B to A target and set that headers file as public and it works.

This is the step that's missing on the Swift side. The Swift "header" equivalent is the B.swiftmodule folder inside the framework, but right now we don't have a way to take that and put it in another framework and have the compiler still find it. It's a reasonable feature request, but it doesn't work today.


(Erhan) #10

Thanks for clarification @jrose.

There might be a chance to manually include the content of B.swiftmodule to the A.swiftmodule, does it work? or copying B.swiftmodule file into A.framework can be an applicable option @jrose? I’m also open a private usage like _exported attribute to handle it :)