rw-r--r--

chown -R toon blog/ && chmod -R u=rw,go=r $_

Link two static libraries in one application

posted on 2009-08-28

Introduction

This is a technical post about compiling a C/C++ application using gcc. This post requires understanding of C programming and building it.

I’m about to discribe a problem that made me lose several hours searching for the problem, while the solution was quite simple.

Situation

I was working on an application that uses two static libraries, or so called archives. My application uses functions from one library, while that library uses functions from another library. This situation sound complex, but I’ll explain using an example.

Example

The application helloWorld.app uses two archives libArchive1.a and libArchive2.a.

libArchive1.a

This first archive is build from:

libArchive1/libArchive1.h

#include <string>
std::string GetHello();

libArchive1/libArchive1.c

#include "libArchive1.h"
std::string GetHello() { return std::string("Hello "); }

You can compile these files to an archive using these 2 commands:

g++ -c libArchive1/libArchive1.c -o
libArchive1/libArchive1.o ar rcs libArchive1/libArchive1.a
libArchive1/libArchive1.o

libArchive2.a

Similar library to libArchive1.a with use of the GetHello() function:

libArchive2/libArchive2.h

#include "libArchive1.h"
std::string GetHelloWorld();

libArchive2/libArchive2.c

#include "libArchive2.h"
std::string GetHelloWorld() { return GetHello() + std::string("World!\n"); }

Compile by:

g++ -c libArchive2/libArchive2.c -IlibArchive1 -o libArchive2/libArchive2.o
ar rcs libArchive2/libArchive2.a libArchive2/libArchive2.o

This will require to provide the parameter -I so the compiler knows where to get the file libArchive1.h.

helloWorld.app

Small application printing “Hello World!” to stdout using the GetHelloWorld() function.

printHelloWorld.c

#include <iostream>         // for cout
#include "libArchive2.h"
int main(int argc, char* argv[]) {
   std::cout << GetHelloWorld();
   return 0;
}

Now here is where the problem did arise, compiling the application. This is what I did:

g++ helloWorldApp/printHelloWorld.c -IlibArchive1 -IlibArchive2 -LlibArchive1 -LlibArchive2 -lArchive1 -lArchive2 -o helloWorld.app

The arguments -lArchive1 and -lArchive2 will tell the compiler to link in libArchive1 and libArchive1. But I got the following

error: undefined reference to GetHello()

After a long search (the application I was working on was a lot more complex, so many things could have been wrong), I found the order of importing libraries with the -l argument matter. So after switching the order of -lArchive1 -lArchive2, the application got compiled and did print the text “Hello World!” when running it.

Conclusion

The order of importing libraries matter. As far as I know it is a compiler bug and seems to be solved in newer versions (on Mac OSX 10.5 it works, on OpenSUSE 11 the error occurs). Anyhow, if you have problem with this place the least depended library last in the argument list:

g++ appHelloWorld/printHelloWorld.c -IlibArchive1 -IlibArchive2 -LlibArchive1 -LlibArchive2 -lArchive2 -lArchive1 -o helloWorldApp

This will sound really technical for a lot of people, but it took me too long solving it to not share it with you. I hope someone will benefit from it.

You can download the source code of this example here.

Further Reading