从Qt应用程序链接到c++静态库

Linking to a C++ Static Library from a Qt Application

本文关键字:c++ 静态 链接 Qt 应用程序      更新时间:2023-10-16

我正在尝试链接一个非qt静态库,到一个基于qt的应用程序(它是一个Visual Studio项目)。
问题是静态库有一些api,这些api将指向TCHAR字符串的指针作为输入之一。当我尝试构建项目时,我得到一个链接错误,抱怨TCHAR。

class Test
{
  public:
  static bool TestFunc( TCHAR *empty );
};

来源
bool Test::TestFunc( TCHAR *empty )
{
  return true;
}
错误:

error LNK2019: unresolved external symbol "public: static bool __cdecl Test::TestFunc(unsigned short *)" (?TestFunc@Test@@SA_NPAG@Z) referenced in function "public: __thiscall TestApp::TestApp(class QWidget *,class QFlags<enum Qt::WindowType>)" (??0TestApp@@QAE@PAVQWidget@@V?$QFlags@W4WindowType@Qt@@@@@Z)
有趣的是,如果我在头文件中有函数实现,它工作得很好。或者,如果我将TCHAR更改为常规字符,并保持声明/定义分开,它也可以工作(使用wchar_t直接失败并产生相同的链接错误)。

有谁知道是什么导致了这个问题,以及如何解决它?
提前感谢,

静态库是用什么编译的?Visual studio ?什么版本?

我将尽力解释你所遇到的问题。

首先,当你把函数体放在头文件中,它工作的原因是,这实际上会导致你的应用程序重新编译函数体。链接器实际上不再需要解析来自静态库的任何符号。因此,链接器问题就解决了。

问题是,当编译静态库时,它导出的函数Test::TestFunc被编译器弄乱了(它实际上是根据一些内部模式重命名它)。函数名混淆是编译器为简化链接器的符号解析所做的工作。在c++标准中没有指定函数名的修改方式。因此,不同的编译器,打开不同的设置,会以不同的方式处理函数名。

当您尝试构建链接此库的应用程序时,Visual Studio现在破坏了称为的函数(可能在main()中)。如果定义函数的静态库的名称混淆与调用函数的名称混淆不匹配,那么就会得到收到的错误。也就是说,链接器将在静态库中查找函数X,而它所能找到的只是函数Y

现在,正如其他海报所指出的,名称混乱也取决于函数作为输入的参数。如果两个地方(定义和用法)的参数类型不同,编译器将以不同的方式处理函数名。因此,链接器将再次无法解析匹配。

底线是,在符号存在的两个地方(库和应用程序),符号必须以相同的方式修改。要做到这一点,最好的方法是使用完全相同的编译器,具有完全相同的设置。

当然,另一种可能性是该符号实际上并不存在于您所链接的静态库中!

确保两个项目的编译器设置相同。特别注意"Character Set"属性,确保它们都是Unicode。这将改变TCHAR宏的定义。

默认情况下,VS编译时启用"将wchar_t视为内置类型" (/Zc:wchar_t)。Qt编译时禁用该选项(/Zc:wchar_t-)。如果在VS中禁用"将wchar_t视为内置类型"(在配置属性> C/c++>语言下),在构建静态库之前,是否可以修复它?

TCHAR是char或wchar(即utf16),这取决于应用程序的构建方式。

编辑:如果你想混合Qt的字符串类型与TCHAR
只需将QString转换为local8bit或utf16(),然后将结果强制转换为TCHAR*

和从TCHAR转换回QString

QString toQString(const char *str) { return QString::fromLocal8Bit(str); }
QString toQString(const wchar_t *str) { return QString::fromWCharArray(str); }