I've inherited some Unix code (see, it's not *all* Microsoft stuff). It's prototype code, but very full featured. One thing it didn't come with was a build system of any kind, no makefile, nothing. So, I've had fun and games (as ever) and put it into Eclipse (running locally on a VPC image, accessing the files via Samba and compiling over rsh. Oh, and I'm doing Test-Driven Development in C++. Is this actually the definition of masochism?)
I've just spent the last 2 days tracking down a very tricky/silly bug. This program uses libxml, which supports threads. This means Pthreads.
Pthreads is just an API standard. POSIX threads defines a set of functions, and the behaviour of those functions. It doesn't sepcify their implementation, and so you can get loads of different versions - kernel mode, user mode, pre-emptive, co-operative, operating system provided, compiler provided, 3rd party library provided, and it's very hard to know what to do.
So I did the obvious thing, and leant on the tools to help me out. Eclipse was handling creating the makefiles, and I very quickly got a clean compile. Excellent. Came to do some testing around the libxml usage, and it all went terribly wrong. Sometimes the tests would work, other times not. I eventually got it failing consistently, and in the debugger, and it became apparent what the problem was. The pthread code in libxml was failing. An initialisation routine that was only supposed to be called once (via a call to pthread_once) wasn't getting called, stuff wasn't getting initialised, bad things were happening.
And the Principle of Least Surprise? Turns out libc has a default implementation of Pthreads that does nothing. A whole bunch of nops. In the default library. If you don't explicitly link against the Pthreads library, your code will not work. You cannot rely on the linker telling you that you haven't linked correctly - you'll just link with broken code. Hardly the Pit of Success.
I can understand the rationale behind it, but it's flawed. The idea is that if you have a single-threaded program that uses a multi-threaded library, you can still compile and use the program. After all, it's a single threaded program, so your mutexes and condition variables and so on will all just work. But what if your library wants to create a thread for background processing such as garbage collection, asynchronous web service calls? Won't work. Single call initialisation functions? Won't work.
And that's by default.
It would have been far better to have had an explicit, no-op Pthread library you can link with if you really have to, rather than default you to a library that just plain doesn't work.
Just further proof that compiling code != working code.