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...
- Why is the
Logger.swiftmodule
necessary to complete the build, even thoughmain.swift
does not import it or use any symbols from it? - Is there a way I could perform the build differently such that it wouldn't be needed?
- Where could I have started looking to figure out these answers on my own?