Introduction

This document explains how to write a new package and how to test code. It assumes you have installed Go using the installation instructions.

Before embarking on a change to an existing package or the creation of a new package, be sure to send mail to the mailing list to let people know what you are thinking of doing. Doing so helps avoid duplication of effort and enables discussions about design before any code has been written.

Community resources

For real-time help, there may be users or developers on #go-nuts on the Freenode IRC server.

The official mailing list for discussion of the Go language is Go Nuts.

Bugs can be reported using the Go issue tracker.

For those who wish to keep up with development, there is another mailing list, golang-checkins, that receives a message summarizing each checkin to the Go repository.

Creating a new package

The source code for the package with import path x/y is, by convention, kept in the directory $GOROOT/src/pkg/x/y.

Makefile

It would be nice to have Go-specific tools that inspect the source files to determine what to build and in what order, but for now, Go uses GNU make. Thus, the first file to create in a new package directory is usually the Makefile. The basic form used in the Go source tree is illustrated by src/pkg/container/vector/Makefile:

include ../../../Make.inc

TARG=container/vector
GOFILES=\
	intvector.go\
	stringvector.go\
	vector.go\

include ../../../Make.pkg

Outside the Go source tree (for personal packages), the standard form is

include $(GOROOT)/src/Make.inc

TARG=mypackage
GOFILES=\
	my1.go\
	my2.go\

include $(GOROOT)/src/Make.pkg

The first and last lines include standard definitions and rules. Packages maintained in the standard Go tree use a relative path (instead of $(GOROOT)/src) so that make will work correctly even if $(GOROOT) contains spaces. This makes it easy for programmers to try Go.

If you have not set $GOROOT in your environment, you must run gomake to use this form of makefile. Gomake also takes care to invoke GNU Make even on systems where it is installed as gmake rather than make.

TARG is the target install path for the package, the string that clients will use to import it. Inside the Go tree, this string should be the same as the directory in which the Makefile appears, with the $GOROOT/src/pkg/ prefix removed. Outside the Go tree, you can use any TARG you want that doesn't conflict with the standard Go package names. A common convention is to use an identifying top-level name to group your packages: myname/tree, myname/filter, etc. Note that even if you keep your package source outside the Go tree, running make install installs your package binaries in the standard location—$GOROOT/pkg—to make it easy to find them.

GOFILES is a list of source files to compile to create the package. The trailing \ characters allow the list to be split onto multiple lines for easy sorting.

If you create a new package directory in the Go tree, add it to the list in $GOROOT/src/pkg/Makefile so that it is included in the standard build. Then run:

cd $GOROOT/src/pkg
./deps.bash

to update the dependency file Make.deps. (This happens automatically each time you run all.bash or make.bash.)

If you change the imports of an existing package, you do not need to edit $GOROOT/src/pkg/Makefile but you will still need to run deps.bash as above.

Go source files

The first statement in each of the source files listed in the Makefile should be package name, where name is the package's default name for imports. (All files in a package must use the same name.) Go's convention is that the package name is the last element of the import path: the package imported as "crypto/rot13" should be named rot13. There is no requirement that package names be unique across all packages linked into a single binary, only that the import paths (their full file names) be unique.

Go compiles all the source files in a package at once, so one file can refer to constants, variables, types, and functions in another file without special arrangement or declarations.

Writing clean, idiomatic Go code is beyond the scope of this document. Effective Go is an introduction to that topic.

Building programs

To build a Go program with gomake, create a Makefile alongside your program's source files. It should be similar to the example above, but include Make.cmd instead of Make.pkg:

include $(GOROOT)/src/Make.inc

TARG=helloworld
GOFILES=\
	helloworld.go\

include $(GOROOT)/src/Make.cmd

Running gomake will compile helloworld.go and produce an executable named helloworld in the current directory.

Running gomake install will build helloworld if necessary and copy it to the $GOBIN directory ($GOROOT/bin/ is the default).

Testing

Go has a lightweight test framework known as gotest. You write a test by creating a file with a name ending in _test.go that contains functions named TestXXX with signature func (t *testing.T). The test framework runs each such function; if the function calls a failure function such as t.Error or t.Fail, the test is considered to have failed. The gotest command documentation and the testing package documentation give more detail.

The *_test.go files should not be listed in the Makefile.

To run the test, run either make test or gotest (they are equivalent). To run only the tests in a single test file, for instance one_test.go, run gotest one_test.go.

If your change affects performance, add a Benchmark function (see the gotest command documentation) and run it using gotest -test.bench=..

Once your new code is tested and working, it's time to get it reviewed and submitted.

An example package with tests

This example package, numbers, consists of the function Double, which takes an int and returns that value multiplied by 2. It consists of three files.

First, the package implementation, numbers.go:

package numbers

func Double(i int) int {
	return i * 2
}

Next, the tests, numbers_test.go:

package numbers

import (
	"testing"
)

type doubleTest struct {
	in, out int
}

var doubleTests = []doubleTest{
	doubleTest{1, 2},
	doubleTest{2, 4},
	doubleTest{-5, -10},
}

func TestDouble(t *testing.T) {
	for _, dt := range doubleTests {
		v := Double(dt.in)
		if v != dt.out {
			t.Errorf("Double(%d) = %d, want %d.", dt.in, v, dt.out)
		}
	}
}

Finally, the Makefile:

include $(GOROOT)/src/Make.inc

TARG=numbers
GOFILES=\
	numbers.go\

include $(GOROOT)/src/Make.pkg

Running gomake install will build and install the package to the $GOROOT/pkg/ directory (it can then be used by any program on the system).

Running gomake test (or just running the command gotest) will rebuild the package, including the numbers_test.go file, and then run the TestDouble function. The output "PASS" indicates that all tests passed successfully. Breaking the implementation by changing the multiplier from 2 to 3 will allow you to see how failing tests are reported.

See the gotest documentation and the testing package for more detail.

Architecture- and operating system-specific code

First, a disclaimer: very few Go packages should need to know about the hardware and operating system they run on. In the vast majority of cases the language and standard library handle most portability issues. This section is a guide for experienced systems programmers who have a good reason to write platform-specific code, such as assembly-language support for fast trigonometric functions or code that implements a common interface above different operating systems.

To compile such code, use the $GOOS and $GOARCH environment variables in your source file names and Makefile.

For example, this Makefile describes a package that builds on different operating systems by parameterizing the file name with $GOOS.

include $(GOROOT)/src/Make.inc

TARG=mypackage
GOFILES=\
	my.go\
	my_$(GOOS).go\

include $(GOROOT)/src/Make.pkg

The OS-specific code goes in my_linux.go, my_darwin.go, and so on.

If you follow these conventional parameterizations, tools such as goinstall will work seamlessly with your package:

my_$(GOOS).go
my_$(GOARCH).go
my_$(GOOS)_$(GOARCH).go

The same holds for .s (assembly) files.