Wednesday, 17 September 2008

Book review: Xcode 3 Unleashed

Details
Book: Xcode 3 Unleashed
Author: Fritz Anderson
Publisher: SAMS 2008
ISBN: 978-0321552631
Pages: 534
Links: Amazon | Safari | Publisher
This is a fairly well-paced introduction to the world of Xcode 3. It's suitably up-to-date (relevant for Leopard development using Xcode 3.0 , it works fine with Xcode 3.1; very little has changed). This means that it will probably have dated within a year, though.

It's well a produced book, printed in full colour with a large number of screenshots and an accessible writing style. The layout has been carefully prepared, with clear and useful warning and tip callouts. This makes it easy to follow.

Anderson begins with a whirlwind tour of the development of an application in Xcode. It is an interesting tutorial. However, it only serves to give you an idea of the available features without really explaining how to use them. You get a cursory look at: developing in C, using the debugger, making libraries, using Cocoa (a frankly too-fast romp through Objective C coding and making apps for the mac, this is too much for the book really - it's such a big and complex topic), using version control (Subversion in this case), plists, bundles, unit tests, documentation and more.

Phew! After that's over you have an idea what's going on, but no great understanding of how to put it into practice in your own Xcode projects.

The second part is a far-too-brief "detailed" description of the IDE. This covers just simple project navigation, the build system (for make veterans), debugging, and some of Apple's cool profiling instrumentation mojo. I'd've hoped that this second part would be about twice the size of the tutorial section. However, it's about half the size.

This book is a good introduction to using Xcode, but ultimately leaves you with as many questions as the answers it provides.

Summary

Pros:
  • Full colour, many screenshots
  • Good writing style
  • Good broad overview of development with Xcode
Cons:
  • Not in-depth on any topic
  • Fairly unless index
I'd recommend this as a fast-paced introductory text for an experienced programmer who knows nothing about Xcode. But it will only whet your appetite. You'll probably need another more in-depth tutorial afterwards to really get under the hood of Xcode.

Recommended with reservations

First steps with Xcode

This past week, I've been taking my first (faltering) steps with Xcode, Apple's development environment (IDE) for producing programs that run on Mac OS. It's been a bit of a mixed experience.

As with any piece of Apple software, the installation is a smooth experience and the program itself, when you fire it up, looks cute, lickable and friendly. So what could possibly go wrong?

Now, I have to admit that I have a first class aversion to IDEs. I use them as rarely as I can possibly manage - I'm a command-line controlling, Vim-loving power user. I've been building software for the Mac for some time, just using those tools and have been perfectly happy. Mac OS is just another UNIX, and everything tends to behave the way I'm used to. It just has perdy windows on the top. Kinda like KDE, but better.

Unfortunately, I don't want to build a simple "Hello, World!" program, and I don't want to learn Apple's freaky Objective-C right now. I need to get real work done, very quickly. I need to get our reasonably large codebase (320k lines of C++, or which 85k are test code, 1797 source files, of which 466 are those tests) which compiles under Linux (cross-targetting embedded ARM products, and local x86 machines) building and running on Mac OS as quickly as possible.

I could do this on the command line with my existing Makefile scaffolding, but I need all the good cross-OS-version/univeral binary magic that Xcode provides for you, and I need to share the project with people who have an aversion to the command line (they're a shifty bunch).

Enter Xcode stage left. Enter a period of stress and frustration for Pete.

So here's a synposis of my experience with Xcode so far:
  • Like any IDE, it's a large and unweidly beast. If you don't know your way around it at first, it's intimidating. I'll admit, though, that it's not as intimidating or just plain wierd (IMVHO) as either Eclipse or Visual Studio when you fire them up for the first time.
  • Like any online help, the bundled documentation is not very useful. Sure, its great that it's there. Sure, it probably describes every aspect of the program. But it's on the computer, it's hard to read, and it takes a while to work out your way around it. I gave up and bought some books from Amazon (more on these another time). Much more useful.
  • I don't like not being in control any more! You are rather more divorced from your file structure and SCM. If you don't work Xcode's way, then you'll be continually swimming upstream. Unfortunately, we have a large existing codebase that we need Xcode to work with, and this is goig to become frustrating.
  • This is the main observation: I imagine Xcode is great for a project that you start off from scratch. However, trying to get it happy with an existing project is a bit of a pain (perhaps less of a pain if you already know how to drive Xcode!)
  • Importing a large project into Xcode isn't too bad. But you have to understand the difference between source groups and folder references, or you'll struggle trying to work out why thinks don't work as you expect. Hint: use source groups.
  • Xcode doesn't really grok C++. Well, it doesnt understand reasonably complex modern C++. The Code Sense thingy just goes horribly wrong. It totally fails to understand anything inside a namespace (that's hardly rare these days!) and can't cope with nested classes, either. We have many, many classes using the Pimpl idiom, with internal classes called Impl. Code Sense throws it's hands up and shows you 367 top-level classes called Impl. Helpful. To add insult to injury, if you try to drill through any of these different Impl class you're always shown the same members for one of the 367 Impl's. It's very, very borked. In the end I had to switch of Code Sense and carry on as if I was still living in the dark ages.
  • Working with third party libraries seems tricky. External source trees appear to be the best way to do this. It's not obvious how to put them on the header include path - with a ittle experimentation I worked out you can list "$(external_tree_name)" in the pointy-clicky-typey-thing and it worked. If that's documented anywhere obvious, I'll be darned if I could find it.
  • The compiler is gcc (which is the compiler we use for our Linux builds) so there shouldn't be an porting issues, should there? Well, thankfully not too many apart from some small issues caused by different sized types.
  • However, it took a long time to get the compilation working. I was getting millions of bizarre errors through impossible header-file include chains. It made no sense at all. The errors seemingly came from inside standard headers (things like 'error: 'strcmp' os mpt a member of 'std' in c++locate.h:64' - last time I checked it was!). This turns out to be a problem with something called a header map, that seems to interact badly with HFS's weird slightly case sensitive/slightly case insensitive filesystem. You have to switch it off. Except there's no Xcode option to do that, and you have to waste time on Google to find the trick is adding a random secret user setting called USE_HEADERMAP and set it to false. This magically fixes the problem. And there was me thinking that IDEs are supposed to make your life easy.
  • The editor. It's OK. It's Mac OS-y. It's got syntax colouring and Code Sense (for what it's worth - for me very little) built in. But it's just not Vim.
  • The Xcode SCM integration (it supports Subversion out of the box) is almost adequate, and certainly a little underwhelming.
Goodness, I've rambled for a long time. You probably skipped most of that. But I found it cathartic. It's interesting to see how development experiences draw such deep emotions from programmers - but it's natural. We spend all day in front of these things, so it's important to be able to get it to work for you, not against you.

So am I converted to Xcode? Hardly. Am I warming to it? Gently. Does my application compile yet? No, but I'm working on it.

Monday, 15 September 2008

Toys: Canon Powershot G9

It was time for a new digital camera, and despite my long-held preference for SLRs, I still do not have the time or the money to plough into the digital SLR world. So I went shopping for the most suitable (that is, the best in my humble opinion) digital compact camera.

I ended up with the Canon Powershot G9. This is the top-end Canon compact camera; effectively one of their SLRs rolled into a compact (it has their top-spec DIGIC III processor). I went with Canon, as they are a name I trust for reliability, quality of optics, and usability of the interface. I haven't been disappointed.

It's a 12.1 megapixel beast (in RAW mode, it burns through SD cards like you wouldn't believe). The large 3 inch LCD screen is really high quality. It has RAW imagine capture. The 6x optical zoom (effective focal 35-210mm) is very good, although my previous (physically larger) camera had 10x optical. Goodness knows how many times digital zoom it offers; I never go near that. The optical image stabilisation appears sound. The camera sports all manner of cunning shooting modes but, most importantly, offers full manual operation, which is what I really want at my disposal.

I've used the G9 for a few months now, and have been very impressed by it. It was a great purchase. It has taken a number of awesome shots, and has proven to be quick. intuitive and easy to use. I took it to Uganda with me and it coped with the handling, dust, and general conditions fine.

The G9 feels good in the hand, it's not too large and the weight is not too great (at 320g is heavier than some compacts). I rather like the pleasing retro styling, but it won't be to everyone's taste.

The problems I've so far encountered:
  • Frustratingly, the ink quickly rubbed off the central FUNC button, but that's a minor (if embarrassing) inconvenience.
  • The front optics wobble slightly. I presume it's OK, as the camera functions fine. It's got no worse, but doesn't feel very good.
  • The Canon PC/Mac software is dire. I run the camera with iPhoto on my mac, which is great. But the Canon-supplied utilities look embarrassingly naff, with a very dated UI. The photo-stitch application really isn't all that clever at all. It makes no attempt to colour-match the photo seams and makes stitches really rather obvious.
I paid £270 for this machine (it was on offer, normally retailing at £300).

Overall: I'd highly recommended the camera if you want a high-quality, high-feature compact.

Thursday, 11 September 2008

New DisplayLink mac driver

Fortune smiles on the brave. Or, perhaps in my case, on the bored.

Today I remembered a problem I suffer running the beta DisplayLink mac os driver, and so took a quick detour to their mac beta driver website. It was a way to amuse myself whilst compiling my 20th broken version of gcc (but that's another story).

It turns out they released a mac driver update less than a week ago. Well, hurrah! Surprising they made no mention of this on their blog.

They claim the update provides: 2D acceleration, improved video playback, and increased stability, as well as addressing several bug fixes. So with excitement I downloaded and installed the new goodies. I haven't messed around with it enough to say how much faster 2D performance is, but it'll be interesting to have a play.

Sadly, however, my original problem still has not been fixed. I have a number of USB pendrives (with chips from SMI Corporation, Product ID 0x1000 and Vendor ID 0x090c) that will no longer mount on the mac when the DisplayLink drivers are installed. It's a shame that I can only use my nice 8G USB drive by starting Parallels and accessing it as a shared drive.

Hopefully they'll be able to solve this problem soon. Or I'll have to cycle up Castle Hill with a baseball bat in my hand and have a quiet word :-)

Tuesday, 9 September 2008

Article: Idioms and Idiosyncrasies

The latest issue of Better Software magazine is out now, and I've written this month's Code Craft column. (And yes, it is a huge coincidence that the column has the same name as my book!) (Aside: I have no idea why Amazon continually switches between the right cover image for the book and an incorrect one. Flipping technology).

Here's the synopsis:
As programmers, we are not merely engineering drones; we are also artisans. The act of programming involves as much artistry as it does technicality. When we craft great software, we naturally use language idioms help to show the elegance, beauty, and artistry of a piece of code. But sometimes the desire for beautiful idiomatic code can trip us up.
You can read it online here.

Monday, 8 September 2008

Cubase 4.5

A surprise present awaited me on return from my holiday: Steinberg have released a new free minor update to my DAW of choice, Cubase. I've always foolishly updated Cubase immediately before finding out problems from early adopters on the forums. New shiney things! Must have! Now!

So is it any good? Yes, thankfully.

Here are my initial impressions:
  • It's no more buggy than before, as far as I can see. Well, that's a start. But it gets better...
  • Support for adding/removing audio interfaces whilst Cubase is open has returned on the Mac!!! Hurrah!!! I cannot say how cross I was when this feature silently disappeared in a Cubase update (somewhere around 4.1 or so). When using my MacBook Pro, I'm always flitting between audio interfaces: I have two firewire devices in my studio at home, another at work, and a USB interface for on the road. Sometimes, I'll also just use the internal mic/speakers for a quick noodle. A desktop installation clearly doesn't suffer this problem, but having to shut down and restart Cubase every time I wanted to use a new audio interface (often) was a real drag. They've fixed it. Steinberg, I love you!!!
  • It uses more CPU than the previous version. This is actually a real bummer, but is (thankfully) offset by the previous bonus point (for me).
  • MP3 export has been fixed - it can now write ID3 tags correctly, so I don't have to resort to a third party tagging program after export.
  • The new Yamaha S90ES piano is a very cute addition. I'm a keyboard player, so this really does it for me. I use a Roland stage piano live, and so now I can look smug at my Yamaha S90ES owning co-band-member. I've got his piano sound too :-) However, I have to be honest: I prefer the sound of the TruePianos plugin that I use. The Saphire module just does it for me, and their new Amber is also great. So I'm not sure that I'll end up using the Yamaha all that much. (However, if I'd had the Yamaha from the start maybe I'd not have bothered with another Piano plugin. Who knows?)
  • New drum loops. Whatever. They'll float someone's boat.
  • New sounds. The guitars are OK. The basses are pants. There's some other stuff, but nothing as impressive as the Yamaha grand.
  • VST3 Sound. It's a low-level thing. You wouldn't notice it as a user. There's no interface change to the MediaBay. You won't until (unless) other VST manufacturers start supporting it.

Friday, 5 September 2008

The trials and tribulations of Boost 1.36.0

I've been updating the toolchain that we use to build our products recently; we've upgraded to a much newer Linux kernel and use an (almost) up-to-date gcc that generates much better ARM code. Woo hoo!

Whilst I was at it, I decided to upgrade some of the third party libraries we depend on. I updated to Boost 1.35.0 (which was the latest version available when I started), and got the ARM build working successfully (some of our source code had to be modified for the new library version, mostly around boost::filesystem and boost::thread).

Since Boost 1.36.0 has recently been released, I thought it would be worth moving up another 0.1 worth of code and using that before I took the new toolchain live. It aparently has bugfixes around the threading code. Sounds useful. But oh, the best-laid plans of mice and men often go awry...

Sigh.

I have suffered two nasty Boost-related problemettes that I will share with you, gentle reader. One, to be fair is not just 1.36.0's fault...

1. shared_ptr with posix threads locks up on x86 platforms

It's easy enough to say it, but it took me a while to work out what was going wrong.

Since we target ARM devices, and ARMs do not have an atomic increment/fetch (which boost::shared_ptr relies on) we have to build it with a Posix thread library shared_count backend (by forcing -DBOOST_SP_USE_PTHREADS through to the compile using evil bjam config foo).

We also run our code on local x86 development machines for convenience (and to run our unit tests locally). To ensure the execution environment is as similar as on the target machine, I've always configured Boost to use posix locks around shared_count on this platform, too. It made sense. And it worked fine on 1.34.x versions.

However, on 1.36.o (and, as it happens, on 1.35.0, too - but I only discovered that later), that combination does not work. At least with gcc 4.2.2 and gcc 4.2.3.

Any boost::thread object you create fails to start, and wedges the calling thread. (Internally, the boost::thread::start_thread method in the posix implementation attempts to assign a shared_ptr variable, which causes a deadlock around the shared_count's pthread_mutex_lock call. I don't understand how or why that would fail; there appears to be no way that mutex would be used elsewhere. But there it is; it locks up. I am wondering about random comsic rays or, more likely, a compiler bug: If you disable compiler optimisations the deadlock magically disappears (which makes stepping through the code in gdb to find out what the problem is... tricky).

Solution #1: don't configure boost with -DBOOST_SP_USE_PTHREADS on Intel machines.

2. ARM builds of boost 1.36.0 will not link.

Blasted thing. I finally got the codebase to compile against the 1.36.0 verison of boost and would it link? No it would not. It gave up with lots of bitching about __sync_add_and_fetch_4. This is a glibc internal function that is not supported on ARM platforms (the ARM instruction set does not make such an operation supportable).

Now, I've stared at this problem for a reasonable length of time, and I can't actually see which bit of the Boost codebase is (directly or indirectly) pulling in a reference to this symbol. But it is. And it shouldn't be. For the time being, this problem has beaten me.

At the moment, I have to get the toolchain live rather than waste more precious developer hours, so I've regressed back to Boost 1.35.0 which does not suffer this linkage problem.

Solution #2: Do not use boost 1.36.0. (Yet.)

Sigh.

I hope this whittering blog entry will help other people who get stuck in similar predicaments.

The incomparable joy of C++ inner classes

More on my love/hate relationship with my programming tool of choice. Oh C++. Oh joy. Literally incomparable joy. Because I discovered that you can't easily compare inner classes if the outer class is a template.

You say what?

OK, take a look at this code...

#include <cassert>

template <typename T>
struct outer
{
class inner;
};

template <typename T>
struct outer::inner
{
inner(const T &a) : a(a) {}

const T a;

//With this uncommented, we find an operator== in main [1]
//bool operator==(const inner &other)
//{ return other.a == a; }
};

// This operator== is never found
template <typename T>
bool operator==(const typename outer::inner &lhs,
const typename outer::inner &rhs)
{
return lhs.a == rhs.a;
}


int main()
{
outer::inner a(10);
outer::inner b(20);

// So this doesn't compile
assert(a == a);
assert(b == b);
assert(!(a == b));
}
I naively expected that to work OK. On gcc 4.x it generates this error:

> g++ test.cpp && ./a.out
test.cpp: In function ‘int main()’:
test.cpp:35: error: no match for ‘operator==’ in ‘a == a’
test.cpp:36: error: no match for ‘operator==’ in ‘b == b’
test.cpp:37: error: no match for ‘operator==’ in ‘a == b’
If you add in the code marked as [1], an operator== is found and all is well. However, there is more flexibility in the second operator== form, and I need to be able to write one. Game over.

This is a case of a classic template problem, where the compiler cannot deduce template type of an outer class based on the inner type - a non-deduced context where the compiler is
not required to figure out what Ts would produce a match for your
inner class. To be fair, that would be rather heroic for it to figure out.

The most workable solution I can find is to move the inner class out to a separate top-level template class. This has the downside that it pollutes the enclosing namespace with detail that needn't actually be there. But it has the advantage of generating code that works, and so I can live with that.

template <typename T>
struct outer_inner
{

T a;
};

template <typename T>
bool operator==(outer_inner const& lhs, outer_inner const& rhs)
{
return lhs.a == rhs.a
}

template <typename T>
struct outer
{

typedef outer_inner inner;
};
As a compromise, I am tempted to make a "details" namespace, just to put the morally "inner" top-level classes in, so that the top-level is (relatively) unpolluted.

Why do I care about this? I'm implementing an STL-like container (more on this another time). If outer was instead spelt std::map, and inner was spelt iterator, then you can begin to see my motivation.