Search code examples
c++linkerg++libtool

Linking a static library into a shared library without -fPIC


I want to combine object files and a static library into a shared library but the static library shall not be exposed, it is only referred in the object files that go into the shared library. I think that in this case, I do not need to compile the static library with -fPIC but I do not know how to tell the linker that the fact that I will not use the symbols from the static library. As an illustration of my problem, take the following files:

File foo.cpp:

#include "static.h"
using namespace std;

string version_info()
{
    return static_version_info();
}

File static.cpp:

#include"static.h"
#include <vector>
using namespace std;
string static_version_info()
{
    std::vector<int> ivec;
    return to_string(ivec.size());
}

File static.h:

#ifndef STATIC_H
#define STATIC_H
#include<iostream>
using namespace std;
std::string static_version_info();
#endif 

Then do

$ g++ -c foo.cpp -o foo.o -fPIC
$ g++ -c static.cpp -o static.o
$ gcc-ar rcs static.a static.o
$ g++ -shared foo.o static.a
/usr/bin/ld: static.a(static.o): relocation R_X86_64_PC32 against symbol `_ZNSt6vectorIiSaIiEEC1Ev' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Bad value
collect2: error: ld returned 1 exit status

Question: How can I adjust the last command such I do not get an error? Is this possible?

Note that I do not want to compile static.cpp with -fPIC and I do not need the symbols (here return_static_version_info()) in the shared library.


Solution

  • You cannot (or at least you should not) link a static library into a shared library.

    Even if you happen to apparently succeed in linking a non-PIC static library libX.a into a shared library libY.so, the resulting thing won't have position-independent code (so would have a lot of "useless" or "annoying" relocations).

    A shared library needs to contain only position-independent code (in practice); but a static library does not contain PIC.

    I do not want to compile static.cpp with -fPIC

    But you really should.

    Read Drepper's How to Write Shared Libraries for details.

    BTW, some Linux distributions (e.g. Debian) provide a libc6-pic package giving files such as /usr/lib/x86_64-linux-gnu/libc_pic.a which are a static library of position-independent code. This might be used to extend your system's libc.so.6 with e.g. your own function (or your own malloc, etc...).

    In practice, you'll better recompile your static library code with -fPIC; BTW the x86-64 ISA was designed to facilitate PIC.

    At last, if you care about optimizations, there are many of them. Did you consider compiling and linking with gcc -O3 -fPIC -flto ? In some cases, you might consider -ffast-math (which enables optimizations against the C standard), or replacing -O3 with -Ofast.

    And you surely should use a recent GCC or Clang compiler (or a recent proprietary icc). This old question (mentioned in your comments) is about 4.7. Current GCC in fall 2018 is GCC 8, and GCC 9 is worked upon (so should appear in spring 2019). Current Clang is Clang 7. Compilers are continuously making progress on optimizations.

    You might want to download the source tarball of the latest release of GCC or of Clang and build that on your computer. This is a good way to have a recent version of these compilers, since distribution makers often prefer an older variant of them (which is compatible even with non-standard compliant code).