Setup Go on Fedora 24 (and other Linux distributions)

This guide will be how I usually setup and get started with Go development environment on Linux. By the end of this document, we will have seen how to:

  • Install the Go compiler and other tools (gofmt, for eaxmple), collectively referred to as go tools
  • Setup Go workspace
  • Working with Go programs using third-party packages

Installing Go tools

The first option to install the Go compiler and other tools from your distro's package manager. On Fedora 24, you can do sudo dnf -y install golang for example. This will install 1.6 version of the Go tools. However, if your distro's packaged version is behind the upstream release we can follow the official install guide to get the latest stable version of the Go tools:

  • Download the Linux binary tarball from the Downloads page
  • sudo tar -C /usr/local -xzf <filename-from-above>
  • export PATH=$PATH:/usr/local/go/bin in your .bashrc or similar file.

When we now open a new terminal session, we should be able to type in go version and get the version we installed:

$ go version
go version go1.6.2 linux/amd64

If we see this, we are all set to go to the next stage

Setting up the Go workspace

Golang expects us to structure our source code in a certain way. You can read all about it in this document. The summarized version is that:

  • All our go code (including those of packages we use) in a single directory
  • The environment variable GOPATH points to this single directory
  • This single directory has three sub-directories: src, bin, pkg
  • It is in the src sub-directory where all our Go code will live

For this guide I will assume that the GOPATH is set to $HOME/work/golang:

$ mkdir -p $HOME/work/golang
$ mkdir -p $HOME/work/golang/src $HOME/work/golang/bin $HOME/work/golang/pkg

At this stage, our $GOPATH directory tree looks like this:

$ tree -L 1 work/golang/
work/golang/
├── bin
├── pkg
└── src

Next, we will add the line export GOPATH=$HOME/work/golang in the .bashrc (or another similar file). If we now start a new terminal session, we should see that GOPATH is now setup correctly:

$ go env GOPATH
/home/asaha/work/golang

You can learn more about GOPATH here.

Writing our first program

There are two types of Golang programs we can write - one is an application program (output is an executable program) and the other is a package which is meant to be used in other programs. We will first write a program which will be compiled to an executable.

First, create a directory tree in src for our package:

$ mkdir -p work/golang/src/github.com/amitsaha/golang_gettingstarted

Our package name for the above directory tree becomes github.com/amitsaha/golang_gettingstarted. Then, type in the following in work/golang/src/github.com/amitsaha/golang_gettingstarted/main.go:

package main

import (
         "fmt"
)

func main() {
         fmt.Printf("Hello World\n")
}

Next, build and run the program as follows:

$ go run work/golang/src/github.com/amitsaha/golang_gettingstarted/main.go
Hello World

Great! Our program compiled and ran successfully. Our workspace at this stage only has a single file - the one we created above:

... code:

$ tree
.
├── bin
├── pkg
└── src
         └── github.com
                 └── amitsaha
                         └── golang_gettingstarted
                             └── main.go

Installing Go applications

Now, let's say that the program above was actually a utility we wrote and we want to use it regularly. Where as we could execute go run as above, but the more convenient approach is to install the program. go install command is used to build and install Go packages. Let's try it on our package:

$ go install github.com/amitsaha/golang_gettingstarted/

You can execute this command from anywhere on your filesystem. Go will figure out the path to the package from GOPATH we set above. Now, you will see that there is a golang_gettingstarted executable file in the $GOPATH/bin directory:

$ tree work/golang/
work/golang/
├── bin
│   └── golang_gettingstarted
├── pkg
└── src
     └── github.com
         └── amitsaha
                └── golang_gettingstarted
                         └── main.go

We can try executing the command:

$ ./work/golang/bin/golang_gettingstarted
Hello World

As a shortcut, we can just execute $GOPATH/bin/golang_gettingstarted. But, you wouldn't need to even do that if $GOPATH/bin is in your $PATH. So, if you want, you can do that and then you could just specify golang_gettingstarted and the program would be executed.

Working with third-party packages

Let's now replace the main.go file above by the example code from the package pb which lets us create nice progress bars:

package main

import (
     "gopkg.in/cheggaaa/pb.v1"
    "time"
)

func main() {
    count := 100000
    bar := pb.StartNew(count)
    for i := 0; i < count; i++ {
        bar.Increment()
        time.Sleep(time.Millisecond)
    }
    bar.FinishPrint("The End!")
}

Let's try and install this package:

$ go install github.com/amitsaha/golang_gettingstarted
golang/src/github.com/amitsaha/golang_gettingstarted/main.go:6:5: cannot find package "gopkg.in/cheggaaa/pb.v1" in any of:
     /usr/lib/golang/src/gopkg.in/cheggaaa/pb.v1 (from $GOROOT)
     /home/asaha/work/golang/src/gopkg.in/cheggaaa/pb.v1 (from $GOPATH)

Basically, this tells us that Go compiler is not able to find the package gopkg.in/cheggaaa/pb.v1. So, let's get it:

  $ go get  gopkg.in/cheggaaa/pb.v1

This will download the package and place it in ``$GOPATH/src``:

.. code::

   $ tree -L 3 $GOPATH/src/
    /home/asaha/work/golang/src/
    ├── github.com
            │   └── amitsaha
            │       └── golang_gettingstarted
    └── gopkg.in
            └── cheggaaa
                   └── pb.v1

If we now install our package again, it will build correclty and an executable golang_gettingstarted will be placed in $GOPATH/bin:

$ go install github.com/amitsaha/golang_gettingstarted
$ $GOPATH/bin/golang_gettingstarted
 100000 / 100000 [======================================================================================================]100.00% 1m49s
 The End!

Golang package objects

If we now display the directory contents of $GOPATH, we will see:

$ tree -L 2 golang/
golang/
    ├── bin
    │    └── golang_gettingstarted
    ├── pkg
    │   └── linux_amd64
    └── src
        ├── github.com
        └── gopkg.in

The contents in pkg sub-directory are referred to as package objects - basically built Golang packages. This is the difference from application programs (programs having package main). This question from a while back on the golang-nuts group may be interesting to read.

If you are to keen to learn more:

That's all for now, you can find the simple source code above here.