$Id: a07cf90837a3c4373b82d6724b97593810766af7 $
I recently needed to build a binary that contained two versions of the same library. I wanted to manually examine any cases where the new version gave different results to verify the output is correct.
Read on for a solution.
Build the libraries you need, let’s call them libtest1.a
and libtest2.a
.
Use nm
to dump a list of all the symbols these libraries define.
$ nm --format=posix --defined-only --extern-only libtest1.a \
| awk '$2 ~ /[A-Z]/ { print $1,"ver1_"$1}' > sym1.lst
$ nm --format=posix --defined-only --extern-only libtest2.a \
| awk '$2 ~ /[A-Z]/ { print $1,"ver2_"$1}' > sym2.lst
The nm
output has an uppercase type letter if it’s global, so the awk command checks if column 2 is uppercase, then appends a prefix to the name.
objcopy
to make all those symbols unique. $ objcopy --redefine-syms=sym1.lst libtest1.a libtest1.a
$ objcopy --redefine-syms=sym2.lst libtest2.a libtest2.a
$ objcopy --redefine-syms=sym1.lst want-ver1.o want-ver1.o
$ objcopy --redefine-syms=sym2.lst want-ver2.o want-ver2.o
Then you can link as usual. I automated all this with a Makefile
, something like:
symbols.lst: libtest1.a
libtest1.a: path/to/version1/libtest.a
$@ | awk '$$2 ~ /[A-Z]/ { print $$1,"ver1_"$$1}' > symbols.lst
nm --format=posix --defined-only --extern-only $@ $@
objcopy --redefine-syms=symbols.lst
wantver1.o: wantver1.c | symbols.lst
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<
$@ $@ objcopy --redefine-syms=symbols.lst