"Include of non-modular header" … Not answered elsewhere - swift

Let's say I have a Sockets framework, that defines an Obj-C protocol SocketResponder. Then let's say in my Services framework which depends upon and links against the Sockets framework. My Services framework has a mixture of Obj-C and little bit of Swift code, and one of the Obj-C types, say NetworkTimeResponder conforms to the SocketResponder protocol, so:
// Services/NetworkTime.h
#import <Sockets/Sockets.h>
#interface NetworkTimeResponder: <SocketResponder>
…
This seems extremely straight forward, but the compiler gives the error:
Include of non-modular header inside framework module 'Services.NetworkTime': "...Sockets.framework/Headers/Sockets.h"
I've read a buuuuunch of "solutions" to this (every page of StackOverflow results), but none apply to this scenario.
I believe I understand the issue as, if the Application then imports the headers for the Services and Sockets frameworks, then there are actually two definitions of the types in Sockets framework headers and so it could be problematic.
But I'm really confused, because how is this different than say, AppKit importing Foundation and declaring types that conform to NSCopying, and my application importing both AppKit and Foundation? The issue seems to only arise in the case of modules, which comes up because one of my framework has a little Swift in it? I'm not familiar with how modules fundamentally differ and affect this.
Can anyone explain this?

TLDR: the target framework being imported and linked against, also needed to be a module.
These projects I am using were started a decade ago, so their compiler settings have evolved over time. Both "Defines Module" and "Enables C and Obj-C Modules" (DEFINES_MODULE and CLANG_ENABLE_MODULES) were off. However, having added a little bit of Swift code to one of my frameworks, Xcode then sets both DEFINES_MODULE and CLANG_ENABLE_MODULES to YES.
So now, if the "modular" framework, inside of any of its public headers, imports any public header from the "non-modular" framework, that's when this error pops up.
What it really comes down to is "hey this target is a module, and that one isn't."
Now, why is that a problem? This digs into part of why modules exist in the first place. If we look at CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES (which some not-so-informed people will suggest turn on), then the answer becomes clearer:
"Enabling this setting allows non-modular includes to be used from
within framework modules. This is inherently unsafe, as such headers
might cause duplicate definitions when used by any client that imports
both the framework and the non-modular includes."
If you know how header includes work, and you understand why C/C++ uses tons of #ifdef guarding in the headers to avoid duplication of declarations, then the crux is: modules avoid all of that headache, and guarantee only a single declaration exists. By "allowing non-modular includes in framework modules" you're now reintroducing the possibility of having duplicates.
https://clang.llvm.org/docs/Modules.html
So the moral of the story is, if a given target is a module, then everything it #imports in a public header should also be a module.

Related

How to selectively import a module in Swift depending on target?

Our Xcode project contains a sub-project that builds first party frameworks which we use as our standard libraries. One is built for each platform (iPhone, iPad, watchOS,...) but there is significant overlap between them (extensions for example).
In our Objective-C code in the main project, I simply have a different prefix header for each target based on its platform, and I import the relevant framework header. This means in my entire project I can use all the symbols that are in our "standard library".
I want this to happen in our Swift code as well (for both Swift and Objective-C symbols). From what I'm aware, Swift doesn't have the concept of prefix headers, so I'm needing to import the framework/module manually in each file.
What's more annoying, my imports won't just need to be
import MyFrameworkForiPhone
But because of the platform specific frameworks, with the help of Swift compiler flags, they'll need to become
#if RD_IPHONE
import MyFrameworkForiPhone
#elseif RD_IPAD
import MyFrameworkForiPad
#endif
Does anyone have any suggestions about how to cleanly work around this problem, or am I stuck with this for the time being?
While it may not be advisable to have separate modules for different platforms, sometimes we find ourselves in this situation and have to deal with it. Fortunately, there is one way to shorten that boilerplate...
Solution
You could create a third module, perhaps called MyFramework that selectively includes the appropriate framework for the current platform. Such a module would only need one source file that looks just like your example above:
#if RD_IPHONE
import MyFrameworkForiPhone
#elseif RD_IPAD
import MyFrameworkForiPad
#endif
Then, every other source file would simply import MyFramework. This works because a module will re-expose anything public from other modules it imports.
Analysis
This approach also provides a sensible location for anything that the two platform-specific modules have in common. Shared code can move into this platform-agnostic module, helping you move closer to the ideal scenario.
Notes
If you're using Swift Package Manager, see the documentation on modules. It's as simple as making a new directory.
In Xcode, creating a module means creating a framework. See Ray Wenderlich's guide for an example. It references iOS, but the same process applies to other platforms.
I would strongly advise against creating frameworks designed only for iPhone or iPad. If there is any UI code It would likely make it impossible for an app to be resizable on iPad and there isn't any code that will compile for one and not the other.
Besides that, you're not compiling separate binaries for iPad and iPhone if it's the same app. Imports are done at compile time, so you cannot dynamically include different frameworks based on the device on which it's being installed.
If you have completely separate apps that only support iPhone or iPad (which should be avoided), you could add compiler flags to each of them to do different things with the same files.
[edit: oops, I answered the wrong question. This answer is for Frameworks that target multiple platforms]
The support for cross-platform frameworks is still pretty bad. In Xcode, I work as follows:
create a single source tree for my library
create subfolders for platform-specific stuff
if a class is implemented differently for different platforms, it appears in each platform subfolder (where it is supported at all)
Now create a "Target" in XCode of type "... Static Library" for each platform you want to support (I have WatchOS, iOS, and MacOS in mine). Name them differently, obviously. However, change the "Build Settings | Basic | Product Name" on every one of these static libraries to be the same, like "MyLibrary" for example.
for each source file in your library, tick the "Target Membership" in the file properties to select which the platform libraries that should include this file. Obviously, everything in the platform-specific folders should only be included in those platform targets.
for other platform-specific targets, add Library linking and Target Dependency for the platform-specific target, like "MyLibrary_MacOS" or whatever you called your library targets above.
Now you can have "import MyLibrary" in your source files and it will automagically find the one that is actually available on the platform that you are compiling. This way, you can have platform abstractions or platform-specific stuff in your library and it doesn't appear everywhere in the code, just like "Foundation."
I also add headers in there for MacOS to provide dummy implementations of WatchOS APIs that I need for testing, for example. That way, I can unit test code on MacOS.
No, this is not optimal, because a formal "Framework" compile would be better, but it is the only way I have found to do it locally with full debuggability.
If anyone else has actually used something that works better, please let me know. Please don't recommend something you haven't actually used :)

How would a closed-source (i.e. precompiled) Swift library work without headers?

In C, C++ and Objective-C you can compile part of an executable into its own "object file" and use it (and/or a library containing multiple object files) from any other code by including a "header file". Highly-templatized C++ code notwithstanding, a "header" typically contains just the declarations needed to validate the correctness of calling code (and assist the IDE with autocomplete, etc.).
But Swift does not have header files.
Now, apparently it is not currently possible to make a Swift static library, but in the future how would a situation like the above work, wanting to use some existing precompiled code from "new" source code, given that Swift does not have headers?
Would it work something like how [I infer] Java must work, where the compiled form can be introspected enough for the compiler to verify it is being used properly? Does Bitcode in addition to its intermediate representation also provide the necessary "protocol" for retaining such metadata?
If Apple were to port Cocoa to Swift (and keep it closed source), how would it then be "imported" into Swift apps?
Although, really, this question is not anything to do with "closed source" per se but rather trying to understand the boundaries around compilation units in Swift. Based on a similar question for the Go language, mine here could be re-phrased as: can you link to a pre-compiled Swift library without the source?
Well, just consider Apple's Swift libraries. They are closed-source, and you can use them fine and you can see pseudo-"headers" for the stuff in the library in the compiler. The exact mechanism of how this works is not currently publicly documented, but it must exist.
In addition to #user102008, the good new is, Swift will be open sourced by the end of this year, and even ported to Linux by Apple. While we can't guarantee it will always work that way (as Apple has poor records on those kind of issues), people will found suitable solutions within this even if Apple has no interests in doing so.
Even more, afaik, Swift objects were actually Objective-C objects. There'll not be that different to make Swift things work than Objective-C. (More details: http://www.eswick.com/2014/06/inside-swift/) After they were compiled, just do a class dump (or load it into a debugger such as IDA) and you can easily create a .h to make it work like normal static library or a framework.

Building pure Swift Cocoa Touch Framework

I'm exploring Swift with Xcode-6 and so far so good although I think the new collections need a little bit of work as I've managed to break the compiler a few times.
Problem is I'm now stuck trying to create the framework package to then use in another project. The project builds without issue and all tests pass successfully. When I go to create Archive (which I assume is what is required) I receive the error:
:0: error: underlying Objective-C module 'Sample' not found
Now I assume this has something to do with the contents of my Sample.h which tells me
// In this header, you should import all the public headers of your framework using statements like #import <Sample/PublicHeader.h>
which is fine except I have only used swift enums, structs and classes for this framework so therefore no .h files exist.
Can anyone shed some light on this one as I can't find any documentation available yet?
EDIT (7/27/2018)
The information in the answer below may no longer be accurate. Your mileage may vary.
I sat down with an engineer and asked this exact question. This was their response:
Xcode 6 does not support building distributable Swift frameworks at this time and that Apple likely won't build this functionality into Xcode until its advantageous for them to do so. Right now, Frameworks are meant to be embedded in your app's project, rather than distributed. If you watch any of the session videos or see the sample projects, this is always the arrangement. Another reason is that Swift is very new and likely to change. Thus your Swift-based framework is not guaranteed to work on the platform you originally built it on.
Slight Update
The engineer mentioned that it's not impossible to make a framework for distribution, just that it's not supported.
I was able to get past the error by going to the target for the framework and on the Build Phases tab under Headers, remove the MyFramework.h file
However I was getting the "Underlying Objective-C module not found" error when I was using a framework to share code between a containing app and an app extension, both of which were pure Swift.
Assuming you are creating a truly pure Swift module, you must disable the Objective-C Compatibility Header and any generated interface headers so the compiler doesn't go off assuming it can find an Objective-C module for the framework.
Do Not remove your public framework header. You'll get a module-map warning at link time if you do.
You might find this useful: Creation of pure swift module
In short: it's possible to make static framework, but there is one issue: it doesn't work in end user' project if "ProjectName-Swift.h" header included.
But, it works fine if you use only swift.
I think it's a bug in XCode 6, or that Apple does not allow archiving the Framework from XCode while in beta.
If you compile to profile XCode generates the framework correctly. (See the Release folder created in DerivedData)

objective-c #import whole framework or only needed file?

When I'm using big frameworks like the Three20 Framework,
I always have the choice whether to #import the whole framework or to #import only the single file of it i'd need.
I guess there's a difference in compilation-overhead since it has to open all files of the framework, but is there also a run-time difference? like bigger memory-usage? Or does the compiler-optimization already remove everything that's not needed?
And if I use the same framework pretty much in every class I use, is it recommended to include the framework in the prefix file instead of every single class?
Greetings
Infinite :)
There will be a compilation difference, yes: including everything will take longer to compile. But there shouldn't be a run-time difference.
Your idea of including the framework in the prefix is a good one for frameworks you're going to be using throughout. However, there is a catch, which is that if you change something in that framework your entire codebase will have to be recompiled.
There is no performance hit in runtime. No matter how many frameworks or files you import, if you don't use whichever classes they won't affect the resultant bytecode when you compile. The compiler doesn't even optimize anything; unused classes just "aren't there" at all.
Include the framework in the precompiled header file if you're sure it's going to be necessary.
You footprint won't be any different unless you actually use the classes however I prefer to be more frugal with my headers, only including the ones I need. If I need a lot from the same library (like Three20) then you can add the whole reference.
Only include headers in the prefix that don't change much, but it will speed up compilation greatly.

How does XCode know which project to debug into when multiple projects are open simultaneously?

TL;DR Version:
This question has arisen due to the fact that I have multiple frameworks (which I have built) and a client project that uses said frameworks. Now, when I open up the client project and try to debug into the framework, it doesn't work.
However, if I have the project associated with the framework open, then debugging appears to work (though there are some weird issues with breakpoints I don't see being triggered).
I have looked at Apple's docs, and perhaps the answer is buried there somewhere, but I couldn't find it on a skim of the Xcode Debugging Guide.
Long Version:
The reason this question is important to me is that a coworker and I had a disagreement about how headers are imported in the frameworks we build.
I have a tendency to use framework headers (with client apps) in the fashion:
#import "FrameworkA/HeaderA.h"
#import "FrameworkB/HeaderB.h"
He, on the other hand, favors importing the framework headers (with client apps) like this:
#import "HeaderA.h"
#import "HeaderB.h"
and specifying the header search paths in the build target of the client application.
Complicating matters further is the fact that some of these frameworks have interdependencies. For example, FrameworkB has headers from FrameworkA referenced in his format:
#import "HeaderA.h"
His argument for doing this is that debugging only works if we import headers this way. It seems dubious to me that there would be a relation between header importing style and debugging, but I am not really certain how XCode chooses the file to link to during debugging, hence the question.
Thanks in advance for any assistance with this query.
you add project references to the target, and make sure Xcode knows where to find the debug symbols.
#import <FrameworkA/HeaderA.h>
that's the way to go (for internal and external declarations). the reason? the other approach is more likely to cause issues as libraries evolve. the additional qualification disambiguates any case (unless of course there are two FrameworkA/s in your search path), it's best to qualify the file explicitly now, rather than when your clients tell you they cannot use your library with other libraries, or that they can only use them in some conditions. then you have to go fix the issues and reship (this stuff has a way of happening at inconvenient times =p). it's one simple measure to ensure you've developed a robust interface.
perhaps the most important part that people overlook is the location of the products: use a customized central build location for your targets -- many people use the default location, which is by the xcodeproject. otherwise, Xcode may not be able to locate debug information.
finally, debugging complex projects in Xcode can be quite... let's call it 'problematic'. So don't expect the debugging experience to be perfect, even if you've configured everything correctly. all the more reason to integrate assertions and unit tests into your development cycle early on with Xcode. truth is, the debugger may be useless no matter how hard you try - this is not a new issue. hopefully LLDB will improve our debugging experiences.
good luck