From 718de6f4c64a439a867dd0b8aad05f7da630bf76 Mon Sep 17 00:00:00 2001 From: Andrew Gerrand Date: Fri, 2 Mar 2012 15:35:36 +1100 Subject: [PATCH] doc: expand code.html to discuss the go tool in more depth R=golang-dev, balasanjay, r CC=golang-dev https://golang.org/cl/5640045 --- doc/code.html | 647 +++++++++++++++++++++++++++++++------------------- 1 file changed, 403 insertions(+), 244 deletions(-) diff --git a/doc/code.html b/doc/code.html index 625a98c1f1..ff3d7dcf00 100644 --- a/doc/code.html +++ b/doc/code.html @@ -5,129 +5,152 @@

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. +This document demonstrates the development of a simple Go package and +introduces the go command, the standard way to fetch, +build, and install Go packages and commands.

-

Creating a new package

+

Code organization

-

Choosing an import path

+

GOPATH and workspaces

-The standard packages are given short names like fmt and -net/http for convenience. -For your own projects, choose a name space that is unlikely -to collide with future additions to the standard library or other +One of Go's design goals is to make writing software easier. To that end, the +go command doesn't use Makefiles or other configuration files to +guide program construction. Instead, it uses the source code to find +dependencies and determine build conditions. This means your source code and +build scripts are always in sync; they are one and the same. +

+ +

+The one thing you must do is set a GOPATH environment variable. +GOPATH tells the go command (and other related tools) +where to find and install the Go packages on your system. +

+ +

+GOPATH is a list of paths. It shares the syntax of your system's +PATH environment variable. A typical GOPATH on +a Unix system might look like this: +

+ +
+GOPATH=/home/user/ext:/home/user/mygo
+
+ +

+(On a Windows system use semicolons as the path separator instead of colons.) +

+ +

+Each path in the list (in this case /home/user/ext or +/home/user/mygo) specifies the location of a workspace. +A workspace contains Go source files and their associated package objects, and +command executables. It has a prescribed structure of three subdirectories: +

+ + + +

+Subdirectories of the src directory hold independent packages, and +all source files (.go, .c, .h, and +.s) in each subdirectory are elements of that subdirectory's +package. +

+ +

+When building a program that imports the package "widget" the +go command looks for src/pkg/widget inside the Go root, +and then—if the package source isn't found there—it searches +for src/widget inside each workspace in order. +

+ +

+Multiple workspaces can offer some flexibility and convenience, but for now +we'll concern ourselves with only a single workspace. +

+ +

+Let's work through a simple example. First, create a $HOME/mygo +directory and its src subdirectory: +

+ +
+$ mkdir -p $HOME/mygo/src # create a place to put source code
+
+ +

+Next, set it as the GOPATH. You should also add the +bin subdirectory to your PATH environment variable so +that you can run the commands therein without specifying their full path. +To do this, add the following lines to $HOME/.profile (or +equivalent): +

+ +
+export GOPATH=$HOME/mygo
+export PATH=$PATH:$HOME/mygo/bin
+
+ + +

Import paths

+ +

+The standard packages are given short import paths such as "fmt" +and "net/http" for convenience. +For your own projects, it is important to choose a base import path that is +unlikely to collide with future additions to the standard library or other external libraries.

+The best way to choose an import path is to use the location of your version +control repository. For instance, if your source repository is at example.com or code.google.com/p/example, you should begin your package paths with that URL, as in "example.com/foo/bar" or "code.google.com/p/example/foo/bar". -This way the go tool can automatically -check out and build the source code from its import path. +Using this convention, the go command can automatically check out and +build the source code by its import path alone.

-If you don't intend your code to be installed in this way, you should at +If you don't intend to install your code in this way, you should at least use a unique prefix like "widgets/", as in "widgets/foo/bar". A good rule is to use a prefix such as your -company or project name since it is unlikely to be used by another group. -

- - -

The go tool and GOPATH

- -

-The go tool is the standard means of -building and installing Go libraries and programs. It is a "zero configuration" -tool; it determines how to build Go packages from their source code alone. +company or project name, since it is unlikely to be used by another group.

-To use the go tool effectively you must set the -GOPATH variable. -GOPATH specifies a list of paths that contain Go source code -and package binaries. Source code, package objects, and command binaries are -located inside the GOPATHs' src, pkg, -and bin subdirectories respectively. -

- -

-You should set GOPATH in your shell profile -($HOME/.bashrc, $HOME/.profile, or equivalent). -

- -

-This shell session demonstrates setting GOPATH, creating a trivial -widgets/foo package, and building and installing the package. +We'll use example/ as our base import path:

-$ export GOPATH=$HOME/gocode
-$ mkdir -p $GOPATH/src/widgets/foo
-$ cat > $GOPATH/src/widgets/foo/foo.go
-package foo
-const String = "Go rules!"
-^D
-$ go install widgets/foo
-$ ls $GOPATH/pkg/*/widgets
-foo.a
+$ mkdir -p $GOPATH/src/example
 
-

(^D means to type Control-D.)

+ +

Package names

-Type go help gopath on the command line for more information -about GOPATH. +The first statement in a Go source file should be

- -

Go source files

+
+package name
+

-The first statement in a Go source file should be package -name, where name is the package's default -name for imports. +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. @@ -137,208 +160,344 @@ 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

- -

-The go tool treats code belonging to -package main as an executable command, and installs the package -binary to the GOPATH's bin subdirectory. -

- -

-Building executable commands is the same as building packages. -Use "go install": +Create a new package under example called newmath:

-$ mkdir -p $GOPATH/src/widgets/bar
-$ cat > $GOPATH/src/widgets/bar/bar.go
-package main
-
-import (
-    "fmt"
-    "widgets/foo"
-)
-
-func main() {
-    fmt.Println(foo.String)
-}
-^D
-$ go install widgets/bar
-$ $GOPATH/bin/bar
-Go rules!
+$ cd $GOPATH/src/example
+$ mkdir newmath
 

-Run go help build and go help install for more -about building and installing Go binaries. +Then create a file named $GOPATH/src/example/newmath/sqrt.go +containing the following Go code:

+
+// Package newmath is a trivial example package.
+package newmath
+
+// Sqrt returns an approximation to the square root of x.
+func Sqrt(x float64) float64 {
+        // This is a terrible implementation.
+        // Real code should import "math" and use math.Sqrt.
+        z := 0.0
+        for i := 0; i < 1000; i++ {
+                z -= (z*z - x) / (2 * x)
+        }
+        return z
+}
+
+ +

+This package is imported by the path name of the directory it's in, starting +after the src component: +

+ +
+import "example/newmath"
+
+ +

+See Effective Go to learn more about +Go's naming conventions. +

+ + +

Building and installing

+ +

+The go command comprises several subcommands, the most central being +install. Running go install importpath builds +and installs a package and its dependencies. +

+ +

+To "install a package" means to write the package object or executable command +to the pkg or bin subdirectory of the workspace in +which the source resides. +

+ +

Building a package

+ +

+To build and install the newmath package, type +

+ +
+$ go install example/newmath
+
+ +

+This command will produce no output if the package and its dependencies +are built and installed correctly. +

+ +

+As a convenience, the go command will assume the current directory +if no import path is specified on the command line. This sequence of commands +has the same affect as the one above: +

+ +
+$ cd $GOPATH/src/example/newmath
+$ go install
+
+ +

+The resulting workspace directory tree (assuimg we're running Linux on a 64-bit +system) looks like this: +

+ +
+pkg/
+    linux_amd64/
+        example/
+            newmath.a  # package object
+src/
+    example/
+        newmath/
+            sqrt.go    # package source
+
+ + +

Building a command

+ +

+The go command treats code belonging to package main as +an executable command and installs the package binary to the +GOPATH's bin subdirectory. +

+ +

+Add a command named hello to the source tree. +First create the example/hello directory: +

+ +
+$ cd $GOPATH/src/example
+$ mkdir hello
+
+ +

+Then create the file $GOPATH/src/example/hello/hello.go +containing the following Go code. +

+ +
+// Hello is a trivial example of a main package.
+package main
+
+import (
+        "example/newmath"
+        "fmt"
+)
+
+func main() {
+        fmt.Printf("Hello, world.  Sqrt(2) = %v\n", newmath.Sqrt(2))
+}
+
+ +

+Next, run go install, which builds and installs the binary to +$GOPATH/bin: +

+ +
+$ go install example/hello
+
+ +

+To run the program, invoke it by name as you would any other command: +

+ +
+$ $GOPATH/bin/hello
+Hello, world.  Sqrt(2) = 1.414213562373095
+
+ +

+If you added $HOME/mygo/bin to your PATH, you may omit +the path to the executable: +

+ +
+$ hello
+Hello, world.  Sqrt(2) = 1.414213562373095
+
+ +

+The workspace directory tree now looks like this: +

+ +
+bin/
+    hello              # command executable
+pkg/
+    linux_amd64/ 
+        example/
+            newmath.a  # package object
+src/
+    example/
+        hello/
+            hello.go   # command source
+        newmath/
+            sqrt.go    # package source
+
+ +

+The go command also provides a build command, which is +like install except it builds all objects in a temporary directory +and does not install them under pkg or bin. +When building a command an executable named after the last element of the +import path is written to the current directory. When building a package, +go build serves merely to test that the package and its +dependencies can be built. (The resulting package object is thrown away.) +

+ +

Testing

-Go has a lightweight test framework composed of the go tool and -the testing package. +Go has a lightweight test framework composed of the go test +command and the testing package. +

+ +

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. -Run go help test and see the -testing package documentation for more detail.

-To run the test, run "go test": +Add a test to the newmath package by creating the file +$GOPATH/src/example/newmath/sqrt_test.go containing the following +Go code.

-$ cat > $GOPATH/src/widgets/foo/foo_test.go
-package foo
+package newmath
 
 import "testing"
 
-func TestString(t *testing.T) {
-    const expect = "Go rules!"
-    if String != expect {
-        t.Errorf("String == %q, want %q", String, expect)
-    }
+func TestSqrt(t *testing.T) {
+	const in, out = 9, 3
+	if x := Sqrt(in); x != out {
+		t.Errorf("Sqrt(%v) = %v, want %v", in, x, out)
+        }
 }
-^D
-$ go test widgets/foo
-ok  	widgets/foo	0.018s
 

-If your change affects performance, add a Benchmark function -(run go help testfunc) and run it using go test --test.bench=.*. -

- -

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 two files. -

- -

-First, the package implementation, numbers.go: +Now run the test with go test:

-package numbers
-
-func Double(i int) int {
-	return i * 2
-}
+$ go test example/newmath
+ok  	example/newmath
 

-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)
-		}
-	}
-}
-
- -

-Running go install will build and install the package to -the GOPATH's pkg directory -(it can then be imported by any other Go program). -

- -

-Running go test will rebuild the package, including the -numbers_test.go file, and then run the TestDouble -function. The output "ok" 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. -

- -

-Run go help test, go help testfunc, -and go help testflag and see the +Run go help test and see the testing package documentation 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.

+

Remote packages

-

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

- -

For example, consider the package foo that consists of four -files:

+

+An import path can describe how to obtain the package source code using a +revision control system such as Git or Mercurial. The go command uses +this property to automatically fetch packages from remote repositories. +For instance, the examples described in this document are also kept in a +Mercurial repository hosted at Google Code, +code.google.com/p/go.example. +If you include the repository URL in the package's import path, +go get will fetch, build, and install it automatically: +

-foo.go
-foo_386.go
-foo_amd64.go
-foo_arm.go
+$ go get code.google.com/p/go.example/hello
+$ $GOPATH/bin/hello
+Hello, world.  Sqrt(2) = 1.414213562373095
 
-

describes a package that builds on -different architectures by parameterizing the file name with -$GOARCH.

+

+If the specified package is not present in a workspace, go get +will place it inside the first workspace specified by GOPATH. +(If the package does already exist, go get skips the remote +fetch and behaves the same as go install.) +

-

The general code goes in foo.go, while architecture-specific -code goes in foo_386.go, foo_amd64.go, and -foo_arm.go.

- -

If you follow these conventional parameterizations, tools such as the go tool will work seamlessly with your -package:

+

+After issuing the above go get command, the workspace directory +tree should now now look like this: +

-foo_$GOOS.go
-foo_$GOARCH.go
-foo_$GOOS_$GOARCH.go
+bin/
+    hello                 # command executable
+pkg/
+    linux_amd64/ 
+        code.google.com/p/go.example/
+            newmath.a     # package object
+        example/
+            newmath.a     # package object
+src/
+    code.google.com/p/go.example/
+        hello/
+            hello.go      # command source
+        newmath/
+            sqrt.go       # package source
+            sqrt_test.go  # test source
+    example/
+        hello/
+            hello.go      # command source
+        newmath/
+            sqrt.go       # package source
+            sqrt_test.go  # test source
 
-

The same holds for .s (assembly) and .c files.

+

+The hello command hosted at Google Code depends on the +newmath package within the same repository. The imports in +hello.go file use the same import path convention, so the go +get command is able to locate and install the dependent package, too. +

+ +
+import "code.google.com/p/go.example/newmath"
+
+ +

+This convention is the easiest way to make your Go packages available for +others to use. +The Go Package Dashboard +displays a list of packages recently installed with the go command. +

+ +

+For more information on using remote repositories with the go command, see +go help remote. +

+ + +

Further reading

+ +

+See Effective Go for tips on writing +clear, idiomatic Go code. +

+ +

+Take A Tour of Go to learn the language +proper. +

+ +

+Visit the documentation page for a set of in-depth +articles about the Go language and its libraries and tools. +