Currently, for go run <arg>
to work, the <arg>
must have a package main
and a func main
. If it has the latter, but not the former, you get error:
package command-line-arguments is not a main package
Why not change go run
to allow it to run any package that has a func main
?
This needs 2 changes to the go run <arg>
command:
- if resolves to a package path and that package has a
func main
, run that. - otherwise (current behavior), look in for a
main
package with afunc main
and run that or, if not found, give an error. The error should be changed from:
package command-line-arguments is not a main package
to
package command-line-arguments does not have a main function and is not a main package
(or words to that effect)
Pros:
- makes go toolchain more regular, and, I assert, simpler. Removes what appears to be an arbitrary restriction (“
func main
only means command entry point if it’s inpackage main
”) - is a backward compatible extension of the API. Doesn’t break any program that was previously working.
Cons:
- There might be some existing cmd projects that already have
main()
in non-main packages. This proposal wouldn’t break any existing way of invoking such a project (since they all go throughpackage main
). But it could conceivably cause a test to fail, e.g the project had an explicit test for an error fromgo run <non-main-package>
. So there are code changes that a project might have to make simply to retain all-tests-pass status if the proposal were implemented.
Here’s my use case:
I have a collection of documentation samples, each of which is a short, standalone program (meaning reader could run it by a go run
command). I want to maintain the sources in a single project (i.e. in a single module). How should I structure the project so I can run any chosen sample?
- I could put each sample in a separate package but with a
func main
, then implement a top-level driver that knows how to invoke each individual code sample package. The invocation would be something likego run driver <sample>
.
There’s the redundancy of having to provide this driver and also of having to put each sample program in a separate subdirectory because it’s in a separate package. - (What I’m currently doing as a workaround) I maintain each sample program in a separate source file (in the project root). Each file has
package main
andfunc main
.
I can invoke the selected sample viago run <sample>.go
(note it is a file path). I cannotgo test
orgo build
the module (because of duplicate definitions offunc main
), but I live with that for now.