Moc'ed 文件神秘地从 Visual Studio 项目中排除

Moc'ed file gets mysteriously excluded from Visual Studio project

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

从一段时间以来,一些项目开始报告 link 错误,例如

error LNK2001: unresolved external symbol "public: static struct 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 文件以从调试配置中删除排除项,则该项目可以运行。

仅当与 Q_OBJECTed class 关联的 main .cpp 文件被修改时才会出现此问题(在我的示例中为 MyQtClass.cpp ).保存此类文件时,.vcxproj 文件会使用排除项进行修改。

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

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

有没有人遇到过同样的问题?有什么解决办法吗?


更新:仅当修改后的文件是 .cpp 文件且头文件的基本名称相同时才会出现此问题(在我的示例中为 MyQtClass.cpp)。如果我修改了另外一个文件也定义了MyQtClassclass的更多方法(比如MyQtClass_more_definitions.cpp),没有报错。


因为它似乎是 Qt Visual Studio 工具中的一个错误,没有解决方法,我已经在 QTVSADDINBUG-555.

下报告了它

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

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

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

  • 我必须用 Q_OBJECT 宏删除所有 header 文件并手动删除 re-add 它们以便能够移动它们(我也removed/re-added 所有 .ui 文件,不确定是否受到影响)。

  • 预编译的 headers 设置(使用 PCH)在添加现有文件(.h with Q_OBJECT)时没有得到遵守。文件是通过拖放添加的。如果我关闭 PCH 然后打开它来处理已经添加的文件,新文件仍然需要手动干预(PCH off/on 或编辑 .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>
    

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

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

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

    或使用 .qrc 属性:

    此外,它们的输出文件是 C++ 源代码(qrc_*.cpp,而不是原始项目中的输出名称,*.rcc)。只需将 DynamicSource 设置为 false 并将相应 ItemGroup 中的 OutputFile 元素更改为:

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

    或使用 GUI:

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

PS:这似乎是一个已知问题(或至少与其他问题有关),但没有提供更多信息。另一方面,自定义 build 步骤即将被 Qt VS Tools 弃用,取而代之的是 MSBuild,所以我不确定它是否会被修复。