Monday 28 November 2011

Creating a Treeview in Glade

Preface: This was one of the first articles I wrote for my blog but never published it. I can't say why but I didn't. It's quite old and it's a little embarrassing. I figure I may as well post it though since it might just help another Glade/GTK+ newbie out there!


Disclaimer: This article assumes you have an understanding of how to implement the Model/View/Controller methodology of a GTK+ treeview. It is also intended for GTK+ 2.xx but may still be applicable to GTK+ 3.xx.

It seems like every day I program I am reminded about how much more I have to learn. Some days, like the name of my blog suggests, I feel like I have no idea what I'm doing. Or more appropriately, what I'm doing wrong. Take for example, a few nights several months ago.

I was continuing the process of converting the user interface for Vocab Builder from a C source code implementation to a gtk-builder xml user interface via Glade. Glade makes designing and maintaining a user interface a dream when it's behaving properly. I am using the latest version of Glade (3.8.0 at the time of writing) on Ubuntu 10.10 Maverick Meerkat and I have experienced a few problems. One of them is a real show-stopper. Literally. Somehow the widget tree gets corrupted and isn't displayed properly. Some widgets are just blank lines where the widget should be or are a garbled mess. If that happens, and you click on the place where the widget SHOULD be, Glade crashes. No warnings, just straight back to the desktop. All unsaved work is lost. Good times! The only work-around is to not click on the spot and instead find the widget (if you can) in your UI and click on it, hoping all the while that it's a visible widget because if its a vbox or adjustment widget you might be out of luck. A work around is to restart Glade. Closing the UI file and re-opening it may fix the issue too, I don't know.

Creating more than just the treeview widget seems to be a relatively new feature to Glade which might explain some of its oddities. First of all, how you add columns isn't exactly clear. Unlike other widgets, there's no treeview subcategory in the tools section where you can click on a category and easily add it to the treeview as a child widget. No sirree, you have to right-click on the treeview widget and select Edit. Okay, fine. Not a big deal. An odd design but whatever. How about a cell renderer? There is absolutely no visual clue that tells you how to add one. What you have to do is go into the Hierarchy tab, where you add new columns, and right-click on each column and select Add. Again, it sort of makes sense but with how easy it is to implement other widgets you would think there would be some kind of a clue like a button or tooltip which would indicate how you add a renderer. At least the Hierarchy tab had an Add button that let you know you could add something to it. View and controller done. What about the model?

Well, there's a property for the treeview where you can select the model to attach to it. It pops up a handy window that allows you to either select a tree model you've already created or, if you haven't created one yet, you can click New and Glade will create one for you. By default, Glade gives you a ListStore. This is where my problems began. I didn't clue in that it was a ListStore that was created by default. To be fair, Glade does call the model ListStore1 or something like that. I just never picked up on it. So I edited the model and put in the values I needed to store in the model. Uh-oh, what's this? Another stumbling block? Where's the string type? There MUST be a string type...Nope, can't find one! As it turns out, while a string is TYPE_STRING in GDK in Glade its called a gchararray. Yes, a string is a character array. So...why change what its called? Why not gstring? Oh...maybe that's why? G-string? Naw...must be another reason. Maybe just to piss me off? Either way, off I went and re-ran Vocab Builder to see if my changes were working. Yup, the treeview headers are clickable and the sort indicators look like they work. It does almost everything I want sans a few options I haven't implemented, yet. However, when selecting New in the Editor the ability to sort by columns disappears. What the heck? What's going on? After hours of trying to solve the issue, nothing. Bah! "I'll fix it tomorrow."

Here it is tomorrow the following day and I'm still not sure what's going on with the treeview so I start converting the Builder interface to get my mind off the Editor. Turns out I use a treeview in the preferences window, too. I can't escape these darned treeviews! Well, I decide to take another stab at it. I go through all the steps, forgetting how to do some of them and getting frustrated again, but I muddle through it. In my original code, I simply removed the old model and created a new one whenever I needed to update the treeview because it would always be new data. However, I realized that I could do away with all that if I just cleared the old treeview. Hrm...why isn't it working? It says it's not a TreeStore...I stared blankly at the screen in consternation. Ya, right, it's not. Its a ListStore. Ohhhh....what an idiot I am! I quickly convert my functions to use that of a ListStore and viola! Everything works as intended! Fantastic! Now, what if I want a TreeStore?

Luckily, this fix was relatively easy to figure out. Rather than have Glade create a default model for me I can just create the TreeStore model first and then attach it to the treeview. Easy. Fixed. Wish I'd known that yesterday the day before after spending hours trying to figure it out...

Addendum: If there turns out to be some interest in an actual step-by-step example of the process of creating a treeview in Glade/GTK+ I'd be more than happy to do so.

Wednesday 16 November 2011

Making the Switch from Ubuntu to Arch

I'd like deviate from Go for a moment. These last few weeks I've been distracted from programming due to switching my main desktop from Ubuntu to Arch Linux and helping my wife with our home-based business Geekling Designs. The Christmas shopping season is busy enough as it is but we're also in the midst of some major upgrades to our business. What with setting up a new small-business ERP software system (an oxymoron, I realize), building a new custom light exposure unit and purchasing a commercial grade screen printing press, we've been a tad busy. And then there's the desktop switch.

As I stated in a previous article, I've been a long-time fan of Ubuntu. Say what you will about it, it allowed me to move from a casual Linux user to a full-time user. It gave me the experience required to build an LFS system for the first time and encouraged me to finally grow as a programmer and invest in Open Source Software.

I've now finished the process of switching over my main system from Ubuntu to Arch Linux. I elected to use LXDE for my desktop environment for something with a little more pep. Neither my wife or myself care too much for the flash of most modern desktops (KDE, Gnome 3) and LXDE can be made quite elegant in its own right without all the cruft that come with the other two environments. I considered using Lubuntu but I felt it was time to cut my ties with the whole Ubuntu ecosystem for a little while. It's nothing personal against Lubuntu, I run it on my venerable laptop and I've installed it on friend's computers, I just need my space. It's not you, it's me.

Of all the things that Arch has going for it, I must say that it's wiki documentation and  forums are absolutely top-notch. It's rare I can't find an answer to my issues in either source. Even my wife has supported the change and has been impressed with the difference in speed between the two systems. I even changed to using the nouveau graphics driver. For regular desktop use, it appears to work superbly, much to my surprise!

Every system has it's quirks. Take, for example, installing the Eclipse IDE. Now, let me first preface this by saying this is less an Arch issue but an eclipse one. The version of Eclipse in the pacman repositories does not come with the Marketplace plugin installed. Nor could I get it installed. Needless to say, it struck me as odd that the version of Eclipse recommended by it's developers was not the one I found in the repositories. I'm sure there is a valid reason for it but it irked me none-the-less. I ended up uninstalling the Arch version and installing it from the Eclipse website. What can I say? I'm lazy and I like the ease of installing plugins from within Eclipse itself.

That said, the move has gone as smoothly as can be expected. No loss of personal data (thank's to keeping my /home directory on a separate HDD) and just the usual issues with installing required software and tweaking settings to work with the new system. Tough things usually "work out of the box" like they tend to do in Ubuntu some packages do need a little extra work.

That's the price you pay for freedom!

Sunday 23 October 2011

Experimenting with Cgo - Part 3: Errno

In this third installment of introducing cgo to novice Go programmers I want to talk about error handling. More specifically, how to handle C functions that utilize errno. At first glance one would think that this is something no harder to implement than anything else. Not so. There are a couple of "gotchas" with errno in particular you need to be aware of and little to no documentation to help you out. In particular, there was absolutely no documentation describing how to extract errno from os.Error.

  1. errno can't be accessed directly in Go. The cgo documentation clearly states why this is the case. In two words, 'thread safety'.
  2. There is a handy way to trap errno as an os.Error in Go but no obvious way to extract the actual error number.
After a lot of trial and error I finally pieced the puzzle together. First, if the C functions you're implementing set a common system error, as a function like fopen() would, then cgo provides a simple and easy way to get a Go-like error. Again, I refer you to the cgo documentation and you don't really need to look any further. If, however, you're using a library that doesn't you'll need to follow these steps, or at least some of them.

1. Map the error codes to sensible strings describing the error. Documentation on the library you're implementing usually does a good job helping here.

var errText = map[int]string {
    C.EINVAL: "Invalid mode specified",
}

2. Create a helper function to handle printing the error.

func error(e os.Error) os.Error {
    s, ok := errText[int(e.(os.Errno))]
    if ok {
        return os.NewError(s)
    }
    return os.NewError(fmt.Sprintf("Unknown error: %d", int(e.(os.Errno))))
}

This was the hard part. The os package provides Errno, which is Go's equivalent to errno. In order to extract Errno from Error you have to use a type assertion. Errno is typed to int64 which won't work with our C.int error codes so we need to then type cast it to an int.

3. Catch the error value returned by the function utilizing errno to describe errors.

    f, err := C.fopen(cpath, cmode)
    if f == nil {
        return nil, error(err)
    }

It's as simple as that. Complete source code follows:

Makefile:
include $(GOROOT)/src/Make.inc

TARG=cgoexample
CGOFILES=cgofopen.go

include $(GOROOT)/src/Make.pkg

cgofopen.go:
package cgoexample

//#include <stdio.h>
//#include <stdlib.h>
//#include <errno.h>
import "C"

import (
    "fmt"
    "os"
    "unsafe"
)

var errText = map[int]string {
    C.EINVAL: "Invalid mode specified",
}

func error(e os.Error) os.Error {
    s, ok := errText[int(e.(os.Errno))]
    if ok {
        return os.NewError(s)
    }
    return os.NewError(fmt.Sprintf("Unknown error: %d", int(e.(os.Errno))))
}

type File C.FILE

func Open(path, mode string) (*File, os.Error) {
    cpath, cmode := C.CString(path), C.CString(mode)
    defer C.free(unsafe.Pointer(cpath))
    defer C.free(unsafe.Pointer(cmode))
    
    f, err := C.fopen(cpath, cmode)
    if f == nil {
        return nil, error(err)
    }
    return (*File)(f), nil
}

func (f *File) Close() {
    if f != nil {
        C.fclose((*C.FILE)(f))
    }
}

example/Makefile:
include $(GOROOT)/src/Make.inc

TARG=cgoexample
GOFILES=fopen.go

include $(GOROOT)/src/Make.cmd

example/fopen.go
package main

import (
    "cgoexample"
    "fmt"
)

func main() {
    f, e := cgoexample.Open("foobar", "qq")
    defer f.Close()
    
    if e != nil {
        fmt.Println("Error: ", e)
    }
}

Tuesday 4 October 2011

Experimenting with Cgo - Part 2

In this second cgo article, I am going to demonstrate how to handle strings. There is already an excellent post by Andrew Gerrand, one of the Go developers at Google, on using strings in cgo. My own post will provide a slightly more complete example.

The first thing to understand is that C has no concept of a string. Unlike in Go, where a string is an actual type, a string in C is just a pointer to an array of characters. Thankfully, the "C" package has two simple functions to convert between the two types. However, there are two problems: One, converting from a Go string to a C string (character array) allocates memory to the string which is NOT garbage collected by Go. This is important! The reason for this is because Go has no way of knowing when the C library you're creating a language binding for will be done with the string. Once your function exists, any local variables will go out of scope and Go's garbage collector will at some point free the allocated memory even though the C library involved may not be finished with the string. Therefore, you have to free the memory when you know the C library is finished with it. Second, you still need a means of storing characters into a buffer and there isn't an immediately obvious way to do that.

This article assumes you've read my previous post and already know how to start a basic cgo project and have a working Go development environment. I am going to provide a very simple wrapper for the following functions from stdio.h: fopen, fclose, fputs, fgets and frewind.

Important: Absolutely no attempt was made to provide error handling in this code in order to provide absolute clarity for the code itself. While I believe proper examples should always contain error handling, handling errno and NULL return values is not easily handled in Go.

1. Include any C headers and import any libraries you will need:


// #include <stdio.h>
// #include <stdlib.h>
import "C"
import "unsafe"

Note that, when converting to a C string, you will need to free the allocated memory. Free() from stdlib.h is required to do this. You will also need to the "unsafe" library to handle C pointers.


2. In order to make stdio feel like Go, type the FILE structure:

type File C.FILE

While embedding the FILE type in a struct would allow us to create much clearer code because we could remove all the casting to/from the C and Go types Go does not allow C types to be embedded into Go structs. So, we must do things the hard way.

3. Implement the fopen() function:


func Open(path, mode string) *File {
    cpath, cmode := C.CString(path), C.CString(mode)
    defer C.free(unsafe.Pointer(cpath))
    defer C.free(unsafe.Pointer(cmode))
    
    return (*File)(C.fopen(cpath, cmode))
}

Notice first that, like the original C code, we accept strings as arguments to indicate the path and mode. The CString() function from the "C" package allocates enough memory for the Go string and then converts it to a C string. You must make sure you free the memory after using it, and the defer statement is the ideal way to accomplish this. Not only does it guarantee to free up the memory it does so after we return the value from fopen(). free() take a void pointer as an argument, so variables passed to the function must be cast to an unsafe.Pointer().


4. Implement the fgets() function:


func (f *File) Get(n int) string {
    cbuf := make([]C.char, n)
    return C.GoString(C.fgets(&cbuf[0], C.int(n), (*C.FILE)(f)))
}

I found this to be tricky to figure out until I thought about it. You need to provide a pointer to a C character array but Go provides no obvious ways to do so. Use Go's make() function to build an array of characters. You could also use a static array size but the dynamic version provides a lot more flexibility and is no more complex to implement. Use C.GoString() to convert the C string to a Go string.

5. Implement the rest of the functions. See below for the complete code.

6. Compile and install your library.

7. Compile and run a test program to complete your proof of concept.


The complete code follows:

godev/src/gostdio/gostdio.h:

package gostdio

// #include <stdio.h>
// #include <stdlib.h>
import "C"
import "unsafe"

type File C.FILE

func Open(path, mode string) *File {
    cpath, cmode := C.CString(path), C.CString(mode)
    defer C.free(unsafe.Pointer(cpath))
    defer C.free(unsafe.Pointer(cmode))
    
    return (*File)(C.fopen(cpath, cmode))
}

func (f *File) Close () {
    C.fclose((*C.FILE)(f))
    return
}

func (f *File) Get(n int) string {
    cbuf := make([]C.char, n)
    return C.GoString(C.fgets(&cbuf[0], C.int(n), (*C.FILE)(f)))
}

func (f *File) Put(str string) {
    cstr := C.CString(str)
    defer C.free(unsafe.Pointer(cstr))
    
    C.fputs(cstr, (*C.FILE)(f))
    return
}

func (f *File) Rewind() {
    C.rewind((*C.FILE)(f))
}


godev/src/cgoexample/cgoexample.go:

package main

import "gostdio"
import "fmt"

func main() {
    f := gostdio.Open("test.txt", "w+")    
    defer f.Close()
    
    f.Put("Some example text\n")
    f.Rewind()
    
    fmt.Println(f.Get(13))
}



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

Wednesday 24 August 2011

Compiling C Programs in Linux

A lot of beginner programmers, especially those new to the Linux world, have a lot of issues compiling programs. This isn't exclusive to C, of course, so hopefully you can take something away from this post and apply it other languages, too.

There are two primary stages to "compiling" a program. The first stage is the compilation stage. There are several intermediary steps but the end result is that your code, in this case C, is translated into a machine readable language. The second stage is called "linking". This is when each part of your program and any external libraries are linked together to create an actual executable binary file you run or a library file.

Disclaimer - This post may be hazardous to your health (not really). It is a non-exhaustive and non-authoritative introduction to compiling and linking programs on the command line in Linux. I can't emphasize enough that you should reference the documentation provided by the compiler you're using and that said documentation will always trump anything contained herein. Side effects may include: nausea, dry mouth, hair loss, severe depression and momentary blindness. If any of these side effects occur, discontinue use immediately and contact your physician.


Stage 1 - Compilation:


The Compiler:

First off, you have your choice of compiler. We are going to concern ourselves with the GNU C Compiler (gcc); currently, the most widely used C compiler for Linux. LLVM has been gaining ground but we won't be discussing it here though it stands to reason much of what you learn would still be applicable. The GNU C Compiler, usually simply referred to as GCC, is actually a collection of tools for compiling programming languages. Each tool has a unique name which reflects the language it is designed for. For example, compilers exist for the following languages in addition to C: C++ (g++), Java (gcj) and Fortran (gfortran). Only some, though possibly all, may be installed on your system by default.

Important: Do NOT use g++ to compile C language sources. There's a reason why they are separate compilers.

In the case of C, make sure you have a GCC installed on your system. Open a terminal and type:


gcc --version

If you get an error of some kind, chances are you don't have GCC installed and will need to do so before you can go any further.

Hint: For those of you running a Linux system like Arch, Debian, Fedora or Ubuntu you can install any of the tools discussed within this document quite easily. For example, Debian based systems usually have a 'build-essential' target via apt-get for installing commonly used tools for building programs from source. You can simply issue the command 'apt-get install build-essential' without the quotesCheck your specific distribution's instructions for installing these tools from their respective repositories.

Everything in this how-to should be run in a terminal. Make sure you change to the directory where your source files are contained and execute the supplied commands within than directory. There are many, many compiler flags to know but the following should be considered a minimum:

gcc -Wall -pedantic -std=c99 my_file.c -o my_program

...replacing "my_file.c" and "my_program" with the proper names of your file(s) and desired program name.

Compiling a source file with the above flags will produce a final binary, skipping the separate linking stage. However, as your programs get more complex it becomes advantageous to build intermediary objects first then link them together later.


Compiler Flags:

These flags are passed to the compiler to tell it what you want. There are some very important ones to know:

-std=c99 - This flag sets the specific standard for gcc to comply with. At the time of writing gcc defaults to a standard called gnu89, which is the c89 standard with GNU extensions. If you plan on writing a program which may be compiled on a system which does not use gcc as it's C compiler (LLVM, MS Visual Studio, Borland C, etc) then it is probably in your best interest to force the use the most current C standard and disable the GNU extensions. gcc is not 100% c99 compliant but the non-compliant features are rarely used. If you require any of the features of c99 which have not yet been implemented in gcc then you'll have to use another compiler anyway.

-o - Specify an output name for the object or binary. In the most basic case, you use it to specify the name of the program you are producing. If you don't use this flag, gcc will default to using the name of the source file and create a .o file for an intermediary object (myfile.c becomes myfile.o) or, in the case of creating a binary, it will default to a.out for the binary file.

Compiler Warnings:

Warnings should always be turned on. Here are some very important/common ones to know:

-Wall - all warnings; this is misleading because it doesn't actually turn on ALL warnings but just the most commonly desired ones.

-Wextra - turns on extra, more strict warnings.

-ansi - specifies that you want to adhere strictly to the C standard. It turns off all GNU extensions to the C language making it fully ANSI compliant. This is important for portability between compilers. This is automatically turned on when you specify the standards c89 or  c99 with the -std flag. However, as stated earlier, gcc defaults to gnu89 (c89 with GNU extensions) and the -ansi flag will explicitly disable these extensions. -std=gnu89 -ansi is equivilent to -std=c89.

-pedantic - makes ANSI warnings fatal, meaning that they'll be reported as errors instead or warnings and halt compilation. It is usually a good idea to always enable this flag when you give -ansi or -std=c89/99.

Extra Compiler Flags:

-c - compile object code but do not link. This produces a file with the .o extension. Object files, those ending with .o, are later linked together to create a final binary or library.

-I <directory> - This flag allows you to specify an additional location for the compiler to find your header (.h) files by replacing <directory> with the location of the headers being searched for. This is useful if you store your header files in a directory other than the one your regular source (.c) files are located. You can chain as many of these flags together to add as many directories as you need. If you don't know why you would need to use this then it's safe to just leave it out.


Stage 2 - Linking:


The Linker:

As noted earlier, building a program is a two step process. The second step, after compiling, is linking. In most, if not all, large projects sources are usually compiled first into object files. On their own, they do nothing and are essentially useless. In order to work, they need to be linked together to create a single binary file, an actual program, then made executable. This is where the linker, named 'ld', comes in. The linker has its own set of flags which may either be passed to gcc or to ld itself. It is probably easier, and in your best interest, to issue the flags to gcc for simplicity's sake.

Linker Flags:

-l<library> - where library is the name of the external library you need to link into your program, sans (minus) the 'lib' prefix. In other words, if you with to link the math library, libmath into your program, you drop the 'lib' part and use: -lmath. Actually, the linker can find libraries with a basic regex so you can link -lm for the math library.

Extra Linker Flags:

-static - Used to force libraries linked to your program statically. This means that the library itself is incorporated (bolted on) into your program. This increases the size of your program but does away with some of the issues associated with dynamic linking. A discussion on dynamic vs. static linking is WAY beyond the scope of this article.

-dynamic - Force libraries to be dynamically linked to your program. This means that the library is linked to your program but not actually loaded until the program is run.

-L <directory> - Specify a path to find extra/custom libraries by replacing <directory> with the location of the libraries being searched for. This can be used to link external libraries not in installed in the normal paths searched by the linker. It is also used to specify directories within your project if you are linking to internal libraries.


The Next Steps:

For compiling very small programs it is usually easiest just to run gcc from the command line. As programs get larger, though, it usually becomes necessary to remove some of the complexity. The next step would be to create a custom Makefile to build your program. You may then simply issue a single command, make, and the rest of the work is done for you. I mentioned earlier that it becomes simpler to compile sources into objects first then link them later. That is because as a project gets larger the longer it takes to compile and link. By utilizing a Makefile only files which have been modified are recompiled and then re-linking thereby speeding up the build process when changes are being made. This is especially helpful when debugging.

The next step would probably to use a full build system like the GNU autotools. Autotools is a general term for a suite of programs: aclocal, autoconf, autoheader, automake, autopoint and libtool. GNU autotools provides a method of making your code more portable and easier to distribute. They can even roll a tarball for you and compress it. By utilizing tools like GNU gettext and GNOME's intltool you can integrate translations into your project, too. The autotools are the backbone of other distribution methods, as well, like creating an .rpm or .deb in Linux and knowing how to use them tends to be an essential skill. There is plenty of help on the Internet on using GNU's autotools. Just do a web search and you'll find plenty of help.

If you're having trouble, read: How to Get Help

Thursday 11 August 2011

Much Adieu About Patents

I can appreciate the significance of patents. Were I an inventor and I created something novel I would want to protect that invention. Why should someone else ride on my coat-tails? I invested time and money creating my invention and I should have the right to protect that investment. There are actually three separate methods I can use to protect them: trademarks, copyrights, and patents. That said, I'm only going to talk about one of them. Patents.

There is a limit, though. An idea must be novel. If it occurs in the natural world, like mathematics, then it can't be patented. Two plus two is four. It is innate to the universe. Most any child can do basic arithmetic. Extrapolate this method to physics, also a mathematical discipline, and you see the same. The universe and Earth existed long before humans evolved and so those things are not novel in the sense of human creation and therefore can not be patented. What of human physiology? What of human creations based on naturally occurring things. Where, in essence, is the line?

You can't patent a human heart but you can patent a creation which mimics one. You can't patent a human gene but you can patent an altered gene; that is, a gene which has been modified to such an extent that it can be said to be non-naturally occurring. You can't patent a mathematical equation but you can patent a computer algorithm. You can patent something that has already been created as long as no one else has patented it first.

Now, those who follow patent law realize that some of my statements aren't entirely true. While yes, you can patent a creation previously developed and lay claim to it, the patent would be invalid if prior art, examples or depictions of your invention prior to patenting it, can be found. A gene therapy which does not alter the genome in such a way that it can still be said to be naturally occurring also can't be patented.

Some patents are so blatantly obvious that you wonder how one was ever granted in the first place. Certainly, it would be nullified upon re-examination but what if it never comes to that? Patents are a weapon. The sharp edge of innovation. What do you do if you are being sued, by a company with nigh unlimited money, for patent infringement for obviously bogus patents and you yourself would run out of money before you could ever hope to have the patent(s) re-examined? What do you do when that same company offers you a license agreement or a settlement for an exorbitant fee but much less than the cost of your defense? Do you go bankrupt or settle? Which is the better choice?

In computing, the idea of patents is very murky. Computing is, in essence, mathematics. a + b = c is equivalent to 1 + 2 = 3. Calculus. a, b and c are variables which contain values. Using a function to add them together via a mathematical equation and returning the result is just that. Math. Math, as we've already stated is naturally occuring and can't be patented. It's not so simple though. What if my equation is made up of a quantification of superfluous things? Take, for example, a dating site. They may use an equation like: personality + interests = compatibility. They quantify intangible things and use an equation to compute a compatibility score. The equation is naturally occurring but the quantification algorithm is supposedly novel thereby making it patent eligible. Strange, isn't it? That little loop-hole? The question is, is it a valid argument?

I, personally, am not sure it is. However, let's assume that's the case. The issue at hand is: at what point does it make sense to patent an idea to protect yourself from people stealing your ideas vs. attacking anyone who may even remotely prove to undermine your stranglehold on a market? That's the difference between anti-trust and legitimate business practice. Let's be real here. If you invent something unique and novel you can patent it. If you create 100 such items you could potentially hold 100 patents. Yet, some companies have patents in the 1,000's, some over 10,000! That doesn't seem logical to me. How can any one company invent that many patent-able things? The truth? They can't, and they didn't. First off, many of the patents are erroneous at best. They wouldn't hold up to re-examination. Second, these are patents that were purchased from others. Companies amass what people term "war chests" of patents specifically to use against others, or protect themselves against attack. Does that sound like the kind of behavior that patents are supposed to protect?

Patent policy is in dire need of reform but don't hold your breath. Industry controls government not the people. Industry, or at least the most powerful members, like patents the way they are. They don't have to innovate, spending millions of dollars on research and development. No, they can't just extort money from other companies too small to defend themselves, forcing them to sign licensing agreements over bankruptcy.

Does this sound like the innovation that patent law is supposed to protect and promote? I think it's rather to the contrary, that current patent law is stifling innovation. "You create something new and we'll sue you." Ya, I'll get right on that band-wagon. Patent law was based on protecting inventors of things. Like, the Frisbee or McDonald's method of building a hamburger/sandwich (I kid you not). Software patents don't make sense. On the surface it does by conventional means but computers, or more specifically the software they run, are not conventional inventions. They're equations. Literature, if you will. That's why we write programs in computer languages. You can't patent the method of assembling a sentence any more than you can patent water or the equation two plus two equals four. All of them are naturally occurring and could be discovered by anyone. There is nothing novel about them.

I agree that patents are a worthy cause to support. I also think that patent law is in dire need of reform. It just saddens me that it will probably never happen and consumers will be the ones to pay for it. Licenses and litigation cost us money because the more costs a company incurs the more they have to pass on to us. Patents really are something that should concern every one of us because they effect our own personal bottom line. That TV, mobile phone, or any other electronic device (each of those items run software even though you're not aware of it) could cost cheaper if it wasn't for patents. Not because there is a patent on that device which allows only one person to create it. Indeed, if you can innovate a different device to compete against it then you finally have true innovation, the purpose for which patents were created. No, it costs more because companies are either paying licensing fees, lawyers or purchasing patents to protect themselves. If software patents were abolished then the world would be a much better place for all of us.

Groklaw, incidentally, is an excellent site to follow. I highly recommend it.

Tuesday 9 August 2011

How to Get Help

Originally, this was going to be a part of another post but I've decided that this piece of information should really be on its own. The idea for this post comes mainly from my experiences and observations on the programming forums I frequent, namely the Ubuntu Programming Forums. Nothing is more frustrating than someone who won't help themselves.

So, my first piece of advice is: Try to figure it out for yourself, first. There is a lot of information on the Internet and in books. Asking for help should not be your go-to course of action. Indeed, consider it your last line of defense. Let's be honest, while it may be the easiest, it's certainly not the fastest and probably not the most exhaustive. Sometimes, you're lucky to get an answer all. So, search first and ask second.

If you want to get an answer quickly, learn how to use search engines properly. I can't stress this enough.  Think about what you're asking. Try to make your search terms very specific but not overly complicated. A good search will likely only contain a couple words. It should not be a full sentence or proper English (or whatever tongue you're searching in). "How do I compile a program," is less effective than, "compile c" isn't. After looking at the first couple results and you decide it's not helping (they're all on how to compile c on windows or in an IDE and you need to know how to compile it on the Linux command line) you need to grow your search criteria, "compile c linux command line." The order of terms isn't usually important. For more help on optimizing your search results try, "google search help," and blam, you get an answer.

My second piece of advice: When asking questions on a web forum make sure you ask something specific and give as much information as possible. Asking, "How do I compile a program," is so nebulous that if you get an answer at all, it likely won't be very friendly. You need to specify what language you need to compile, which operating system and/or distribution, and any prior experience you have. Saying something like, "I've done some searching and couldn't turn anything up..." or "After a couple searching, I'm still confused because..." will help but, let's face it, if you really haven't done that people are going to know. Assume they're a lot smarter than you are until they prove you wrong (and many will). Do your homework. Like I've said already, it becomes obvious quickly if you haven't. People become hostile if all you do is want them to do the work and not do any yourself. Try and be as self-sufficient as possible. Take the initiative. Only ask questions when you just can't figure it out yourself and searches aren't getting you anywhere.

My third piece of advice: Make sure your question is relevant to the forum you're in. If you're on a Linux forum don't ask a Windows-only question. It's not that people can't answer or will be offended by it (though they might) but do you really think that is going to be the best source of answers? Doesn't it make sense to go where a lot of other Windows developers are? Asking why a program won't install or how to create a web page on a programming forum (happens all the time) make sense to you? What relevance does it have? Why kind of help are you really expecting? Would you ask a doctor how to build a house, ask a police officer how to tend your lawn or a cab driver how to fly an airplane? Basically, don't ask off-topic questions! If you have an honest question, no matter how basic or silly, and you've clearly tried to help yourself, then most people will be happy to help.

My last piece of advice: Think for yourself. Think about what you've been told and see if it makes sense. Does it agree with what you already know? Always check more than once source to make sure they agree (in computing, they often don't). There's a lot of bad advice (hopefully, this isn't) out there so it's always a good idea to not accept the first thing you read and keep looking at at least two or three alternative sources. Make sure the sources are credible too. Why would you trust the authority of someone if they've done nothing to back it up. There's a huge difference between theoretical knowledge and practical knowledge.

Good hunting.

Saturday 6 August 2011

An Introduction of Sorts, Part 4

In the final installment of my introduction I'd like to move away from programming. There's no question that Programming is a big part of my life. I am currently working on my Vocab Builder project and it will take me a long time to complete, if ever. I also like computers in general. I like to game. I'm adept at many office programs (both free and propriety). I follow developments in software patents, something I'm fairly against. Patents, I mean, not following the news about them. I use Linux extensively and believe in Free and Open Source Software. Not to be confused with the now nebulous Open Source Software which gets paraded around these days like a wolf in sheeps' clothing. I'm no granola crunching, long haired, smelly hippy mind you. I also support proprietary software; everything has its place. But, on to other things!

First and foremost, I'm a proud father of two young girls. Most days I love being a dad. It is an incredible experience. Most days. I won't lie to you though. It's not all roses and sunshine. Some times it's not fun being a parent. Heck, there are a lot of days like that! Thankfully, though, the good outweighs the bad. There are so many things people never tell you about being a parent and in many ways that does everyone a disservice. Everyone is led to believe that, while parenting isn't easy, it's not hard either. They don't ever give you the full picture. Mind you, if they did, you might make yourself a eunuch or use some other form of irreversible birth control!

I work as a credit manager for a small-medium distribution company. I enjoy working with numbers and finances so the job works well for me. I can support my family and do something I don't hate. Most of the people I work with are fantastic people too. Nutty, like me.To quote J.K. Rowling, we're, "Nuttier than squirrel pooh." What more could you ask for? Well, less of a commute but I'm just being picky now, aren't I?

My lovely wife is a stay-at-home mom. About two years ago, while on maternity leave with my first daughter, she decided to start a hobby making children's shirts. Well, not making the shirts but buying blank shirts and putting a design on them. Mostly they're clever sayings. I came up with the clever ones. No really! The hobby has now changed into a business called Geekling Designs. My wife, Jennifer, and I run the business jointly, discussing new ideas for designs, the company's direction, the acquisition of equipment and regular day-to-day business decisions. Sometimes I'm amazed at how little we fight. I mean, we all have disagreements. Or, should I say, I'm always right and she sometimes, incorrectly, disagrees with me. It's not easy though, having a full time job, two young children and a business to run. I'm just thankful, each and every day, that I'm not where my wife is sitting. At home all day with two young children both under 4 and trying to run a business at the same time? No thanks! It's time to go to work! See ya, hun!

We also have two pets. A cat and a Pug. Pug owners understand why I didn't call our Pug a dog. They're not dogs. They're smelly, snuffly, loud, barrels with legs with so much personality it just oozes out of them. Literally some times. It's ever so fun cleaning eye goop out of their nose fold/wrinkle. She's getting too fat too, from lack of exercise, so we need to get her running about more. Just that the heat makes her wheezy and she chokes on her own tongue. Lovely. The cat, on the other hand, is equally a pain but we love her. If she feels like she's not getting enough attention she likes to bunt your cup containing scalding hot tea as you bring it to your lips. Or sit on your CRT monitor with her back to you and dangle her tail in front of the screen. When that doesn't work, she'll casually stretch out over the monitor and dangle a front and back leg over the screen and try and bring in the tail for some extra added interference. If it's the LCD screen, she just sits in front of it and stares at you.

All in all, the zoo in which I live is incredibly entertaining and fun. I may complain from time to time but make no mistake: I love each and every one of them.They're all a part of me. Who I am and who I'll become. I hope that nothing ever happens to take them away from me as I'll certainly be the lesser for it.

And that, as they say, is that!

An Introduction of Sorts, Part 3

The next step of our journey takes us through the second to last leg of my introduction.

So, in my escapades with C, I have learned the following:

1) C is not the best language for every task. Naively, I thought that if I started with C not only would I be able to write any kind of program (which you can) a person can conceive of but that it would act as the basis for learning any future languages (which it doesn't) should I so desire.

2) There are many cool languages to learn, too many in fact. In working through Beginning Linux Programming I came across Tcl/Tk, Perl and shell scripting (Bash specifically). Through other sources I came across Java, Python, LISP and Go. And from there things explode. There are literally hundreds of languages out there!

3) Learning a language doesn't teach you to program, at least, not well. As it turns out, knowing a language doesn't help you much. Algorithms and structure go a lot further in teaching programming. Understanding how to implement a linked list, the best method to store persistent data or the most efficient method of manipulating data is far more essential than knowing where to place a semi-colon or bracket.

4) A compiled language is not the end-all be-all. The JVM, for example, is very cool and Java has all kinds of implementations. You don't need to write Java to use the JVM. Clojure or Jython are examples of languages which are compiled to Java bytecode for execution on the JVM and can take advantage of everything it can provide.

5) Interpreted languages like Perl, Tcl or Python are not slow. First thing to remember, is that over the years things improve and a lot of information on the Internet is old. Really old. A post from 2002 ranting on how slow Python is, is no longer relevant. A heck of a lot has changed in 9 years. With the way technology changes these days, a matter of months can make all the difference. It also has to do with writing idiomatic code and implementing good/quick algorithms which complement the language. While yes, in certain instances, a C implementation of a specific task is faster than the equivalent in Python. However, compare parsing lines of text with C or C++ to Perl. Write an application with a GUI in C and compare that with Tcl/Tk, Java or Python. It's all about matching the tool with the job. You don't bring a hammer to tighten a screw.

6) There is no one way to do something. Quicksort or Bubble Sort are not the only ways to sort data. Not only that but often language implementations may be faster than anything you come up with on your own. You need to know the strengths and weaknesses of the language you're working in to get the most out of it.

7) Dynamic Linking is not necessarily superior to Static Linking. It is also not to be confused with Dynamic Loading. Google's Go language taught me that.

8) Skills aren't necessarily transferable. Knowing how to manipulate pointers, manage memory and use pre-processor directives doesn't usually apply outside the C world. Many languages don't have pointers (or are at least not the headache they are in C), use garbage collection and have no need of  pre-processor directives. That doesn't mean that C, or any other language (read: all), with non-transferable skills don't have something to teach. It just means that everything you learn won't be transferable to another language.

9) There is a trade-off between writing a fast program and writing a program quickly. No one wants a slow and sluggish application. On the other hand, a couple seconds overall is likely not even noticeable in most situations. Now, compare that with how quickly a program can be written in Python or Go to C or C++. There's no comparison.

10) Design is where you should spend 90% of your time. I can't stress this enough. An excellent programmer following poor design will create a mediocre application. A poor programmer implementing an excellent design will create a good program. If you can combine the two, a good design with a good programmer, and you'll make an awesome application.

11) Benchmarks mean little to nothing. Look no further than this example. Any language can be optimized in such a way but I can't think of a better example.

It's funny that, reading back, I haven't even scratched the surface of what there is to learn but this certainly is a foundation for describing how much I know.

In the end, not much.

Wednesday 3 August 2011

An Introduction of Sorts, Part 2

Learning C without the help of formal education isn't the easiest task. Some times I feel like MacGyver trying to use an elastic band, a paperclip and a funnel to make a rocket ship. No really! That's what trying to write a game or large program is like in C. The language gives you some rudimentary tools with which to craft intricate art with. However, that being said some very powerful programs can be written in C. You just need to learn how to use the tools and fine tune their use.

I would describe myself as an intermediate to advanced C programmer. By no means am I an expert and I'm a far cry from being a master/guru. To understand why I consider myself thus, you need to understand the full breadth of a computer language. Any one computer language consists of two parts: 1) Syntax, 2) Libraries and Tools. Learning the syntax and idioms of a language can be difficult but as you grow and learn it turns out that discovering the idiosyncrasies of a language is the easy part. Learning the standard and third party libraries and tools are the hard part. When I began learning C, I thought that once I had learned the language I was done. I was a master. Just call me Yoda. Ya, right. Let's see...what do we need to know:

1) Language Grammar: punctuation (semi-colons, brackets), code blocks, scope, reserved words, loops, conditionals, macros, preprossessor directives, etc. all make up language syntax;
2) Compiling: compiler flags, linker flags, and all other manners of subtle nuances of each compiler you need to know in order to even build your code;
3) Debuggers: backtraces, core dumps, debugging programs (gdb), profiling and symbol tables are some of the tools you need to learn to be an effective programmer in C;
4) Standard Libraries: printing, strings, locales, file input/output, etc.;
5) Non-Standard Standard Libraries: "You're kidding me, right?" you might be asking. Oh, no! I'm not joking. Unix libraries vs. Windows, POSIX libraries, and all manner of things in between. Start learning sockets, you'll see what I mean;
6) Standards Complient: No, there's no one version of C. There are several C standards and more are on the way. Learning C once isn't the end. You'll need to keep reviewing the new standards, especially when a compiler changes to a different default standard (C89 for gcc but I expect it to change C99 eventually);
7) Third-Party Libraries: This is the balance of all the other libraries out there. For C? There's a LOT.
8) Portability: This one is a mixed bag and it depends on how people are using the word. For some, portable code means it can be ported to other Unix variants like BSD, Linux, etc.. For others, like myself, I take it to mean code can be ported between operating systems. In most cases, this is no easy task and can quickly turn into a nightmare. Remember I mentioned sockets? Just the tip of the iceburg. More on that in another post.

I feel like I'm missing something. I probably am.

Well, there is something. A couple somethings. There are the tools you need to work with your code. The first of these is a development platform. What operating system do you use to program on? I, personally, program on my Ubuntu Linux box. You'll need to pick up a compiler. The most popular in the Linux world are GCC and LLVM. You'll need to install a debugger. How about an automatic build system? Oh, don't forget a programming environment. Now, I prefer to use a terminal and a text editor. Others, especially those from the Windows world, prefer an IDE.

I eventually chose a book called Beginning Linux Programming. Now, I already had enough background to jump right in and this turned out to be a fantastic book for me. Now, it is more focused on Linux programming, as the name implies, but it also teaches theory and techniques usable by anyone. The main thing I learned was that I had a lot more to learn. A lot more.

Your mind fried yet? I know mine is.

An Introduction of Sorts, Part 1

Learning to program can be a very daunting task. It doesn't seem that way at first, of course, but once you dive in you finally get to see what it's all about. It's like being a parent. No one can prepare you for being a parent. I realize that phrase is getting cliche but that makes it no less true. Your kids can make you incredibly happy and unbelievably angry. You're tired all the time. You get no time to yourself. You're delirious with frustration and lack of sleep. Same with programming. Well, except having no time for yourself. You get a lot of that.

Like most kids, my life with computers started with video games. The problem is, the more you play the more critical you become. "These graphics suck!" you say, and "That's a terrible bug! How did this junk ever get out the door?" Eventually, you might even think, "I can do better!" So, you put your money where your mouth is and here you are. Programming. Ya, not so easy is it?

First off is language choice. Now, if you decide to pursue programming as a career and head to college or university your choices are narrow. You basically get to pick whatever it is your school curriculum decides to teach first year students. But, if you're like me and went to school to attain some other degree or didn't go to school at all, you'll find out that the choice isn't a simple one. There are literally hundreds of languages for all kinds of tasks which are all perfect for you! Which one is right? Which should I pick first? I wish I could help you. There's no easy answer and I have neither time or desire to help. Sorry.

Now, I did happen to putter around with BASIC when I was in high-school and I tinkered with a rather obscure language called LPC. I did happen to take a first year programming course in college in which I was introduced to C which was remarkably like LPC. Later on I took a Visual BASIC and second year C++ courses. I did well with Visual BASIC  but I failed miserably in the C++ course, dropping out early in the term. To program you need to be in the right frame of mind. You need to be ready for the world of programming as much as it needs to be ready for you! "Look out world! Here I come!" BLAM! Right into a brick wall. That's how it is. If you expect it to be easy, think again. Anyone who says that it is, is either a liar or a genius. Smart money is on the former.

Many years down the road I decided to give programming another go. I still played with LPC a bit but now I wanted to do "real" programming (to understand why I felt this way, perhaps check what LPC is used for). My path lead to me back to C, and this time, I was ready.