Golang undefined variable - go

I have 2 go files:
/Users/username/go/src/Test/src/main/Test.go
package main
import "fmt"
func main() {
fmt.Printf(SomeVar)
}
and file /Users/username/go/src/Test/src/main/someFile.go
package main
const SomeVar = "someFile"
However I am constantly getting compiler error:
/Users/username/go/src/Test/src/main/Test.go:6: undefined: SomeVar
Can someone explain to me why is SomeVar labeled as undefined?

Try
go run Test.go someFile.go

Quote:
I think you're misunderstanding how the go tool works. You can do "go
build" in a directory, and it'll build the whole package (a package is
defined as all .go files in a directory). Same for go install, go
test, etc. Go run is the only one that requires you to specify
specific files... it's really only meant to be used on very small
programs, which generally only need a single file.
So do:
go build && ./program_name
See also

You code is correct:
someFile.go and Test.go belong to the same package (main)
SomeVar is a const declared at top level, so it has a package block scope, namely the main package block scope
as a consequence, SomeVar is visible and can be accessed in both files
(if you need to review scoping in Go, please refer to the Language Specification - Declarations and Scope).
Why do you get an undefined error then?
You probably launched go build Test.go or go run Test.go, both producing the following output, if launched from /Users/username/go/src/Test/src/main:
# command-line-arguments
./Test.go:6: undefined: SomeVar
You can find the reason here: Command go
If you launch go build or go run with a list of .go files, it treats them as a list of source files specifying a single package, i.e., it thinks there are no other pieces of code in the main package, hence the error.
The solution is including all the required .go files:
go build Test.go someFile.go
go run Test.go someFile.go
go build will also work with no arguments, building all the files it finds in the package as a result:
go build
Note 1: the above commands refer to the local package and, as such, must be launched from the /Users/username/go/src/Test/src/main directory
Note 2: though other answers already proposed valid solutions, I decided to add a few more details here to help the community, since this is a common question when you start working with Go :)

Due to landing on this page when I had a similar question, I'll include this answer alongside of what has already been stated. If you are using go run you may use:
go run . or go run .*
This question was also answered on this question
How to run all .go files within current directory through the command line (multi file package)

Related

Understanding How to Build Go Source

I am confused about how to layout my Go project and then how to build it. I am reasonably new to Go and believe there was a time <1.13 where the GOPATH was important. I am using 1.14, so I believe I do not have to care about that and GOPATH is not set. I do not (for the moment) host my code on GitHub (which is something various articles assume). I have read a number of things, but it all leaves me more confused:
https://golang.org/cmd/go/#hdr-Compile_packages_and_dependencies
https://www.wolfe.id.au/2020/03/10/starting-a-go-project/
https://talks.golang.org/2014/organizeio.slide#1
I have laid out my project according to this: https://github.com/golang-standards/project-layout. (Except this project seems to use a Makefile. I do not want to write a Makefile. I believe this should all work without a Makefile. I really do not want to write a Makefile.)
Here is the structure:
/src
/cmd
main.go
/internal
helper.go
go.mod
go.mod looks like this:
module mycompany/mymodule
go 1.14
service.go looks as follows
package main // this has to be called 'main'
import (
"mycompany/mymodule/internal/helper"
)
func main () {
helper.greet("Jenny")
}
So, if I am in /src and I run build cmd/service.go I get
cmd/service.go:4:2: package mycompany/mymodule/internal/helper is not in GOROOT (/usr/local/Cellar/go/1.14.5/libexec/src/mycompany/mymodule/internal/helper)
Do I have to compile helper.go first? Manually? Surely not. go build surely should be able to build my entire project, right? Including all the dependencies. Could someone please tell me what I am missing?
When you run go build without specifying file path, it will look for the main function inside any .go files at current directory to start. It doesn't build entire project. But it wouldn't be a problem in this case.
You're importing wrong package. The package name to import must be mycompany/mymodule/internal not mycompany/mymodule/internal/helper.
And to invoke a function inside another package, it must be exposed to outside.
So you have to declare the function greet() as Greet()

"undefined" function declared in another file?

I'm trying to write a basic go program that calls a function on a different file, but a part of the same package. However, it returns:
undefined: NewEmployee
Here is the source code:
main.go:
package main
func main() {
emp := NewEmployee()
}
employee.go:
package main
type Employee struct {
name string
age int
}
func NewEmployee() *Employee {
p := &Employee{}
return p
}
func PrintEmployee (p *Employee) {
return "Hello world!"
}
Please read "How to Write Go Code".
Use go build or go install within the package directory, or supply an import path for the package. Do not use file arguments for build or install.
While you can use file arguments for go run, you should build a package instead, usually with go run ., though you should almost always use go install, or go build.
I just had the same problem in GoLand (which is Intellij IDEA for Go) and worked out a solution. You need to change the Run kind from File to Package or Directory. You can choose this from a drop-down if you go into Run/Edit Configurations.
Eg: for package ~/go/src/a_package, use a Package path of a_package and a Directory of ~/go/src/a_package and Run kind of Package or Directory.
If you're using go run, do go run *.go. It will automatically find all go files in the current working directory, compile and then run your main function.
You can try one of the following:
Method 1:
Assume that your project name is MyProject
Go to your path, run go build
It will create an executable file as your project name ("MyProject")
Then run the executable using ./MyProject
You can do both steps at once by typing go build && ./MyProject. Go files of the package main are compiled to an executable.
Method 2:
Just run go run *.go. It won't create any executable but it runs.
go run . will run all of your files. The entry point is the function main() which has to be unique to the main package.
Another option is to build the binary with go build and run it.
If you want to call a function from another go file and you are using Goland, then find the option 'Edit configuration' from the Run menu and change the run kind from File to Directory. It clears all the errors and allows you to call functions from other go files.
you should use go modules now, if you are not following How to write go code
With go module you don't have to put the code in the $GOPATH/src. it can live in any other location as well.
You can move the code to different directory like /employee, To make it work Just under employee directory initialise the go module
go mod init example.com/employee
I ran into the same issue with Go11, just wanted to share how I did solve it for helping others just in case they run into the same issue.
I had my Go project outside $GOPATH, so I had to turned on GO111MODULE=on without this option turned on, it will give you this issue; even if you you try to build or test the whole package or directory it won't be solved without GO111MODULE=on
While this doesn't directly address the OP's specific issue, I thought I'd chime in with the solution to my "undefined" error: the file with the undefined method had a build constraint (build tag).
More specifically, I accidentally included a build constraint to remove testing files from my deployed application binary in a utility function file used by my deployed binary. So in the OP's example - if employee.go had a build constraints their go build command would need to include a -tags flag matching the constraint in in order to have the file included.
For more info read this blog post:
https://dave.cheney.net/tag/build-constraints
Took a while to drill down my own MRE for this, so hopefully it will help others, despite being brief:
This can also occur if your functions / structs are defined in a file that has import "C", which will be silently ignored if CGO_ENABLED=0 is in your go environment, leading to you staring at a two file package that somehow is unable to share between themselves.
In GoLand,
right click a directory
GoLand will give you the option for build it and run it
it will also create a run configuration draft for you
you can save with an option of the upper right dropdown
If you right clic a file, it shows you commands to run, debug, test that file.
If you right clic a directory, it will be the same for that "package", expecting a main.go file inside the directory
I had a nasty import "C" in one of my go files.
If your source folder is structured /go/src/blog (assuming the name of your source folder is blog).
cd /go/src/blog ... (cd inside the folder that has your package)
go install
blog
That should run all of your files at the same time, instead of you having to list the files manually or "bashing" a method on the command line.
Off topic but still :-)
Before:
func NewEmployee() *Employee {
p := &Employee{}
return p
}
After:
func NewEmployee() *Employee {
return &Employee{}
}
No need to create a new variable. Just return.

Importing local library and files in an application

I'm new to Go (but not at programming), I love the language but I have a bit of trouble fully understanding the way I'm supposed to make internal libraries in an application through packages. For reference, getting external packages and then importing/using them is fine.
Let's say I'm making an application A.
/home/me/A/a.go (package main)
Then, I realize a.go start to be rather big, so I cut it into two parts
/home/me/A/a.go (package main)
/home/me/A/b.go (package main)
How am I supposed to import/include b.go from a.go to make its function available ?
As a continuation of the question, in the A I'm manipulation lots of objects O, so I figure it would be a lot better if I just give them their own package and encapsulate the functionalities in a public/exported api. How do I do that ?
I've tried creating ./lib/o.go (package o) and import lib/o but I keep getting error like
./a.go:6: imported and not used: "o"
./a.go:43: undefined: o
I have no GOPATH in my env but I tried export GOPATH=$GOPATH:/home/me/A and it didn't change the result.
I've tried to read the article on "go layout" but it felt a bit too overwhelming at once and I would really love a simpler explanation of that one "small" step I am trying to make
Thanks !
GOPATH/src/me/a/a.go:
package main
func main() {
test()
}
GOPATH/src/me/a/test.go:
package main
import "fmt"
func test() {
fmt.Println("test func !")
}
Exec:
$ go run a.go
# command-line-arguments
./a.go:4: undefined: test
EDIT: got my answer here: https://groups.google.com/forum/?fromgroups#!topic/golang-nuts/qysy2bM_o1I
Either list all files in go run (go run a.go test.go) or use go build and run the resulting executable.
You're trying to use the Go build system while not following the necessaary required directory layouts. You will benefit a lot from reading this document.
In short, these are, wrt the go tool, the show stoppers:
You must have a valid, exported GOPATH
Package files with import path "example/foo" must be located in the $GOPATH/src/example/foo directory.
For more details please see the above linked article.

go test can't find function in a same package

The directory structure is :
src
src/pkg
src/pkg/t1.go
src/pkg/t1_test.go
t1.go
package pkg
import (
"fmt"
)
func SayHI(){
fmt.Println("this is t1")
}
t1_test.go
package pkg
import (
"testing"
)
func TestXYZ(t *testing.T) {
SayHI()
}
Invoke go test from command line at dir src/pkg
go test t1_test.go
error:
./t1_test.go:8: undefined: SayHI
FAIL command-line-arguments [build failed]
but the function is there
thanks for any hints
It is working as intended.
jnml#fsc-r630:~/src/pkg$ go help test
usage: go test [-c] [-i] [build flags] [packages] [flags for test binary]
'Go test' automates testing the packages named by the import paths.
It prints a summary of the test results in the format:
ok archive/tar 0.011s
FAIL archive/zip 0.022s
ok compress/gzip 0.033s
...
followed by detailed output for each failed package.
'Go test' recompiles each package along with any files with names matching
the file pattern "*_test.go". These additional files can contain test functions,
benchmark functions, and example functions. See 'go help testfunc' for more.
By default, go test needs no arguments. It compiles and tests the package
with source in the current directory, including tests, and runs the tests.
The package is built in a temporary directory so it does not interfere with the
non-test installation.
In addition to the build flags, the flags handled by 'go test' itself are:
-c Compile the test binary to pkg.test but do not run it.
-i
Install packages that are dependencies of the test.
Do not run the test.
The test binary also accepts flags that control execution of the test; these
flags are also accessible by 'go test'. See 'go help testflag' for details.
For more about build flags, see 'go help build'.
For more about specifying packages, see 'go help packages'.
See also: go build, go vet.
jnml#fsc-r630:~/src/pkg$
In other words:
go test is okay.
go test pkg (assuming $GOPATH is ~ and the package is in ~/src/pkg) is okay.
go test whatever_test.go is not okay as that is not supported as documented above.
To select which tests to run use the -run <regular_expression> flag (where the <regular_expression> is interpreted as having wildcards on either end, like .*<regular_expression>.*). For example
$ go test -run Say # from within the package's directory
or
$ go test -run Say my/package/import/path # from anywhere
This is somewhat strange in Golang. To be honest it took me some time to figure a way out.
A simple work-around is to include them in the command, eg:
go test src/pkg/t1.go src/pkg/t1_test.go
IMHO, The best way is to keep it clean. So avoid having more than 1 file as dependency per test file. If you are using +1 file as dependency, consider creating a black-box test with a _test package and do not make use of any lowerCase internal vars.
This will avoid you having to deal with complicated dependencies on your day to day testing.
Run
go test ./...
This will find all the tests in all test files. To run individual tests, specify the dependencies like here.
I came across this Stackoverflow question after encountering the exact same issue myself: specifically, attempting to run go test and then seeing a build failure indicating that the function in question isn't defined. I see that this question is somewhat old now (asked 8 years ago) but in my case the issue was that I was attempting to write code in Go 1.16 that seems to now assume the presence/use of modules. See this page for a starting reference on modules and easy follow-along example.
All I had to do in my case was run go mod init [module name] and after that I could run go test without any issues.
Hopefully this is of some value to users coming to this page after using a more modern (1.16+) version of Go.

Build and reference my own local package in Go

I'm playing with Google Go and I'm having fun (!), but I'm having some problems with package subsystem.
I'm running Go 1.0.1 on Mac OS X Lion. I've build also various single file programs without problems (I've also build a small webapp using html/templates without problems and it compiles and runs without any error).
I've defined a "reusable" package (even.go):
package even
func Even(i int) bool {
return i % 2 == 0
}
func Odd(i int) bool {
return i % 2 == 1
}
and a consumer program (useeven.go):
package main
import (
"./even"
"fmt"
)
func main() {
a := 5
b := 6
fmt.Printf("%d is even %v?\n", a, even.Even(a))
fmt.Printf("%d is odd %v?\n", b, even.Odd(b))
}
But when I compile the "library" using
go build even.go
I got nothing... No errors, no message... What happens?
How should I do this?
The answer to your question, "How should I do this?" is explained in How to Write Go Code. It's really pretty important stuff and worth taking a look at.
The behavior of go build might seem puzzling, but is actually conventional for command line programs--no output means that the program ran successfully. So what did it do? For that your answer is in go help build
... Otherwise build compiles the packages but discards the results,
serving only as a check that the packages can be built.
What, you wanted more? Of course. "How to Write Go Code" explains good ways of doing this. For a quick fix to your program, I'll explain that the go command expects each package and each executable program to be in a separate directory. If you just make a directory called even, immediately under the location of useeven.go, and move even.go to it, then go run useeven.go should run just as you have it.
go build only generates an output file when it builds a "single main package". If you want to output a file for your other package you should use go install. That will build and install that package to your pkgs directory.
As noted in a comment by the OP, go build and go run useeven.go work fine, once you put even.go in its own folder: ./even/even.go. There is a bit of Go magic in the ./ (in the import) that makes the "local package" build automatically without requiring it to be installed anywhere.
useeven/
├── even
│   └── even.go
└── useeven.go
If you wanted to make this work without the magic ./, then the library need to be installed. A quick-and-dirty way (at the risk of polluting your library namespace) of making this work for your project is to simply register the library's source location by using a symbolic link like so (in this example GOPATH is ~/go):
[ useeven ]
$ ln -s $(pwd)/even ~/go/src
Now when you build the program, it automatically performs a go get even to install an up-to-date version of your library.
Note that this doesn't make go install* work for the library, it just makes doing that unnecessary.
There are more idiomatic ways of doing this, if you're not in a hurry: How to import local packages in go?
The reason that output is not being generated here is because you're running the
go build even.go
command on the package and not the main go file. Doing so on the package will check for errors on the package, but because it's not a main with an output, no success messages will be generated. If there are issues with the package's contents, errors will be displayed, otherwise if it compiles fine there will be no output
Instead, you should run:
go build useeven.go
To create the binary, then to execute the binary and get output from the program:
./useeven

Resources