I have just put together a Go package that is going to be a part in a fairly large system with a lot of shared packages. I was able to get it to compile by writing its Makefile such that the compiler is called with -I flags:
include $(GOROOT)/src/Make.inc
TARG=foobar
GOFILES=\
foobar.go\
foobar:
$(GC) -I$(CURDIR)/../intmath -I$(CURDIR)/../randnum foobar.go
include $(GOROOT)/src/Make.pkg
It compiles just fine, and being a good boy, I wrote a comprehensive set of tests. However, when I try to run the tests with gotest, I get a compile error:
$ gotest
rm -f _test/foobar.a
8g -o _gotest_.8 foobar.go foobar_test.go
foobar.go:4: can't find import: intmath
make: *** [_gotest_.8] Error 1
gotest: "C:\\msys\\bin\\sh.exe -c \"gomake\" \"testpackage\" \"GOTESTFILES=foobar_test.go\"" failed: exit status 2
So, the Go file itself will compile when I use the -I flags to tell it where to find the intmath and randnum packages, but gotest doesn't seem to use the Makefile.
Answering peterSO's question:
foobar.go's import section looks like this:
import (
"intmath"
"randnum"
"container/vector"
)
And the compile works fine as long as I have the -I flags going to the compiler. I have tried to use relative paths, like this:
import (
"../intmath"
"../randnum"
"container/vector"
)
but that just doesn't seem to work.
EDIT: answering further peterSO questions:
GOROOT is set to C:\Go the directory where I have all of the Go stuff -- aside from my source code -- installed. I was expecting the relative path to be relative to the directory in which the source file lives.
My source tree looks like this:
server/
foobar/
randnum/
intmath/
So, while I am open to a different, more Go-idiomatic directory structure, my instinct is to arrange them as peers.
Is there some way that I can nudge gotest into compiling foobar.go with the needed flags?
Create the Windows source code directory structure:
C:\server
C:\server\foobar
C:\server\intnum
For intnum.go:
package intnum
func IntNum() int {
return 42
}
Makefile:
include $(GOROOT)/src/Make.inc
TARG=server/intnum
GOFILES=\
intnum.go\
include $(GOROOT)/src/Make.pkg
Run:
$ cd c/server/intnum
$ make install
For foobar.go:
package foobar
import (
"math"
"server/intnum"
)
func FooBar() float64 {
return float64(intnum.IntNum()) * math.Pi
}
Makefile:
include $(GOROOT)/src/Make.inc
TARG=server/foobar
GOFILES=\
foobar.go\
include $(GOROOT)/src/Make.pkg
Run:
$ cd /c/server/foobar
$ make install
After the install, the intnum.a and foobar.a package files will be in the $GOROOT\pkg\windows_386\server (C:\Go\pkg\windows_386\server) directory`.
Related
I have 2 .proto files in the same directory such that second.proto is dependent on first.proto
second.proto
import "first.proto"
enum ThingINeed {
...something
}
I have no problem running these commands:
$ protoc --go_out=generatedsources/first -I. first.proto
$ protoc --go_out=generatedsources/second -I. second.proto
so the directory structure looks something like
src
|-first.proto
|-second.proto
|-generatedsources
|-first
|-first.pb.go
|-second
|-second.pb.go
My problem is that when I run
$ cd generatedsources/second
$ go build second.pb.go
I recieve a "./second.pb.go: Undefined: ThingINeed" since second.pb.go uses ThingINeed from first.pb.go (seen in first.proto as well)
I notice that second.pb.go doesn't have an import . "generatedsources/first" line in it. When I put it in manually, it works just fine. But I mean, I'm not supposed to edit these .pb.go files, so was wondering how to fix this. I also would very rather not edit these .proto files.
Would appreciate any help!
I'm wondering how to properly reference external proto files. Say I've got a .proto file which references standard protobuf types such as Timestamp:
syntax = "proto3";
package api;
import "google/protobuf/timestamp.proto";
message ServerTimeResponse {
google.protobuf.Timestamp ts = 1;
}
Easy. Timestamp is automatically available when compiling.
Now I add an external
type, say google.rpc.Status:
syntax = "proto3";
package api;
import "google/protobuf/timestamp.proto";
import "google/rpc/status.proto";
message ServerTimeResponse {
google.protobuf.Timestamp ts = 1;
google.rpc.Status status = 2;
}
Of course we have to tell protoc how to find this file where it is via -I/--proto_path.
My question is this: What is the best practice for actually referencing this file, in particular to make version control happy? There appears not to be a go mod equivalent for protobufs. I've seen it copied verbatim into projects (such as in grpc-gateway) or just referenced from the local filesystem.
I think you sort of answered your own question here. I've done both successfully: manually copied the necessary files in verbatim (from https://github.com/googleapis/googleapis/tree/master/google and https://github.com/protocolbuffers/protobuf/tree/master/src/google/protobuf), and referenced local copies of the files.
If you want to do this and make version control happy, you could add these two repositories as git submodules inside your repository. Just make sure to pass the right locations to protoc using -I. E.g.:
cd $PROJECT_DIR
mkdir third_party && cd third_party
git submodule add https://github.com/googleapis/googleapis/tree/master/google
cd $PROJECT_DIR
<git commit the change>
protoc -I third_party/google <the rest of your protoc command>
As for referencing local copies of the files, and making sure they're present before attempting to build, you may find that adding something like the following to your Makefile will help (this is in a Go build environment):
go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway
go get -u github.com/golang/protobuf/protoc-gen-go
grpc_gateway_path=$(go list -m -f '{{.Dir}}' github.com/grpc-ecosystem/grpc-gateway)
googleapis_path="$grpc_gateway_path/third_party/googleapis"
protoc -I $googleapis_path --go_out=. <list of input files>
Is there a way to configure/direct go build, go test etc to report file locations using absolute paths? I frequently run go build from my editor (which parses the output) and it would be convenient if the current working directory of the go build process and the editor itself did not need to match.
So far, the only solution I've found is to wrap go build in a script that determines absolute paths to files, then immediately cds to a temporary directory before invoking go build with the realpath'd original arguments.
Creating a temporary directory and cd'ing to it just to trick the go tools seems like a bizarre workaround, so I'm wondering if there's a more direct solution.
Is there a way to configure the go tools to report absolute paths besides wrapping them and cding to random directories?
Suppose that my GOPATH is /go and that I have the following file.
// /go/src/nonexistent-website.com/example-2019-10-26/main.go
package main
import (
"fmt"
)
func main() {
fmt.Println("hi")
}
Suppose I intentionally introduce an error in this file.
// /go/src/nonexistent-website.com/example-2019-10-26/main.go
package main
// import (
// "fmt"
// )
func main() {
fmt.Println("hi")
}
go build main.go reports the following error:
/go/src/nonexistent-website.com/example-2019-10-26$ go build main.go
# command-line-arguments
./main.go:9: undefined: fmt in fmt.Println
2
go build ... still reports ./main.go as the path to the file if given an absolute path
/go/src/nonexistent-website.com/example-2019-10-26$ go build `realpath main.go`
# command-line-arguments
./main.go:9: undefined: fmt in fmt.Println
2
go build seems to produce paths relative to the directory it was invoked from:
These are the paths that go build produces when directed to cd to the root directory first.
/go/src/nonexistent-website.com/example-2019-10-26$ (a=`realpath main.go` && cd / && go build $a)
# command-line-arguments
go/src/nonexistent-website.com/example-2019-10-26/main.go:9: undefined: fmt in fmt.Println
2
It's possible to coax go build into emitting absolute paths by cd-ing to a directory that's guaranteed to be fresh
/go/src/nonexistent-website.com/example-2019-10-26$ (a=`realpath main.go` && cd `mktemp -d` && go build $a)
# command-line-arguments
/go/src/nonexistent-website.com/example-2019-10-26/main.go:9: undefined: fmt in fmt.Println
2
Is there a way to configure the go tools to report absolute paths besides wrapping them and cding to random directories?
No.
I have a project structured like this:
Makefile
src/
main.ml
tests/
tests.ml
and the Makefile is something like this:
tests:
ocamlbuild -Is src,tests tests.byte -build-dir $(BUILDDIR) $(TESTFLAGS) -lflags -I,/usr/lib/ocaml/oUnit -cflags -I,/usr/lib/ocaml/oUnit -libs oUnit
Running make tests (after building main.byte) returns this error:
ocamlbuild -Is src,tests tests.byte -build-dir build -lflags -I,/usr/lib/ocaml/oUnit -cflags -I,/usr/lib/ocaml/oUnit -libs oUnit
+ /usr/bin/ocamlc -c -I /usr/lib/ocaml/oUnit -I tests -I src -o tests/tests.cmo tests/tests.ml
File "tests/tests.ml", line 3, characters 46-50:
Error: Unbound value main
Command exited with code 2.
Compilation unsuccessful after building 2 targets (0 cached) in 00:00:00.
make: *** [tests] Error 10
showing that ocamlbuild cannot link to main.byte. What should the tests rule of the Makefile look like?
Since OCaml programs don't have a default main function (OCaml just runs the top-level code in each module at start-up) you'll probably want to have a separate file for starting the code. e.g.
main.ml
myprog.ml
tests.ml
Where:
main.ml defines a main function let main args = ...
myprog.ml just calls it: let () = Main.main Sys.argv
tests.ml calls it in the same way from each test-case
Then build myprog.byte and tests.byte as your two targets to ocamlbuild. Run myprog.byte to run the program and tests.byte to run the tests.
unbound value main does not sound like an error related to main.byte, but a genuine mistake in the OCaml code of tests.ml. Could you provide (possibly simplified) sources to experiment?
(Thomas' advice on program structure of course still stands, independently.)
I use gccgo to compile my projects. here is my directory layout. I read this Q/A thread How to use custom packages in golang?
so followed this one
src/
+-fibo/
| +-fibo.go
+main.go
and here are the code listing
main.go
package main
import (
"os"
"fmt"
"strconv"
"src/fibo"
)
func main(){
if len(os.Args) < 2 {
fmt.Printf("ur input sucks\n")
}
num,_ := strconv.Atoi(os.Args[1])
fibo.Fibo(num)
}
fibo/fibo.go
package fibo
import "fmt"
func Fibo(num int) {
var a,b int
for i :=0; i< num; i++ {
a, b = b, a+b
fmt.Print(a, " ")
}
fmt.Print("\n")
}
but when I try to compile, i follwed usual gcc procedure. compile files separately and link them together into final executable. I get this error
.../go-lang-expts/src $ gccgo -c -ofibo/fibo.o fibo/fibo.go
.../go-lang-expts/src $ gccgo -c -omain.o main.go
main.go:7:10: error: import file ‘src/fibo’ not found
main.go:18:2: error: reference to undefined name ‘fibo’
.../go-lang-expts/src $
I am stuck here. I tried different combination of directory structures. none helped. what am I missing? is there any environment variable I should set, even for this??
It looks like you may not have set the GOPATH Environment Variable
From How to Write Go Code
The GOPATH environment variable specifies the location of your workspace. It is likely the only environment variable you'll need to set when developing Go code.
Given your current directory structure of
src/
+-fibo/
| +-fibo.go
+main.go
If your src directory is under GOPATH then you should be able to just do:
import "fibo"
in main.go.
See also "GOPATH environment variable" from The go command documentation.
This set of commands worked for me.
.../go-lang-expts/src $ gccgo -c -fgo-pkgpath=fibo -ofibo/fibo.o fibo/fibo.go
This will name the package fibo, so you will have to import it as such in main.go
import "fibo"
Now you can compile main.go by telling where fibo.o library is
.../go-lang-expts/src $ gccgo -c main.go -Ifibo
Then you need to link the two file to create an executable main
.../go-lang-expts/src $ gccgo -o main main.o fibo/fibo.o