Skip to content
This repository has been archived by the owner on Jan 2, 2021. It is now read-only.

Swift does not import underlying module #92

Closed
grp opened this issue Jul 19, 2016 · 8 comments
Closed

Swift does not import underlying module #92

grp opened this issue Jul 19, 2016 · 8 comments

Comments

@grp
Copy link
Contributor

grp commented Jul 19, 2016

Split out of #88.

@keith wrote:

Ok so as far as I can tell, based on your branch, the original issue here is fixed. If this next issue doesn't sound related to you, feel free to close this one and I can open a different one as needed!

The next issue I've ran into, which I can't yet tell if it's related, is that using xcodebuild it seems like (for better or worse) many imports are implicitly added. For example we have files like this:

$ cat Foo.swift
extension UIView {
   ...
}

Where we have no explicit import UIKit, yet these work somehow. I think some of this might have to do with other files that are importing 3rd party dependencies, and maybe those imports are polluting the entire modules namespace. Another similar case we have is:

$ cat Foo.swift
import UIKit

... NSBundle ...

Which will also fail to compile because of a missing import to Foundation. Although it seems like in other places, import UIKit will implicitly make the Foundation import. Again I'm not a fan of this behavior, but it has apparently been something we're relying on. I'm currently adding all the missing imports by running xcbuild until it fails, copying the command that fails, running it, fixing the imports, repeat. Also as a note, these don't get surfaced in xcpretty, which would probably make this easier, instead I've been grepping the log for exit-status": 1

Let me know if you think this is at all related.

@keith wrote:

Ok so after finding all these missing imports, it seems like that issue only applies to the non-app dependencies of our project. I'm not sure exactly what the difference is there, but I only had to modify imports in our first party dependencies, some from CocoaPods and some just custom frameworks in our main project, but none of our main project files. There could be a difference here since the main project is the only place with a bridging header, which might be a slightly more explicit way of polluting the global namespace 😬

@grp wrote:

Hm, very interesting! It would be useful to see a comparison of the swiftc invocations between xcbuild and xcodebuild for a target hitting the issue. Hard to imagine what could cause a difference like that, though!

@keith
Copy link

keith commented Jul 21, 2016

Ok so interestingly enough, I think I figured out a little bit more about this. And both are intricacies with CocoaPods and how it generates dynamic frameworks.

So there are a few parts to this. First CocoaPods includes a pch file via GCC_PREFIX_HEADER. This imports UIKit globally..

Second in the generated umbrella headers, CocoaPods also imports UIKit. So if you remove the GCC_PREFIX_HEADER build setting via your Podfile, you still have this imported everywhere.

And lastly the generated .modulemap files export all sub-modules of the module. Meaning anything being imported there, also seems to be imported by the caller.

I'm not sure what the "right" solution to these problems are. I think first of all, CocoaPods shouldn't be doing any of these things unless absolutely necessary. Unfortunately I think with some static library configurations it becomes difficult to determine whether or not it is necessary. For example CardIO depends on the fact that the pch file is importing UIKit, otherwise it does not compile.

But I assume the issue that sparked this conversation as it relates to xcbuild is that some of these settings must not be respected with xcbuild. Is that true?

@grp
Copy link
Contributor Author

grp commented Jul 21, 2016

It looks like xcbuild only passes the GCC_PREFIX_HEADER to clang, not swiftc. That seems very plausibly the cause! Thanks for investigating & writing that up.

@grp
Copy link
Contributor Author

grp commented Jul 21, 2016

It looks like GCC_PREFIX_HEADER should only go to clang, so that's good. Currently investigating the -import-underlying-module flag to swiftc which xcbuild doesn't pass. That's related to some additional module maps, header maps, and VFS overlays that might also need to be generated in some cases — at least for Swift frameworks.

@grp
Copy link
Contributor Author

grp commented Jul 21, 2016

OK, I was able to reproduce the issue in a sample Swift framework. Modifying the xcbuild command line to include -import-underlying-module and -Xcc -ivfsoverlay -Xcc <path> with an appropriate overlay allows the Swift code to use the imports from the Objective-C umbrella header. Current question is when this layout is necessary: only for frameworks? Does it depend on the existing module map?

@grp grp changed the title Swift sometimes (?) needs additional imports to compile Swift does not import underlying module Jul 21, 2016
@keith
Copy link

keith commented Jul 21, 2016

It seems like it only applies to our frameworks. I did not have to add any imports to the main target, only its framework dependencies. Also probably applies because CocoaPods is overzealous about adding those imports, so it would make sense to be a frameworks problem.

@grp
Copy link
Contributor Author

grp commented Jul 21, 2016

I just created an empty framework project in Xcode and it had import Foundation in the Swift file but #import <UIKit/UIKit.h> in the underlying module's umbrella header, so UIKit was available in Swift without anything extra. (I didn't know that umbrella headers were automatically available at all — I thought you needed a bridging header for that!)

@keith
Copy link

keith commented Jul 21, 2016

I think in an ideal scenario, we wouldn't have that UIKit import in there as it seems like that unnecessarily pollutes the namespace. I removed a few of those locally to see what kind of imports we were missing and that was definitely part of it..

grp added a commit that referenced this issue Jul 22, 2016
…92.

Frameworks expect that their underlying Objective-C module is available
in Swift without an explicit bridging header. In order to support that,
a custom module map is needed at build time and an additional flag tells
the Swift compiler to import the underlying module automatically.
@grp
Copy link
Contributor Author

grp commented Jul 22, 2016

OK, I updated #93 with a bunch of changes that implement the missing pieces to make this work. It works on my super basic test project, but it'd be awesome if you could let me know if it fixes this for you too.

grp added a commit that referenced this issue Jul 22, 2016
…92.

Frameworks expect that their underlying Objective-C module is available
in Swift without an explicit bridging header. In order to support that,
a custom module map is needed at build time and an additional flag tells
the Swift compiler to import the underlying module automatically.
@grp grp closed this as completed in a07f339 Sep 1, 2016
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants