Sunday, October 30, 2011

Go packages and goinstall - creating and using your own packages in Go

For a small beginner’s introduction to packages you can read my other writeup: Go ‘Hello World’ - A line by line approach. In this tutorial we will look at how you can work with the goinstall tool to create, install, and use your own packages locally.
goinstall has larger functionality than this alone and you can read more about it here: Command goinstall.
Warning! goinstall is still experimental and not all features are extremely user friendly or perfect. But goinstall seems to the official direction that go will take, so might make sense to fiddle around with it to learn its functionality.
Also, there wasn’t a lot of documentation that I found and so most of it is trial and error, and there is bound to be some inconsistencies here.

What will we attempt to do in this sample?

* Learn how GOPATH variable is used, and set it accordingly
* Learn how the file will be compiled and installed
* Learn where the compiled file will be installed.
* Learn how to import and use the installed package, along with the current quirks of goinstall.

Directory structure and environment variables

First, I need to inform you what my current directory structures are and you can follow the same.
* I have all my go stuff under /home/vj/coding/golang/. So, for me, there are also the directories /home/vj/coding/golang/go (the directory where the go binaries and libraries are installed) and /home/vj/coding/golang/mygo.
* /home/vj/coding/golang/mygo is where I have all my personal projects. You also create some directory like this. It could be anywhere, but I shall carry on with the rest of this writeup taking my directory structure as the base.
* Set the environment variable GOPATH to point to this directory. So for me in my .bashrc I have an entry export GOPATH=/home/vj/coding/golang/mygo. GOPATH is used by the goinstall tool to find out where to install your local packages and also to find out what should be the package names for the installed packages.
* Create a directory called src in the directory corresponding to GOPATH. So mine is $GOPATH/src

To summarize,my directory structure is
/home/vj/coding/golang/mygo
/home/vj/coding/golang/mygo/src

and there is an environment variable
GOPATH=/home/vj/coding/golang/mygo

Code and package structure

We shall now write a illustrative code example for which we shall use identifiable names for the folder, package name, and file name. Please note that this is not the convention used in Go. Typically in Go, one would have the package name the same as the directory it is in. So, for now for the purpose of learning, go ahead and do the following.

* Under $GOPATH/src, create a directory pkgdirname. So I now have $GOPATH/src/pkgdirname
* Within $GOPATH/src/pkgdirname, create the file fileinpkgdir.go. So I now have $GOPATH/src/pkgdirname/fileinpkgdir.go

* Add the code below into the file fileinpkgdir.go
Full program - $GOPATH/src/pkgdirname/fileinpkgdir.go
package pkgnameinfile

func Add2Ints(i, j int) int {
    return i + j
}

At this point, if you want, you can check whether your syntax is right by compiling the file thus: 6g fileinpkgdir.go. But it is not necessary since goinstall will also do the compilation for you.

* Go back to the src directory and type the following command: goinstall pkgdirname.
* Now check the contents of the directory at GOPATH and you should now be seeing a new file there pkg/"system_arch"/pkgdirname.a. Since my system is a linux 64 bit machine, my directory is
$GOPATH/pkg/linux_amd64/pkgdirname.a.

To summarize how that happened, goinstall will
* automatically compile go files
* look for GOPATH
* find directory name following GOPATH/src, and retain that as the package directory structure for the target package
* create a folder GOPATH/pkg/"system_arch" if it is not already present
* and copy into it the compiled package with the name of the directory.

Notice here that the name used for the package is not the file name (fileinpkgdir.go), nor the name of the package that we put within the file (package pkgnameinfile). Instead it is the name of the directory that the file was in. I repeat that I named these items such only to distinguish for you which name is automatically taken by goinstall. Conventionally, you would have the same name for the directory as you would have in the package statement within the code.

Using our local package

At this point we have a simple package that provides a function to add two integers. We shall now learn how to use it. Please follow the below steps.

* Create a go file wherever you choose. I have called my file testpkg.go.
* Add the following code to the file
Full program
package main

import (
    "fmt"
    "pkgdirname"  //use the file name without the ".a"
    )

func main() {
    fmt.Println(pkgnameinfile.Add2Ints(3, 4)) //use the name of package in the file
}

* To compile the file now you need to additionally indicate the path to the library files by providing the -I option.
6g -I $GOPATH/pkg/linux_amd64 testpkg.go
* Next to link this, you need to provide the path to the library files by providing the -L option.
6l -L $GOPATH/pkg/linux_amd64 testpkg.6
* At this point, you ought to have an executable and you can execute it. For me on linux, I ran ./6.out.

To summarize,
* we import a package with the name of the file under the pkg directory (minus the extension ".a")
* to use a function within it, you use the name given in the package statement in the file where this function is defined - by convention and for ease of use, this name is usually the same as the directory name.
* to compile the file we need to give the directory where the local packages are with the -I option
* to link the compiled file we need to give the directory where the local packages are with the -L option

One takeaway for me is the understanding that if you were working on multiple big projects, all you have to do is only change the value of your GOPATH to have separate local package directories corresponding to each project. This appears to be a much better option than attempting to use relative paths in import statements.

5 comments:

  1. Good writeup on a subject that needs more documentation! I think that you can use goinstall to compile your command example too. Did you try it?

    ReplyDelete

  2. Thanks for sharing this informative post for house and land craigieburn and best house and land packages. Keep post further...

    ReplyDelete
  3. In Java we can give package name like "org.com.cal". Do we have this option in GO ?

    ReplyDelete
  4. Go has a unix style directory name for indicating package depth. For example check: http://docs.golang.org/pkg/image/color/palette/ You would import the package name as import "image/color/palette".

    ReplyDelete
  5. Thanks a lot. It had exactly what I was looking for.

    ReplyDelete

If you think others also will find these tutorials useful, kindly "+1" it above and mention the link in your own blogs, responses, and entries on the net so that others also may reach here. Thank you.

Note: Only a member of this blog may post a comment.