You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
SR-1393 [SwiftPM] Enforce Swift module import dependencies
Issue Description:
This is more of a spm "ergonomics" bug that outright functionality issue. The build still fails as it should but it fails unexpectedly as a link-time error.
Rationale: while it might take a split second for a C/C++ veteran to decipher, link errors are confusing for many people, especially newer programers or those coming from a scripting language background. It's also one of several little usability hiccups that in aggregate make spm painful to use IMO.
Setup (using swift 4.2 / xcode beta 10)
Create a Package.swift with a dependency MyDep (assuming MyDep is also the name of the single module in the MyDep library) and 2 executable targets (A and B).
Make A depend on MyDep but NOT B
Coding along without thinking about it you 'import MyDep' in a source file in module B
Expected: you get a compiler error that you can't "import MyDep" in target B. Bonus would be an additional message to add MyDep to the dependencies of target B in Package.swift (spm doesn't currently do this but it could / should).
Actual: You can import and use any symbol in MyDep throughout the project. This only fails as a link error
Cause:
There's an "immediate" cause and a more nuanced design decision cause so I'll list both.
A bit of debugging shows that SPM creates a .build/debug.yaml with an include path of .build/debug, which includes ALL the modules. This is too permissive and allows the compiler to allow programs that it shouldn't
1) Swift-build-tool happily invokes swiftc with overly permissive "-I .build/debug" include search path to produce the .swiftmodule
2) swiftc is again invoked with the very permissive "-L .build/debug" link search path
3) No where is the final executable linked explicitly with "-l MyDep.swiftmodule", instead, the .build/target-triple/debug/A.product/Objects.LinkFileList explicitly contains a reference to .build/target-triple/debug/MyDep.build/MyStruct.swift.o
Possible solutions:
Solve it at the SPM level. Don't put Foo.swiftmodule results directly under ./build/target-triple-debug/*. Instead, create a directory for each target. Keep each swiftmodule under the target's directory (possibly moving the target.build, target.dsym target.product directories under the target folder too). Change the single -I and -L directories to multiple search directories.
2) Add another flag to swiftc to specifically list individual .swiftmodule files rather than a search directory and change SPM so that it enumerates each .swiftmodule dependency specifically. The rationale being one of symmetry. If swiftc can emit individual .swiftmodule files then it should be able to quickly consume them as a "serialized compiler database". I haven't read Jordan Rose's latest updates on swiftmodule files vs swift 5 https://forums.swift.org/t/plan-for-module-stability/14551 but this seems like a consideration.
Aside: Having the A target executable directly list a partial build output of MyDep in its link files was additionally surprising. I know it probably speeds things up but from a usability standpoint, it breaks the understanding that a module is a unit of compilation. I'd love to just double down on making modules the fast path (I have no idea how the current .swiftmodule format is setup but the first part could be an efficient table of contents for tools to consume).
The text was updated successfully, but these errors were encountered:
Additional Detail from JIRA
md5: cf866095e972f30f19c86168f6664b53
duplicates:
Issue Description:
This is more of a spm "ergonomics" bug that outright functionality issue. The build still fails as it should but it fails unexpectedly as a link-time error.
Rationale: while it might take a split second for a C/C++ veteran to decipher, link errors are confusing for many people, especially newer programers or those coming from a scripting language background. It's also one of several little usability hiccups that in aggregate make spm painful to use IMO.
Setup (using swift 4.2 / xcode beta 10)
Create a Package.swift with a dependency MyDep (assuming MyDep is also the name of the single module in the MyDep library) and 2 executable targets (A and B).
Make A depend on MyDep but NOT B
Coding along without thinking about it you 'import MyDep' in a source file in module B
Expected: you get a compiler error that you can't "import MyDep" in target B. Bonus would be an additional message to add MyDep to the dependencies of target B in Package.swift (spm doesn't currently do this but it could / should).
Actual: You can import and use any symbol in MyDep throughout the project. This only fails as a link error
Cause:
There's an "immediate" cause and a more nuanced design decision cause so I'll list both.
A bit of debugging shows that SPM creates a .build/debug.yaml with an include path of .build/debug, which includes ALL the modules. This is too permissive and allows the compiler to allow programs that it shouldn't
1) Swift-build-tool happily invokes swiftc with overly permissive "-I .build/debug" include search path to produce the .swiftmodule
2) swiftc is again invoked with the very permissive "-L .build/debug" link search path
3) No where is the final executable linked explicitly with "-l MyDep.swiftmodule", instead, the .build/target-triple/debug/A.product/Objects.LinkFileList explicitly contains a reference to .build/target-triple/debug/MyDep.build/MyStruct.swift.o
Possible solutions:
2) Add another flag to swiftc to specifically list individual .swiftmodule files rather than a search directory and change SPM so that it enumerates each .swiftmodule dependency specifically. The rationale being one of symmetry. If swiftc can emit individual .swiftmodule files then it should be able to quickly consume them as a "serialized compiler database". I haven't read Jordan Rose's latest updates on swiftmodule files vs swift 5 https://forums.swift.org/t/plan-for-module-stability/14551 but this seems like a consideration.
Aside: Having the A target executable directly list a partial build output of MyDep in its link files was additionally surprising. I know it probably speeds things up but from a usability standpoint, it breaks the understanding that a module is a unit of compilation. I'd love to just double down on making modules the fast path (I have no idea how the current .swiftmodule format is setup but the first part could be an efficient table of contents for tools to consume).
The text was updated successfully, but these errors were encountered: