Skip to content

Instantly share code, notes, and snippets.

@Pitometsu
Forked from briancroom/Swift.md
Created May 4, 2017 13:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Pitometsu/923323500f206ef695305e3327b5457b to your computer and use it in GitHub Desktop.
Save Pitometsu/923323500f206ef695305e3327b5457b to your computer and use it in GitHub Desktop.
How to create a Swift modular library

I am trying to determine if it is possible to build a Swift dynamic library which is itself composed of one of more private modules, without needing to expose to that fact to outside users. My hope was that I could build the private module as a static library, which would be linked into the primary (dynamic) library. The dylib could then be deployed together with its swiftmodule and swiftdoc and be imported, with the private module and its symbols not being exposed at all.

Unfortunately, what I'm currently observing seems to indicate that the private module's swiftmodule also has to be available for the primary library to be successfully imported.

This can be reproduced as follows. I have the following directory structure:

./Greeter/Logger/Logger.swift:

public func log(_ message: String) {
    print(fullLogString(message))
}

internal func fullLogString(_ message: String) -> String {
    return "(Logger): \(message)"
}

./Greeter/Greeter.swift:

import Logger

public func greet(_ name: String) {
    log("Hello \(name)!")
}

./main.swift:

import Greeter

greet("Swift")

I am building these as follows:

$ cd Greeter/Logger
$ swiftc -emit-object -emit-module -force-single-frontend-invocation -parse-as-library Logger.swift
$ ar -r libLogger.a Logger.o
$ cd ../
$ swiftc -emit-library -emit-module -parse-as-library -ILogger -lLogger -Xlinker -LLogger -Xlinker -install_name -Xlinker @rpath/libGreeter.dylib Greeter.swift
$ cd ../
$ swiftc -emit-executable -IGreeter -IGreeter/Logger -lGreeter -Xlinker -LGreeter -Xlinker -rpath -Xlinker Greeter main.swift

On the final command, if I omit the -IGreeter/Logger flag, compilation fails with the message:

main.swift:1:8: error: missing required module 'Logger'

So I'm wondering...

  1. Why is the Logger.swiftmodule necessary to complete the build, even though main.swift does not import it or use any symbols from it?
  2. Is there a way I could perform the build differently such that it wouldn't be needed?
  3. Where could I have started looking to figure out these answers on my own?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment