Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SR-8344] SPM include path is too permissive, leads to link errors that should have been compile errors #5349

Closed
swift-ci opened this issue Jul 23, 2018 · 0 comments
Labels

Comments

@swift-ci
Copy link
Contributor

Previous ID SR-8344
Radar None
Original Reporter strangemonad (JIRA User)
Type Bug
Status Resolved
Resolution Duplicate
Additional Detail from JIRA
Votes 0
Component/s Package Manager
Labels Bug
Assignee None
Priority Medium

md5: cf866095e972f30f19c86168f6664b53

duplicates:

  • 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

Unable to find source-code formatter for language: bash. Available languages are: actionscript, html, java, javascript, none, sql, xhtml, xmlUndefined symbols for architecture x86_64:
  "_$S9MyDep6MyFooOMa", referenced from:
      _$S9MyDep6MyFooOy4BlaBlaBlaMa in main.swift.o
ld: symbol(s) not found for architecture x86_64
<unknown>:0: error: link command failed with exit code 1 (use -v to see invocation)
error: terminated(1): /Library/Developer/Toolchains/swift-4.2-DEVELOPMENT-SNAPSHOT-2018-07-20-a.xctoolchain/usr/bin/swift-build-tool -f /Users/shawn/Dropbox/Development/Project/.build/debug.yaml main -v output

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:

  1. 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).

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
@shahmishal shahmishal transferred this issue from apple/swift May 4, 2022
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant