Bug 62280 - Symbols visibility not equivalent to class visibility (-fvisibility=hidden)
Summary: Symbols visibility not equivalent to class visibility (-fvisibility=hidden)
Status: UNCONFIRMED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.9.1
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: visibility
Depends on:
Blocks: visibility
  Show dependency treegraph
 
Reported: 2014-08-27 09:13 UTC by Mathieu Malaterre
Modified: 2021-09-17 14:49 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Mathieu Malaterre 2014-08-27 09:13:12 UTC
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