If you have already started playing with swift, you probably thought about how to include third party libraries into your project or how to distribute yours.Apple provides a mechanism to distribute code via frameworks (eventually, for iOS too), so making a custom framework, which will include both ObjC and Swift code is very easy. But let’s dig deeper and create a
pure Swift module, like apple does with Swift’ std lib and Cocoa/CocoaTouch bridge.
Note: this module will work in swift-only projects, in case if ObjC compiler generates Swift-to-ObjC bridging header and includes swift-module via @import
directive, which doesn’t work with current Xcode/Apple Clang version.Toy Swift Module
We’re going to create a simple module call
Logger
which will contain only one method:
log
.You can see sample project
here.Each swift module consists of at least three files, so we should get all of them as an output:
Logger.swiftmodule
– public interface/definitions
Logger.swiftdoc
– docs (surprisingly)
libLogger.a
– built library (there also might be a
dylib
, it depends on your task)
Note: you should switch xcrun
to beta xcode’ version before running swift
commandssudo xcode-select -switch $xcode_dir/Contents/Developer
libLogger.a
Let’s create the simplest and useless
Logger
“library”.
class Logger
{
var prefix: String
init(_ prefix: String)
{
self.prefix = prefix
}
func log<T>(object: T)
{
print(prefix)
println(object)
}
}
The class just takes some prefix and logs it before actual object
var logger = Logger("> ")
logger.log("Hello, World!")
Now it’s time to make a
libLogger.a
:
xcrun swift -emit-library -emit-object Logger.swift -sdk $(xcrun --show-sdk-path --sdk macosx) -module-name Logger
ar rcs libLogger.a Logger.o
-emit-library
generates dynamically linked shared library, while
-emit-object
generates object file
and includes main
function, so you will have linker errors due to duplicated symbols.Solution is pretty simple: include both flags
-emit-object
and
-emit-library
, as I did above.
Logger.swiftmodule
xcrun swift -emit-module Logger.swift -sdk $(xcrun --show-sdk-path --sdk macosx) -module-name Logger
This command will generate
Logger.swiftdoc
and
Logger.swiftmodule
.Now we have complete module and can integrate it into real project. Just create simple swift-project and add the files:

Then setup ‘Import paths’ for Swift

We’re ready to check how it works:
import Foundation
import Logger
var logger = Logger("> ")
logger.log("Hello")
Just run and you’ll see an expected output:
> Hello
If you see linker errors, check your ‘Library search paths’ and ‘Other linker flags’ — they should contain path to
libLogger.a
and
-lLogger
respectively.
Logger.swiftdoc
Let’s figure out how to deal with documentation.To add documentation to module you just need to comment it using
///
, e.g.:
/// Simple Logger
///
/// Constructor takes prefix string which will be printed before actual object
///
class Logger
{
var prefix: String
init(_ prefix: String)
{
self.prefix = prefix
}
/// Prints `object` with specified `prefix`
func log<T>(object: T)
{
print(prefix)
println(object)
}
}
After integrating module into a project you will see documentation on the right

But I didn’t manage to get it work without restarting Xcode after integrating.
Conclusion
This approach is not very nice for “everyday” usage for a regular iOS/OSX developer (because it requires creating and supporting Make/CMake file), but it might be useful if you want to create pure module which doesn’t use ObjC at all.Also, Swift modules are similar to Java’s
jar
binaries.The source code:
import Foundation
/// Simple Logger
///
/// Constructor takes prefix string which will be printed before actual object
///
class Logger
{
var prefix: String
init(_ prefix: String)
{
self.prefix = prefix
}
/// Prints `object` with prefix
func log<T>(object: T)
{
print(prefix)
println(object)
}
}
transforms into module interface without details of implementation
/// Simple Logger
///
/// Constructor takes prefix string which will be printed before actual object
///
class Logger {
var prefix: String
init(_ prefix: String)
/// Prints `object` with prefix
func log<T>(object: T)
}
So you can even distribute proprietary libraries without any problems (except of crazy reverse engineers), but I hope you won’t do this in favor of Open Source Software ;)