Knetic
Knetic

Reputation: 2127

Statically link multiple libraries into one .so

I've got a project foo which depends upon a, which in turn depends upon b, in turn depends upon c. My build script pull/configure/make's the three dependencies from source in the correct order, and they compile fine.

Right now, to distribute foo.so, I also need to distribute all of its dependencies (a.so, b.so, and c.so) alongside. I want to build a foo.so containing all the objects of both foo and all of its dependencies; that way I can distribute a single library.

a, b, and c all use autotools, and generate the associated *.o files in the src/ directory, as well as a .libs/ directory containing the usual smattering of *.ar, *.lo, *.lai, and *.so files, all valid. Right now, I'm using this set of gcc flags to build my foo.so:

gcc -shared ./my/src/*.c \
    -I./a/include -I./b/include -I./c/include \
    -L ./a/.libs -L./b/.libs -L./c/.libs \
    -la -lb -lc \
    -o ./foo.so \
    -w -fPIC -m64 \
    -std=c99

(note that "-la -lb -lc" are just "-l" flags for each dependency, i'm not just messing up the flags).

Using readelf -d on the resultant foo.so indeed shows that it has a dependency on a. Given that I've got all the build files for all the dependencies, it really feels like I'm just missing some flag for "include this path when looking for *.o files to link".

I've tried a variety of things, and honestly can't even remember the different errors and conditions that led to them. The most promising lead was this question, but after removing my "-l" lines in favor of "-Wl,--whole-archive" lines, I get this error (note that "a.a" is just the *.a for a):

/usr/bin/ld: ./a/.libs/a.a(bands.o): relocation R_X86_64_32S against `.rodata' can not be used when making a shared object; recompile with -fPIC
./a/.libs/a.a(bands.o): error adding symbols: Bad value

Which makes no sense to me, since those files need to be PIC in order to build them into a *.so, right? The build process for these dependencies makes a *.so.

I'm on Mint Linux, if it matters.

Upvotes: 1

Views: 1143

Answers (2)

Knetic
Knetic

Reputation: 2127

With help from the answerers here, I was able to get a working solution. I had fundamentally misunderstood that autotools generates two sets of *.o files, one which is PIC, one which isn't. The location for each one is in the *.lo file. My dependencies (a, b, and c) were all built with autotools, and i needed to link against the PIC versions, not the combined static *.a version.

I also needed to split my build process into two parts with libtool. A compile phase just to build my code, and the linker phase that looked at the PIC versions of the dependencies.

I didn't end up with a pretty script, but if anyone hits the same scenario, my ugly gcc lines look like. Hopefully it will be a jumping point to something less... awful than what I came up with.

find ./my/src -name "*.c" -exec \
libtool --mode=compile gcc -c -O -g \
    -I./a/include -I./b/include -I./c/include \
    -L./a/.libs/*.lo -L./b/.libs/*.lo -L./c/.libs/*.lo \
    -la -lb -lc \
    -w -m64 \
    -std=c99 \
    {} \;

gcc \
    -g -O -w -fPIC -m64 -std=c99 -shared \
    -o ./foo.so \
    $(find . -wholename "*.libs/*.o");

Upvotes: 1

R Sahu
R Sahu

Reputation: 206557

The error message is very clear on what needs to be done.

/usr/bin/ld: ./a/.libs/a.a(bands.o): relocation R_X86_64_32S against
`.rodata' can not be used when making a shared object; recompile with -fPIC
                                                      ^^^^^^^^^^^^^^^^^^^^^

./a/.libs/a.a(bands.o): error adding symbols: Bad value

The object code that we are part of the static libraries cannot be put in a shared library unless they are compiled with the -fPIC option.

Upvotes: 3

Related Questions