command-line-arguments : handling "undefined" error message - go

Following is how the source files are organized
✘-1 ~/Go/src/github.com/krmahadevan/packages
18:24 $ tree .
.
├── sample_main.go
└── sample_one.go
0 directories, 2 files
Here's how the source code looks like:
sample_one.go
package main
var data map[string]string
func init() {
data = make(map[string]string, 0)
}
sample_main.go
package main
import "fmt"
func main() {
data["foo"] = "bar"
fmt.Println(data)
}
Now when I attempt at running sample_main.go I get errors stating that data is undefined.
18:24 $ go run sample_main.go
# command-line-arguments
./sample_main.go:6:2: undefined: data
./sample_main.go:7:14: undefined: data
✘-2 ~/Go/src/github.com/krmahadevan/packages
But when I build the code into a binary and then execute it, it runs fine.
✔ ~/Go/src/github.com/krmahadevan/packages
18:27 $ go build
✔ ~/Go/src/github.com/krmahadevan/packages
18:28 $ ./packages
map[foo:bar]
✔ ~/Go/src/github.com/krmahadevan/packages
I would like to understand why is this behavior ?
Environment:
18:31 $ go version
go version go1.11.4 darwin/amd64
The closest I found was this post : Golang : command-line-arguments undefined: variable
But this post talks about scoped variables that are defined in main.
But my problem statement involves variables defined in another go file and accessed in the main method.

To understand why, read the go command documentation:
Command go
Compile and run Go program
Usage:
go run [build flags] [-exec xprog] package [arguments...]
Run compiles and runs the named main Go package. Typically the package
is specified as a list of .go source files, but it may also be an
import path, file system path, or pattern matching a single known
package, as in 'go run .' or 'go run my/cmd'.
Compile packages and dependencies
Usage:
go build [-o output] [-i] [build flags] [packages]
Build compiles the packages named by the import paths, along with
their dependencies, but it does not install the results.
If the arguments to build are a list of .go files, build treats them
as a list of source files specifying a single package.
For more about specifying packages, see 'go help packages'. For more
about where packages and binaries are installed, run 'go help gopath'.
go run: Typically the package is specified as a list of .go source files.
For your go run example, list the files:
go run sample_main.go sample_one.go

To fix it, just run the following command:
Windows: go run * or go build *
Unix: go run . or go build .
You are going to run it inside the folder of the files you want to use.

Related

How to stop Go 1.11 from building quicktemplate .qtpl files?

I have some Go packages that use quicktemplate. Quicktemplate compiles template files with the .qtpl extension to Go files with the .qtpl.go extension using the qtc CLI app. In Go versions prior to 1.11, having .qtpl files in a Go package wasn't a problem as the .qtpl files would be ignored by the compiler. However, Go 1.11 appears to process .qtpl files, causing compilation failures.
An example that works with Go 1.3-1.10 but not 1.11 is available here and described below.
Source: https://github.com/grokify/gocharts/tree/master/charts/c3
Build Logs: https://travis-ci.org/grokify/gocharts/builds/431794367 (Go 1.0-1.11)
The package directory contains:
timeseries_page.qtpl template file
timeseries_page.qtpl.go template file compiled to Go using qtc
Previously, only the file ending in .go would be compiled and everything builds fine. With 1.11, there is an error thrown while parsing the .qtpl file which isn't intended to be built by the Go compiler.
Here is a minimal Go program using that package will fail to build in Go 1.11, but work with 1.10.
package main
import (
"github.com/grokify/gocharts/charts/c3"
)
func main() {
_ = c3.C3Chart{}
}
Here's the error showing the timeseries_page.qtpl file:
$ go build main.go
# github.com/grokify/gocharts/charts/c3
timeseries_page.qtpl:42: undefined: TimeseriesHTML
timeseries_page.qtpl:48: undefined: TimeseriesHTML
TimeseriesHTML is a function that is called in that template file and built by another quicktemplate file in the timeseries_js.qtpl.go file.
The same result and output is encountered with the following:
$ go run main.go
$ go test main.go
Is there a way to get back the prior Go behavior, or ignore .qtpl files during builds?

Command line application install using GoLang

I'm not sure how this would work but I'm basically trying to write a command line app that I can run commands and subcommands from. I'm using this popular third party library for parsing command line parameters:
https://github.com/urfave/cli
My problem is I have a project folder where my .go files will live:
MyProject
so even if in the code in my main.go file, using their example, I have:
package main
import (
"fmt"
"os"
"github.com/urfave/cli"
)
func main() {
app := cli.NewApp()
app.Name = "greet"
app.Usage = "fight the loneliness!"
app.Action = func(c *cli.Context) error {
fmt.Println("Hello friend!")
return nil
}
app.Run(os.Args)
}
when I run go install,
in my $GOPATH/bin directory, I actually get MyProject built. And then when I run MyProject from the terminal, I get
USAGE:
myproject [global options] command [command options] [arguments...]
But in reality, I don't need the myproject command first. Is there a way this is normally done with command line apps or third party packages to create command line apps so that I can run greet from the command line instead of myproject as the first command?
Check the documentation for the go build command
go build [-o output] [-i] [build flags] [packages]
When compiling a single main package, build writes the resulting
executable to an output file named after the first source file ('go
build ed.go rx.go' writes 'ed' or 'ed.exe') or the source code
directory ('go build unix/sam' writes 'sam' or 'sam.exe'). The '.exe'
suffix is added when writing a Windows executable.
When compiling multiple packages or a single non-main package, build
compiles the packages but discards the resulting object, serving only
as a check that the packages can be built.
The -o flag, only allowed when compiling a single package, forces
build to write the resulting executable or object to the named output
file, instead of the default behavior described in the last two
paragraphs.
Try building it like this go build -o greet and do not forget to add the resulting executable to your $PATH if you want it to be accessible from everywhere.
Alternatively, you can just 1) create an alias; or 2) symlink to the actual executable:
alias greet='myproject'
ln -s $GOPATH/bin/myproject greet (the link will be created in the current dir)

How can I "go run" a project with multiple files in the main package?

I have a single file in the main package called main.go. Because the code isn't reusable I want to separate part of the code in a different file but in the same package.
How do I split the contents of main.go into multiple files without creating a separate package?
I want a directory structure like this:
ls foo
# output:
main.go
bar.go
File: bar.go
package main
import "fmt"
func Bar() {
fmt.Println("Bar")
}
File: main.go
package main
func main() {
Bar()
}
When I run go run main.go, it gives me:
# command-line-arguments
./main.go:4:2: undefined: Bar
Update 26th July 2019 (for go >=1.11)
go run .
Will work on windows as well.
Original answer (for non windows environments)
The code actually works. The problem was that instead of running go run main.go I should run:
go run *.go
Update August 2018, with Go 1.11, a section "Run" states:
The go run command now allows a single import path, a directory name or a pattern matching a single package.
This allows go run pkg or go run dir, most importantly go run .
Original answer Jan. 2015
As mentioned in "How to compile Go program consisting of multiple files?", go run expects a list of files, since it "compiles and runs the main package comprising the named Go source files".
So you certainly can split your main package in several files with go run.
That differs from go build/go install which expect package names (and not go filenames).
A simple go build would produce an executable named after the parent folder.
Note that, as illustrated by this thread, a go run *.go wouldn't work in a Windows CMD session, since the shell doesn't do wildcard expansion.
In my opinion, the best answer to this question is hidden in the comments to the top answer.
Just run this:
go run .
This will run all the files in main package, but will not give an error message like
go run: cannot run *_test.go files (main_test.go)
Kudos to #BarthesSimpson
As mentioned, you can say go run *.go but for Windows you can just list the script files (since *.go won't work) - go run main.go other.go third.go
The first method to do so will be to run
go run *.go
The another method is to generate an exe file
go build
Then run that .exe file
./filename.exe
Multiple options
go run .
go run *.go
make run using Makefile where, add any of the above command as build target.
for testing
go test ./...
make test using Makefile with go test ./... as build target
For Windows install Cygwin and use it instead of command prompt. "go run *.go" will work then.
If you are trying to run multiple files on localhost using gorilla mux in go as per latest version(1.11). Try using any of the following 2 commands.
go install && FolderName -port 8081 .
go build && ./FolderName -port 8081.
Make sure that you are in the source folder ie go/src/FolderName before executing the command in the Terminal.

How to compile Go program consisting of multiple files?

I have a small program that consists of three files, all belonging to the same package (main). But when I do go build main.go the build doesn't succeed. When it was just one file (main.go), everything worked fine.
Now that I took some effort to separate the code, it looks like the compiler is unable to find the stuff that was taken out of main.go and put into these two other files (that reside in the same directory as the main.go). Which results in undefined 'type' errors.
How to compile this program that consists of multiple files?
New Way (Recommended):
Please take a look at this answer.
Old Way:
Supposing you're writing a program called myprog :
Put all your files in a directory like this
myproject/go/src/myprog/xxx.go
Then add myproject/go to GOPATH
And run
go install myprog
This way you'll be able to add other packages and programs in myproject/go/src if you want.
Reference : http://golang.org/doc/code.html
(this doc is always missed by newcomers, and often ill-understood at first. It should receive the greatest attention of the Go team IMO)
When you separate code from main.go into for example more.go, you simply pass that file to go build/go run/go install as well.
So if you previously ran
go build main.go
you now simply
go build main.go more.go
As further information:
go build --help
states:
If the arguments are a list of .go files,
build treats them as a list of source files specifying a single package.
Notice that go build and go install differ from go run in that the first two state to expect package names as arguments, while the latter expects go files. However, the first two will also accept go files as go install does.
If you are wondering: build will just build the packages/files, install will produce object and binary files in your GOPATH, and run will compile and run your program.
Since Go 1.11+, GOPATH is no longer recommended, the new way is using Go Modules.
Say you're writing a program called simple:
Create a directory:
mkdir simple
cd simple
Create a new module:
go mod init github.com/username/simple
# Here, the module name is: github.com/username/simple.
# You're free to choose any module name.
# It doesn't matter as long as it's unique.
# It's better to be a URL: so it can be go-gettable.
Put all your files in that directory.
Finally, run:
go run .
Alternatively, you can create an executable program by building it:
go build .
# then:
./simple # if you're on xnix
# or, just:
simple # if you're on Windows
For more information, you may read this.
Go has included support for versioned modules as proposed here since 1.11. The initial prototype vgo was announced in February 2018. In July 2018, versioned modules landed in the main Go repository.
In Go 1.14, module support is considered ready for production use, and all users are encouraged to migrate to modules from other dependency management systems.
You could also just run
go build
in your project folder myproject/go/src/myprog
Then you can just type
./myprog
to run your app
It depends on your project structure. But most straightforward is:
go build -o ./myproject ./...
then run ./myproject.
Suppose your project structure looks like this
- hello
|- main.go
then you just go to the project directory and run
go build -o ./myproject
then run ./myproject on shell.
or
# most easiest; builds and run simultaneously
go run main.go
suppose your main file is nested into a sub-directory like a cmd
- hello
|- cmd
|- main.go
then you will run
go run cmd/main.go
You can use
go build *.go
go run *.go
both will work also you may use
go build .
go run .
Yup! That's very straight forward and that's where the package strategy comes into play. there are three ways to my knowledge.
folder structure:
GOPATH/src/
github.com/
abc/
myproject/
adapter/
main.go
pkg1
pkg2
warning: adapter can contain package main only and sun directories
navigate to "adapter" folder. Run:
go build main.go
navigate to "adapter" folder. Run:
go build main.go
navigate to GOPATH/src
recognize relative path to package main, here "myproject/adapter". Run:
go build myproject/adapter
exe file will be created at the directory you are currently at.

How do I make go find my package?

Where should I put my package so that it can be imported by another package?
$ tree
.
├── main.go
└── src
└── test.go
1 directory, 2 files
$ cat src/test.go
package test
$ cat main.go
package main
import "test"
$ go build main.go
main.go:3:8: import "test": cannot find package
Set your GOPATH. Put your package foo source(s) in GOPATH/src/optional-whatever/foo/*.go and use it in code as
import "optional-whatever/foo"
You don't need to explicitly install foo, the go tool is a build tool, it will do that automagically for you whenever necessary.
There are a few things that need to happen. You must install the "test" package first:
$ export GOPATH=$(pwd) # Assumes a bourne shell (not csh)
$ mkdir src/test
$ mv src/test.go src/test/test.go
$ mkdir pkg # go install will put packages here
$ go install test # build the package and put it in $GOPATH/pkg
$ go build main.go
Note that it is not necessary to create pkg, as go install will do that for you.
Once you've installed the test package (generally a bad name, BTW) go build main.go should now give different errors (eg, "imported and not used")
maybe, you can put the test.go file in the same directory with the main.go, and
in test.go, it uses something like this:
import "./test"

Resources