From ee923e3f907adbe99352fe27a5a4994f7d9c4917 Mon Sep 17 00:00:00 2001 From: Andrew Gerrand Date: Thu, 4 Apr 2013 08:19:24 +1100 Subject: [PATCH] doc: simplify How to write Go code article This version just tells you what to do, rather than trying to teach you how it all works. Should be much better for newcomers. R=dave, gary.burd, alcosholik, r CC=golang-dev https://golang.org/cl/8247044 --- doc/code.html | 461 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 275 insertions(+), 186 deletions(-) diff --git a/doc/code.html b/doc/code.html index 82b211870d..26f3e6d9b9 100644 --- a/doc/code.html +++ b/doc/code.html @@ -6,344 +6,381 @@

This document demonstrates the development of a simple Go package and -introduces the go command, the standard way to fetch, +introduces the go tool, the standard way to fetch, build, and install Go packages and commands.

-This content is also available as a screencast. +The go tool requires you to organize your code in a specific +way. Please read this document carefully. +It explains the simplest way to get up and running with your Go installation. +

+ +

+A similar explanation is available as a +screencast.

Code organization

-

GOPATH and workspaces

+

Workspaces

-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 go tool is designed to work with open source code maintained +in public repositories. Although you don't need to publish your code, the model +for how the environment is set up works the same whether you do or not.

-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. +Go code must be kept inside a workspace. +A workspace is a directory hierarchy with three directories at its root:

+ +

-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: +The go tool builds source packages and installs the resulting +binaries to the pkg and bin directories.

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

-(On a Windows system use semicolons as the path separator instead of colons.) +The src subdirectory typically contains multiple version control +repositories (such as for Git or Mercurial) that track the development of one +or more source packages.

-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: +To give you an idea of how a workspace looks in practice, here's an example:

- +
+bin/
+    streak                         # command executable
+    todo                           # command executable
+pkg/
+    linux_amd64/
+        code.google.com/p/goauth2/
+            oauth.a                # package object
+        github.com/nf/todo/
+            task.a                 # package object
+src/
+    code.google.com/p/goauth2/
+        .hg/                       # mercurial repository metadata
+        oauth/
+            oauth.go               # package source
+            oauth_test.go          # test source
+    github.com/nf/
+        streak/
+	    .git/                  # git repository metadata
+            oauth.go               # command source
+            streak.go              # command source
+        todo/
+	    .git/                  # git repository metadata
+            task/
+                task.go            # package source
+            todo.go                # command source
+

-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. +This workspace contains three repositories (goauth2, +streak, and todo) comprising two commands +(streak and todo) and two libraries +(oauth and task).

-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. +Commands and libraries are built from different kinds of source packages. +We will discuss the distinction later.

+ +

The GOPATH environment variable

+

-Multiple workspaces can offer some flexibility and convenience, but for now -we'll concern ourselves with only a single workspace. +The GOPATH environment variable specifies the location of your +workspace. It is likely the only environment variable you'll need to set +when developing Go code.

-Let's work through a simple example. First, create a $HOME/mygo -directory and its src subdirectory: +To get started, create a workspace directory and set GOPATH +accordingly. Your workspace can be located wherever you like, but we'll use +$HOME/go in this document. Note that this must not be the +same path as your Go installation.

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

-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): +For convenience, add the workspace's bin subdirectory +to your PATH:

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

Import paths

+

Package 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 packages from the standard library are given short paths such as +"fmt" and "net/http". +For your own packages, you must choose a base 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". -Using this convention, the go command can automatically check out and -build the source code by its import path alone. +If you keep your code in a source repository somewhere, then you should use the +root of that source repository as your base path. +For instance, if you have a GitHub account at +github.com/user, that should be your base path.

-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. +Note that you don't need to publish your code to a remote repository before you +can build it. It's just a good habit to organize your code as if you will +publish it someday. In practice you can choose any arbitrary path name, +as long as it is unique to the standard library and greater Go ecosystem.

-We'll use example/ as our base import path: +We'll use github.com/user as our base path. Create a directory +inside your workspace in which to keep source code:

-$ mkdir -p $GOPATH/src/example
+$ mkdir -p $GOPATH/src/github.com/user
 
-

Package names

+

Your first program

-The first statement in a Go source file should be +To compile and run a simple program, first choose a package path (we'll use +github.com/user/hello) and create a corresponding package directory +inside your workspace:

-package name
+$ mkdir $GOPATH/src/github.com/user/hello
 

-where name is the package's default name for imports. -(All files in a package must use the same name.) +Next, create a file named hello.go inside that directory, +containing the following Go code.

-

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

+
+package main
 
-

-Create a new package under example called newmath: -

+import "fmt" -
-$ cd $GOPATH/src/example
-$ mkdir newmath
+func main() {
+	fmt.Printf("Hello, world.\n")
+}
 

-Then create a file named $GOPATH/src/example/newmath/sqrt.go -containing the following Go code: +Now you can build and install that program with the go tool:

-// 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
-}
+$ go install github.com/user/hello
 

-This package is imported by the path name of the directory it's in, starting -after the src component: +Note that you can run this command from anywhere on your system. The +go tool finds the source code by looking for the +github.com/user/hello package inside the workspace specified by +GOPATH. +

+ +

+You can also omit the package path if you run go install from the +package directory:

-import "example/newmath"
+$ cd $GOPATH/src/github.com/user/hello
+$ go install
 

-See Effective Go to learn more about -Go's naming conventions. +This command builds the hello command, producing an executable +binary. It then installs that binary to the workspace's bin +directory as hello (or, under Windows, hello.exe). +In our example, tha will be $GOPATH/bin/hello, which is +$HOME/go/bin/hello.

- -

Building and installing

+

+The go tool will only print output when an error occurs, so if +these commands produce no output they have executed successfully. +

-The go command comprises several subcommands, the most central being -install. Running go install importpath builds -and installs a package and its dependencies. +You can now run the program by typing its full path at the command line:

+
+$ $GOPATH/bin/hello
+Hello!
+
+

-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. +Or, as you have added $GOPATH/bin to your PATH, +just type the binary name:

-

Building a package

+
+$ hello
+Hello!
+

-To build and install the newmath package, type +If you're using a source control system, now would be a good time to initialize +a repository, add the files, and commit your first change. Again, this step is +optional: you do not need to use source control to write Go code.

-$ go install example/newmath
+$ cd $GOPATH/src/github.com/user/hello
+$ git init
+Initialized empty Git repository in /home/user/go/src/github.com/user/hello/.git/
+$ git add hello.go
+$ git commit -m "initial commit"
+[master (root-commit) 0b4507d] initial commit
+ 1 file changed, 1 insertion(+)
+  create mode 100644 hello.go
 

-This command will produce no output if the package and its dependencies -are built and installed correctly. +Pushing the code to a remote repository is left as an exercise for the reader. +

+ + +

Your first library

+ +

+Let's write a library and use it from the hello program.

-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 effect as the one above: +Again, the first step is to choose a package path (we'll use +github.com/user/newmath) and create the package directory:

-$ cd $GOPATH/src/example/newmath
-$ go install
+$ mkdir $GOPATH/src/github.com/user/newmath
 

-The resulting workspace directory tree (assuming we're running Linux on a 64-bit -system) looks like this: +Next, create a file named sqrt.go in that directory with the +following contents.

-pkg/
-    linux_amd64/
-        example/
-            newmath.a  # package object
-src/
-    example/
-        newmath/
-            sqrt.go    # package source
-
- +// Package newmath is a trivial example package. +package newmath -

Building a command

+// Sqrt returns an approximation to the square root of x. +func Sqrt(x float64) float64 { + z := 0.0 + for i := 0; i < 1000; i++ { + z -= (z*z - x) / (2 * x) + } + return z +} +

-The go command treats code belonging to package main as -an executable command and installs the package binary to the -GOPATH's bin subdirectory. +Now, test that the package compiles with go build:

+
+$ go build github.com/user/newmath
+
+

-Add a command named hello to the source tree. -First create the example/hello directory: +Or, if you are working in the package's source directory, just:

-$ cd $GOPATH/src/example
-$ mkdir hello
+$ go build
 

-Then create the file $GOPATH/src/example/hello/hello.go -containing the following Go code. +This won't produce an output file. To do that, you must use go +install, which places the package object inside the pkg +directory of the workspace. +

+ +

+After confirming that the newmath package builds, +modify your original hello.go (which is in +$GOPATH/src/github.com/user/hello) to use it:

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

-Next, run go install, which builds and installs the binary to -$GOPATH/bin (or $GOBIN, if set; to simplify -presentation, this document assumes GOBIN is unset): +Whenever the go tool installs a package or binary, it also +installs whatever dependencies it has. So when you install the hello +program

-$ go install example/hello
+$ go install github.com/user/hello
 

-To run the program, invoke it by name as you would any other command: +the newmath package will be installed as well, automatically.

-
-$ $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: +Running the new version of the program, you should see some numerical output:

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

-The workspace directory tree now looks like this: +After the steps above, your workspace should look like this:

 bin/
     hello              # command executable
 pkg/
-    linux_amd64/ 
-        example/
+    linux_amd64/       # this will reflect your OS and architecture
+        github.com/user/
             newmath.a  # package object
 src/
-    example/
+    github.com/user/
         hello/
             hello.go   # command source
         newmath/
@@ -351,13 +388,55 @@ src/
 

-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.) +Note that go install placed the newmath.a object in a +directory inside pkg/linux_amd64 that mirrors its source +directory. +This is so that future invocations of the go tool can find the +package object and avoid recompiling the package unnecessarily. +The linux_amd64 part is there to aid in cross-compilation, +and will reflect the operating system and architecture of your system. +

+ +

+Go command exectuables are statically linked; the package objects need not +be present to run Go programs. +

+ + +

Package names

+ +

+The first statement in a Go source file must 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. +

+ +

+Executable commands must always use package main. +

+ +

+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. +

+ +

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

@@ -379,8 +458,8 @@ if the function calls a failure function such as t.Error or

Add a test to the newmath package by creating the file -$GOPATH/src/example/newmath/sqrt_test.go containing the following -Go code. +$GOPATH/src/github.com/user/newmath/sqrt_test.go containing the +following Go code.

@@ -397,12 +476,22 @@ func TestSqrt(t *testing.T) {
 

-Now run the test with go test: +Then run the test with go test: +

+ +
+$ go test github.com/user/newmath
+ok  	github.com/user/newmath 0.165s
+
+ +

+As always, if you are running the go tool from the package +directory, you can omit the package path:

-$ go test example/newmath
-ok  	example/newmath 0.165s
+$ go test
+ok  	github.com/user/newmath 0.165s
 

@@ -415,7 +504,7 @@ Run go help test and see t

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 +revision control system such as Git or Mercurial. The go tool 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, @@ -425,8 +514,8 @@ If you include the repository URL in the package's import path,

-$ go get code.google.com/p/go.example/hello
-$ $GOPATH/bin/hello
+$ go get code.google.com/p/go.example/hello
+$ $GOPATH/bin/hello
 Hello, world.  Sqrt(2) = 1.414213562373095
 
@@ -449,7 +538,7 @@ pkg/ linux_amd64/ code.google.com/p/go.example/ newmath.a # package object - example/ + github.com/user/ newmath.a # package object src/ code.google.com/p/go.example/ @@ -458,7 +547,7 @@ src/ newmath/ sqrt.go # package source sqrt_test.go # test source - example/ + github.com/user/ hello/ hello.go # command source newmath/ @@ -485,7 +574,7 @@ has a list of external Go projects including programs and libraries.

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

-- 2.50.0