One of the tenets of software development is to reuse code as much as possible. For iVolve’s onboard data collection/processing application, this means writing the application once and building/compiling it for (currently) six different hardware platforms plus a couple of “virtual” platforms used for unit and integration testing.
The application makes extensive use of a “plugin” architecture using Linux’s runtime dynamic linking loader to load only those shared libraries that are configured to run for a particular deployment. One of the outcomes of this approach is that each shared library exposes a number of symbols whose names are duplicated in each of those libraries. For example, both libA.so and libB.so (both shared libraries) might expose “getVersion()”. The duplicated names are handled by the loader at runtime.
One of our more recent applications requires us to statically link all components that are needed by the application. Following the tenet described above, the goal is to re-use the same source code and have the compiler/linker/Make system do all the work for us. While it is easy to rebuild the code for each .so module into a static library, we run into issues when attempting to link the static libraries into the final application. They have duplicate symbol names that the static linker cannot cope with.
../plugins/bm/src/arm-fsl-linux-gnueabi/bm.a(interface.o): In function 'processServerMsg': ../plugins/bm/src/interface.c:132: multiple definition of 'processServerMsg' ../plugins.vcs/src/arm-fsl-linux-gnueabi/vcs.a(interface.o):../plugins/vcs/src/interface.c:352:first defined here
So how do we resolve this using a single source code base? As it is, it will compile and run for application 1 (which uses dynamic loading) but not application 2 (which uses static linking). Changing the symbol names will break application 1. Leaving them as-is breaks application 2.
As with many problems of this nature, the solution is not immediately obvious. Google to the rescue… Unfortunately problems of this nature are generally obscure and many of the solutions out there are somewhat relevant but don’t fit my problem exactly. The closest solution that showed the most promise was this excellent article from Stack Overflow: https://stackoverflow.com/questions/6940384/how-to-deal-with-symbol-collisions-between-statically-linked-libraries. While not immediately relevant to my situation, it did an excellent job of describing how to use objcopy and nm tools to inspect and manipulate the symbols in an object file, and gave me a starting point for what to try next.
The example describes how to rename the symbols of an object file using objcopy’s --prefix-symbols option. This works will with the simple sample code provided, but in the real world, software is much more complex. The --prefix-symbols option is a brute force approach that renames all symbols in the target file, not just the ones that are suffering from collisions. The --wildcard option doesn’t seem to apply when using --prefix-symbols.
Hunting through the objcopy man page some more, I came across the --redefine-sym option. This permits individual symbols to be completely renamed. Using this option, I can rename just the symbols that are suffering from collisions and leave the others alone. This is great, but how do we do this without breaking other usages of the statically linked library (such as when it is linked into unit tests)? A workable solution is to run the run objcopy -redefine-sym command on the regular .a (static library) file and write the output to a new file, then link that new file only into the application that needs it. In my case, this worked well for me because I ensured that the newly-named symbols are only referenced from within the static library. If they are referenced from outside the static library in when they are defined, then you have a whole other problem on your hands.
Follow Matt on twitter here
Follow iVolve on LinkedIn here
Follow iVolve on twitter here