1

Consider the following setup consisting of two shared libraries which both use a static library:

static.cpp

#include "static.h"
static int a = 0;
int getA()
{
    return a++;
}

static.h

#pragma once
int getA();

shareda.cpp

#include <iostream>
#include "shareda.h"
#include "static.h"
void printA()
{
    std::cout << getA() << std::endl;
}

shareda.h

#pragma once
void printA();

sharedb.cpp

#include <iostream>
#include "sharedb.h"
#include "static.h"
void printB()
{
    std::cout << getA() << std::endl;
}

sharedb.h

#pragma once
void printB();

main.cpp

#include "shareda.h"
#include "sharedb.h"
int main()
{
    printA();
    printA();
    printB();
    printA();
    printB();
    return 0;
}

I compiled and ran these files with the following commands (using Clang 3.8.0, compiled from source, and 64-bit Debian with GNU ld 2.25):

clang++ -c static.cpp -o static.o -fPIC
ar rcs libstatic.a static.o
clang++ -c shareda.cpp -o shareda.o -fPIC
clang++ -shared -o libshareda.so shareda.o libstatic.a
clang++ -c sharedb.cpp -o sharedb.o -fPIC
clang++ -shared -o libsharedb.so sharedb.o libstatic.a
clang++  -L. -lshareda -lsharedb -o main main.cpp
LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ./main

To my surprise, the output was the following:

0
1
2
3
4

My expectation was this:

0
1
0
2
1

Apparently, despite the static keyword in front of a in static.cpp, only one instance of a exists. Is there a way to have two instances of a, one for each of the shared libraries?

2
  • I would work as expected for static library Commented Dec 20, 2015 at 13:50
  • The behaviour under msvc is opposite, and I am trying to obtain the result you get (same function call using same static accross all the dlls and exe). No luck for now, would you have any pointer on how to get it? Commented May 21, 2017 at 18:48

1 Answer 1

3

Apparently, despite the static keyword in front of a in static.cpp, only one instance of a exists.

That is incorrect: two instances of a exist, but only one is actually used.

And that is happening because (contrary to your expectations) printB calls the first getA available to it (the one from libshareda.so, not the one from libsharedb.so). That is one major difference between UNIX shared libraries and Windows DLLs. UNIX shared libraries emulate what would have happened if your link was:

clang++  -L. -o main main.cpp shareda.o sharedb.o libstatic.a

So what can you do to "fix" this?

  1. You could link libsharedb.so to prefer its own getA, by using -Bsymbolic.
  2. You could hide getA inside libsharedb.so completely (as if it's a private implementation detail):

    clang++ -c -fvisibility=hidden -fPIC static.cpp ar rcs libstatic.a static.o clang++ -shared -o libsharedb.so sharedb.o libstatic.a

  3. You could achieve similar result using linker version script.

P.S. Your link command:

clang++  -L. -lshareda -lsharedb -o main main.cpp

is completely backwards. It should be:

clang++  -L. -o main main.cpp -lshareda -lsharedb

The order of sources/object files and libraries on command line matters, and libraries should follow object files that reference them.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.