compiling projects with multiple files in go - compilation

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

Related

How to clear the execution cache in go

When I use flag package
// main.go
import (
...
"flag"
)
func main() {
...
flag.Parse()
switch flag.Arg(0) {
case "doSomething1":
...
case "doSomething2":
...
}
}
If doSomething1 argument print some error message for me, whatever I fix the source code, it can not remove the old error code and compile again.
// command-line
# go build ./main.go
# ./main doSomething1
# error doSomething1 can not work
-- I fix my code
# ./main doSomething1
# error doSomething1 can not work
-- the error message also show me again
-- I have to delete main and build again
# rm ./main
# go build ./main.go
# ./main.go doSomething1
# doSomething1 now can work
Go is a compiled language. When you run go build, it will compile your sources and create an executable binary. This is what you run when executing ./main doSomething1.
When you change your sources and run ./main doSomething1, you are not compiling again, you just run the previously built (and unchanged) binary.
To quickly test changes, use go run instead:
go run main.go doSomething1
That will always compile your sources, build a binary in a temporary folder, launch it and clear it once your app exits.
For details, see What does go build build?

configure [go build]/[go test] etc to show absolute paths in diagnostic messages

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.

Go + GoLand calling function in other file

Directory layout:
~ cd $GOPATH
~ tree src/simple
src/simple
└── main
├── main.go
└── other.go
main.go:
package main
import "fmt"
func main() {
fmt.Println("This is in main. calling somefunc...")
somefunc()
fmt.Println("done. bye :)")
}
other.go:
package main
import "fmt"
func somefunc() {
fmt.Println("This is in somefunc in other.go")
}
This works fine with go build:
~ cd $GOPATH/src/simple/main/
~ go build
~ ./main
This is in main. calling somefunc...
This is in somefunc in other.go
done. bye :)
From within the GoLand IDE, If I run, I get:
main/main.go:7:2: undefined: somefunc
Normally, there is editor highlighting of all syntax errors. The somefunc call is treated as valid syntax in the editor but when I run it doesn't work. I can even cmd-click into the function to jump to the definition.
This is with GoLand 2018.2.3 and go version go1.11
In GoLand create a Run Configuration Run -> Edit Configurations based on Go Build template and set
Name: Build (or whatever you like)
Run kind: Directory
Directory: /Users/gopher/go/src/simple/main/
^^^^^^
Run after build: checked
Working directory: /Users/gopher/go/src/simple
Change /Users/gopher/go/ part accordingly, to match your actual path of $GOPATH
And then Run -> Build the project
This is in main. calling somefunc...
This is in somefunc in other.go
done. bye :)
Process finished with exit code 0

Is there a way to define a constant at build time in Go?

I have a program in Go that I want to compile in a bunch of binaries, each having a const value defined differently. More clearly, I have something like that:
const wordLen = 6
type knowledge [wordLen]byte
Here, wordLen is associated with the value 6, but I want to have different binaries, with values ranging from 5 to 10. I could make it a variable, and then use a slice rather than an array, but that would have a huge performance impact on my soft (yes, I tried).
I would love to have some build tag on go build argument to indicate what the value of wordLen is for a given binary. So, what is the (as idiomatic as possible) way to do this ?
Yes, this is possible using Build Constraints.
You can supply a list of these constraints to go build using the -tags flag.
Example:
main.go
package main
import "fmt"
func main() {
fmt.Println(f)
}
foo.go
// +build foo
package main
const f = "defined in foo.go"
bar.go
// +build bar
package main
const f = "defined in bar.go"
Compiling the code with different tags will give different results:
$ go build -tags foo
$ ./main
defined in foo.go
$ go build -tags bar
$ ./main
defined in bar.go
It doesn't solve your exact problem but it may solve others so I add for compelteness that you can use the -ldflags option of the go compiler:
go build -ldflags "-X main.wordLen=6"
Its however has two downsides:
Only works for strings
Only works on vars

Can I make gotest pass compiler flags?

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`.

Resources