8

I have the following project structure, outside of GOPATH.

. // Project root
├── Dockerfile
├── .env
├── README.md
└── src
    ├── main.go
    ├── go.mod
    ├── go.sum
    ├── internal
    │   ├── somepackage
    │   │   ├── main.go
    │   │   └── types.go
    │   ├── someother
    │   │   ├── main.go
    │   │   ├── oauth.go
    │   │   └── types.go
    │   └── models
    │       └── main.go
    └── pkg
        ├── somepackage
        │   └── main.go
        └── anotherpackage
            └── main.go

I want to run my Go module code located in the src directory. When I cd into the src directory and go run . or go build . my code, it works perfectly.

When I stand at the root of my project, I am unable to run go run ./src or go build ./src. I get the following error.

src/service.go:8:2: cannot find package "web-service/internal/auth" in any of:
        /usr/lib/go/src/web-service/internal/auth (from $GOROOT)
        /home/miloertas/Packages/go/src/web-service/internal/auth (from $GOPATH)
src/endpoints.go:3:8: cannot find package "web-service/internal/handlers" in any of:
        /usr/lib/go/src/web-service/internal/handlers (from $GOROOT)
        /home/miloertas/Packages/go/src/web-service/internal/handlers (from $GOPATH)

It's important that my source code remains in this src directory. It is equally important that I am able to run and build my code from the root of my project (For example the .env file is located at the root of the repository).

I am therefore looking for a way to run or build my code in the src directory from the root of my project.

I tried moving the go.mod at the root of the project and running and ran go run ./src but this causes issues of its own:

  • The go command is now unable to locate all the sub-packages in internal and pkg
  • VSCode is now lost and executing tests is impossible for some reasons (Mainly because all sub-packages are not found).
Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
Diego ROJAS
  • 509
  • 1
  • 7
  • 14
  • 5
    I dunno why the question got heavily downvoted, really. While it displays lack of what one could call ground knowledge of Go's do-s and dont-s, I'd say it's rather well formulated and clearly shows that the OP did their research before posting. – kostix Nov 11 '20 at 16:59
  • One would have expected something like `go build ./src/...` to work, or that there would be a common option meaning _"this is the project root where my go.mod is, work from here"_ like `go build --root src ./...` but obviously I live in fantasyland. Perhaps fall back to a good old fashioned `Makefile` and encode your targets and commands there, wrapped up in `(cd src; go build ./...)`. – Ed Randall Feb 25 '22 at 09:14

2 Answers2

6

Since Go 1.18, it's now possible to achieve this with Go workspaces.

Using the following directory structure

parent-dir/
└─ go.work
   hello-world/
   ├─ go.mod
   └─ main.go

You can run the hello-world module from the parent-dir using go run hello-world.

go.work

go 1.18

use ./hello-world

go.mod

module hello-world

go 1.18

Note: it is possible, not recommended as pointed out by @Volker

Diego ROJAS
  • 509
  • 1
  • 7
  • 14
2

It's important that my source code remains in this src directory. It is equally important that I am able to run and build my code from the root of my project (For example the .env file is located at the root of the repository).

These two requirements are contradictory. You have to let go of one.

Especially the second one is unfounded: Do not use go run, use go build. Make the path to look for the .env file a command line option to your program (Go is not PHP or JavaScript, there simply is no project or source root for the executing binary). Or build the executable somewhere but execute it in you project root.

Note that having a src folder is -- to put it mildly -- uncommon.

I tried moving the go.mod at the root of the project and running and ran go run ./src but this causes issues of its own:

Well, start by not using go run at all, use go build. And then try building the actual main package. All the go tooling works best on packages, not on file system folders. If your module is named playing.hardball/for-unspecific-reasons and package main is in src try go build playing.hardball/for-unspecific-reasons/src.

Takeaways even if this doesn't work out the way you want:

  • Do not use go run. The reasons are manyfold, it is useful to run single file scripts and a loaded footgun for basically every other use case.
  • The go tool works on import paths. In simple cases the import path can be inferred from the filesystem.
  • A compiled executable has no notion of a "project directory", "source", "classpath" or whatever, it is a standalone executable runnable everywhere and completely detached from its sources.
  • Make all filesystem lookup path a configuration option (cmdline flag or environment variable); provide practical defaults (e.g. ./); use that when running your executable to announce where to find static stuff like .env files, templates, icons, css files, etc.
Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
Volker
  • 40,468
  • 7
  • 81
  • 87
  • 2
    I was looking to know whether this was possible as in "Is there a way". I am aware that my design choices are highly unusual and not "best practice" but that's not my point.Thanks anyways. – Diego ROJAS Nov 11 '20 at 07:44
  • 4
    Okay: No there is no way to do it _exactly_ the way you want. You must redesign at least some aspects of your solution. – Volker Nov 11 '20 at 07:47
  • 2
    Okay, I think I'm going to change my layout. Thank you. I suggest you specify that it cannot be achieved at the top of your answer to avoid confusion. – Diego ROJAS Nov 11 '20 at 08:45
  • 2
    _"Note that having a src folder is -- to put it mildly -- uncommon."_ - probably because the go tooling is so damn opinionated and inflexible, it's nigh-on impossible, as the OP has found. The proposed layout makes perfect sense if you live in a heterogeneous world of multi-module-type development. – Ed Randall Feb 25 '22 at 09:08