I'd like to add support for @main
in Swift Packages, and would be interested in hearing thoughts about the following approach.
The Swift Package Manager doesn’t currently provide a way for a package manifest to declare that a target is the main module of an executable. Instead, SwiftPM infers this by looking for a source file named main.swift
(or main.c
, main.cpp
, etc) in the source directory of the target.
Knowing unambiguously whether or not a target is intended to be executable is important, because it affects the flags that are passed to the compiler at build time. It also affects the quality of diagnostics, such as detecting product declarations that mistakenly include multiple or no executable targets in an executable product.
Relying on specially named source files also doesn’t work when using @main
to specify the entry point of an executable. In addition, there are ergonomic problems with using specially named source files (e.g. SR-1379) that would be addressed by being able to explicitly declare a target as being executable in the manifest.
Proposal
The most straightforward approach would be allow a target to be marked as executable in the manifest. This could take the form of either a parameter to the target
type or a new target type. There is already an established pattern of using the type itself to denote the kind of target being declared (e.g. testTarget
as a specialization of target
), so the most natural approach seems to be to add a new executableTarget
type for this purpose.
Using a separate target type in the manifest would also support any future differences between the parameters for an executable target and a library target.
Details
This proposal introduces a new target type as a peer of target
, testTarget
, systemTarget
, and binaryTarget
. The new target type would have the same parameters as the target
and testTarget
types.
Compiler flags
The Swift Package Manager is already passing -parse-as-library
to targets that are not marked as executable, and doesn’t pass that flag to targets that are. Since the Swift compiler still treats the source file name main.swift
as special, SwiftPM may need to pass additional flags if a target has both a main.swift
file that does not contain @main
but does contain a differently named source file that does contain it.
Backward compatibility
The executableTarget
type would only be available for package manifests that specify a tools version newer that 5.3. Package manifests specifying tools versions 5.3 or older would behave exactly as before.
Alternatives Considered
Adding a parameter to the target
type
Another approach would be to add another parameter to the existing target
type. That type already has many parameters, however, and it seems ill advised to add more. Using a separate target type in the manifest would also support any future differences between the parameters for an executable target and a library target.
Scanning source files for @main
Another approach would be to scan source files for occurrences of @main
, and to use that to infer whether a target is an executable target. This seems even more subtle than basing the detection of executable targets on a filename, however, making any mistakes in package authoring even harder to detect.