我在 Windows 上遇到了 CMake 生成的 DLL 文件的一个令人困惑的问题。在我的库中,我使用 Curiously Recurring Template Pattern 给某些类一个唯一的 ID 号:
// da/Attribute.h:
#ifndef DA_ATTRIBUTE_H
#define DA_ATTRIBUTE_H
namespace da {
typedef unsigned int AttributeId;
class AttributeBase {
public:
virtual AttributeId getTypeId() const=0;
protected:
/** Static ID counter. Every class that derives da::AttributeBase is
assigned an increment of this counter as its type ID number */
static AttributeId sNextId;
};
template <class Derived>
class Attribute : public AttributeBase {
private:
static AttributeId msTypeId;
public:
Attribute() {
if (msTypeId == 0) {
msTypeId = ++sNextId;
}
}
virtual ~Attribute() {
}
/** For static contexts */
static AttributeId typeId() {
if (msTypeId == 0) {
msTypeId = ++sNextId;
}
return msTypeId;
}
AttributeId getTypeId() const {
return typeId();
}
};
template <class Derived> AttributeId Attribute<Derived>::msTypeId = 0;
}
#endif
问题是,当我将 DLL 链接到可执行项目时,不同的 ID 方法似乎存在一些不一致。例如:
// Foo.h
struct Foo : public da::Attribute<Foo> {
Foo() { }
};
...
// main.cpp
Foo *foo = new Foo;
Foo->getTypeId() == 1 // True
Foo::typeId() == 1 // Should be true, but isn't. Foo::typeId() == 2
通过 GDB 运行,在 Foo::getTypeID() 中中断,我发现“msTypeId”和“Foo::msTypeId”具有不同的内存地址。 我勒个去。
不过,这只发生在 Foo 在 DLL 中定义时。(显然,仅在 Windows 7 中——我的 Debian 构建中没有这个问题)如果我在 main.cpp 中创建派生类,或者我只是将库中的所有代码编译到可执行文件中,跳过DLL 步骤完全,它可以正常工作。
一切都是使用 MSYS 和 MinGW 编译的,在 Windows 7 Home Premium 上使用 GCC 4.7。
这是图书馆的 CMakeLists.txt,以防我在那里搞砸了:
cmake_minimum_required(VERSION 2.6)
project(foo)
add_definitions(-std=c++0x)
set(CMAKE_BUILD_TYPE Debug)
set(sources
Foo.cpp
)
add_library(foo SHARED ${sources})