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

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.

Related

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

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.

Swift Run Time Library vs. Swift Standard Library

In this tutorial on how to use CocoaPods I am having trouble understanding the following paragraph:
Unlike Objective-C, the standard Swift runtime libraries aren’t
included in iOS! This means your framework must include the necessary
Swift runtime libraries. As a consequence, pods written in Swift must
be created as dynamic frameworks. If Apple allowed Swift static
libraries, it would cause duplicate symbols across different libraries
that use the same standard runtime dependencies.
Here are my questions:
What exactly are the "standard Swift Runtime Libraries"? Is the Swift Standard Library one such standard swift run time library, would a framework I write in swift be considered a swift run time library?
What exactly does "Swift runtime libraries are not included in iOS" mean? I guess I am having trouble inferring what "iOS" refers too.
Any additional insight, links, resources or explanations regarding this paragraph would be greatly appreciated!
Edit:
After reading the runtime library wiki article I am no longer confused about Q1. The following paragraph clarified this for me:
The concept of a runtime library should not be confused with an
ordinary program library like that created by an application
programmer or delivered by a third party, nor with a dynamic library,
meaning a program library linked at run time. For example, the C
programming language requires only a minimal runtime library (commonly
called crt0), but defines a large standard library (called C standard
library) that has to be provided by each implementation.
However I am still confused about Q2.
Objective C has a stable (unchanging) runtime library, so it makes sense for there to be one shared copy of the library, provided by the OS (macOS/iOS), available to all applications that need it. In contrast Swift is a rapidly evolving language, which means that its runtime library undergoes vast changes between versions. Because of this, Xcode bundles in a copy of the Swift runtime library as part of each app, to ensure that a copy of the correct version (the version the app uses) of the runtime library is available to the app.
Swift Standard Library vs Swift Run Time Library
[Swift Standard Library]
Swift Run Time Library is a part of Swift Standard Library
Before iOS v12.2 there were not ABI[About] stability on iOS level, that is why you could see a lot of frameworks(Swift standard library[About]) inside each built target
Also you are able to adjust it via Always Embed Swift Standard Libraries(ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES) for targets before iOS v12.2

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)

iPhone SDK static library versioning

I've been writing iOS apps for some time now and for this particular project, I decided that I needed a static library for code sharing purposes.
I've followed some tutorials in creating static libraries and everything works perfectly.
Now I wonder, is there any way of versioning the static library?
I couldn't find any files regarding version number in the static library project, nor any good search results (both Google and here) regarding this particular issue.
I think I could create some kind of "fake" Info.plist and store the version info there.
Is that the way of doing it? Any other approaches to the problem?
Edit:
I think I may have not been clear on my purpose:
I have a workspace that has both my library project and related projects using the library, which is imported using the .xcodeproj file, then configured the dependencies so it builds whenever needed.
I just need some way of versioning the library, so that I can include that in some sort of about box, just in case.
I think you should stay away from bundling binary builds of your own code. Unless you're building a really, really, really massive library, you're better off just importing the code in any of your projects, and rebuilding it each time. You can put it in a separate target though, so Xcode doesn't rebuild it all the time.
You might want to write a tool that takes version info in a .plist and writes it out as literal strings defined in a .h file, which you can then include in your own code.
To make it foolproof (avoid mismatch between the header and the library), define a class method like [YourLibraryClass versionString] that returns a NSString with the version number or signature.

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