Right on Darwin platforms Foundation gets automatically linked. I actually never dove into where and how this gets done. Building the same package on Linux should produce a compile error that you are not importing Foundation
But the correct auto-link behavior is for Darwin target instead of host. There should be some bug hereā¦ Can someone replicate the bug with it?
I don't think it will, according to documentation trimmingCharacters(in:)
is declared in the Swift standard library.
Oh right. Sorry I was just checking this from my mobile and assumed it was a Foundation API. Disregard my comments then
This is reallyā¦ Shocking.
It turns out that CharacterSet
is a Foundation
type, that should be why Foundation
is required and linked.
https://developer.apple.com/documentation/foundation/characterset
https://swiftinit.org/reference/foundation/characterset
Which documentation? The stdlib code doesn't show this method:
Search Ā· trimmingCharacters Ā· GitHub
This documentation refers to NSString: Apple Developer Documentation
I'm referring to the function available on StringProtocol
, not the one on NSString
.
It is an extension from Foundation
. This is definitely ruining the rule of not extending a type you donāt own (I believe Foundation
adds a bunch of extensions to String
, but additions to StringProtocol
is even worse).
Perhaps from the very beginning Apple engineers thought they own both, but thatās incorrect now. And unfortunately I suppose fixing it is ABI breaking.
P.S. Definitely wants to give @taylorswift a credit here since swiftinit
has proved to be more precise and useful than the official documentationā¦ It saves a lot.
I hope there's a way to add a requirement for import Foundation
when using protocol extensions declared in Foundation as a source-breaking, not ABI-breaking change. In my understanding, this shouldn't change how the linker works, or what binary code is emitted.
Isn't this how it normally works for other modules provided via SwiftPM?
thank you so much!!
I guess thereās something wrong to make the code compile. Even on macOS where Foundation is automatically linked, Foundation.swiftmodule
wonāt be pulled in without manual import
, so the code shouldnāt compile.
I am as confused as anyone by this. But I keep coming back to the finding that adding import JavaScriptKit
to any file in the module causes Foundation to be linked implicitly. Even for Darwin with a plain swift build
and even though JavaScriptKit
itself has not even a single mention of the word Foundation
in the entire repo. I will investigate it further though ā maybe it's importing something which has a transitive dependency on Foundation
dependencies: [
.package(url: "https://github.com/swiftwasm/JavaScriptKit", from: "0.15.0"),
],
is needed to import JavaScriptKit
To be precise, Foundation is unexpectedly imported. We should check the compiler and importer first. I donāt think the linker flags makes sense given that weāre seeing symbols from Foundation leaked into the code.
I have tracked this down to a simple reproduction. In short, it appears to be a bug in SwiftPM with bundled resources.
edit: I removed the original post, which outlined the contents of the reproduction in text form and posted the minimal reproduction as a SwiftPM project to GitHub - ephemer/swiftpm-implicit-foundation-imports-reproduction
Yet another edit: so my workaround for now will be to fork JavaScriptKit
and remove the resources:
line of Package.swift
+1 to this, -lFoundation
is probably always passed, but the toolchain (or the linker specifically) is not linking with that static library if no symbol is referencing it.
@Geordie_J Which toolchain did you use that has the bug? I canāt replicate it locally.
EDIT: Okay I got it. You may want to place a .gitkeep
file under Sources/Dep/Runtime
to let Git recognize the directory.
Great catch! The issue is with resources and SwiftPM then. As soon as resources are specified in Package.swift
, SwiftPM generates a file for referencing this resource through the Bundle
type, which is declared in Foundation.
If you're using carton
, excluding JSKit resources may cause issues though, because we're relying on SwiftPM resources to make runtime files discoverable.
Seems like SPM will always create such accessor file that depends on Foundation.Bundle if we have at lease one resource file(a bundle exists)
Should we consider adding a flag to control this?
What would be the point of bundling resources that can't be used? Bundle.module
is the only supported way to access resources.
The downstream user who is importing the dependency may be using only a sliver of the library's functionality and not need or know about the bundled resource; that Foundation APIs are imported should (IMO) remain under explicit user control. Put another way, if the bundled resources aren't being used, better to bundle just resources that can't be used than both resources and all of Foundation.