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

cmd/go: clarify go.mod documentation for trivial relative modules #27274

Closed
gazed opened this issue Aug 27, 2018 · 8 comments
Closed

cmd/go: clarify go.mod documentation for trivial relative modules #27274

gazed opened this issue Aug 27, 2018 · 8 comments
Labels
Documentation FrozenDueToAge modules NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone

Comments

@gazed
Copy link

gazed commented Aug 27, 2018

What version of Go are you using (go version)?

go version go1.11 darwin/amd64

Does this issue reproduce with the latest release?

Yes.

What operating system and processor architecture are you using (go env)?

GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/rust/Library/Caches/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/rust/code"
GOPROXY=""
GORACE=""
GOROOT="/usr/local/go"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/Users/rust/code/modtest/b/go.mod"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/_d/8n_wrc4n32d1rgx80bn6hsl80000gn/T/go-build056371648=/tmp/go-build -gno-record-gcc-switches -fno-common"

What did you do?

Created two modules a and b in the same directory, not on the GOPATH.

Module a contains a.go, go.mod:

~/code/modtest/a: cat a.go
package a

func Hello() string {
	return "Hello"
}
~/code/modtest/a: cat go.mod
module a

Module b contains b.go, go.mod:

~/code/modtest/b: cat b.go
package main

import (
    "fmt"

    "a"
)

func main() {
	fmt.Printf("%s\n", a.Hello())
}
~/code/modtest/b: cat go.mod 
module b

require ../a v0.0.0

What is the proper syntax for the line require ../a v0.0.0 in this particular case?
The closest I found in the docs (go help modules, go help go.mod, go help mod) was from go help importpath:

Relative import paths

An import path beginning with ./ or ../ is called a relative path.
The toolchain supports relative import paths as a shortcut in two ways.

First, a relative path can be used as a shorthand on the command line.
...

Second, if you are compiling a Go program not in a work space,
you can use a relative path in an import statement in that program
to refer to nearby code also not in a work space.
This makes it easy to experiment with small multipackage programs
outside of the usual work spaces, but such programs cannot be
installed with "go install" (there is no work space in which to install them),
so they are rebuilt from scratch each time they are built.
To avoid ambiguity, Go programs cannot use relative import paths
within a work space.

It is unclear to me if the second case is supposed to apply in this situation.

What did you expect to see?

I expect this to compile and run similarly to how it works with the existing GOPATH.
For example, copying the modules to the GOPATH gives the following:

~/code/src: cd a
~/code/src/a: go build
~/code/src/a: cd ../b
~/code/src/b: go build
~/code/src/b: ./b
Hello

What did you see instead?

~/code/modtest: cd a
~/code/modtest/a: go build
~/code/modtest/a: cd ../b
~/code/modtest/b: go build
go: ../a@v0.0.0: unrecognized import path "../a" (https fetch: Get https://../a?go-get=1: dial tcp: lookup ..: no such host)
go: error loading module requirements
~/code/modtest/b: 
@thepudds
Copy link
Contributor

Setting aside for the moment the question of whether the documentation could be improved, here is a concrete example that might help.

Sample file structure on my local system, all outside of GOPATH:

    /tmp/playground/hello
    |-- go.mod
    `-- hello.go
    /tmp/playground/goodbye
    |-- go.mod
    `-- goodbye.go

And the contents of /tmp/playground/hello/go.mod:

    module example.com/me/hello

    require (
     example.com/me/goodbye v0.0.0
     rsc.io/quote v1.5.2
    )

    replace example.com/me/goodbye => ../goodbye

See a longer discussion and the rest of the example here (which is a runnable example if you are interested):
https://groups.google.com/d/msg/golang-nuts/1nYoAMFZVVM/eppaRW2rCAAJ

@thepudds
Copy link
Contributor

@gopherbot please add label modules

@gazed
Copy link
Author

gazed commented Aug 27, 2018

Thank you for the working module solution. Setting aside for the moment whether or not this is the canonical solution moving forward, it breaks when moving the code to the GOPATH, making the code non-backwards compatible. Is there another solution that works without changing the source code files? Otherwise it feels like a missing feature or a bug, instead of "a me not finding the right documentation" problem as I had assumed.

Here is the original problem source updated to work with modules.

~/code/modtest/a: cat a.go
package a

func Hello() string {
	return "Hello"
}
~/code/modtest/a: cat go.mod 
module example.com/me/a
~/code/modtest/a: go build
~/code/modtest/a: cd ../b
~/code/modtest/b: cat b.go 
package main

import (
    "fmt"
    
    "example.com/me/a"
)

func main() {
	fmt.Printf("%s\n", a.Hello())
}
~/code/modtest/b: cat go.mod 
module example.com/me/b

require example.com/me/a v0.0.0

replace example.com/me/a => ../a
~/code/modtest/b: go build
~/code/modtest/b: ./b
Hello

Moving both modules into the GOPATH results in the following:

~/code/src: cd a
~/code/src/a: go build
~/code/src/a: cd ../b
~/code/src/b: go build
b.go:6:2: cannot find package "example.com/me/a" in any of:
	/usr/local/go/src/example.com/me/a (from $GOROOT)
	/Users/rust/code/src/example.com/me/a (from $GOPATH)

@thepudds
Copy link
Contributor

If you return to the GOPATH world, then you would place the go source code back where Go 1.10 and earlier would expect it based on the import paths you are using in the code.

E.g., something like $GOPATH/src/example.com/me/a/a.go?

If you don't like that example.com, then you don't need to use it in your go.mod and corresponding import paths.

And sorry if I am misunderstanding; this is all new...

@gazed
Copy link
Author

gazed commented Aug 27, 2018

Thank you for your patience, adding just the replace a => ../a works. Thank you!

~/codeold/modtest: cd a
~/codeold/modtest/a: cat a.go 
package a

func Hello() string {
	return "Hello"
}
~/codeold/modtest/a: cat go.mod 
module a
~/codeold/modtest/a: cd ../b
~/codeold/modtest/b: cat b.go
package main

import (
    "fmt"
    "a"
)

func main() {
	fmt.Printf("%s\n", a.Hello())
}
~/codeold/modtest/b: cat go.mod
module b

require a v0.0.0

replace a => ../a

@FiloSottile FiloSottile added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Aug 30, 2018
@FiloSottile FiloSottile added this to the Go1.12 milestone Aug 30, 2018
@FiloSottile FiloSottile changed the title cmd/go: Please clarify go.mod documentation for trivial relative modules. cmd/go: clarify go.mod documentation for trivial relative modules Aug 30, 2018
@klaus
Copy link

klaus commented Aug 31, 2018

it's important to note, that you need the "require" AND the "replace" in the go.mod file.
I like to add them via the commandline, the commands should be encouraged and documented with examples.

the go mod init command does not populate go.mod with packages it cannot resolve. Therefore you must do:

go mod edit require example.com/post-adressdaten
go mod edit -replace example.com/post-adressdaten=../post-adressdaten/

@myitcv
Copy link
Member

myitcv commented Sep 7, 2018

@klaus

I like to add them via the commandline, the commands should be encouraged and documented with examples.

They are documented under go help mod edit

That a replace requires (!) a require is something that is going to be addressed in Go 1.12 via #26241

I'm going to close this issue on the basis I think all questions have been answered, but please shout it not.

@myitcv myitcv closed this as completed Sep 7, 2018
@dfang
Copy link

dfang commented Jul 19, 2019

@myitcv how about this case ?

/tmp/modtest1X9IT λ  tree
.
├── cmd
│   └── main.go
├── go.mod
└── handler.go

1 directory, 3 files
/tmp/modtest1X9IT λ  cat go.mod
module modtest

go 1.12
/tmp/modtest1X9IT λ  cat handler.go
package handler

import (
    "fmt"
)

func Handler() {
	fmt.Println("hello")
}
/tmp/modtest1X9IT λ  cat cmd/main.go
package main

import "handler"

func main() {
	// how to call handler.Handler here
	handler.Handler()
}

how to call handler.Handler in cmd/main.go if code is not hosted on github but on cloud storage or private google cloud source repo ?

I'd like to run cmd/main.go like this codelab for testing handler locally

thanks !

@golang golang locked and limited conversation to collaborators Jul 18, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Documentation FrozenDueToAge modules NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
None yet
Development

No branches or pull requests

7 participants