https://gcc.gnu.org/bugzilla/show_bug.cgi?id=62280

            Bug ID: 62280
           Summary: Symbols visibility not equivalent to class visibility
                    (-fvisibility=hidden)
           Product: gcc
           Version: 4.9.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: mathieu.malaterre at gmail dot com

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/gcc-4.9.1 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][1] and indeed exporting at class level directly
(instead of per symbol) solves the symptoms:

    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][2])

Of course the obvious solution of changing:

    struct Base

into

    struct DLL_EXPORT Base

does solve the symptoms.

ref:
http://stackoverflow.com/questions/25522229/tracking-an-issue-with-fvisibility-hidden-that-triggers-a-undefined-reference-t

Reply via email to