Monday, 26 September 2011

Experimenting with Cgo - Part 1

** Modified: Updated to comply with Go 1.1 release. **

This is the first in a planned series of posts on cgo. Cgo is a program in the Go language tool suite that allows programmers to wrap C language libraries for use in Go. I have found it to be an incredibly useful tool and I am sure will help provide Go with the ability to grow it's third-party, non-standard library more quickly.

I am currently designing some software for personal business use which would utilize the ncurses library as an interface. There is already a curses wrapper library available for Go but I wasn't entirely satisfied by the completeness of the library. For one, the mouse isn't implemented at all, along with a myriad of other functions. Nor are the form, menu or panel libraries. So I decided that this would the perfect time to learn cgo.

To create a wrapper library for a C library you need to take the following steps:

1. Setup your build environment. I recommend using a sub-directory in your home directory. On Linux you would use:


$ cd ~
$ mkdir -p godev/src/mylibwrapper


Of course, you can change the 'godev' to whatever you want and 'mylibwrapper' to the name of the library you're creating a wrapper for but 'src' must be a sub-directory of your development hierarchy.

You will also need to set your $GOPATH to this new directory. On Linux you might use:


$ export GOPATH="$GOPATH:/home/username/godev"


Take care not to add a slash at the end of the directory name as the go tools won't like it.

2.  Within your wrapper library you need to include the C library header(s) you need to use followed by the C import directive:



// #include <math.h>
import "C"



It is essential that 'import "C"' is on its own, directly after the commented C code in order for cgo to work properly. Or, at all for that matter. You can write your own C code prior to the import call and use either of Go's comment styles. 


3. If you need to pass any compile flags or link to the C library, like the C math library, you would use cgo's LDFLAGS and CFLAGS:



// #cgo LDFLAGS: -lm



4. To access any of the C functions from your Go code, you use the C namespace. Same goes for C types. As a matter of fact, no Go types are available in C and vice versa. Therefore, everything you need to pass to or from a C function must be cast to or from a C or Go type. Unfortunately, strings aren't so easy. In order to convert a Go string to a C string, you need to use the CString function. For a good example and explanation, see Andrew Gerrards blog post on the subject.



func Pow(b, e float64) float64 {
    return float64(C.pow(C.double(b), C.double(e)))
}



5. Run 'go build' to compile your code. This step is not strictly necessary as installing automatically builds the library for you and will not install it if the build stage fails.

6. In order to test your new wrapper, you'll need to run 'go install' and then import your library into some Go source.

That's it, start to finish. To view a complete example:


godev/src/mylibwrapper/mylibwrapper.go:

package mylibwrapper

// #cgo LDFLAGS: -lm
// #include <math.h>
import "C"

func Pow(b, e float64) float64 {
    return float64(C.pow(C.double(b), C.double(e)))
}


godev/src/cgoexample/example.go:

package main

import (
    "mylibwrapper"
    "fmt"
)

func main() {
    b, e := 5.0, 2.0
    f := mylibwrapper.Pow(b, e)
    fmt.Println(b, "raised to the power of", e, "is", f)
}


Friday, 2 September 2011

An Ubuntu User Testing Arch Linux

First, some background.

I run Linux on an older computer. Were I to have purchased it from a retail store I would likely call it "venerable" but since I built it from scratch as a gaming computer the old girl has a bit more kick. Irregardless, it's nine to ten years old and just can't handle modern gaming any more. Still, as a basic desktop machine, it works fantastic!

I have tried several Linux distributions over the years. I shudder to recall that my first distribution was Caldera Linux (see SCO to understand), which was soon followed by Mandrake Linux (now Mandriva) because of its easier customization. I was always in love with the idea of Linux but I struggled with the technical side of maintaining it, like upgrading applications from source. Installation, too, wasn't like it is today with distributions like Fedora and Ubuntu. You actually had to know something about your system. You usually needed to know every small detail about your sound card, if you could get it running at all. You needed to know every spec and detail about almost every piece of hardware in your system and that assumed it was compatible with Linux in the first place (Winmodems anyone?). It wasn't for the feint of heart and is likely how Linux got the reputation for being only for computer geeks.

I heard about Ubuntu early on but it's quirky release names initially turned me off. However, it's quick rise in popularity and numerous glowing reviews finally convinced me to give it a try so when it's fourth version was released, 6.06 Dapper Drake, I burned a copy and installed it. I loved it. Ubuntu altered my perception of Linux forever. I turned into a fanboy overnight and was suddenly encouraging anyone I could find to switch away from the diabolical Microsoft and finally live a life of Freedom! Even if I couldn't get them to switch from Windows I was at least pushing free software. What can I say? I was naive. My heart was in the right place, though.

Now, at version 11.04 I am starting to get frustrated with Ubuntu. I love all the software in their repositories. I love Launchpad and how you can set up PPA's  (Personal Package Archive's) as additional repositories. Yet, I have also a few contentions. I don't like how software is only updated at 6 month intervals unless a security patch needs to be released. This is especially important with web browsers because they change so quickly and have so many security updates that the Ubuntu team just can't, or won't, keep up with. What if you want to use a feature in a new version of a program but it won't be updated for another few months? This is problematic for me because of the age of my video card but more on that in a moment. That leaves me with either manually upgrading them myself from source binaries or utilizing non-official repositories or .deb files. Either way, installing by those means often proves problematic during a system upgrade (were I to later do so) and negates the entire reason for using a system like Ubuntu anyway.

At the time of purchase, my nVidia GeForce 4 4800 Ti was top of the line for consumer video cards. Unfortunately, it has been considered a legacy card by nVidia for many years. Despite that they still update it to run with the latest Xorg server but it always takes a few months while they make sure their most recent cards are kept up to date first. Understandable. Ubuntu, though, has a long process to integrate fixes in their software distribution. So, while you may be able to install the nVidia Linux driver from scratch (which I've done) you have the additional issue of having to re-install the driver every time the kernel is updated. Installing the driver isn't as simple as just running the installer, either, because you can't install it while X is running so the process gets old fast. I could, also, just choose not to upgrade to new releases of Ubuntu but then my applications won't get updated and support eventually gets dropped altogether. It's a no-win situation.

Now that I've set the stage, let's move on to Arch.

So, I've begun the task of looking at other distributions which may be more friendly to my situation. Now, I have accepted the fact that I am always going to have issues with my graphics driver being out of date because of it's age. So, what I really want to overcome is keeping my applications up to date while I wait for the appropriate updates to the nVidia driver. Oh, and not have to monitor, hunt down, and manually upgrade each application myself. There's a reason I don't use Windows as my main desktop any more after all. My only real choice therefore is a rolling or semi-rolling distribution. The first distribution of that type that popped into my head was Arch.

Arch Linux has interested me for a while, namely because it started Canada where I was born and continue to live. It's not for the uninitiated though. It's installation process is a bit of a throw-back to the Linux days of old where you need to understand the entire process to install the system. Not that that scares me any more. I've built an LFS system (an experience I HIGHLY recommend to anyone with the guts to try it) at least three times now. It's not my first time to the rodeo. It more came down to whether I was too lazy to go through the process and maintain such a system or not.

Rather than install Arch on my main system I opted to run it on my backup/test Linux box. This second box is almost identical to my main one in most respects but has an ATI video card and smaller hard drives. I was testing out Fedora 15 on it, which is a good distribution in it's own right, but I decided to deep-six it (I still have the installation CD, I can re-install it if I choose to) and installed Arch. As I mentioned before, Arch is not for the weak. This is both a negative and a positive. On the negative side, it makes it very unapproachable to the common or new user. I've seen many complaints on forums and in articles about their installation procedure. However, you have to understand their counter argument to appreciate the approach they've taken. They're not trying to be another Debian, Fedora or Ubuntu. No, Arch Linux is aimed at someone more like me. Someone who wants a cutting edge system with a great deal of control (i.e. less software bloat). Once I installed Arch, I really got to appreciate what they, the Arch Developers, are trying to accomplish.

Installing Arch isn't actually that hard if you have a little patience. For one, it uses a text/ncurses based installer rather than a graphical one. While "ugly" when compared to a GUI it actually makes the process much, much faster. It also asks some tough questions that an absolute newbie may not know the answers to but help is near. It helps if you can run two PC's side by side, one with installation instructions on it and a second to install the OS onto. If you don't have two computers you may want to consider printing the instructions first. The installer also tries to recommend settings and offers some advice for people who just want the most basic setup and a lot of steps can be skipped. By in large, you can just select the default choices and you'll be fine. Arch also requires you edit some configuration files with an editor both during the installation process and post-installation. This will scare a lot of people off but again it's not so bad. The installation instructions on the website holds your hand through the process and tells you what to edit and why. Trust me, it's not that hard. It's like looking up a mountain and thinking you can never get to the top but once you get on the path you realize that it's really not so steep and can turn into a pleasurable experience.

Once the base system is installed you can reboot to run your new system. I already knew that I was only going to get a command prompt but those who are used to ready-out-of-the-box systems might be in for a little shock. Arch only sets up a basic, mostly bare-bones system with a command line interface. Therein lies the advantage of Arch. Similar to Ubuntu's core installation setup, you can pick and choose what exactly you want to install. Dependencies are resolved for you just like in other distributions that use package repositories. Arch lets you choose between installing helpful meta packages, which install a complete set of software such as a desktop environment, or you can choose the specific individual packages you need. You may, for example, want to install the X11 meta package but hand-pick a window manager, file manager, etc. to build your own desktop environment. Removing packages installed by a meta-package doesn't break the upgrade process either like it can with Ubuntu. Try and uninstall a program installed by a meta-package like ubuntu-desktop and Ubuntu will scare the pants of you by saying it's going to uninstall the ubuntu-desktop package too! It doesn't uninstall the whole system, of course, just the meta package but it scares a lot of newbies to Ubuntu, myself included.

I am still learning Arch but I like what I see so far. I have a lot to learn yet about pacman, Arch's aptly named package manager. Pacman seems to be faster overall than apt, too, likely because it doesn't use the Debian package system, just a compressed tarball. There is still a lot of tweaking left to be done too to get the system running exactly as I'd like. I love how easily things are configured. It's both a plus and a negative that newly installed software isn't automatically configured to run optimally with your system like Ubuntu but then it's not as necessary with Arch because there aren't a lot, if any, Ubuntu-only changes to other packages or systems you have to contend with. Settings in Arch are the same settings you'd use on any built-from-scratch or configured-from-scratch system so finding help is universal to Arch. Again, no Ubuntu-only solutions. That's not to say Arch doesn't automatically create the very minimal configuration settings to make sure the new application will run in a secure and efficient manner but only that you're encouraged to tweak to your hearts content.

My first impression is that Arch is the system for someone who wants a lot of control over their system mixed with the conveniences of a hands-off system like Ubuntu. Ubuntu could, if they wanted, be what Arch is I think but not with their current model. Yes, the Ubuntu team is talking about allowing rolling releases of specific pieces of software, like Firefox, but one or two applications being kept up-to-date doesn't really help me.

Arch could, potentially, be my own personal silver bullet. I can even block specific packages like the Kernel, nVidia/ATI drivers and Xorg from being updated until the time of my choosing while the rest of my software is continually updated. Nice! Now to see it in practice...