-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Pass compiler flags to alllow use of @main
in single-source-file executable modules
#3410
Pass compiler flags to alllow use of @main
in single-source-file executable modules
#3410
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, looks good... I guess
219dd49
to
8344de2
Compare
-parse-as-library
when compiling an executable module that has a single source file that isn't named main.swift
@main
in single-source-file executable modules
@main
in single-source-file executable modules@main
in single-source-file executable modules
@swift-ci please smoke test |
@abertelrud thanks for working to fix this unfortunate state of things. is there a better fix that we can do in the compiler instead of working around the limitation in SwiftPM? @nate-chandler @airspeedswift ? |
Absolutely. Had a good conversation with @nate-chandler about this, and added notes to https://bugs.swift.org/browse/SR-14488. I think that a long-term solution here is to take advantage of the fact that SwiftPM knows that it is building an executable (from the manifest), so there is no need for heuristics. I elaborate on this in the SR, but conveying the intent to the compiler is the basic idea, and then there would not be any need for heuristics based on the number and names of source files. But @nate-chandler indicated that this would not be possible in the 5.5 timeframe. |
adopting a short term solution is fine if we are tracking fixing it the right way for the version that comes after 5.5. We should also add code comments + radar number to that end as part of this short term workaround. |
Adding comments and a reference to the SR is a great point. I'll update the PR. |
… a single source file that isn't named `main.swift` The Swift compiler has certain special behaviors regarding main source files: - if a module has just a single source file of any name, it's treated as the main source file - if a module has a source file named `main.swift`, it's treated as the main source file If a source file is considered the main source file, it can have top level code. But a source file that has top level code can't also have `@main`. This means that a single source file executable module can't use `@main`, regardless of the name of that source file. A second empty source file can be added as a workaround, but we can employ some countermeasures in SwiftPM. Specifically, if the executable module consists of a single source file and it is not named `main.swift`, we pass `-parse-as-library` so that a single-source file module will work. This matches what can be seen in the build logs in Xcode, meaning that packages will build the same in SwiftPM and in Xcode. Note that this still does not allow use of `@main` in source files named `main.swift`, but that will require compiler support to address. Since this has the potential to break existing packages that use top-level code in a single source file that isn't named `main.swift`, this behavior is gated by a 5.5 tools version. See https://bugs.swift.org/browse/SR-14488 for discussion about improvements so that SwiftPM can convey the intent to build an executable module to the compiler regardless of the number of files in the module or their names. rdar://76746150
8344de2
to
e333dbe
Compare
@swift-ci please smoke test |
@swift-ci please smoke test macos |
@swift-ci please smoke test macos |
… a single source file that isn't named `main.swift` (swiftlang#3410) The Swift compiler has certain special behaviors regarding main source files: - if a module has just a single source file of any name, it's treated as the main source file - if a module has a source file named `main.swift`, it's treated as the main source file If a source file is considered the main source file, it can have top level code. But a source file that has top level code can't also have `@main`. This means that a single source file executable module can't use `@main`, regardless of the name of that source file. A second empty source file can be added as a workaround, but we can employ some countermeasures in SwiftPM. Specifically, if the executable module consists of a single source file and it is not named `main.swift`, we pass `-parse-as-library` so that a single-source file module will work. This matches what can be seen in the build logs in Xcode, meaning that packages will build the same in SwiftPM and in Xcode. Note that this still does not allow use of `@main` in source files named `main.swift`, but that will require compiler support to address. Since this has the potential to break existing packages that use top-level code in a single source file that isn't named `main.swift`, this behavior is gated by a 5.5 tools version. See https://bugs.swift.org/browse/SR-14488 for discussion about improvements so that SwiftPM can convey the intent to build an executable module to the compiler regardless of the number of files in the module or their names. rdar://76746150 (cherry picked from commit 41b97c8)
… a single source file that isn't named `main.swift` (#3410) (#3421) The Swift compiler has certain special behaviors regarding main source files: - if a module has just a single source file of any name, it's treated as the main source file - if a module has a source file named `main.swift`, it's treated as the main source file If a source file is considered the main source file, it can have top level code. But a source file that has top level code can't also have `@main`. This means that a single source file executable module can't use `@main`, regardless of the name of that source file. A second empty source file can be added as a workaround, but we can employ some countermeasures in SwiftPM. Specifically, if the executable module consists of a single source file and it is not named `main.swift`, we pass `-parse-as-library` so that a single-source file module will work. This matches what can be seen in the build logs in Xcode, meaning that packages will build the same in SwiftPM and in Xcode. Note that this still does not allow use of `@main` in source files named `main.swift`, but that will require compiler support to address. Since this has the potential to break existing packages that use top-level code in a single source file that isn't named `main.swift`, this behavior is gated by a 5.5 tools version. See https://bugs.swift.org/browse/SR-14488 for discussion about improvements so that SwiftPM can convey the intent to build an executable module to the compiler regardless of the number of files in the module or their names. rdar://76746150 (cherry picked from commit 41b97c8)
This matches the behavior implemented in swiftlang/swift-package-manager#3410 for single file modules.
This matches the behavior implemented in swiftlang/swift-package-manager#3410 for single file modules.
This matches the behavior implemented in swiftlang/swift-package-manager#3410 for single file modules. Fixes #913
This matches the behavior implemented in swiftlang/swift-package-manager#3410 for single file modules. Fixes bazelbuild#913
Pass
-parse-as-library
when compiling an executable module that has a single source file that isn't namedmain.swift
. This avoids a compiler error when using@main
in single-file executable modules.Motivation
It should be possible to use
@main
in executables, even if they are implemented as a single source file.Background
The Swift compiler has certain special behaviors regarding main source files:
main.swift
, then that file is treated as the main source fileIf a source file is considered the main source file, it can have top level code. But a source file that has top level code can't also have
@main
.This means that a single source file executable module can't use
@main
, regardless of the name of that source file. A second empty source file can be added as a workaround, but we can employ some countermeasures in SwiftPM.The issue of wanting more control over the compiler's semantics continues to be tracked by https://bugs.swift.org/browse/SR-14488. What would really be needed here would be for SwiftPM to be able to tell the compiler that it knows it wants to build and executable, and for the compiler to allow either top-level code or
@main
in any one of the source files (regardless of how many source files there are or what they are named). Until we have that, adding this workaround (and matching the same heuristics as Xcode has) seems desirable.Changes
-parse-as-library
if the executable module consists of a single source file and it is not namedmain.swift
, and if the tools version of the package is 5.5Results
Packages that specify 5.5 as their required tools version can now used
@main
in single-source-file executables as long as those source files aren't named "main.swift" (in which case top-level code is expected).This still does not allow use of
@main
in source files namedmain.swift
, but that will require compiler support to address (in the absence of scanning source files to see which ones use@main
).It is worth noting that, according to experiments, such package targets already don't build in Xcode (which is of course not something that SwiftPM can fix, but there is a certain advantage to having matching semantics, and it's arguable better to require renaming a single source file rather than to completely block use of
@main
in single-source file executable modules).Notes
We should consider updating the documentation for executable targets. The special casing going on here is tricky to explain but stems from the applying of the compiler's heuristics around source files (which are motivated by direct invocation of the compiler without additional information) to package targets (where the intent is already known).
rdar://76746150