diff options
author | Miguel Costa <miguel.costa@qt.io> | 2022-05-10 18:39:10 +0200 |
---|---|---|
committer | Miguel Costa <miguel.costa@qt.io> | 2022-05-16 14:51:54 +0000 |
commit | 9b518c7bb67a7529169434bd8826325f91e76d96 (patch) | |
tree | 260c6a923c003763ecd5205d63fb44354b982310 | |
parent | d7250825ea7758525ed164dd89fac084bdf70c1d (diff) |
Improve intellisense performance for Qt projects
* Avoid running background builds when projects are loaded or changed.
* Add outer/inner build targets also for design time builds.
* Add project option to enable/disable running Qt tools in design-time.
* Stop using project system notification subscriptions.
* Detect relevant project changes using only DTE events.
Change-Id: I7fe0508b2d9ed63c1e3f3b2741ee57ffad366527
Reviewed-by: Karsten Heimrich <karsten.heimrich@qt.io>
-rw-r--r-- | QtMSBuild/QtMSBuild.csproj | 4 | ||||
-rw-r--r-- | QtMSBuild/QtMsBuild/qt_defaults.props | 3 | ||||
-rw-r--r-- | QtMSBuild/QtMsBuild/qt_globals.targets | 98 | ||||
-rw-r--r-- | QtMSBuild/QtMsBuild/qt_inner.targets | 138 | ||||
-rw-r--r-- | QtMSBuild/QtMsBuild/qt_private.props | 46 | ||||
-rw-r--r-- | QtMSBuild/QtMsBuild/qt_settings.xml | 8 | ||||
-rw-r--r-- | QtMSBuild/QtMsBuild/qt_vars.targets | 6 | ||||
-rw-r--r-- | QtVsTools.Package/Editors/Editor.QtDesigner.cs | 6 | ||||
-rw-r--r-- | QtVsTools.Package/Package/DteEventsHandler.cs | 22 | ||||
-rw-r--r-- | QtVsTools.Package/QtMsBuild/QtProjectBuild.cs | 42 | ||||
-rw-r--r-- | QtVsTools.Package/QtMsBuild/QtProjectIntelliSense.cs | 16 | ||||
-rw-r--r-- | QtVsTools.Package/QtMsBuild/QtProjectTracker.cs | 78 |
12 files changed, 309 insertions, 158 deletions
diff --git a/QtMSBuild/QtMSBuild.csproj b/QtMSBuild/QtMSBuild.csproj index 3e2a0e0e..a6140a9d 100644 --- a/QtMSBuild/QtMSBuild.csproj +++ b/QtMSBuild/QtMSBuild.csproj @@ -172,6 +172,10 @@ <SubType>Designer</SubType> <CopyToOutputDirectory>Always</CopyToOutputDirectory> </Content> + <Content Include="QtMSBuild\qt_inner.targets"> + <SubType>Designer</SubType> + <CopyToOutputDirectory>Always</CopyToOutputDirectory> + </Content> <!-- /////////////////////////////////////////////////////////////////////////////////////////////// // Qt/MSBuild moc property pages and targets diff --git a/QtMSBuild/QtMsBuild/qt_defaults.props b/QtMSBuild/QtMsBuild/qt_defaults.props index 83f7c8e5..2d212157 100644 --- a/QtMSBuild/QtMsBuild/qt_defaults.props +++ b/QtMSBuild/QtMsBuild/qt_defaults.props @@ -71,6 +71,9 @@ <QtPathBinaries>bin</QtPathBinaries> <QtPathLibraryExecutables>bin</QtPathLibraryExecutables> + <!--// Run Qt tools during design-time build --> + <QtToolsDesignTime>true</QtToolsDesignTime> + <!--// qmake template --> <QtQMakeTemplate>vcapp</QtQMakeTemplate> diff --git a/QtMSBuild/QtMsBuild/qt_globals.targets b/QtMSBuild/QtMsBuild/qt_globals.targets index 661bc144..cddba5d0 100644 --- a/QtMSBuild/QtMsBuild/qt_globals.targets +++ b/QtMSBuild/QtMsBuild/qt_globals.targets @@ -84,6 +84,29 @@ <!-- ///////////////////////////////////////////////////////////////////////////////////////////////// + // Set up inner build if Qt vars property file is outdated + // --> + <PropertyGroup Condition="'$(QtInnerBuild)' == ''"> + <QtVarsOutdated>false</QtVarsOutdated> + <QtVarsOutdated + Condition="!Exists('$(QtVarsFilePath)') + OR '$(QtBkup_QtInstall)' != '$(QtInstall)' + OR '$(QtBkup_QtModules)' != '$(QtModules)' + OR '$(QtBkup_QtPathBinaries)' != '$(QtPathBinaries)' + OR '$(QtBkup_QtPathLibraryExecutables)' != '$(QtPathLibraryExecutables)' + OR '$(QtBkup_QtHeaderSearchPath)' != '$(QtHeaderSearchPath)' + OR '$(QtBkup_QtLibrarySearchPath)' != '$(QtLibrarySearchPath)' + OR '$(QtBkup_QtVars)' != '$(QtVars)' + OR '$(QtBkup_QMakeCodeLines)' != '$(QMakeCodeLines)' + OR '$(QtBkup_QtBuildConfig)' != '$(QtBuildConfig)'" + >true</QtVarsOutdated> + </PropertyGroup> + + <!-- // Enable inner build targets --> + <Import Condition="'$(QtVarsOutdated)' == 'true'" Project="qt_inner.targets"/> + + <!-- + ///////////////////////////////////////////////////////////////////////////////////////////////// /// TARGET QtGetDefaultClCompile ///////////////////////////////////////////////////////////////////////////////////////////////// // Get default C++ properties @@ -201,7 +224,8 @@ OR ('$(project_changed)' == 'true' AND '$(log_hash)' != '$(work_hash)')" >true</do_work> <skip_work - Condition="'$(do_work)' != 'true' OR '$(DesignTimeBuild)' == 'true'" + Condition="'$(do_work)' != 'true' + OR ('$(QtDesignTimeBuild)' == 'true' AND '$(QtToolsDesignTime)' != 'true')" >true</skip_work> </PropertyGroup> @@ -268,8 +292,7 @@ // --> <QtRunWork Condition="'$(ApplicationType)' != 'Linux' AND '@(QtWork)' != '' - AND '%(QtWork.ParallelBuild)' == 'true' - AND '$(DesignTimeBuild)' != 'true'" + AND '%(QtWork.ParallelBuild)' == 'true'" QtWork="@(QtWork)" QtMaxProcs="$(QtMaxProcs)" QtDebug="$(QtDebug)"> <Output TaskParameter="Result" ItemName="QtWorkResult" /> </QtRunWork> @@ -280,8 +303,7 @@ // --> <QtRunWork Condition="'$(ApplicationType)' != 'Linux' AND '@(QtWork)' != '' - AND '%(QtWork.ParallelBuild)' != 'true' - AND '$(DesignTimeBuild)' != 'true'" + AND '%(QtWork.ParallelBuild)' != 'true'" QtWork="@(QtWork)" QtMaxProcs="1" QtDebug="$(QtDebug)"> <Output TaskParameter="Result" ItemName="QtWorkResult" /> </QtRunWork> @@ -293,13 +315,13 @@ <!-- // Translate local paths to host paths --> <Flatten Condition="'$(ApplicationType)' == 'Linux' - AND '@(QtWork)' != '' AND '$(DesignTimeBuild)' != 'true'" + AND '@(QtWork)' != '' AND '$(QtDesignTimeBuild)' != 'true'" Items="@(QtWork)" Metadata="ResourceFiles"> <Output TaskParameter="Result" ItemName="ResourceFiles"/> </Flatten> <ItemGroup Condition="'$(ApplicationType)' == 'Linux' - AND '@(QtWork)' != '' AND '$(DesignTimeBuild)' != 'true'"> + AND '@(QtWork)' != '' AND '$(QtDesignTimeBuild)' != 'true'"> <LocalPath Include="%(QtWork.Identity)"> <Name>InputPath</Name> <Item>%(QtWork.Identity)</Item> @@ -320,7 +342,7 @@ </ItemGroup> <HostTranslatePaths Condition="'$(ApplicationType)' == 'Linux' - AND '@(QtWork)' != '' AND '$(DesignTimeBuild)' != 'true'" + AND '@(QtWork)' != '' AND '$(QtDesignTimeBuild)' != 'true'" Items="@(LocalPath)" Names="InputPath;OutputPath"> <Output TaskParameter="Result" ItemName="HostPath"/> </HostTranslatePaths> @@ -332,7 +354,7 @@ <!-- // Run command --> <HostExec Condition="'$(ApplicationType)' == 'Linux' - AND '%(Identity)' != '' AND '$(DesignTimeBuild)' != 'true'" + AND '%(Identity)' != '' AND '$(QtDesignTimeBuild)' != 'true'" Message="@(QtWork->'%(WorkType) %(Identity)')" Command="@(QtWork->'%(ToolPath) %(Options)')" Inputs="@(InputPath)" @@ -344,7 +366,7 @@ <!-- // Generate result item --> <ItemGroup Condition="'$(ApplicationType)' == 'Linux' - AND '@(QtWork)' != '' AND '$(DesignTimeBuild)' != 'true'"> + AND '@(QtWork)' != '' AND '$(QtDesignTimeBuild)' != 'true'"> <QtWorkResult Include="@(QtWork)"> <ExitCode>0</ExitCode> </QtWorkResult> @@ -354,9 +376,11 @@ /////////////////////////////////////////////////////////////////////////////////////////////// // Save tracking log of files read during build; used by VS to check the up-to-date status // --> - <ItemGroup Condition="'$(DesignTimeBuild)' != 'true' AND '$(QtVSToolsBuild)' != 'true'"> + <ItemGroup> <read_log Include="^%(QtWorkResult.FullPath);%(QtWorkResult.AdditionalDependencies)" - Condition="'%(QtWorkResult.ExitCode)' == '0' AND '%(QtWorkResult.DisableLog)' != 'true'"> + Condition="'%(QtWorkResult.ExitCode)' == '0' + AND '%(QtWorkResult.DisableLog)' != 'true' + AND '%(QtWorkResult.Skipped)' != 'true'"> <WorkType>%(QtWorkResult.WorkType)</WorkType> </read_log> <read_log> @@ -377,9 +401,11 @@ /////////////////////////////////////////////////////////////////////////////////////////////// // Save tracking log of files written during build; used by VS to check the up-to-date status // --> - <ItemGroup Condition="'$(DesignTimeBuild)' != 'true' AND '$(QtVSToolsBuild)' != 'true'"> + <ItemGroup> <write_log Include="^%(QtWorkResult.FullPath);%(QtWorkResult.OutputFile)" - Condition="'%(QtWorkResult.ExitCode)' == '0' AND '%(QtWorkResult.DisableLog)' != 'true'"> + Condition="'%(QtWorkResult.ExitCode)' == '0' + AND '%(QtWorkResult.DisableLog)' != 'true' + AND '%(QtWorkResult.Skipped)' != 'true'"> <WorkType>%(QtWorkResult.WorkType)</WorkType> </write_log> <write_log> @@ -398,7 +424,7 @@ /////////////////////////////////////////////////////////////////////////////////////////////// // Log output files; this is used by VS to determine what files to delete on "Clean" // --> - <ItemGroup Condition="'$(DesignTimeBuild)' != 'true' AND '$(QtVSToolsBuild)' != 'true'"> + <ItemGroup> <clean_log Include="%(QtWorkResult.OutputFile)" Condition="'%(QtWorkResult.ExitCode)' == '0'"> <Source>@(QtWorkResult, '|')</Source> @@ -414,7 +440,7 @@ /////////////////////////////////////////////////////////////////////////////////////////////// // Log calls to Qt tools; used in QtWorkPrepare to detect changes to the options of Qt tools // --> - <WriteLinesToFile Condition="'@(QtWorkLog)' != '' AND '$(DesignTimeBuild)' != 'true'" + <WriteLinesToFile Condition="'@(QtWorkLog)' != ''" File="$(QtLogFilePath)" Lines="@(QtWorkLog->'%(Identity)|%(Hash)')" Overwrite="true" Encoding="Unicode"/> @@ -425,8 +451,7 @@ // --> <Error Condition="'%(QtWorkResult.ExitCode)' != '' - AND '%(QtWorkResult.ExitCode)' != '0' - AND '$(DesignTimeBuild)' != 'true'" + AND '%(QtWorkResult.ExitCode)' != '0'" File="%(QtWorkResult.Identity)" Code="%(QtWorkResult.ExitCode)" Text="%(QtWorkResult.WorkType) (%(QtWorkResult.ToolPath))"/> @@ -673,48 +698,13 @@ // --> <Target Name="Qt" - DependsOnTargets="QtPrepare;QtWork;QtSetAdditionalOptions" - BeforeTargets="FixupCLCompileOptions"> + DependsOnTargets="QtPrepare;QtWork;QtSetAdditionalOptions"> <CriticalSection Lock="false" Name="$(ProjectGuid)" /> <OnError ExecuteTargets="QtLeaveCriticalSection_OnError"/> </Target> <!-- ///////////////////////////////////////////////////////////////////////////////////////////////// - /// TARGET QtOuterBuild - ///////////////////////////////////////////////////////////////////////////////////////////////// - // Run targets in $(QtOuterBuildDependsOn) and then recursively invoke build - // --> - <Target Name="QtOuterBuild" DependsOnTargets="$(QtOuterBuildDependsOn)"> - <!--// Invoke inner build: recursive build in second MSBuild instance --> - <MSBuild - Projects="$(MSBuildProjectFullPath)" - Targets="Build" - Properties="QtInnerBuild=$(MSBuildProjectFullPath);RandomFileName=$(RandomFileName);BuildProjectReferences=false"> - </MSBuild> - <OnError ExecuteTargets="QtLeaveCriticalSection_OnError"/> - </Target> - - <PropertyGroup - Condition="'$(QtInnerBuild)' == '' AND '$(DesignTimeBuild)' != 'true'"> - <!--// Outer build: invoke inner build --> - <BuildDependsOn> - $(QtOuterBuildPrepare); - QtOuterBuild; - $(QtOuterBuildFinalize) - </BuildDependsOn> - <QtInnerBuild>$(MSBuildProjectFullPath)</QtInnerBuild> - <RandomFileName>$([System.IO.Path]::GetRandomFileName())</RandomFileName> - </PropertyGroup> - - <PropertyGroup - Condition="'$(QtInnerBuild)' != '$(MSBuildProjectFullPath)' AND '$(DesignTimeBuild)' != 'true'"> - <!--// Dependent project inner build: skip build --> - <BuildDependsOn>$(QtOuterBuildPrepare);$(QtOuterBuildFinalize)</BuildDependsOn> - </PropertyGroup> - - <!-- - ///////////////////////////////////////////////////////////////////////////////////////////////// /// TARGET QtEnterCriticalSection_... / QtLeaveCriticalSection_InitializeBuildStatus ///////////////////////////////////////////////////////////////////////////////////////////////// // Synchronize calls to InitializeBuildStatus diff --git a/QtMSBuild/QtMsBuild/qt_inner.targets b/QtMSBuild/QtMsBuild/qt_inner.targets new file mode 100644 index 00000000..a0675838 --- /dev/null +++ b/QtMSBuild/QtMsBuild/qt_inner.targets @@ -0,0 +1,138 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt VS Tools. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +--> +<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + + <PropertyGroup + Condition="'$(QtInnerBuild)' == ''"> + <!--// Outer build: invoke inner build --> + <BuildDependsOn> + $(QtOuterBuildPrepare); + QtOuterBuild; + $(QtOuterBuildFinalize) + </BuildDependsOn> + <QtInnerBuild>$(MSBuildProjectFullPath)</QtInnerBuild> + <RandomFileName>$([System.IO.Path]::GetRandomFileName())</RandomFileName> + </PropertyGroup> + + <PropertyGroup + Condition="'$(QtInnerBuild)' != '$(MSBuildProjectFullPath)'"> + <!--// Dependent project inner build: skip build --> + <BuildDependsOn>$(QtOuterBuildPrepare);$(QtOuterBuildFinalize)</BuildDependsOn> + </PropertyGroup> + + <!-- + ///////////////////////////////////////////////////////////////////////////////////////////////// + /// TARGET QtOuterBuild + ///////////////////////////////////////////////////////////////////////////////////////////////// + // Run targets in $(QtOuterBuildDependsOn) and then recursively invoke build + // --> + <Target Name="QtOuterBuild" DependsOnTargets="$(QtOuterBuildDependsOn)"> + <!--// Invoke inner build: recursive build in second MSBuild instance --> + <MSBuild + Projects="$(MSBuildProjectFullPath)" + Targets="Build" + Properties="QtInnerBuild=$(MSBuildProjectFullPath);RandomFileName=$(RandomFileName);BuildProjectReferences=false"> + </MSBuild> + <OnError ExecuteTargets="QtLeaveCriticalSection_OnError"/> + </Target> + + <!-- + ///////////////////////////////////////////////////////////////////////////////////////////////// + /// TARGET GetClCommandLineForReference + ///////////////////////////////////////////////////////////////////////////////////////////////// + // + // --> + <Target + Name="GetClCommandLineForReference" + DependsOnTargets="$(QtOuterBuildDependsOn)" + Returns="@(ClCommandLineForReference)"> + <MSBuild + Projects="$(MSBuildProjectFullPath)" + Targets="GetClCommandLineForReference" + Properties="QtInnerBuild=$(MSBuildProjectFullPath);RandomFileName=$(RandomFileName);BuildProjectReferences=false"> + <Output TaskParameter="TargetOutputs" ItemName="ClCommandLineForReference"/> + </MSBuild> + </Target> + + <!-- + ///////////////////////////////////////////////////////////////////////////////////////////////// + /// TARGET GetGeneratedFiles + ///////////////////////////////////////////////////////////////////////////////////////////////// + // + // --> + <Target + Name="GetGeneratedFiles" + DependsOnTargets="$(QtOuterBuildDependsOn)" + Returns="@(_GeneratedFiles)"> + <MSBuild + Projects="$(MSBuildProjectFullPath)" + Targets="GetGeneratedFiles" + Properties="QtInnerBuild=$(MSBuildProjectFullPath);RandomFileName=$(RandomFileName);BuildProjectReferences=false"> + <Output TaskParameter="TargetOutputs" ItemName="_GeneratedFiles"/> + </MSBuild> + </Target> + + <!-- + ///////////////////////////////////////////////////////////////////////////////////////////////// + /// TARGET GetProjectReferencesInfo + ///////////////////////////////////////////////////////////////////////////////////////////////// + // + // --> + <Target + Name="GetProjectReferencesInfo" + DependsOnTargets="$(QtOuterBuildDependsOn)" + Returns="@(_ProjectReferencesInfo)"> + <MSBuild + Projects="$(MSBuildProjectFullPath)" + Targets="GetProjectReferencesInfo" + Properties="QtInnerBuild=$(MSBuildProjectFullPath);RandomFileName=$(RandomFileName);BuildProjectReferences=false"> + <Output TaskParameter="TargetOutputs" ItemName="_ProjectReferencesInfo"/> + </MSBuild> + </Target> + + <!-- + ///////////////////////////////////////////////////////////////////////////////////////////////// + /// TARGET GetClCommandLines + ///////////////////////////////////////////////////////////////////////////////////////////////// + // + // --> + <Target + Name="GetClCommandLines" + DependsOnTargets="$(QtOuterBuildDependsOn)" + Returns="@(ClCommandLines)"> + <MSBuild + Projects="$(MSBuildProjectFullPath)" + Targets="GetClCommandLines" + Properties="QtInnerBuild=$(MSBuildProjectFullPath);RandomFileName=$(RandomFileName);BuildProjectReferences=false"> + <Output TaskParameter="TargetOutputs" ItemName="ClCommandLines"/> + </MSBuild> + </Target> +</Project> diff --git a/QtMSBuild/QtMsBuild/qt_private.props b/QtMSBuild/QtMsBuild/qt_private.props index f688ae1e..007d87a9 100644 --- a/QtMSBuild/QtMsBuild/qt_private.props +++ b/QtMSBuild/QtMsBuild/qt_private.props @@ -57,6 +57,18 @@ <!-- ///////////////////////////////////////////////////////////////////////////////////////////////// + // Check if design-time build + // --> + <PropertyGroup> + <QtDesignTimeBuild>false</QtDesignTimeBuild> + <QtDesignTimeBuild + Condition="'$(DesignTimeBuild)' == 'true' + OR '$(QtVSToolsBuild)' == 'true'" + >true</QtDesignTimeBuild> + </PropertyGroup> + + <!-- + ///////////////////////////////////////////////////////////////////////////////////////////////// // Setup Qt installation path // --> <PropertyGroup Condition="'$(QtVsProjectSettings)' == 'true'"> @@ -112,21 +124,29 @@ >$([System.String]::Copy($([System.IO.File]::ReadAllText('$(QtVarsIndexPathDesignTime)'))).Replace('
',''))</QtVarsDesignTime> </PropertyGroup> - <!--// Import Qt variables (full build) --> - <Import - Condition="'$(DesignTimeBuild)' != 'true' AND Exists('$(QtVarsFilePath)')" - Project="$(QtVarsFilePath)"/> + <PropertyGroup> + <!--// Path to Qt variables .props: full build --> + <QtVarsImportPath + Condition="'$(QtDesignTimeBuild)' != 'true' + AND Exists('$(QtVarsFilePath)')" + >$(QtVarsFilePath)</QtVarsImportPath> - <!--// Import Qt variables (design-time build) --> - <Import - Condition="'$(DesignTimeBuild)' == 'true' AND Exists('$(QtVarsDesignTime)')" - Project="$(QtVarsDesignTime)"/> + <!--// Path to Qt variables .props: design-time build --> + <QtVarsImportPath + Condition="'$(QtDesignTimeBuild)' == 'true' + AND Exists('$(QtVarsDesignTime)')" + >$(QtVarsDesignTime)</QtVarsImportPath> - <!--// Import Qt variables (fall-back) --> - <Import - Condition= -"'$(DesignTimeBuild)' == 'true' AND !Exists('$(QtVarsDesignTime)') AND Exists('$(QtVarsFilePath)')" - Project="$(QtVarsFilePath)"/> + <!--// Path to Qt variables .props: fall-back --> + <QtVarsImportPath + Condition="'$(QtDesignTimeBuild)' == 'true' + AND !Exists('$(QtVarsDesignTime)') + AND Exists('$(QtVarsFilePath)')" + >$(QtVarsFilePath)</QtVarsImportPath> + </PropertyGroup> + + <!--// Import Qt vars property file --> + <Import Condition="Exists('$(QtVarsImportPath)')" Project="$(QtVarsImportPath)"/> <!-- ///////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/QtMSBuild/QtMsBuild/qt_settings.xml b/QtMSBuild/QtMsBuild/qt_settings.xml index 9c1b2549..53b2f526 100644 --- a/QtMSBuild/QtMsBuild/qt_settings.xml +++ b/QtMSBuild/QtMsBuild/qt_settings.xml @@ -100,6 +100,14 @@ Category="QtSettings_01_General" DisplayName="Run Deployment Tool" Description="Select whether Qt for Windows Deployment Tool (windeployqt) should be called after build."/> + <EnumProperty + Name="QtToolsDesignTime" + Category="QtSettings_01_General" + DisplayName="Design Time Build" + Description="Run Qt tools during IntelliSense builds."> + <EnumValue Name="true" DisplayName="Run Qt Tools"/> + <EnumValue Name="false" DisplayName="Skip Qt Tools"/> + </EnumProperty> <StringProperty Name="QtPathBinaries" Category="QtSettings_02_Paths" diff --git a/QtMSBuild/QtMsBuild/qt_vars.targets b/QtMSBuild/QtMsBuild/qt_vars.targets index 174b9b56..5d6f08da 100644 --- a/QtMSBuild/QtMsBuild/qt_vars.targets +++ b/QtMSBuild/QtMsBuild/qt_vars.targets @@ -501,15 +501,15 @@ <!--// In design-time, copy generated .props to randomly named file --> <PropertyGroup> <QtVarsDesignTimeNew - Condition="'$(ErrorLevel)' == '0' AND '$(QtVSToolsBuild)' == 'true'" + Condition="'$(ErrorLevel)' == '0' AND '$(QtDesignTimeBuild)' == 'true'" >$([System.IO.Path]::Combine('$(TEMP)','$([System.IO.Path]::GetRandomFileName()).designtime.props')) </QtVarsDesignTimeNew> </PropertyGroup> <Copy - Condition="'$(ErrorLevel)' == '0' AND '$(QtVSToolsBuild)' == 'true'" + Condition="'$(ErrorLevel)' == '0' AND '$(QtDesignTimeBuild)' == 'true'" SourceFiles="$(QtVarsFilePath)" DestinationFiles="$(QtVarsDesignTimeNew)"/> <WriteLinesToFile - Condition="'$(ErrorLevel)' == '0' AND '$(QtVSToolsBuild)' == 'true'" + Condition="'$(ErrorLevel)' == '0' AND '$(QtDesignTimeBuild)' == 'true'" File="$(QtVarsIndexPathDesignTime)" Overwrite="true" Lines="$(QtVarsDesignTimeNew)"/> <!--// Clean-up --> diff --git a/QtVsTools.Package/Editors/Editor.QtDesigner.cs b/QtVsTools.Package/Editors/Editor.QtDesigner.cs index cddc7fa5..b6cee8a6 100644 --- a/QtVsTools.Package/Editors/Editor.QtDesigner.cs +++ b/QtVsTools.Package/Editors/Editor.QtDesigner.cs @@ -81,13 +81,11 @@ namespace QtVsTools.Editors var latestWriteTime = File.GetLastWriteTime(filePath); if (lastWriteTime != latestWriteTime) { lastWriteTime = latestWriteTime; - await QtProjectIntellisense.RefreshAsync( - project, projectPath, selectedFiles: itemId); + await QtProjectIntellisense.RefreshAsync(project, projectPath); } } if (lastWriteTime != File.GetLastWriteTime(filePath)) { - await QtProjectIntellisense.RefreshAsync( - project, projectPath, selectedFiles: itemId); + await QtProjectIntellisense.RefreshAsync(project, projectPath); } }); } diff --git a/QtVsTools.Package/Package/DteEventsHandler.cs b/QtVsTools.Package/Package/DteEventsHandler.cs index 30ca31c0..b5cfdfc1 100644 --- a/QtVsTools.Package/Package/DteEventsHandler.cs +++ b/QtVsTools.Package/Package/DteEventsHandler.cs @@ -185,8 +185,10 @@ namespace QtVsTools if (debugStartWithoutDebuggingEvents != null) debugStartWithoutDebuggingEvents.BeforeExecute -= debugStartWithoutDebuggingEvents_BeforeExecute; - if (vcProjectEngineEvents != null) + if (vcProjectEngineEvents != null) { vcProjectEngineEvents.ItemPropertyChange -= OnVCProjectEngineItemPropertyChange; + vcProjectEngineEvents.ItemPropertyChange2 -= OnVCProjectEngineItemPropertyChange2; + } if (windowEvents != null) windowEvents.WindowActivated -= WindowEvents_WindowActivated; @@ -520,6 +522,7 @@ namespace QtVsTools if (vcProjectEngineEvents != null) { try { vcProjectEngineEvents.ItemPropertyChange += OnVCProjectEngineItemPropertyChange; + vcProjectEngineEvents.ItemPropertyChange2 += OnVCProjectEngineItemPropertyChange2; } catch { Messages.DisplayErrorMessage("VCProjectEngine events could not be registered."); } @@ -590,6 +593,23 @@ namespace QtVsTools } } + private void OnVCProjectEngineItemPropertyChange2( + object item, + string propertySheet, + string itemType, + string propertyName) + { + ThreadHelper.ThrowIfNotOnUIThread(); + if (!propertyName.StartsWith("Qt") || propertyName == "QtLastBackgroundBuild") + return; + if (item is VCConfiguration vcConfig + && vcConfig.project is VCProject vcProject + && vcProject.Object is Project project) { + QtProjectIntellisense.Refresh( + QtProjectTracker.Get(project, project.FullName).Project, vcConfig.Name); + } + } + private static VCFile GetVCFileFromProject(string absFileName, VCProject project) { foreach (VCFile f in (IVCCollection)project.Files) { diff --git a/QtVsTools.Package/QtMsBuild/QtProjectBuild.cs b/QtVsTools.Package/QtMsBuild/QtProjectBuild.cs index 59049a1a..d893fe64 100644 --- a/QtVsTools.Package/QtMsBuild/QtProjectBuild.cs +++ b/QtVsTools.Package/QtMsBuild/QtProjectBuild.cs @@ -48,11 +48,18 @@ namespace QtVsTools.QtMsBuild using Common; using Core; using VisualStudio; + using static Common.EnumExt; class QtProjectBuild : Concurrent<QtProjectBuild> { static LazyFactory StaticLazy { get; } = new LazyFactory(); + public enum Target + { + // Mark project as dirty, but do not request a build + [String("QtVsTools.QtMsBuild.QtProjectBuild.Target.SetOutdated")] SetOutdated + } + static PunisherQueue<QtProjectBuild> BuildQueue => StaticLazy.Get(() => BuildQueue, () => new PunisherQueue<QtProjectBuild>( getItemKey: (QtProjectBuild build) => @@ -148,6 +155,35 @@ namespace QtVsTools.QtMsBuild .Forget(); } + public static void SetOutdated( + EnvDTE.Project project, + string projectPath, + string configName, + LoggerVerbosity verbosity = LoggerVerbosity.Quiet) + { + if (project == null) + throw new ArgumentException("Project cannot be null."); + if (configName == null) + throw new ArgumentException("Configuration name cannot be null."); + + _ = Task.Run(() => SetOutdatedAsync(project, projectPath, configName, verbosity)); + } + + public static async Task SetOutdatedAsync( + EnvDTE.Project project, + string projectPath, + string configName, + LoggerVerbosity verbosity = LoggerVerbosity.Quiet) + { + await StartBuildAsync( + project, + projectPath, + configName, + null, + new[] { Target.SetOutdated.Cast<string>() }, + verbosity); + } + public static void Reset() { BuildQueue.Clear(); @@ -208,6 +244,12 @@ namespace QtVsTools.QtMsBuild { var msBuildProject = await writeAccess.GetProjectAsync(ConfiguredProject); + if (Targets.Any(t => t == Target.SetOutdated.Cast<string>())) { + msBuildProject.MarkDirty(); + await writeAccess.ReleaseAsync(); + return true; + } + var solutionPath = QtProjectTracker.SolutionPath; var configProps = new Dictionary<string, string>( ConfiguredProject.ProjectConfiguration.Dimensions.ToImmutableDictionary()) diff --git a/QtVsTools.Package/QtMsBuild/QtProjectIntelliSense.cs b/QtVsTools.Package/QtMsBuild/QtProjectIntelliSense.cs index 101b51af..2597e22f 100644 --- a/QtVsTools.Package/QtMsBuild/QtProjectIntelliSense.cs +++ b/QtVsTools.Package/QtMsBuild/QtProjectIntelliSense.cs @@ -60,14 +60,15 @@ namespace QtVsTools.QtMsBuild (configId != null) ? configId : "(all configs)", project.FullName)); } string projectPath = project.FullName; - _ = Task.Run(() => RefreshAsync(project, projectPath, configId, selectedFiles)); + _ = Task.Run(() => RefreshAsync(project, projectPath, configId, selectedFiles, false)); } public static async Task RefreshAsync( EnvDTE.Project project, string projectPath, string configId = null, - IEnumerable<string> selectedFiles = null) + IEnumerable<string> selectedFiles = null, + bool refreshQtVars = false) { if (project == null || !QtProjectTracker.IsTracked(projectPath)) return; @@ -92,9 +93,14 @@ namespace QtVsTools.QtMsBuild } foreach (var config in configs) { - await QtProjectBuild.StartBuildAsync( - project, projectPath, config, properties, targets, - LoggerVerbosity.Quiet); + if (refreshQtVars) { + await QtProjectBuild.StartBuildAsync( + project, projectPath, config, properties, targets, + LoggerVerbosity.Quiet); + } else { + await QtProjectBuild.SetOutdatedAsync( + project, projectPath, config, LoggerVerbosity.Quiet); + } } } } diff --git a/QtVsTools.Package/QtMsBuild/QtProjectTracker.cs b/QtVsTools.Package/QtMsBuild/QtProjectTracker.cs index 01e3156f..464322e8 100644 --- a/QtVsTools.Package/QtMsBuild/QtProjectTracker.cs +++ b/QtVsTools.Package/QtMsBuild/QtProjectTracker.cs @@ -75,51 +75,11 @@ namespace QtVsTools.QtMsBuild Initialized = new EventWaitHandle(false, EventResetMode.ManualReset); } - class Subscriber : IDisposable - { - public Subscriber(QtProjectTracker tracker, ConfiguredProject config) - { - Tracker = tracker; - Config = config; - Subscription = Config.Services.ProjectSubscription.JointRuleSource.SourceBlock - .LinkTo(new SubscriberAction(ProjectUpdateAsync), - ruleNames: new[] - { - "ClCompile", - "QtRule10_Settings", - "QtRule30_Moc", - "QtRule40_Rcc", - "QtRule60_Repc", - "QtRule50_Uic", - "QtRule_Translation", - "QtRule70_Deploy", - }, - initialDataAsNew: false - ); - } - - QtProjectTracker Tracker { get; } - ConfiguredProject Config { get; } - IDisposable Subscription { get; set; } - - public void Dispose() - { - Subscription?.Dispose(); - Subscription = null; - } - - async Task ProjectUpdateAsync(IProjectVersionedValue<IProjectSubscriptionUpdate> update) - { - await Tracker.OnProjectUpdateAsync(Config, update.Value); - } - } - public EnvDTE.Project Project { get; private set; } public string ProjectPath { get; private set; } public VCProject VcProject { get; private set; } public UnconfiguredProject UnconfiguredProject { get; private set; } public EventWaitHandle Initialized { get; } - List<Subscriber> Subscribers { get; set; } public static bool IsTracked(string projectPath) { @@ -221,13 +181,11 @@ namespace QtVsTools.QtMsBuild Initialized.Set(); - Subscribers = new List<Subscriber>(); int n = configs.Count; int d = (100 - p) / (n * 2); foreach (var config in configs) { var configProject = await UnconfiguredProject.LoadConfiguredProjectAsync(config); UpdateInitStatus(p += d); - Subscribers.Add(new Subscriber(this, configProject)); configProject.ProjectUnloading += OnProjectUnloadingAsync; if (QtVsToolsPackage.Instance.Options.BuildDebugInformation) { Messages.Print(string.Format( @@ -239,37 +197,6 @@ namespace QtVsTools.QtMsBuild } } - - async Task OnProjectUpdateAsync(ConfiguredProject config, IProjectSubscriptionUpdate update) - { - var changes = update.ProjectChanges.Values - .Where(x => x.Difference.AnyChanges) - .Select(x => x.Difference); - var changesCount = changes - .Select(x => x.AddedItems.Count - + x.ChangedItems.Count - + x.ChangedProperties.Count - + x.RemovedItems.Count - + x.RenamedItems.Count) - .Sum(); - var changedProps = changes.SelectMany(x => x.ChangedProperties); - if (changesCount == 0 - || (changesCount == 1 - && changedProps.Count() == 1 - && changedProps.First() == "QtLastBackgroundBuild")) { - return; - } - - if (QtVsToolsPackage.Instance.Options.BuildDebugInformation) { - Messages.Print(string.Format( - "{0:HH:mm:ss.FFF} QtProjectTracker({1}): Changed [{2}] {3}", - DateTime.Now, Thread.CurrentThread.ManagedThreadId, - config.ProjectConfiguration.Name, - config.UnconfiguredProject.FullPath)); - } - await QtProjectIntellisense.RefreshAsync(Project, config.ProjectConfiguration.Name); - } - async Task OnProjectUnloadingAsync(object sender, EventArgs args) { var project = sender as ConfiguredProject; @@ -283,11 +210,6 @@ namespace QtVsTools.QtMsBuild project.UnconfiguredProject.FullPath)); } lock (CriticalSection) { - if (Subscribers != null) { - Subscribers.ForEach(s => s.Dispose()); - Subscribers.Clear(); - Subscribers = null; - } project.ProjectUnloading -= OnProjectUnloadingAsync; Instances.TryRemove(project.UnconfiguredProject.FullPath, out QtProjectTracker _); } |