Question

I have read the thread on Creating Library with backward compatible ABI that uses Boost and I'm now trying to understand how I should link my shared libraries to maintain a stable ABI, and avoid problems with interfering symbols.

I have created the following simple test project:

cat <<EOF > a.c
#define ABI __attribute__((visibility("default")))

int common();
int ABI a() { return common() + 1; }
EOF

cat <<EOF > b.c
#define ABI __attribute__((visibility("default")))

int common();
int ABI b() { return common() + 2; }
EOF

cat <<EOF > common_v1.c
int common() { return 1; }
EOF

cat <<EOF > common_v2.c
int common() { return 2; }
EOF

cat <<EOF > test.c
#include <assert.h>

int a();
int b();

int main(int argc, const char *argv[])
{
    assert( a() + b() == 6 );
    return 0;
}
EOF

cat <<EOF > CMakeLists.txt
cmake_minimum_required(VERSION 2.8)

project(TEST)

add_library(common_v1 STATIC common_v1.c)
add_library(common_v2 STATIC common_v2.c)

SET_SOURCE_FILES_PROPERTIES( a.c b.c COMPILE_FLAGS -fvisibility=hidden )
add_library(a SHARED a.c)
target_link_libraries(a common_v1)

add_library(b SHARED b.c)
target_link_libraries(b common_v2)

add_executable(test test.c)
target_link_libraries(test a b)
EOF

The libraries common_v1 and common_v2 should emulate an external dependency of the libraries a and b (like Boost). Because common_v1 and common_v2 is considered as external libraries, I would prefer not to change their build system (and there by not change the flags they are compiled with).

The project above, compiles fine, but it does not work! When the test application is executed it jumps into the assert statement.

This makes me believe the same definition of common is used in both liba and libb. Why is this the case, and what am I doing wrong?

Was it helpful?

Solution

You can fix your test program by using --retain-symbols-file option of ld when creating your a and b libraries and retain only a() and b() symbols, so that common() symbol will not be exported by these libraries (and therefore one library will not try to use common() symbol from another):

  --retain-symbols-file filename
        Retain only the symbols listed in the file filename, discarding all
        others. filename is simply a flat file, with one symbol name per line.

Also you can use --version-script option:

  --version-script=version-scriptfile
        Specify the name of a version script to the linker.

where the version-scriptfile is the following:

  FOO {
    global: a; b; # symbols to be exported
    local: *;     # hide others
  };

Related threads:

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top