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-12683] @main is no longer usable due to misdetection of top level code #55127

Open
compnerd opened this issue Apr 27, 2020 · 11 comments
Open
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior.

Comments

@compnerd
Copy link
Collaborator

Previous ID SR-12683
Radar rdar://problem/62475602
Original Reporter @compnerd
Type Bug

Attachment: Download

Additional Detail from JIRA
Votes 16
Component/s
Labels Bug
Assignee None
Priority Medium

md5: d99a1a03d2003d32b1bfd6a2ae65a2fa

is duplicated by:

Issue Description:

There seems to be a recent regression with comment blocks and functions being treated as top level code which prevents the use of `@main`.

@natecook1000
Copy link
Member

@swift-ci create

@natecook1000
Copy link
Member

It looks like compilation is failing whenever the compiler's in single-file mode. Using the two attached source files, I get this result from trying to compile just MyMain.swift:

$ swiftc MyMain.swift
MyMain.swift:3:1: error: 'main' attribute cannot be used in a module that contains top-level code
@main
^
MyMain.swift:1:1: note: top-level code defined in this source file
// @main attribute test
^

When I add Empty.swift, the issue goes away:

$ swiftc MyMain.swift Empty.swift
(compiles without issue)

@natecook1000
Copy link
Member

To make this work, you can tell the compiler to parse the file as a library instead of in single-file mode with the -parse-as-library flag:

$ swiftc -parse-as-library MyMain.swift

@swift-ci
Copy link
Collaborator

swift-ci commented Aug 6, 2021

Comment by Josh Wright (JIRA)

Any updates to this? Hitting this issue as well when writing a single file script.

Nate's workaround works, but would be great to have this work out of the box (was using it indirectly through https://github.com/mxcl/swift-sh so it wasn't apparent how to update the compiler flags).

@swift-ci
Copy link
Collaborator

Comment by Eneko Alonso (JIRA)

This seems to still be an issue for new Swift 5.5 packages containing a main.swift file.

Steps to reproduce:

  1. mkdir myapp && cd myapp
  2. swift package init --type executable
  3. Replace `main.swift` content with the following

{{
@main
struct Program {
static func main() {
print("Hello, world!")
}
}
}}

4. swift run
5. Observe error: main.swift:2:1: error: 'main' attribute cannot be used in a module that contains top-level code

Multiple files

Adding a second file does not seem to fix the issue:

  1. create a second file Hello.swift with this content

{{
func hello() {
print("Hello, world!")
}
}}

2. Update `main.swift` as follows:

{{
@main
struct Program {
static func main() {
hello()
}
}
}}

3. swift run
4. Observe error: main.swift:2:1: error: 'main' attribute cannot be used in a module that contains top-level code

Solution

Renaming `main.swift` to something else (eg. `Program.swift`) solves the issue, whether there are only one file or more.

  1. Delete Hello.swift
  2. Update main.swift as follows:

{{
func hello() {
print("Hello, world!")
}

@main
struct Program {
static func main() {
hello()
}
}
}}

3. swift run
4. Observer the output "Hello, world!"

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
@ubunatic
Copy link

I can confirm the issue for this example where I import a cooperating module:

// Swift version 5.6 (swift-5.6-RELEASE)
// Target: arm64-apple-macosx12.0
import Foundation
import SwiftUI
import HelloCore

@main
struct HelloApp: App {
    var body: some Scene {
        WindowGroup {
            HelloView().onAppear {
                print("loaded")
                signal(SIGINT) { _ in
                    print("exit")
                    exit(EXIT_SUCCESS)
                }
            }
        }
    }
}

The renaming solution works. However, you may then see swift build errors such as:

'Hello': error: executable product 'Hello' expects target 'Hello' to be executable;
an executable target requires a 'main.swift' file

You can fix that by changing the .target in your Package.swift to .executableTarget.

ykws added a commit to ykws/swift-cloud-example that referenced this issue Aug 18, 2022
Fix 'main' attribute cannot be used in a module that contains top-level code

apple/swift#55127
@jhoughjr
Copy link

jhoughjr commented May 26, 2023

Trying to use this example for using raw nio:https://theswiftdev.com/swiftnio-tutorial-the-echo-server/
its only from 3 months ago, but I the newest info I've found.
seems the renaming worked for me was well.

cybersonik added a commit to cybersonik/github-stats that referenced this issue May 28, 2023
Add argument parsing using ArgumentParser Swift package

- Create options for GitHub URLs or repo and organization (including validation)
- Setup Async commands including one for retrieving PRs
- Rename main.swift to work around swift ([SR-12683](apple/swift#55127))

Implement PR endpoint with PR state filtering and results limiting

- Add Repo struct that maps to the GitHub repo and can be initialized with various forms of the GitHub URL details
- Add PR endpoint and associated types to create and asynchronously fetch PR data from corresponding GitHub endpoint
- Create types for resulting PR model objects
- Add tests for Repo initialization and fetching PRs using endpoint

Update VS Code project with:

- Fix new environment builds by creating package resolve task that build depends on
- Move GITHUB_TOKEN environment variable to env file used by debug launch task
- TODO: Remove postCreateCommand from devcontainer.json so container can be used by VS Code (and doesn't just call swift --version)
- Swift extension incorrectly expects `cwd` being set in tasks but since it can't be hardcoded or use the `workspaceFolder` variable, set it to an empty string

Address Linux build issues:

- Import new FoundationNetworking library yon Linux
- Implement asynchronous version of `URLSession.dataTask()` on Linux where async `URLSession.data()`

Follow up tasks:

- TODO: Refactor top-level GitHubRepo object and delete associated GitHubStatsCore tests
cybersonik added a commit to cybersonik/github-stats that referenced this issue May 28, 2023
Add argument parsing using ArgumentParser Swift package
- Create options for GitHub URLs or repo and organization (including validation)
- Setup Async commands including one for retrieving PRs
- Rename main.swift to work around swift ([SR-12683](apple/swift#55127))

Implement PR endpoint with PR state filtering and results limiting
- Add Repo struct that maps to the GitHub repo and can be initialized with various forms of the GitHub URL details
- Add PR endpoint and associated types to create and asynchronously fetch PR data from corresponding GitHub endpoint
- Create types for resulting PR model objects
- Add tests for Repo initialization and fetching PRs using endpoint

Update VS Code project with:
- Fix new environment builds by creating package resolve task that build depends on
- Move GITHUB_TOKEN environment variable to env file used by debug launch task
- TODO: Remove postCreateCommand from devcontainer.json so container can be used by VS Code (and doesn't just call swift --version)
- Swift extension incorrectly expects `cwd` being set in tasks but since it can't be hardcoded or use the `workspaceFolder` variable, set it to an empty string

Address Linux build issues:
- Import new FoundationNetworking library on Linux
- Implement asynchronous version of `URLSession.dataTask()` on Linux where async `URLSession.data()`

Follow up tasks:
- TODO: Refactor top-level GitHubRepo object and delete associated GitHubStatsCore tests
cybersonik added a commit to cybersonik/github-stats that referenced this issue May 28, 2023
Add argument parsing using ArgumentParser Swift package
- Create options for GitHub URLs or repo and organization (including
    validation)
- Setup Async commands including one for retrieving PRs
- Rename main.swift to work around swift
    ([SR-12683](apple/swift#55127))

Implement PR endpoint with PR state filtering and results limiting
- Add Repo struct that maps to the GitHub repo and can be initialized
    with various forms of the GitHub URL details
- Add PR endpoint and associated types to create and asynchronously
    fetch PR data from corresponding GitHub endpoint
- Create types for resulting PR model objects
- Add tests for Repo initialization and fetching PRs using endpoint

Update VS Code project with:
- Fix new environment builds by creating package resolve task that build
    depends on
- Move GITHUB_TOKEN environment variable to env file used by debug
    launch task
- Remove postCreateCommand from devcontainer.json so container can be
    used by VS Code (and not just call swift CLI)
- Swift extension incorrectly expects `cwd` being set in tasks but since
    it can't be hardcoded or use the `workspaceFolder` variable, set it
    to an empty string

Address Linux build issues:
- Import new FoundationNetworking library on Linux
- Implement asynchronous version of `URLSession.dataTask()` on Linux
    where async `URLSession.data()`

Follow up tasks:
- TODO: Refactor top-level GitHubRepo object and delete associated
    GitHubStatsCore tests
cybersonik added a commit to cybersonik/github-stats that referenced this issue May 28, 2023
Add argument parsing using ArgumentParser Swift package
- Create options for GitHub URLs or repo and organization (including
    validation)
- Setup Async commands including one for retrieving PRs
- Rename main.swift to work around swift
    ([SR-12683](apple/swift#55127))

Implement PR endpoint with PR state filtering and results limiting
- Add Repo struct that maps to the GitHub repo and can be initialized
    with various forms of the GitHub URL details
- Add PR endpoint and associated types to create and asynchronously
    fetch PR data from corresponding GitHub endpoint
- Create types for resulting PR model objects
- Add tests for Repo initialization and fetching PRs using endpoint

Update VS Code project with:
- Fix new environment builds by creating package resolve task that build
    depends on
- Move GITHUB_TOKEN environment variable to env file used by debug
    launch task
- Remove postCreateCommand from devcontainer.json so container can be
    used by VS Code (and not just call swift CLI)
- Swift extension incorrectly expects `cwd` being set in tasks but since
    it can't be hardcoded or use the `workspaceFolder` variable, set it
    to an empty string

Address Linux build issues:
- Import new FoundationNetworking library on Linux
- Implement asynchronous version of `URLSession.dataTask()` on Linux
    where async `URLSession.data()`

Follow up tasks:
- TODO: Refactor top-level GitHubRepo object and delete associated
    GitHubStatsCore tests
cybersonik added a commit to cybersonik/github-stats that referenced this issue Sep 9, 2023
Add argument parsing using ArgumentParser Swift package
- Create options for GitHub URLs or repo and organization (including
    validation)
- Setup Async commands including one for retrieving PRs
- Rename main.swift to work around swift
    ([SR-12683](apple/swift#55127))

Implement PR endpoint with PR state filtering and results limiting
- Add Repo struct that maps to the GitHub repo and can be initialized
    with various forms of the GitHub URL details
- Add PR endpoint and associated types to create and asynchronously
    fetch PR data from corresponding GitHub endpoint
- Create types for resulting PR model objects
- Add tests for Repo initialization and fetching PRs using endpoint

Update VS Code project with:
- Fix new environment builds by creating package resolve task that build
    depends on
- Move GITHUB_TOKEN environment variable to env file used by debug
    launch task
- Remove postCreateCommand from devcontainer.json so container can be
    used by VS Code (and not just call swift CLI)
- Swift extension incorrectly expects `cwd` being set in tasks but since
    it can't be hardcoded or use the `workspaceFolder` variable, set it
    to an empty string

Address Linux build issues:
- Import new FoundationNetworking library on Linux
- Implement asynchronous version of `URLSession.dataTask()` on Linux
    where async `URLSession.data()`

Follow up tasks:
- TODO: Refactor top-level GitHubRepo object and delete associated
    GitHubStatsCore tests
@DeCarabas
Copy link

This issue seems very old but I'd like to chime in that it doesn't seem fixed at all in Swift 5.9. See apple/swift-getting-started-cli#3 - I hit the bug midway through the "getting started" tutorial for a command line program.

@MaxMacleod
Copy link

Studying Apple's tutorial Getting Started with ArgumentParser, perhaps this is expected behaviour. See:

Note
The Swift compiler uses either the type marked with @main or a main.swift file as the entry point for an executable program. You can use either one, but not both — rename your main.swift file to the name of the command when you add @main. In this case, rename the file to Count.swift.

@ghost
Copy link

ghost commented Dec 27, 2023

Studying Apple's tutorial Getting Started with ArgumentParser, perhaps this is expected behaviour.

That was my conclusion as well, but then you get a different error if you don't have any main.swift files:

executable product 'currgen' expects target 'Generator' to be executable; an executable target requires a 'main.swift' file

@ubunatic had the actual fix in his comment above: executable target.
The problem is that Getting Started with ArgumentParser has target, so that example code actually fails to compile. But the example in ArgumentParser's README does use executableTarget.

That seems like a different issue. First, the tutorial should be updated. Second, the error could probably say something that would help direct the person to using executableTarget.
Which repo would be the right place to log an issue about the error message?

@shepazon
Copy link

shepazon commented Feb 5, 2024

This is frustrating for someone writing tutorials about Swift development using an asynchronous API for both Apple platforms and Linux, because:

  1. This issue doesn't seem to happen on Linux.
  2. When you write that people can create a single-file project using swift package init, they get a source file named "main.swift".
  3. This means the reader needs to rename the file before they do their first build that uses the SDK. This is a hack, and a hack that's only necessary under certain conditions.
  4. That makes the "how to start this sample project" explanation either more complex than necessary (you go through all the details, when to rename the file and when not to, why to do so, etc), prone to being obsoleted (you just tell everyone to always rename the main source file), or not working at all for some readers (you ignore the problem and leave the default source file name alone).

It would be nice if whoever needs to fix this would just do it. I can't imagine it being that hard to fix...

bisgardo added a commit to Concordium/concordium-swift-sdk that referenced this issue Mar 28, 2024
When working on the next features, we ran into a [known bug in Swift](apple/swift#55127) that prevents the annotation `@main` from being usable from within a file named `main.swift`.

According to a [note in the docs of `ArgumentParser`](https://apple.github.io/swift-argument-parser/documentation/argumentparser/gettingstarted/) (and apparently not documented anywhere else), this shouldn't work at all:

> The Swift compiler uses either the type marked with @main or a main.swift file as the entry point for an executable program. You can use either one, but not both [...]

So it's a bit of a mystery why it works in the current version...

To fix the problem we rename `main.swift` to `CLI.swift`.

Also, the executable is renamed to `concordium-example-client` to ensure that it never is mistaken for a production ready tool.

Finally, some variables were renamed for consistency and the readme got an overhaul.
bisgardo added a commit to Concordium/concordium-swift-sdk that referenced this issue Apr 2, 2024
When working on the next features, we ran into a [known bug in Swift](apple/swift#55127) that prevents the annotation `@main` from being usable from within a file named `main.swift`.

According to a [note in the docs of `ArgumentParser`](https://apple.github.io/swift-argument-parser/documentation/argumentparser/gettingstarted/) (and apparently not documented anywhere else), this shouldn't work at all:

> The Swift compiler uses either the type marked with @main or a main.swift file as the entry point for an executable program. You can use either one, but not both [...]

So it's a bit of a mystery why it works in the current version...

To fix the problem we rename `main.swift` to `CLI.swift`.

Also, the executable is renamed to `concordium-example-client` to ensure that it never is mistaken for a production ready tool.

Finally, some variables were renamed for consistency and the readme got an overhaul.
bisgardo added a commit to Concordium/concordium-swift-sdk that referenced this issue Apr 2, 2024
# Example CLI renaming

When working on the next features, we ran into a [known bug in Swift](apple/swift#55127) that prevents the annotation `@main` from being usable from within a file named `main.swift`.

According to a [note in the docs of `ArgumentParser`](https://apple.github.io/swift-argument-parser/documentation/argumentparser/gettingstarted/) (and apparently not documented anywhere else), this shouldn't work at all:

> The Swift compiler uses either the type marked with @main or a main.swift file as the entry point for an executable program. You can use either one, but not both [...]

So it's a bit of a mystery why it works in the current version, but not once more features are added...

To fix the problem we rename `main.swift` to `commands.swift`. It also turns out that by upgrading to `swift-tools-version: 5.9`, we can abbreviate the setup to omit the "executable product" declaration and the intermediary directory inside `Sources`.

Also, the executable is renamed to `concordium-example-client` to ensure that it never is mistaken for a production ready tool.

Finally, some variables are renamed for consistency and the readme got an overhaul.

# Vaious cleanup

- Some types and variables that aren't named according to the official [API Design Guidelines](https://www.swift.org/documentation/api-design-guidelines/) but were missed in #21 have been renamed appropriately.
- New type aliases for identity parameters are added.
- The intermediate type `VerifyKeyGrpc` is replaced with an extension `fromGRPCType` on `VerifyKey` from `ConcordiumWalletCrypto`.
- The functions the convert values from the generated gRPC types have been tightened up to not accept `nil` values and ensure that optional values are explicitly handled at the right place.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior.
Projects
None yet
Development

No branches or pull requests

8 participants