简体   繁体   中英

Moc'ed file gets mysteriously excluded from Visual Studio project

I have several Visual Studio projects created with the Qt Visual Studio Tools (always the latest version available at the moment of the project creation, some dating from the first versions supporting Qt 5, now is the 2.2.1). All projects are compiled with VS 2010, although the IDE is VS 2017 (15.7.4 so far).

From some time on, some projects started to report link errors such as

error LNK2001: unresolved external symbol "public: static struct QMetaObject const MyQtClass::staticMetaObject" (?staticMetaObject@MyQtClass@@2UQMetaObject@@B)

For this example, MyQtClass.h file declares MyQtClass and has the Q_OBJECT macro. MyQtClass.cpp defines the methods.

After a quick inspection, I discovered that the problem came from fact that the associated moc'ed file ( moc_MyQtClass.cpp for above example) was excluded from compilation for current configuration. Here the extract of the .vcxproj file:

<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>

If I modify the .vcxproj file to remove the exclusion from the Debug configuration, then the project works.

The problem only happens when the main .cpp file associated to the Q_OBJECT ed class is modified ( MyQtClass.cpp in my example). At the time such file is saved, the .vcxproj file is modified with the exclusions.

This issue doesn't appears in every Qt project I have, but once it starts it keeps appearing every time the associated .cpp file is modified. I haven't been able to discover a pattern for it. In addition, it happens in several development systems at the company, so it doesn't seem to be a problem of my computer.

The only workaround I've found is to discard the changes from the project file, but it is a headache to be discarding and relaunching the project every time those files are modified (which happens to be a lot of times).

Has anybody experienced the same issue? Any ideas how to solve it?


Update: the issue only happens when the modified file is the .cpp file with identical basename regarding the header file ( MyQtClass.cpp in my example). If I modified another file that also defines more methods of the MyQtClass class (such as MyQtClass_more_definitions.cpp ), no error is given.


As it seems to be a bug in the Qt Visual Studio Tools with no workaround, I've reported it under QTVSADDINBUG-555 .

After discussing it with the Qt VS Tools team, I managed to solve the problem. I've tested it using the latest version of the plugin currently available (2.2.1).

Solution consisted in converting the custom build steps into Qt/MSBuild commands (more about it here ). To do so I used the menu option Qt VS Tools / Convert custom build steps to Qt/MSBuild .

After conversion, I had to deal with some issue tough. I document them here:

  • I had to remove all header files with the Q_OBJECT macro and re-add them manually in order to be able to moc'ed them (I also removed/re-added all .ui files, not sure if influenced in anyway).

  • Precompiled headers setting (using PCH) was not respected when adding existing files (.h with Q_OBJECT ). Files were added through drag&drop. If I switched PCH off and then on it work for already added files, new ones still needed manual intervention (PCH off/on or editing the .vcxproj as shown below).

    Invalid entry in .vcxproj :

     <QtMoc Include="new_file_added.h" /> 

    Changed to:

     <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> 

    Another way to solve it is to open the properties of the affected header file and change Qt Meta-Object Compiler / Force Include option to StdAfx.h;../../%(Filename)%(Extension) (change StdAfx.h with your PCH filename if different):

    头文件属性

  • I had some QRC files being compiled to a binary file. The binary output was set for every QRC file by default. I had to change the global property to false to solve it:

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

    Or using .qrc properties:

    QRC属性

    Also, output files for them were C++ sources ( qrc_*.cpp , instead of the output name in the original project, *.rcc ). Just change set the DynamicSource to false and the OutputFile elements in the corresponding ItemGroup s:

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

    Or using the GUI: DynamicSource

After those changes it worked perfectly (in my two environments, VS 2010 and VS 2017).

PS: It seems to be a known issue (or at least related to other ones), but no more information was given. On the other hand, custom build steps are on their way to be deprecated by Qt VS Tools in favor of MSBuild, so I'm not sure if it's going to be fixed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM