首页 > 解决方案 > Moc'ed 文件神秘地从 Visual Studio 项目中排除

问题描述

我有几个使用 Qt Visual Studio 工具创建的 Visual Studio 项目(始终是项目创建时可用的最新版本,有些可以追溯到支持 Qt 5 的第一个版本,现在是 2.2.1)。所有项目都是用 VS 2010 编译的,尽管 IDE 是 VS 2017(到目前为止是 15.7.4)。

从一段时间开始,一些项目开始报告链接错误,例如

错误 LNK2001:未解析的外部符号“公共:静态结构 QMetaObject const MyQtClass::staticMetaObject”(?staticMetaObject@MyQtClass@@2UQMetaObject@@B)

对于此示例,MyQtClass.h文件声明MyQtClass并具有Q_OBJECT宏。MyQtClass.cpp定义方法。

经过快速检查后,我发现问题来自关联的 moc'ed 文件(moc_MyQtClass.cpp例如上面的示例)被排除在当前配置的编译之外。这里是 .vcxproj 文件的摘录:

<ClCompile Include="GeneratedFiles\Debug\moc_MyQtClass.cpp">
  <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
  <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Release\moc_MyQtClass.cpp">
  <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
</ClCompile>

如果我修改 .vcxproj 文件以从调试配置中删除排除项,则该项目可以工作。

该问题仅在修改与 ed 类关联的.cpp 文件时发生(在我的示例中)。保存此类文件时,会使用排除项修改 .vcxproj 文件。Q_OBJECTMyQtClass.cpp

这个问题不会出现在我拥有的每个 Qt 项目中,但是一旦启动,每次修改关联的 .cpp 文件时都会出现此问题。我还没有找到它的模式。另外,公司的几个开发系统都出现这种情况,所以好像不是我电脑的问题。

我发现的唯一解决方法是丢弃项目文件中的更改,但是每次修改这些文件时丢弃并重新启动项目是一件令人头疼的事情(这恰好是很多次)。

有没有人遇到过同样的问题?任何想法如何解决它?


更新:仅当修改后的文件是与头文件(MyQtClass.cpp在我的示例中)具有相同基本名称的 .cpp 文件时,才会出现此问题。如果我修改了另一个也定义了MyQtClass类的更多方法的文件(例如MyQtClass_more_definitions.cpp),则不会给出错误。


由于它似乎是 Qt Visual Studio Tools 中的一个错误,没有解决方法,我已经在QTVSADDINBUG-555下报告了它。

标签: c++visual-studioqtqt-vs-addin

解决方案


在与 Qt VS Tools 团队讨论之后,我设法解决了这个问题。我已经使用当前可用的插件的最新版本(2.2.1)对其进行了测试。

解决方案包括将自定义构建步骤转换为 Qt/MSBuild 命令(更多信息请参见此处)。为此,我使用了菜单选项Qt VS Tools / Convert custom build steps to Qt/MSBuild

转换后,我不得不处理一些棘手的问题。我在这里记录它们:

  • 我必须使用Q_OBJECT宏删除所有头文件并手动重新添加它们以便能够对它们进行移动(我还删除/重新添加了所有 .ui 文件,不确定是否受到影响)。

  • 添加现有文件(.h 和 )时,不考虑预编译的标头设置(使用 PCH Q_OBJECT)。文件是通过拖放添加的。如果我关闭 PCH 然后再打开它来处理已添加的文件,新文件仍然需要手动干预(PCH 关闭/打开或编辑.vcxproj如下所示)。

    输入无效.vcxproj

    <QtMoc Include="new_file_added.h" />
    

    变成:

    <QtMoc Include="example.h">
      <ForceInclude Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">StdAfx.h;../../%(Filename)%(Extension)</ForceInclude>
      <ForceInclude Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">StdAfx.h;../../%(Filename)%(Extension)</ForceInclude>
    </QtMoc>
    

    另一种解决方法是打开受影响的头文件的属性并将Qt Meta-Object Compiler / Force Include选项StdAfx.h;../../%(Filename)%(Extension)更改为(StdAfx.h如果不同,请使用您的 PCH 文件名更改):

    头文件属性

  • 我有一些 QRC 文件被编译成二进制文件。默认情况下,为每个 QRC 文件设置二进制输出。我不得不改变全局属性false来解决它:

    <QtRcc>
      <BinaryOutput>false</BinaryOutput>
    </QtRcc>
    

    或使用 .qrc 属性:

    QRC 属性

    此外,它们的输出文件是 C++ 源代码(qrc_*.cpp,而不是原始项目中的输出名称,*.rcc)。只需更改 set DynamicSourcetofalseOutputFile相应ItemGroups 中的元素:

    <ItemGroup>
      <QtRcc Include="resources\resources.qrc">
        <BinaryOutput>true</BinaryOutput>
        <DynamicSource>false</DynamicSource>
        <OutputFile>$(SolutionDir)\output\resources.rcc</OutputFile>
      </QtRcc>
    </ItemGroup>
    

    或使用图形用户界面: 动态源

经过这些更改后,它运行良好(在我的两个环境中,VS 2010 和 VS 2017)。

PS:这似乎是一个已知问题(或至少与其他问题有关),但没有提供更多信息。另一方面,自定义构建步骤正在被 Qt VS Tools 弃用,转而支持 MSBuild,所以我不确定它是否会得到修复。


推荐阅读