我正在尝试编译一个用可移植 C++ 编写的项目。它可以在 Windows 7 上与 Visual Studio 2010 一起正常编译,并使用符号可见性宏。
但是,当我在 linux 上使用 gcc-4.7 编译这个项目时,我收到了这个链接器错误:
g++ -fvisibility=hidden -fvisibility-inlines-hidden [...]
/tmp/ccegevbt.o:(.rodata._ZTI12subclass[_ZTI12subclass]+0x10): undefined reference to `typeinfo for ns::baseclass'
我确实阅读了以前的报告,并且确实直接在类级别(而不是每个符号)导出解决了症状,我想了解的是为什么它不能在符号级别工作:
class __attribute__ ((visibility ("default"))) baseclass {
然而,代码实际上是为了导出一些成员函数而编写的,所以它应该与 Visual Studio C++ 编译器产生相同的行为,对吧?
class baseclass {
public: // Member functions
DLL_EXPORT baseclass();
DLL_EXPORT virtual ~baseclass();
我的问题:在 Visual Studio 2010 和 gcc-4.7 之间导出符号的行为是否略有不同?如何跟踪哪个符号实际上导致了问题?
为了澄清,这里是一个非常小的玩具示例,它在 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
和
$ cat test.cpp
#include "test.h"
Base::~Base()
{
}
和
$ 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;
}
使用cmake,它很简单:
$ 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)
从Linux:
$ export CXXFLAGS="-fvisibility=hidden -fvisibility-inlines-hidden"
$ cmake . && make
从窗户:
$ cmake . -G"NMake Makefiles"
$ nmake
对于不使用 cmake 的人,您可以使用:
$ 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
这导致:
$ 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
万一这件事,添加-fno-devirtualize
没有帮助(根据 sug from here)