[cfe-dev] clang, -fvisibility=hidden, static class method
Narinder Claire
narinder.claire at gmail.com
Tue Jul 26 13:48:33 PDT 2011
Hello,
I am seeing some unexpected (unwanted) behaviour from clang concerning
-fvisibility=hidden and static class method. When I build a shared
library with -fvisibility=hidden consisting of a function with a
static variable as expected the static variable is NOT exported.
However if I build the same library with -fvisibility=hidden but
modified so that the same function is now a static method method is a
method of a class, the static variable IS exported. I am NOT
decorating anything with :
__attribute__ ((visibility("default")))
To better illustrate I have pasted the code below
My dev environment has the following components:
OS
-----
Ubuntu 11.04 x64
g++
------
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro
4.5.2-8ubuntu4'
--with-bugurl=file:///usr/share/doc/gcc-4.5/README.Bugs
--enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr
--program-suffix=-4.5 --enable-shared --enable-multiarch
--with-multiarch-defaults=x86_64-linux-gnu --enable-linker-build-id
--with-system-zlib --libexecdir=/usr/lib/x86_64-linux-gnu
--without-included-gettext --enable-threads=posix
--with-gxx-include-dir=/usr/include/c++/4.5
--libdir=/usr/lib/x86_64-linux-gnu --enable-nls --with-sysroot=/
--enable-clocale=gnu --enable-libstdcxx-debug
--enable-libstdcxx-time=yes --enable-plugin --enable-gold
--enable-ld=default --with-plugin-ld=ld.gold --enable-objc-gc
--disable-werror --with-arch-32=i686 --with-tune=generic
--enable-checking=release --build=x86_64-linux-gnu
--host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.5.2 (Ubuntu/Linaro 4.5.2-8ubuntu4)
clang
---------
clang version 2.8 (branches/release_28)
Target: x86_64-pc-linux-gnu
Thread model: posix
The source code an makefile are shown below:
makefile
------------
CXX = clang++
VISIBILITY = -fvisibility=hidden
MODE = AS_NAMESPACE
all: clean
$(CXX) -D$(MODE) $(VISIBILITY) dll.cpp -I./ -fPIC -shared -o libdll.so
$(CXX) -D$(MODE) $(VISIBILITY) main.cpp -I./ -fPIC -ldl -o main
clean:
rm -fr *.so *.o main
klass.h
----------
#ifndef KLASS_HEADER_GUARD
#define KLASS_HEADER_GUARD
#include<string>
#include<set>
typedef std::set<std::string>::const_iterator const_iterator ;
#ifdef AS_CLASS
class scope
{
public:
static
#else
namespace scope
{
#endif
std::set<std::string>& Instance()
{
static std::set<std::string> inst;
return inst;
}
}
#ifdef AS_CLASS
;
#endif
struct Insert
{
Insert(const std::string & x)
{
scope::Instance().insert(x);
}
};
#endif
dll.cpp
---------
#include"klass.h"
namespace
{
Insert x("SHOULD NOT SEE THIS INSERTION");
}
main.cpp
-------------
#include<iostream>
#include<dlfcn.h>
#include"klass.h"
using namespace std;
typedef const_iterator Iterator;
int main()
{
void* D = dlopen("libdll.so",RTLD_LOCAL|RTLD_LAZY);
if(!D)
{
throw("Cannot load DLL\n");
}
if(scope::Instance().empty())
{
cout << "Set is empty\n";
}
else
{
cout << "CONTENTS OF SET\n";
for(Iterator theIterator = scope::Instance().begin();
theIterator != scope::Instance().end();
theIterator++)
{
cout << *theIterator << "\n";
}
}
}
-------------------------------------------------------------------------------------------------------------------
To see the unexpected behaviour we first set LD_LIBRARY_PATH
export LD_LIBRARY_PATH=./:$LD_LIBRARY_PATH
and then 'make' the exectuable with the following variations:
Test 1:
``````````
make MODE=AS_NAMESPACE
output is from the executable is:
Set is empty
make CXX=g++ MODE=AS_NAMESPACE
output is from the executable is:
Set is empty
As expected ( and wanted) the output between clang and g++ is consistent.
Test 2
`````````
make MODE=AS_CLASS
output is from the executable is:
CONTENTS OF SET
SHOULD NOT SEE THIS INSERTION
make CXX=g++ MODE=AS_CLASS
output is from the executable is:
Set is empty
Unexpected (and unwanted) the output is inconsistent between clang and
g++. The behaviour from g++ appears correct whereas the behaviour from
clang appears incorrect since it seems to be exporting a static
variable inside a static method of a class that was never designated
to have default visibility.
I have seen one other email from a few months ago concerning
unexpected behaviour of clang concerning visibility but from what I
understand it doesn't look the same. Any help or explanation would be
appreciated.
Regards
Narinder
More information about the cfe-dev
mailing list