whyme
whyme

Reputation: 253

Protocol buffers in Go: cannot find package

I'm following the Protocol Buffer for Go tutorial but I have the following problem:

  1. I create the addressbook proto definition
syntax = "proto3";
package tutorial;

message Person {
  string name = 1;
...
}
  1. I successfully run the compiler and generate the go code
  2. I try to import the pb package but it fails

Here is exactly what happens: I specifying the --go_out to be same as my proto definition: (protoc --go_out=. addressbook.proto)

then in same folder, I create a test.go with these simple lines:

package main

import "tutorial"

but go build test.go returns error:

test.go:3:8: cannot find package "tutorial" in any of:
    /usr/local/go/src/tutorial (from $GOROOT)
    /home/vagrant/go2/src/tutorial (from $GOPATH)

then I change test.go to this:

package main

import "protobufs/tutorial"

and get this error:

test.go:3:8: cannot find package "protobufs/tutorial" in any of:
    /usr/local/go/src/protobufs/tutorial (from $GOROOT)
    /home/vagrant/go2/src/protobufs/tutorial (from $GOPATH)

but if I change the import to only:

package main

import "protobufs"

it finds that there's a "tutorial" package in that location:

test.go:3:8: found packages tutorial (addressbook.pb.go) and main (list_people.go) in /home/vagrant/go2/src/protobufs

What am I doing wrong ? How should the import look like in order to make this work ?

Thank you !

FYI: a snippet of my go env:

GOARCH="amd64"
GOBIN="/home/vagrant/go2/bin"
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/vagrant/go2"
GORACE=""
GOROOT="/usr/local/go"

Upvotes: 2

Views: 3998

Answers (2)

Izana
Izana

Reputation: 3135

check GO workspace:

A workspace is a directory hierarchy with two directories at its root:

src contains Go source files, and
bin contains executable commands.

The tutorial is based on this structure, i.e.,

src/
    github.com/protocolbuffers/protobuf/examples/
      tutorial/
         addressbook.pb.go
      list_address.go

In the makefile of that tutorial, it generates pb.go under examples dir through:

mkdir -p tutorial
protoc $$PROTO_PATH --go_out=tutorial addressbook.proto

Under the add_person.go, it just assumes the import path is under worksapce/src, which is $GOPATH/src mentioned above:

import (
....

pb "github.com/protocolbuffers/protobuf/examples/tutorial"
// find through $GOPATH/src/github.com/protocolbuffers/protobuf/examples/tutorial
)

What you need to do is to set the right GOPATH and generate that pb.go under $GOPATH/src

protoc -I=. --go_out=/Users/guihaoliang/Playground/go/my_workspace/src addressbook.proto

where . refers to where the addressbook.proto is located.

The GOPATH workspace is going to be superseded by go modules so that you don't have to maintain the src and bin structure. The protobuf example is not using the new module structure.

Upvotes: 0

whyme
whyme

Reputation: 253

This question showed my lack of understanding of Go's packaging. After some reading, here are my conclusions/rules:
1. one package per folder: all the .go files in directory "abc" will indicate package abc
2. you can't have package main and package abc in same folder
3. go install creates package object abc.a in $GOPATH/pkg/GOOS_GOARCH/<path_to_abc_excluding_abc>
4. for the package main in folder $GOPATH/src/x/y/z/foo/ then go install compiles and installs an executable called foo (the name of the last directory in the path) in $GOPATH/bin

Now, back to the initial question: the directory $GOPATH/src/protobufs contains multiple packages:
- the compiled protobuf with the package name tutorial and
- the main package in test.go
This contradicts with the above listed rules.

I believe that one elegant solution is:
- assuming I'm in $GOPATH/src/protobufs
- create a subdir called tutorials
- install the compiled protobuf in that subdir: protoc --go_out=./tutorial ./addressbook.proto
- the test.go can now have package main and import "protobufs/tutorial"

Thanks for putting on the right track !

Upvotes: 2

Related Questions