1

I am trying to compile a project that is written in portable C++. It does compile fine with Visual Studio 2010 on Windows 7 and makes uses of symbol visibilty macros.

However when I compile this project with gcc-4.7 on linux, I am getting this linker error:

g++ -fvisibility=hidden -fvisibility-inlines-hidden [...]
/tmp/ccegevbt.o:(.rodata._ZTI12subclass[_ZTI12subclass]+0x10): undefined reference to `typeinfo for ns::baseclass'

I did read a previous report and indeed exporting at class level directly (instead of per symbol) solves the symptoms, what I would like to understand is why it does not wok at symbol level:

class __attribute__ ((visibility ("default"))) baseclass {

However the code is actually written to export only some member function, so it should produce identical behavior with Visual Studio C++ compiler, right ?

class baseclass {
public: // Member functions
  DLL_EXPORT baseclass();
  DLL_EXPORT virtual ~baseclass();

My question: is what slightly different behavior in exporting symbols is happening in between Visual Studio 2010 and gcc-4.7 ? How do I track which symbol is actually causing issue ?

For clarification here is a very small toy example which works fine on Visual Studio 2010

$ cat test.h
#pragma once

#ifdef __GNUC__
#define DLL_EXPORT __attribute__((visibility("default"))) 
#else
#define DLL_EXPORT  __declspec(dllexport)
#endif

struct Base
{
    DLL_EXPORT virtual ~Base();
    DLL_EXPORT virtual Base* clone() {
        return 0;
    }
};

#undef DLL_EXPORT

and

$ cat test.cpp
#include "test.h"

Base::~Base()
{
}

and

$ cat main.cpp
#include "test.h"

struct Foo : public Base
{
    virtual ~Foo();
    virtual Base* clone() {
        return new Foo();
    }
};

Foo::~Foo()
{
}

int main()
{
    Base* f = new Foo();
    f->clone();
    return 0;
}

using cmake, it is simply:

$ cat CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
project(bla)

add_library(test SHARED test.cpp)
add_executable(main main.cpp)
target_link_libraries(main test)

From linux:

$ export CXXFLAGS="-fvisibility=hidden -fvisibility-inlines-hidden"
$ cmake . && make

From windows:

$ cmake . -G"NMake Makefiles"
$ nmake

For people not using cmake, you could use:

$ cat Makefile
main: main.cpp test.h libtest.so
    g++ -fvisibility=hidden -fvisibility-inlines-hidden -L. -ltest main.cpp -o main
libtest.so: test.cpp test.h
    g++ -fvisibility=hidden -fvisibility-inlines-hidden -fPIC -shared test.cpp -o libtest.so

which leads to:

$ make
g++ -fvisibility=hidden -fvisibility-inlines-hidden -fPIC -shared test.cpp -o libtest.so
g++ -fvisibility=hidden -fvisibility-inlines-hidden -L. -ltest main.cpp -o main
/tmp/cc5lGsdn.o: In function `Base::Base()':
main.cpp:(.text._ZN4BaseC2Ev[_ZN4BaseC5Ev]+0xf): undefined reference to `vtable for Base'
/tmp/cc5lGsdn.o:(.rodata._ZTI3Foo[_ZTI3Foo]+0x10): undefined reference to `typeinfo for Base'
collect2: error: ld returned 1 exit status
make: *** [main] Error 1

In case this matter, adding -fno-devirtualize does not help (as per sug from here)

Community
  • 1
  • 1
malat
  • 12,152
  • 13
  • 89
  • 158
  • How are you using this class? – CashCow Aug 27 '14 at 08:58
  • 1
    I think you'll have to export the entire class; this question shows a possible solution: http://stackoverflow.com/questions/10226580/how-do-i-export-class-functions-but-not-the-entire-class-in-a-dll – trojanfoe Aug 27 '14 at 10:43
  • well you are quoting my original post, yes it does solve the symptoms, but I cannot change upstream source code. – malat Aug 27 '14 at 13:05
  • You need to make the class visible as whole if you want to use it outside the library. As you can see RTTI and vtables are hidden with per method visibility selection. g++ wants you to write code so that you mark classes visible and then hide methods one by one. https://gcc.gnu.org/wiki/Visibility – Pauli Nieminen Aug 27 '14 at 13:37

0 Answers0