Search code examples
gccg++shared-librarieslinker-scripts

C++ shared library symbols versioning


I'm trying to create library with two versions of the same function using

__asm__(".symver ......

approach

library.h

#ifndef CTEST_H
#define CTEST_H

int first(int x);
int second(int x);

#endif

library.cpp

#include "simple.h"
#include <stdio.h>

__asm__(".symver first_1_0,first@LIBSIMPLE_1.0");
int first_1_0(int x)
{
    printf("lib: %s\n", __FUNCTION__);
    return x + 1;
}

__asm__(".symver first_2_0,first@@LIBSIMPLE_2.0");
int first_2_0(int x)
{
    int y;
    printf("lib: %d\n", y);
    printf("lib: %s\n", __FUNCTION__);
    return (x + 1) * 1000;
}

int second(int x)
{
    printf("lib: %s\n", __FUNCTION__);
    return x + 2;
}

And here is the version scripf file

LIBSIMPLE_1.0{
    global:
    first; second;
    local:
    *;
};

LIBSIMPLE_2.0{
    global:
    first;
    local:
    *;
};

When build library using gcc, everything works well, and i am able to link to a library binary. Using nm tool i see that both first() and second() function symbols are exported. Now, when i try to use g++, non of the symbols are exported. So i tried to use extern "C" directive to wrap both declarations

extern "C" {

int first(int x);
int second(int x);
}

nm shows that second() function symbol is exported, but first() still remain unexported, and mangled.

What is here i am missing to make this to work? Or it is impossible with the c++ compiler to achieve this?


Solution

  • I don't know why, with 'extern "C"', 'first' was not exported - suspect there is something else interfering.

    Otherwise C++ name mangling is certainly a pain here. The 'asm' directives (AFAIK) require the mangled names for C++ functions, not the simple 'C' name. So 'int first(int)' would need to be referenced as (e.g.) '_Z5firsti' instead of just 'first'. This is, of course, a real pain as far as portability goes...

    The linker map file is more forgiving as its supported 'extern "C++" {...}' blocks to list C++ symbols in their as-written form - 'int first(int)'.

    This whole process is a maintainance nightmare. What I'd really like would be a function attribute which could be used to specify the alias and version...


    Just to add a reminder that C++11 now supports inline namespaces which can be used to provide symbol versioning in C++.