Archive for December, 2006

Statically-linking libstdc++ on AIX

Sunday, December 10th, 2006

Yesterday I spent the whole day trying to build a statically-linked binary of XSD for AIX. I have done this for numerous other platforms but on AIX the C++ exception handling stopped working once I linked libstdc++ in statically. I was lucky to detect this problem at all; the application appears to work just fine as long as there is no throw on the execution path. The fix is to also link libsupc++.a in:

g++ -static-libgcc ... -Wl,-bstatic -lstdc++ -Wl,-bdynamic \
-lsupc++

If all you are looking for is the fix, then you can stop reading here. Read on if you want to know why we need libsupc++.a. When your application is linked to a number of shared libraries, it is important that they all use the same exception handling runtime to allow exceptions to propagate across library boundaries. To ensure this, GCC places the exception handling runtime into a shared library called libgcc_s.so (libgcc.a on AIX) which is then used by all shared C++ libraries and executables, including libstdc++.so.

The -static-libgcc option instructs GCC to use a static equivalent of libgcc_s.so called libgcc_eh.a with the difference being that some of the exception handling code found in libgcc_s.so is placed into the static libstdc++.a (tell me if you know why). In other words, shared libstdc++.so and static libstdc++.a have a different amount of code in them. This fact is important to understand why things fail on AIX.

The second part of the problem is an eccentric shared library architecture implemented on AIX. In short, both shared libraries and static archives on AIX use the same file suffix—.a. In fact, they are both archives. In such an archive there could be one or more shared object (which is just a normal XCOFF file with the SHROBJ bit set) or normal object files. Furthermore, you can link a shared library (archive with shared objects) statically. That’s exactly what happens when you instruct g++ to link libstdc++.a statically by using the -bstatic linker option.

We can see the cause of the problem clearly now: we are linking shared libstdc++.a statically but it is missing some of the exception handling code that a proper static libstdc++.a would have. The libsupc++.a is a subset of libstdc++.a. It provides core language support without STL and streams. It also includes the exception handling code we need. That’s why linking this library fixes the problem.

Default Argument or Overloading?

Wednesday, December 6th, 2006

While testing the XSD-generated code on IBM XL C++ 7.0, I discovered an interesting difference between expressing the same semantic using default arguments and function overloading. Consider the following code snippet:

template <typename X>
struct sequence
{
  void resize (size_t, X const& x = X ());
};

What happens when the template argument for X does not have a default constructor? The majority of C++ compilers think this is fine as long as you don’t call resize with the default values for its second argument. But IBM XL C++ 7.0 does not. While I agree that we only need the default constructor at the function’s call site, it is still a part of the interface. If we were to write something like this:

template <typename X>
struct sequence
{
  void f (typename X::foo);
};

And the template argument for X didn’t have a type named foo, then it would have been an error even though we might never actually have called f. Fortunately, it is fairly easy to resolve this issue by rewriting the original example using overloading instead of the default argument:

template <typename X>
struct sequence
{
  void resize (size_t);
  void resize (size_t, X const&);
};