How to compile Go program consisting of multiple files? - go

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.

Related

How do go modules work with installable commands?

I've recently started with Go 1.11 and love the modules. Apart from runtime dependencies I need to work with go modules during the build, e.g. during go generate.
How can I install a specific build dependency (e.g. github.com/aprice/embed/cmd/embed) and run that specific tool from which folder? Is go get the right tool for doing so?
If you get an error
I was not seeing the dependency that I wanted added to the go.mod and I was getting this error:
internal/tools/tools.go:6:5: import "github.com/UnnoTed/fileb0x" is a program, not an importable package
(fileb0x is the thing I'm trying to add)
I'm not 100% clear on the sequence of events that fixed it, but I did all of these things:
Using a "tools" package
I made a tools directory:
mkdir -p internal/tools
I put the tools package inside of it (as mentioned above):
internal/tools/tools.go:
// +build tools
package tools
import (
_ "github.com/UnnoTed/fileb0x"
)
Note that the tag is mostly not important. You could use foo:
// +build foo
However, you cannot use ignore. That's a special predefined tag.
// +build ignore
// NO NO NO NO NO
// `ignore` is a special keyword which (surprise) will cause
// the file to be ignore, even for dependencies
Updating go.mod
The best way is probably to run go mod tidy:
go mod tidy
However, before I did that I ran a number of commands trying to figure out which one would cause it to go into go.mod:
go install github.com/UnnoTed/fileb0x # didn't seem to do the trick
go get
go generate ./...
go build ./...
go install ./...
go mod vendor
Later I did a git reset and rm -rf ~/go/pkg/mod; mkdir ~/go/pkg/mod and found that go mod tidy did well enough on its own.
vendoring
In order to actually take advantage of the modules cache in a project you need to copy-in the source code
go mod vendor
That will grab all dependencies from go.mod
You also need to change nearly all of your go commands to use -mod=vendor in any Makefiles, Dockerfiles or other scripts.
go fmt -mod=vendor ./... # has a bug slated to be fixed in go1.15
go generate -mod=vendor ./...
go build -mod=vendor ./...
That includes go build, go get, go install, and any go run called by go generate (and even the go generate itself)
//go:generate go run -mod=vendor github.com/UnnoTed/fileb0x b0x.toml
package main
// ...
https://github.com/golang/go/issues/25922 proved helpful for me, especially
when using build-only dependencies with modules the main point is version selection (not installing these!)
To avoid installing you can modify your //go:generate directive to something like:
//go:generate go run golang.org/x/tools/cmd/stringer ARGS
There is also the best practices repo: https://github.com/go-modules-by-example/index/blob/master/010_tools/README.md
The convention is to add a file named "tools.go" that is guarded by a build constraint and imports all required tools:
// +build tools
package tools
import (
_ "github.com/aprice/embed/cmd/embed"
)
https://github.com/golang/go/issues/25922#issuecomment-412992431
The tools are then installed as usual in one of
$GOBIN
$GOPATH/bin
$HOME/go/bin
You may also want to follow https://github.com/golang/go/issues/27653, which discusses future explicit support for tools.
tools.go is a great solution if you're building an app or service. But if you're building a library, tools.go still leaks dependencies to things consuming your library (your tools are still there as indirect dependencies, and go mod tidy will pull them in since it considers every possible target). That's not the end of the world since those modules never end up in the actual built binaries of the consumer, but it's still messy.
https://github.com/myitcv/gobin/issues/44 is probably the most promising approach to fixing this long term, but short term I've used a combination of the "internal module" approach explained there along with https://github.com/izumin5210/gex.
First, I install gex globally:
GO111MODULE=off go get github.com/izumin5210/gex/cmd/gex
Then before actually using gex I create a structure like this:
myproject/
\
- go.mod: module github.com/ysamlan/myproject
\
internal/
\
tools/
- go.mod: module github.com/ysamlan/myproject/tools
To install a build-only tool I just cd internal/tools and run gex --add (sometool), which puts that tool in internal/tools/bin. CI scripts and other folks that want to build my stuff locally just need to run cd internal/tools && gex --build to reliably and reproducibly populate the tool binaries, but the top-level go.mod is unchanged.
The key piece there is creating that internal/tools/go.mod file with a different module path than the one the root project uses, and then only running gex from that directory.

Standalone install for file like go run myfile.go

I have a go project that consists of separate files (each having a main function) inside the project folder. Initially it was meant to be run as go run file1.go. But now I need a build for it like regular projects. Creating separate project for each file feels dumb.
The go run compiles input file into a temporary executable and executes it. What is the compilation step that go run does. I need to install different files as separate executables (with a name given by me). Can anyone give the steps on how to do this.
Thanks.
As shown in the comments, you can use
go install ./...
If your working directory is not where all your packages are currently located, use
go install path/to/your/packages/...
The important thing are the three dots "...", indicating you want to build and install all packages from sub-directories as well.
This will create executables of all your packages in $GOPATH/bin/ .

Go: How does go run file.go work

The commands go build and go install compile the files into binaries. Does go run compile or interpret the file? I couldn't find explanations online and may have missed it. Appreciate pointers. Thanks!
It's more or less the equivalent of running go build X.go -o /tmp/random-tmp-folder/exe && /tmp/random-tmp-folder/exe
The go run command compiles and runs a main package comprised of the .go files specified on the command line. The command is compiled to a temporary folder.
The go build and go install examine the files in the directory to determine which .go files are included in the main package.
Command go run performs project's building under the hood (so yes it builds project)
and with flag --work (go run --work main.go) you can see the location of temporary build files.
Also in official documentation (go1.11) you can find:
go run - compiles and runs the named main Go package.
go build - compiles the packages named by the import paths,
along with their dependencies, but it does not install the results.
go install - compiles and installs the packages named by the import paths.
Unlike in java, where the bytcode is created and interpreted at the execution time, go creates an executable file that is dependent on the machine being used,like in c, c++.

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.

GOPATH and Go Web Server: 'go run myserver.go'

I'm at the point where want to organize my Go web server into packages. Currently I have everything in a few files and I simply type: 'go run server.go foo.go bar.go'
How do I organize my files so I don't need to keep adding files to the command line. I've investigated the GOPATH variable but it doesn't seem to work.
export GOPATH=$HOME/myserver
I moved my files to the src/ subdirectory.
myserver/src/server.go
myserver/src/foo.go
myserver/src/bar.go
Shouldn't 'go run' search $HOME/myserver/src for all go files?
I've tried these examples but they don't work.
go run server.go; # Doesn't work
go run src/server.go; # Doesn't work
By the way, all files are in 'package main'
This info is covered really well on golang.org
Read this about how to write Go code
And this about organizing go code
Tip: you can run go run * to run all files in a folder
Your above example should look something like this
$GOPATH=$HOME
The GOPATH should have:
$GOPATH
src/
pkg/
bin/
$GOPATH/src is where you would store your source code for each go project
$GOPATH/src/myserver would contain your myserver program
cd to $GOPATH/src/myserver and run go install and you would now have your myserver binary located at $GOPATH/bin/myserver
Add the location of your bin to your path export PATH=$PATH:$GOPATH/bin and you can run myserver to start your go program
go run will look for a file (or wildcard) in your current working directory.
If you would like to run your programs from anywhere, either use go build same as you would go run and move the binaries where appropriate or, better yet, set your $GOBIN environment variable and add it your $PATH -- then run go install * in your project directory.
It's also probably a good idea to make specific directories for projects instead just dumping it all in $GOPATH/src

Resources