Guadec is great!

Been fucking awesome so far. I've met lots of great people all very friendly. The partyin has been long and tough with no nights ending before 3am. I have no clue why I'm not sleepy at all. Must be the strange Canary coffee... It's not hot, not cold and tastes kind of sweet, very different from what I'm used to.

The beach is great and the weather almost perfect. It's hot as hell but a cold breeze is blowing so it never becomes unbearable. I already sunburned which is as expected. The best thing about the beach is the topless girls. And I am a dirty bastard so I've been staring until my neck gets sore. Haven't taken a dump either. Probably I should be doing it right about now but I'd rather first walk back to the hotel. I don't like shitting in public toilets.

Fucking Fair Scheduling

I'm running a compile in a terminal which takes most of the CPU. In another terminal I'm viewing a log with less. And less is fucking lagging!! How fucking broken is that?

Deep Space 9

Turns out Deep Space 9 is quite good after all. There are a little to many similarities with TNG, but that's also good in a way since the TNG seasons was fantastic. Ben Sisko is the station commander and is in many ways comparable to Picard. Except he doesn't have the same interesting personality and charisma that Picard had. He is kind of a light version of Picard.

I almost wrote black version of Picard. It wouldn't have been accurate because he fits the role well and his skin color neither adds nor subtracts from it.

I like Julian Bashere as the stations doctor. He manages to convey his role very well and isn't as bland as Bevery Crusher was. My guess is that he will play even better in the next seasons of the series (I've only watch the first one so far).

Even the child actors are bearable. Nogg and Jake. They bring some mischevious funnyness into the series. Definitely not my type but since they are good actors it manages to become decent. That's in stark contrast with TNG in which all child actors without exception were horrible. Especially Wesley Crusher, yuck. I believe one of their reasons for existance is also to give Odo some "lighter" scenes.

Odo is a shapeshifter, grumpy and seem to dislike everyone and is the chief of security on DS9. I don't know who the actor is but I know it's someone famours. I just can't remember where I've seen him before. His character is in many ways like Worf, but I'd say his acting is a tad bit stronger than Worf. Or maybe like Data in that he is a non-human and have special powers.

I miss Data. There is no Data on Deep Space 9. And also no Geordie LaForge, which is a shame. Those were the best actors in TNG.

Then we come to Commander Kiera, Sisko's right hand. She is not bad and not good. Kind of bland so far and cries to much. Apparently one of the main storylines will be the Bajoran independence (DS9 is a Federation outpost in the Bajoran system). Since she was a member of the resistance movement during the Cardassian occupation. Undoubtedly there will be more sad, emotional and heart breaking scenes to come for her. Which is BOOORING.

Not to forget, Chief O'Brian were transferred from Enterprise to DS9 and now serves as chief of technology on the station. He is exactly like he was on Enterprise but now he gets more scenes. Good move by the produces, I like him.

And then to forget, Liuetenant Dax. Totally boring, emotionless and perfect in every way. She has a nice ass, firm tits and tight costume. I hope the producers were smart enough to include some shower scenes with her.

Quark is the ferengi bartender. Not in the least similar to Guinan. He has already got lots of scenes and been able to build up a lot of character. In the DS9 universe, ferengi apparently aren't as disguisting as in TNG. Nogg is even wearing some kind of "cute ferengi" costume. Like fewer wrinkles and better teeth. I can live with that.

Who ever is playing Q is playing well. But it just makes no fucking sense that he would stop harassing Picard and begin harassing Sisko. It's just silly and unrealistic. I always had a hard time for the Q episodes even the good ones (e.g. the trial against humanity), the DS9 ones will be worse.

All in all, I've enjoyed the episodes so far. I'll give it four out of five comm badges.

I'm an ASSHOLE

Alltid. Dagen efter jag varit full oroar jag mig för ifall jag varit ett arsle eller inte. Gjorde jag bort mig, var jag ett svin mot folk eller bara allmänt social och trevlig? Det är svårt att veta för jag kan ju inte fråga de inblandade vad de tyckte om Björns beteénde på en skala ett till tio liksom... Den här gången tänker jag inte grunna på det iallafall.

GUADEC 2009

Realized I'm in the exact same situation regarding GUADEC as I was two years ago. :( Excep this time no girlfriend. I really want to go, but damn is it expensive.

Branches..

are stupid. Very stupid. Especially subversion ones. :(

The Defragmentation Lie

It has been said for years that files on Linux does not become fragmented so it doesn't need defragmentation. It is not true!. Large files can certainly be fragmented on Linux, especially if they are written to often. Bittorrented files for example. Here is the proof:

$ sudo filefrag big-500mb-file filefrag big-500mb-file: 4316 extents found, perfection would be 3 extents $ sudo sh -c "echo 3 > /proc/sys/vm/drop_caches" # Clears fs caches and forces Linux to read from disk. $ time cat big-500mb-file > /dev/null real 0m24.842s user 0m0.032s sys 0m0.592s

Thats the time it takes to read the whole file sequentially takes when it is heavily fragmented. Compared to how long it would take if the file was not fragmented:

$ cp big-500mb-file 500mb-copy $ sudo filefrag 500mb-copy 500mb-copy: 6 extents found, perfection would be 3 extents $ sudo sh -c "echo 3 > /proc/sys/vm/drop_caches" $ time cat 500mb-copy > /dev/null $ time cat 500mb-copy > /dev/null real 0m6.501s user 0m0.024s sys 0m0.508s

Note that the file is still fragmented, possibly because other IO operations are going on in the background. Three things can be learned from this exercise.

  • Fragmentation does matter!. It took four times as long to read the fragmented file as it did the unfragmented one. The overhead could be even worse for smaller files because the seek time dominates. E.g. a 2mb file in 10 fragments could in worst case be 10 times as slow to read as if it was in one fragment.
  • Bittorrent leaves files in a heavily fragmented state. Likely because thousands of writes are performed to the same file and it is hard to get them all in order. But I don't understand why it could preallocate the files in advance and then write to them?
  • cp can defragment files.

Bazaar loses to git

And now I have tried bzr too. Maybe it is to early to declare a winner in the epic battle between it and git since I only have about 20 minutes of bzr experience under my belt.

Never the less, git is the winner and bzr is the total loser. I have used both tools to mirror the waf Subversion repository. Here are my conclusions:

  • Both tools take a long time to clone a Subversion repository. Like an hour for bzr and two hours for git for a repository with about 4000 commits.
  • bzr version 1.3.1 released in April 2008 has some severe performance problems. Simple commands like bzr diff, blame and log takes almost ten seconds to execute. Those commands are instanteous in git.
  • git log and diff are colized by default. Their bzr equivalents are not.
  • git uses some kind of smarts so that it automatically pages output through less when needed. bzr does not.
  • The Bazaar User Guide at least looks much more helpful than the Git User's Manual.

The last point is Bazaar's only redeeming quality. But it is a big one and I will spend some more time with it before deciding if Bazaar is rubbish or not.

The reason why I'm even considering bzr is because I'm getting sick of gits branch model. It just doesn't fit my brain. There is no such thing as a branch in git, branches are just pointers to commits. That leads to annoying problems when you want to rebase a branch tree.

Say that you are working on feature branch foo. In that branch you branch of to an experimental branch bar-foo. Then you want to update foo because some new commits has arrived at master while keeping your private branch structure intact. The only way to do that, I've found, is to rebase both branches. First you rebase foo to master, which probably involves solving some conflicts. Now your branch structure is messed up, the bar-foo branch will contain all the commits from the foo branch. That is, the foo branchs commits are duplicated!

It is totally stupid and absolutely not what i wanted. The solution is to rebase bar-foo on top of foo. But now you will have to resolve all the conflicts from the foo branch again!

Multiply with the number of branches you have combined with gits unwillingness to automatically resolve conflicts and you get lots of work needed just to keep some feature branches up to date with a Subversion master. I really hope bzr's workflow is better.

The Year in Review

It is the day after New Year's Eve and yet another year has passed. Most people are doing these reviews of the past year so guess I have too.

In my life there has been upsides and downsides. I have accomplished some goals and failed to reach others. Has it been a good year? I don't really know, maybe I should have been able to complete more goals or been able to avoid more of the bad moments.

On the relationship front, Im Western nicht Neues, sums it up nicely. I haven't gotten a new girlfriend and I haven't really looked for anyone either. I don't think I want to maintain a full-time relationship that I used to have. Though I am completely over my last one. A girl that I would only have to visit a few times a week or something would suit me better.

I have still met some girls over the year and have had some kisses. It is still hard for me to meet people, but at least I've learnt the basics. I'm especially proud of my performance with the chubby teacher. But I'll keep the details to myself. :)

The autumn vacation in France was totally awesome. I went alone to Lacanau for surfing and got to know some wonderfully cool people. It was a total blast. One of my new year's resolutions will be to keep in touch with them. I definitely want to visit Jeff, Jean-Sebastien, Olivia and the others some time this year. I have some great photos from it that I should publish somewhere.

I did some great stuff last year. Unfortunately, I did almost everything on my own. Sometimes that can be a little lonely. I bathed in Mälaren twice, saw Dark Knight in the movies and went to the gym dozens of time, but all by myself. I even went out to nightclubs alone.

Which brings me to the major downside of the year; I didn't make very many close friends. That's simply it. I should be good friends with the boys from Ericsson, I should be closer to the guys I go out with, I should have someone I can play guitar with. But it just hasn't happened and I can't explain why really. It is my biggest goal not reached this year. I hesitate to call it a failure, but that is probably what it is, I'll try harder this year!

I bought a condo in Akalla (actually in December 2007) which I moved into from Södertälje. It is three times larger than my old apartment and I'm quite happy with it. Close to the metro and 20 minutes to the city. Of course I know it was a bad deal and the housing market has tanked. Bo fucking ho, I'm much happier here than in Södertälje. Now I can vacuum clean without having to move the furniture around. :) And I have an oven!!

I like the girls in Husby, they are all dark brown and very hot. I met one in the summer but it didn't work out at all. :) And the mall by Kista station that is open to 21:00 every day is extraordinarily convenient. Hell, it is almost walking distance to IKEA too.

But the major thing in 2008 is that I'm learning to play the guitar. Now I have two hobbies, programming and music. Practicing guitar is like meditation for me, it takes my mind of all the problems and I can't stay sad while strumming my six string. I'm not very good yet but I have no doubt that I will be someday, because I'm practicing very hard. I even took a course.

Now to the shitty things. It doesn't work out with my family. Maybe we are to different or something. I believe that everyone can accomplish their dreams as long as they put their minds to it. They do not agree. So if you can't do something you set out to do, I'd say try harder, they'd feel sorry instead. And I can't stand people feeling sorry for themselves or others. The ambient undertone quite often becomes very inconvenient.

I have to run to the gym soon, because I want to get out before the sun sets. So the last thing I'll mention is that I've taken a new job! I also got a pretty sizeable raise which I'm more than happy with. I can't mention how much I earn for obvious reasons but my salary is now quite decent. :) My previous job wasn't bad at all, and working with Erlang in Ericsson is a total blast. But I couldn't refuse the offer I got from Caliber Media. The new language is Java which frankly is a huge step below Erlang. J2EE has a very time consuming deployment cycle which means that for each change you do, you have to redeploy the application which takes closer to five minutes. That is about four minutes longer than it took to compile an Erlang module, scp it to a live blade cluster and reboot the site. Nevertheless, there are girls on this job which is a big plus. :)

What else is new? Obama won in America! It restores some of my faith in the human race. It is hard to describe how important that was to me personally. It shows that stuff is still possible despite everything. Some things never change though, Israel's recent massacre in Gaza is despicable. Our government apparently has nothing to say about it. Fuck the foreign minister, fuck the rest of the corrupted scoundrels.

That's all for my year. Next year I will quit snuffing. I'll get abs on my stomach and go through another accutane regimen. Oh yeah, my acne/rosacea got worse this year. I'll also double my salary, get a whole harem of fuck buddies and move to a 120m2 flat in Vasastan. Then I'll be golden, but maybe I should move to Japan instead... Hm. Life is still full of possibilities and I enjoy it very much.

Not much action on gtk-devel-list

The mailing list for GTK+ is gtk-devel-list@gnome.org. Unfortunately, it seem to be serverly underused and it is almost impossible to get discussions going there. Most discussions seem to take place at bugzilla or the (in)famous planet.gnome.org. But part of the problem also seem to be that most gtk developers are employed by a few companies, namely Red Hat and Imendio. When you work in the same office it becomes easier to communicate orally, than having to use a text medium.

I think it would be nice if there was more "flow" on the mailing list. I fear that important information is getting lost and it creates a divide between employed hackers and others.

Jumpstarting Waf

Introduction

This document is an introduction to the build-tool waf. Waf is a tool written in Python for setting up automated build systems for a programming projects.

Intended Audience and Prerequisite Knowledge

It is assumed that the reader is interested in using waf for setting up the build for a project. The instructions given were recorded on a Linux system and might not be suitable for Windows users.

Why is a Build System Needed?

The build and distribution problem is one of the hardest problems in applied computer science. You have to make sure that your software works in a totally unknown environment radically different from the one in which it was developed.

Additionally if the build fails, the user of the software must be informed in a graceful way with a description of why.

Why Waf?

As previously described, building software is hard. There are many build systems out there, but only waf and autotools provides a holistic system that takes care of every step from configure to distribution. waf has several advantages over autotools that makes it preferable:

  • waf uses Python while autotools mixes shell scripting, M4 and Perl.
  • waf does not generate intermediate files that confuses users like autotools does.
  • waf is many times faster than autotools.

Installing Waf

The first step in using Waf is to install it. I recommend checking it out from Subversion instead of downloading a tarball as the former usually is much more up to date and contains the latest bugfixes. As of this writing, the repository is at revision 4813. Create a checkout using:

$ svn checkout http://waf.googlecode.com/svn/trunk/ waf-read-only

To build waf, enter the waf-read-only directory generate the waf script:

$ cd waf-read-only
$ ./waf-light --make-waf

This creates an exectuable Python script called waf. This script should be copied to the root directory of any project you want to use waf for. It is also possible to install waf globally, although that is not recommended. The README file has more details.

The First wscript

Each build tool has its own kind of configuration files. make has Makefiles, autoconf has configure.in-files, scons has SConstruct files and so on. waf has wscripts. So the first step is to create an initial bare-bone wscript file. Copy this to a file named wscript in your project root directory:

srcdir = '.' blddir = 'build' def set_options(opt): pass def configure(conf): pass def build(bld): pass

Note that this a regular Python program and that you can enter whatever Python code you want in it.

Explanation

srcdir = '.'

The srcdir variable informs waf of where the source files are in relation to the wscript. Its value will almost always be '.' which is the current directory.

blddir = 'build'

This variable tells waf where to put the built files. By default, waf uses an out-of-tree build process, in contrast to most autotooled projects which are built in-tree, which means that waf will not litter your source directories.

def set_options(opt): pass

The set_options function is used for modifying the global options object passed in as the opt parameter. Here you can add extra options both for configuring and building.

def configure(conf): pass

This function performs the exact same task as the configure script in autotooled projects -- it checks that all the requirements for the software is fullfilled.

def build(bld): pass

build defines how the software is to be built. Target rules are specified here.

Running the Build

Provided that the waf program is in the same directory, it is now possible to run this empty build process:

$ ./waf configure
Configuration finished successfully (00:00:00); project is now ready to build.
$ ./waf build
Compilation finished successfully (00:00:00)

We haven't told waf what to do yet, so it outputs nothing interesting. waf creatures a directory called build/ which contains the result of the build process:

$ find build/
build/
build/config.log
build/c4che
build/c4che/build.config.py
build/c4che/default.cache.py
build/default
build/.wafpickle-6

Each built file is placed in build/default, the other files are just house-keeping for waf. Truth be told, this isn't all that interesting, but it gets better in the next section where we make waf actually do something useful.

wafing a Project

Lets talk about the imagined project we are using waf for for a while. We are creating a very simple shared library written in C complete with documentation, tests and example programs.

File Structure

Our project contains the following files and directories:

$ find
.
./wscript
./waf
./src
./src/hello.c
./src/hello.h
./src/wscript_build
./tests/test.c
./tests/demo.c
./tests/wscript_build
build/
As mentioned before, this is where waf puts the built files.
docs/
Project documentation.
src/
C sources and header files for the shared library.
tests/
Tests and example programs.

The hello.c and hello.h files are the C sources. First hello.c:

#include <stdio.h> #include "hello.h" void say_hi () { printf ("Ho\n"); }

And hello.h:

#ifndef HELLO_H #define HELLO_H void say_hi(); #endif

The other files will be introduced as needed in later sections.

Source Targets

Since this a C project, we must add configure checks to waf to ensure that the user has a C compiler installed before the project can be built. Lets begin with that:

def set_options(opt): opt.tool_options('compiler_cc') def configure(conf): conf.check_tool('compiler_cc')

These lines adds C compiler options and configure checks. Rerunning ./waf configure outputs the following:

$ ./waf configure
Checking for program gcc                 : ok /usr/bin/gcc
Checking for compiler version            : ok 4.2.4
Checking for program cpp                 : ok /usr/bin/cpp
Checking for program ar                  : ok /usr/bin/ar
Checking for program ranlib              : ok /usr/bin/ranlib
Checking for gcc                         : ok
Configuration finished successfully (00:00:00); project is now ready to build.

This proves that waf is now verifying that the user has a C compiler installed. Next we add target definitions for the source files in the src directory. Create a file called wscript_build to the src directory.

obj = bld.new_task_gen('cc', 'shlib') obj.source = ['hello.c'] obj.target = 'hello'

These three lines work similar to a build rule in a makefile. The file hello.c is used as input to build the shared library libhello.so. Note that waf automatically adds the prefix "lib" and the suffix ".so" because we are using Linux. To add this target to the build process change the build function in the wscript file:

def build(bld): bld.add_subdirs('src')

This instructs waf to add the rules from any wscript or wscript_build file located in src. The code serves the same purpose as the SUBDIRS variable in Makefile.am variables. Naturally, it is also possible to put all build information in the main wscript file but that might get messy because all paths gets longer. On the other hand, fewer files might feel less cluttered.

Let's test the build:

$ ./waf build
[1/2] cc: src/hello.c -> build/default/src/hello_1.o
[2/2] cc_link: build/default/src/hello_1.o -> build/default/src/libhello.so
Compilation finished successfully (00:00:00)

Excellent! waf first executed the compilation creating hello_1.o and then linked it to produce libhello.so. Both stored in build/default/src/:

$ ls build/default/src/
hello_1.o  libhello.so

Preprocessor Defines

A preprocessor define instructs the compiler to replace all subsequent occurences of a macro with specified replacement tokens. The canonical way to pass compile time options is to let the build system create a "config.h" header file that all C source files includes.

Using config.h

Let's say we wan't to add a function to our hello library that returns its version. First we add the necessary code to the wscript file to create the config.h file with the necessary define:

VERSION = '1.0.0' srcdir = '.' blddir = 'build' def set_options(opt): opt.tool_options('compiler_cc') def configure(conf): conf.check_tool('compiler_cc') conf.define('PACKAGE_VERSION', VERSION) conf.write_config_header('config.h') def build(bld): bld.add_subdirs('src')

The two new lines in the configure function creates the macro PACKAGE_VERSION and writes it to the config.h file. Configuring the project creates the config.h file in the build/default/ directory:

/* Configuration header created by Waf - do not edit */ #ifndef _CONFIG_H_WAF #define _CONFIG_H_WAF #define PACKAGE_VERSION "1.0.0" #endif /* _CONFIG_H_WAF */

By including config.h in hello.c, the macro can be used in the new function:

#include <stdio.h> #include "hello.h" #include "config.h" void say_hi () { printf ("Ho\n"); } const char * get_version () { return PACKAGE_VERSION; }

The function is also added to the header:

#ifndef HELLO_H #define HELLO_H void say_hi(); const char *get_version () #endif

The defines attribute

It is also possible to pass the defines as compiler arguments using gcc's -D option (or the equivalent for other compilers). Each target object in waf has a "defines" attribute where the defines are listed.

So to accomplish what we did in the previous chapter, without using a config.h file, change src/wscript_build to the following:

obj = bld.new_task_gen('cc', 'shlib') obj.source = ['hello.c'] obj.target = 'hello' obj.defines = 'PACKAGE_VERSION=\\"%s\\"' % VERSION

Note that an extra level of string escaping is needed to get the string literal correctly passed to the compiler from the shell.

Which ever way you prefer to use is a matter of taste. But when the list of defines grow large, the config.h method certainly becomes more pleasant. Even if it sometimes can increase recompile times.

Building GTK-Doc Documentation

Integrating the documentation building step into the build tool is usually tricky. End users usually does not need to rebuild the documentation and most documentation tools such as Javadoc and Doxygen does not integrate very easily into a target-based system.

Never the less, the popular documentation extraction tool GTK-Doc for GTK+ libraries contains a bunch of autotools macros so that it can be built using make. waf can do that too, ofcourse.

First, we have to write some documentation for our two functions in hello.c. GTK-Doc uses a pretty self-explanatory doc comment syntax reminiscent of Javadoc. We also add a third function, just for fun. The resulting hello.c and hello.c files are:

#include <stdio.h> #include "hello.h" /** * say_hi: * * Prints "Ho\n" on standard out. **/ void say_hi () { printf ("Ho\n"); } /** * get_version () * @returns: a string containing the version of this library. * * Returns a string on the format "major.minor.micro" describing which * is this librarys version. **/ const char * get_version () { return PACKAGE_VERSION; } /** * get_day_name: * @day_index: index of a week-day, in the range 0-6. * @sunday_first: one if a calendar with the week starting on Sunday * is desired, zero otherwise. * @returns: the name of the day, or %NULL if @day_index is out of * range. * * Returns the name of the day corresponding to the specified day * index. **/ const char * get_day_name (int day_index, int sunday_first) { const char *days[] = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"}; if (day_index < 0 || day_index > 6) return NULL; if (sunday_first) day_index = (day_index + 6) % 7; return days[day_index]; }

and hello.h:

void say_hi (); const char *get_version (); const char *get_day_name (int day_index, int sunday_first); #endif

Adding Documentation Option

Autotooled projects employing GTK-Doc all have a --enable-gtk-doc configure option that determines whether the build process will build the documentation or not. It is easily added to waf by modifying the set_options function in the wscript file:

def set_options(opt): opt.tool_options('compiler_cc') opt.add_option('--enable-gtk-doc', action = 'store_true', default = False, help = 'use gtk-doc to build documentation ' + '[default: %default]')

Waf uses the standard library optparse module for parsing the command line, so any option format accepted by optparse will work for waf. See the documentation for that module for more information.

We can check that the extra option has become available:

$ ./waf configure --help
usage: waf [options] [commands ...]

* Main commands: configure build install clean dist distclean uninstall distcheck
* Example: ./waf build -j4

options:
  --version             show program's version number and exit
  -h, --help            show this help message and exit
  -j JOBS, --jobs=JOBS  amount of parallel jobs [Default: 2]
  -f, --force           force file installation
  -k, --keep            keep running happily on independent task groups
  -p, --progress        -p: progress bar; -pp: ide output
  -v, --verbose         verbosity level -v -vv or -vvv [Default: 0]
  --destdir=DESTDIR     installation root [Default: '']
  --nocache             compile everything, even if WAFCACHE is set
  -b BLDDIR, --blddir=BLDDIR
                        build dir for the project (configuration)
  -s SRCDIR, --srcdir=SRCDIR
                        src dir for the project (configuration)
  --prefix=PREFIX       installation prefix (configuration only) [Default: '/usr/local/']
  --zones=ZONES         debugging zones (task_gen, deps, tasks, etc)
  --targets=COMPILE_TARGETS
                        compile the targets given only [targets in CSV format, e.g. "target1,target2"]
  -d DEBUG_LEVEL, --debug-level=DEBUG_LEVEL
                        Specify the debug level, does nothing if CFLAGS is set in the environment. [Allowed
                        Values: 'ultradebug', 'debug', 'release', 'optimized', 'custom']
  --enable-gtk-doc      use gtk-doc to build documentation [default: False]
  ^<- here it is!

  C Compiler Options:
    --check-c-compiler=CHECK_C_COMPILER
                        On this platform (linux) the following C-Compiler will be checked by default: "gcc
                        suncc"

Go Obama!

Pretty, pretty please make the Americans vote right this time.

Bloggarkiv