一般情况下,我们从动态库导出类会有这样的宏定义:
 

#ifndef SHARED_GLOBAL_H
#define SHARED_GLOBAL_H

#ifdef _WIN32
#ifdef PROJECT_EXPORTS
#define PROJECT_API Q_DECL_EXPORT
#else
#define PROJECT_API Q_DECL_IMPORT
#endif
#else
#define PROJECT_API
#endif

#endif // SHARED_GLOBAL_H

同时在CMakeLists.txt中会有:
 

target_compile_definitions("" PRIVATE "PROJECT_EXPORTS")

这样在编译dll的时候,PROJECT_API 被展开为Q_DECL_EXPORT,使用dll的时候被展开为Q_DECL_IMPORT.
这通常不会有问题,但是当我们导出的类带有信号槽,也就包含QT的Q_OBJECT宏的情况下,Q_OBJECT宏会给class添加静态变量,而windows确切的说是visual studio不允许dllimort 静态变量,就会导致报错:“xxx:staticMetaObject”: 不允许 dllimport 静态数据成员 的定义。”
解决办法就是把#define PROJECT_API Q_DECL_IMPORT中的Q_DECL_IMPORT去掉,这样就不会报错了。

有人可能会担心去掉Q_DECL_IMPORT会不会导致调用dll的地方缺少dllimport导致错误,其实不会的原因如下:
 

动态链接的机制

  • Windows的动态链接在运行时通过DLL的导出表解析符号。即使客户端代码未显式使用dllimport,函数和变量的地址仍会在运行时正确绑定。
  • dllimport的主要作用是优化性能(避免间接调用),但并非必需。没有它,程序仍能运行,只是效率稍低。

以上说法大概是错误的。

造成这个错误的真正原因,很可能是你引用dll的项目(通常是exe)中,添加了dll所在工程的头文件,导致二次moc了。每个工程在add_library或者add_executable必须只包含自己所在工程的头文件和源文件,就可以避免这个错误了。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐