У меня есть несколько проектов Visual Studio, созданных с помощью инструментов Qt Visual Studio (всегда последняя версия, доступная на момент создания проекта, некоторые датируются первыми версиями, поддерживающими Qt 5, теперь это 2.2.1). Все проекты скомпилированы с VS 2010, хотя IDE — VS 2017 (пока 15.7.4).
С некоторых пор некоторые проекты начали сообщать об ошибках ссылок, таких как
ошибка LNK2001: неразрешенный внешний символ «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, чтобы удалить исключение из конфигурации отладки, тогда проект будет работать.
Проблема возникает только тогда, когда главный .cpp файл, связанный с Q_OBJECT
Редактируемый класс изменен (MyQtClass.cpp
в моем примере). Во время сохранения такого файла файл .vcxproj изменяется с исключениями.
Эта проблема не появляется в каждом проекте Qt, который у меня есть, но как только он запускается, он появляется каждый раз, когда изменяется связанный файл .cpp. Я не смог найти образец для этого. Кроме того, это происходит в нескольких системах разработки в компании, так что это не проблема моего компьютера.
Единственный обходной путь, который я нашел, — это отменить изменения из файла проекта, но это головная боль, от которой нужно отказаться и перезапустить проект. каждый раз эти файлы изменены (что, оказывается, много раз).
Кто-нибудь испытывал такую же проблему? Есть идеи как это решить?
Обновление: проблема возникает, только когда измененный файл является .cpp файлом с идентичным базовым именем относительно файла заголовка (MyQtClass.cpp
в моем примере). Если я изменил другой файл, который также определяет больше методов MyQtClass
класс (такой как MyQtClass_more_definitions.cpp
), ошибки не выдается.
Поскольку это кажется ошибкой в инструментах Qt Visual Studio без обходного пути, я сообщил об этом в QTVSADDINBUG-555.
После обсуждения этого вопроса с командой Qt VS Tools мне удалось решить проблему. Я протестировал его, используя последнюю версию плагина, доступную в настоящее время (2.2.1).
Решение состояло в преобразовании пользовательских шагов сборки в команды Qt / MSBuild (подробнее об этом Вот). Для этого я использовал опцию меню Qt VS Tools / Конвертировать пользовательские шаги сборки в Qt / MSBuild.
После конвертации мне пришлось столкнуться с какой-то проблемой. Я документирую их здесь:
Я должен был удалить все файлы заголовков с Q_OBJECT
макрос и повторно добавить их вручную, чтобы иметь возможность их moc’ed (я также удалил / заново добавил все файлы .ui, не уверен, если это как-то повлияло).
Параметр предварительно скомпилированных заголовков (с использованием PCH) не учитывался при добавлении существующих файлов (.h с 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 / Force Include возможность StdAfx.h;../../%(Filename)%(Extension)
(менять StdAfx.h
с вашим именем PCH, если оно отличается):
У меня было несколько QRC-файлов, скомпилированных в двоичный файл. Двоичный вывод был установлен для каждого файла QRC по умолчанию. Мне пришлось изменить глобальное свойство на false
решить это:
<QtRcc>
<BinaryOutput>false</BinaryOutput>
</QtRcc>
Или используя свойства .qrc:
Кроме того, выходные файлы для них были источниками C ++ (qrc_*.cpp
вместо имени вывода в исходном проекте, *.rcc
). Просто измените набор DynamicSource
в false
иOutputFile
элементы в соответствующем ItemGroup
s:
<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, поэтому я не уверен, будет ли он исправлен.
Других решений пока нет …