Statically linked Linux executables with Go

You might have seen my previous article about creating executables without dependencies http://www.codeblog.ch/2011/06/statically-linked-linux-executables/. While I still try to focus on Oracle and concrete5, there’s often a situation where I have to build a small, portable and fast tool. I didn’t look at something specific, I rather tried several solutions and now it’s time to add another language to this list.

Google created Go a while ago and released version 1.0 at the end of March 2012. Some might wonder why Google created yet another new language. You can find the official answer here: http://golang.org/doc/go_faq.html#What_is_the_purpose_of_the_project. To me the most important things worth mentioning are:

  • Fully garbage-collected
  • Support for concurrent execution and communication
  • Doesn’t need a virtual machine like JRE
  • Construction of system software on multicore machines

This doesn’t mean that Go is restricted to those things, you does a lot more but when comparing it to Java and other languages, these are a few major points of interest. I’ve run my experiment on a freshly installed Debian 6.0 operating system. My favourite distribution as it’s small and efficient, I can’t give you instructions for Fedora and other system but if you’re familiar with some of the basic libraries for your distribution, it shouldn’t be too difficult to get Go up and running.

Installing Go on Debian

First we use the Debian package management to install three components we need to build Go:

apt-get install gcc libc6-dev mercurial

Once everything is installed, we can clone the source code repository by running the following command:

hg clone -u release https://code.google.com/p/go

That’s already enough to compile Go!

cd go/src
./all.bash

Once everything has been compiled, we change into the directory where the go binaries are located and create a hello world application. Of course, we could set some environment variables to make that path accessible from everywhere, but for now we try to keep things as quick as possible. For those who want to do it properly, check this page for more instructions: http://golang.org/doc/install/source#environment

This creates the hello world file in the linux_amd64 directory, if you’re running a 32bit system you have to change that path to match your platforms architecture of course:

cd ../pkg/tool/linux_amd64/
echo "package main
 
import fmt \"fmt\"
 
func main() {
fmt.Printf(\"Hello world\");
}" > hello.go

We’re ready to compile our code:

1
2
3
./6g hello.go
./6l hello.6
./6.out

This will simply print “Hello world” as we we all have seen several times. The compiled binary has a size of 1’268’722 bytes, still fits on a 3 1/2 floppy disk! Let’s look at the dynamic sections in this file:

debian:~/go/pkg/tool/linux_amd64# readelf -d 6.out
There is no dynamic section in this file.

Neat, nothing!

Now let’s try to look how “strip” changes the size:

strip 6.out

The binary shrunk to 901’848 bytes! Still not as small as a binary created with some assembler but still very handy to work with!

First impression of Go

To me Go looks already very impressive, even though it’s hasn’t been on the market for very long. I’m able to get Go up and running quickly and I can create small, independent binaries in a language similar to others I’ve been working with. Everyone who worked with C++, Java or C# will feel at least a bit at home! There are a few things I’d like to mention which surprised me a bit, in a positive way!

Multiple return values

Everyone wanted to create a function which returns more than just one discrete value. How did we do that in the past? We either created a structure to hold multiple values or made a call by reference or pointer depending on the language. Go has a different approach which I haven’t seen before, let’s look at some basic go:

1
2
3
4
5
6
7
8
9
10
11
12
package main
 
import fmt "fmt"
 
func Magic(i, j int) (int, int) {
   return i*j, i+j
}
 
func main() {
   prod, sum := Magic(6, 7)
   fmt.Printf("product %d, sum %d", prod, sum)
}

Once you realize that Go supports multiple return values, the code is pretty easy to read. The function Magic returns two integers separated by a comma. When calling the function Magic, you then have two variables as well. Great!

Deferred function

If you made it to this point of the article, you probably know the basic control flow commands like if, else etc. Go has a few more like defer, panic, what are they doing? Those commands are handy if you want to make sure something is executed once a function returns. Let’s look at some very basic code:

1
2
3
4
5
6
7
8
package main
 
import fmt "fmt"
 
func main() {
   defer fmt.Printf("I'm last!")
   fmt.Printf("I'm first?")
}

As you can imagine, “I’m first” comes first. Due to “defer”, “I’m last” comes last, even if it’s placed before the second output in the code. Easy to understand but why on earth would Go have something like that? In the example above it’s a bit silly but imagine you open a file handle to read something from your disk. After you opened the file, you have to close it at some point. Sometimes, this happens quite a few lines later as you work with the file for a bit. With Go you can make sure the file handle get closed right when you open it. The following example has been copied from http://blog.golang.org/2010/08/defer-panic-and-recover.html:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
func CopyFile(dstName, srcName string) (written int64, err error) {
    src, err := os.Open(srcName)
    if err != nil {
        return
    }
    defer src.Close()
 
    dst, err := os.Create(dstName)
    if err != nil {
        return
    }
    defer dst.Close()
 
    return io.Copy(dst, src)
}

Another neat concept I haven’t seen before but could get used to it.

First impression about Go summarized

Go looks nice and it seems like some smart people have worked on it, I’m sure it doesn’t not only seem like that! There are a few ideas which I haven’t seen before, they might have another origin which I’m not aware of but I like that Go combined those things. It has a small footprint, doesn’t need a VM, is statically typed, compiles fast, ships with a bunch of libraries/packages (http://golang.org/pkg/) and is fun to work with.

While I currently don’t have any projects for Go, it’s certainly going to be on my watch list!




No Comments


You can leave the first : )



Leave a Reply

Your email address will not be published. Required fields are marked *