diff options
author | Miguel Costa <miguel.costa@qt.io> | 2018-03-22 18:12:06 +0100 |
---|---|---|
committer | Miguel Costa <miguel.costa@qt.io> | 2018-03-28 10:08:32 +0000 |
commit | f553ff6cb8ccea033e639f02a2373dcf3a8a98fb (patch) | |
tree | 4c4d76a0beb01549fd560b459f54d8a79e25f92f | |
parent | ef0cf3b7ce3d4ce3cf9ccbf6384e0c9a7d7a2673 (diff) |
Improve performance of conversion to Qt/MSBuild
Modified the conversion from custom build steps to Qt/MSBuild such that
larger projects can be converted faster. The optimization focused on the
code that removes generated items from the project: instead of looking
at every item in the project, only .cpp files will now be checked if
they are generated sources and should therefore be excluded from the
project. To further speed up this process, added an index on the path of
.cpp files.
Additionally, to provide UI feedback during the conversion procedure, a
progress dialog is now displayed when converting whole solutions.
Task-number: QTVSADDINBUG-515
Change-Id: Ib9326554bcf99dbff8b6dd0c65d1a44e18ab68b1
Reviewed-by: Oliver Wolff <oliver.wolff@qt.io>
-rw-r--r-- | src/qtprojectlib/MsBuildProject.cs | 64 | ||||
-rw-r--r-- | src/qtvstools/QtMsBuildConverter.cs | 65 | ||||
-rw-r--r-- | src/qtvstools/Resources.resx | 10 |
3 files changed, 100 insertions, 39 deletions
diff --git a/src/qtprojectlib/MsBuildProject.cs b/src/qtprojectlib/MsBuildProject.cs index aca3f4a8..06d78097 100644 --- a/src/qtprojectlib/MsBuildProject.cs +++ b/src/qtprojectlib/MsBuildProject.cs @@ -375,11 +375,12 @@ namespace QtProjectLib } bool RemoveGeneratedFiles( + string projDir, List<CustomBuildEval> cbEvals, string configName, string itemName, - IEnumerable<XElement> projectItems, - IEnumerable<XElement> filterItems) + Dictionary<string, XElement> projItemsByPath, + Dictionary<string, XElement> filterItemsByPath) { //remove items with generated files bool hasGeneratedFiles = false; @@ -387,21 +388,21 @@ namespace QtProjectLib .Where(x => x.ProjectConfig == configName && x.Identity == itemName) .FirstOrDefault(); if (cbEval != null) { - var outputFiles = cbEval.Outputs.Split(new char[] { ';' }); + var outputFiles = cbEval.Outputs + .Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries) + .Select(x => HelperFunctions.CanonicalPath( + Path.IsPathRooted(x) ? x : Path.Combine(projDir, x))); + var outputItems = new List<XElement>(); foreach (var outputFile in outputFiles) { - if (!string.IsNullOrEmpty(outputFile)) { - var outputItems = new List<XElement>(); - outputItems.AddRange(projectItems - .Where(x => HelperFunctions.PathEquals( - outputFile, (string)x.Attribute("Include")))); - outputItems.AddRange(filterItems - .Where(x => HelperFunctions.PathEquals( - outputFile, (string)x.Attribute("Include")))); - hasGeneratedFiles |= outputItems.Any(); - foreach (var item in outputItems) - item.Remove(); - } + XElement mocOutput = null; + if (projItemsByPath.TryGetValue(outputFile, out mocOutput)) + outputItems.Add(mocOutput); + if (filterItemsByPath.TryGetValue(outputFile, out mocOutput)) + outputItems.Add(mocOutput); } + hasGeneratedFiles = outputItems.Any(); + foreach (var item in outputItems) + item.Remove(); } return hasGeneratedFiles; } @@ -413,26 +414,32 @@ namespace QtProjectLib var qtMsBuild = new QtMsBuildContainer(new MsBuildConverterProvider()); qtMsBuild.BeginSetItemProperties(); + var projDir = Path.GetDirectoryName(this[Files.Project].filePath); + var configurations = this[Files.Project].xml .Elements(ns + "Project") .Elements(ns + "ItemGroup") .Elements(ns + "ProjectConfiguration"); - var projectItems = this[Files.Project].xml + var projItemsByPath = this[Files.Project].xml .Elements(ns + "Project") .Elements(ns + "ItemGroup") - .Elements() + .Elements(ns + "ClCompile") .Where(x => ((string)x.Attribute("Include")) - .IndexOfAny(Path.GetInvalidPathChars()) == -1); - + .IndexOfAny(Path.GetInvalidPathChars()) == -1) + .ToDictionary(x => HelperFunctions.CanonicalPath( + Path.Combine(projDir, (string)x.Attribute("Include"))), + StringComparer.InvariantCultureIgnoreCase); - var filterItems = this[Files.Filters].xml + var filterItemsByPath = this[Files.Filters].xml .Elements(ns + "Project") .Elements(ns + "ItemGroup") - .Elements() - .Where(x => projectItems.Where(y => - ((string)x.Attribute("Include")).Equals((string)y.Attribute("Include"), - StringComparison.InvariantCultureIgnoreCase)).Any()); + .Elements(ns + "ClCompile") + .Where(x => ((string)x.Attribute("Include")) + .IndexOfAny(Path.GetInvalidPathChars()) == -1) + .ToDictionary(x => HelperFunctions.CanonicalPath( + Path.Combine(projDir, (string)x.Attribute("Include"))), + StringComparer.InvariantCultureIgnoreCase); var cppIncludePaths = this[Files.Project].xml .Elements(ns + "Project") @@ -518,7 +525,8 @@ namespace QtProjectLib //remove items with generated files var hasGeneratedFiles = RemoveGeneratedFiles( - cbEvals, configName, itemName, projectItems, filterItems); + projDir, cbEvals, configName, itemName, + projItemsByPath, filterItemsByPath); //set properties qtMsBuild.SetItemProperty(qtMoc, @@ -559,7 +567,8 @@ namespace QtProjectLib var configName = (string)qtRcc.Attribute("ConfigName"); //remove items with generated files - RemoveGeneratedFiles(cbEvals, configName, itemName, projectItems, filterItems); + RemoveGeneratedFiles(projDir, cbEvals, configName, itemName, + projItemsByPath, filterItemsByPath); //set properties qtMsBuild.SetItemProperty(qtRcc, @@ -582,7 +591,8 @@ namespace QtProjectLib var configName = (string)qtUic.Attribute("ConfigName"); //remove items with generated files - RemoveGeneratedFiles(cbEvals, configName, itemName, projectItems, filterItems); + RemoveGeneratedFiles(projDir, cbEvals, configName, itemName, + projItemsByPath, filterItemsByPath); //set properties qtMsBuild.SetItemProperty(qtUic, diff --git a/src/qtvstools/QtMsBuildConverter.cs b/src/qtvstools/QtMsBuildConverter.cs index 479129a2..23a76803 100644 --- a/src/qtvstools/QtMsBuildConverter.cs +++ b/src/qtvstools/QtMsBuildConverter.cs @@ -75,14 +75,64 @@ namespace QtVsTools return WarningMessage(SR.GetString("CancelConvertingProject")); } - foreach (var project in projects) { - if (!ProjectToQtMsBuild(project, false)) + var projectPaths = projects.Select(x => x.FullName).ToList(); + + string solutionPath = solution.FileName; + solution.Close(true); + + IVsThreadedWaitDialog2 waitDialog = null; + var waitDialogFactory = (IVsThreadedWaitDialogFactory)Vsix + .GetGlobalService(typeof(SVsThreadedWaitDialogFactory)); + if (waitDialogFactory != null) + waitDialogFactory.CreateInstance(out waitDialog); + int projCount = 0; + if (waitDialog != null) + waitDialog.StartWaitDialogWithPercentageProgress( + SR.GetString("Resources_QtVsTools"), + SR.GetString("ConvertWait"), + null, null, null, true, 0, projectPaths.Count, 0); + bool canceled = false; + foreach (var projectPath in projectPaths) { + if (waitDialog != null) + waitDialog.UpdateProgress(string.Format(SR.GetString("ConvertProgress"), + projCount + 1, projectPaths.Count, + Path.GetFileNameWithoutExtension(projectPath)), + null, null, projCount, projectPaths.Count, false, out canceled); + if (canceled) + break; + if (!ConvertProject(projectPath)) return false; + ++projCount; + } + if (waitDialog != null) { + int dummy; + waitDialog.EndWaitDialog(out dummy); + } + Vsix.Instance.Dte.Solution.Open(solutionPath); + if (canceled && projCount < projectPaths.Count) { + MessageBox.Show(string.Format(SR.GetString("ConvertCanceled"), + projectPaths.Count - projCount), SR.GetString("Resources_QtVsTools"), + MessageBoxButtons.OK, MessageBoxIcon.Warning); } return true; } + static bool ConvertProject(string pathToProject) + { + var xmlProject = MsBuildProject.Load(pathToProject); + bool ok = (xmlProject != null); + if (ok) + ok = xmlProject.AddQtMsBuildReferences(); + if (ok) + ok = xmlProject.ConvertCustomBuildToQtMsBuild(); + if (ok) + ok = xmlProject.EnableMultiProcessorCompilation(); + if (ok) + ok = xmlProject.Save(); + return ok; + } + public static bool ProjectToQtMsBuild(EnvDTE.Project project, bool askConfirmation = true) { if (project == null) @@ -134,16 +184,7 @@ namespace QtVsTools string.Format("{0}\r\n{1}", projectName, e.Message))); } - var xmlProject = MsBuildProject.Load(pathToProject); - bool ok = (xmlProject != null); - if (ok) - ok = xmlProject.AddQtMsBuildReferences(); - if (ok) - ok = xmlProject.ConvertCustomBuildToQtMsBuild(); - if (ok) - ok = xmlProject.EnableMultiProcessorCompilation(); - if (ok) - ok = xmlProject.Save(); + bool ok = ConvertProject(pathToProject); try { solution.ReloadProject(ref projectGuid); } catch (Exception e) { diff --git a/src/qtvstools/Resources.resx b/src/qtvstools/Resources.resx index d716cd46..67f194f8 100644 --- a/src/qtvstools/Resources.resx +++ b/src/qtvstools/Resources.resx @@ -213,6 +213,16 @@ <data name="ConvertSaveConfirmation" xml:space="preserve"> <value>Projects must be saved before conversion. Save projects?</value> </data> + <data name="ConvertWait" xml:space="preserve"> + <value>Converting solution to Qt/MSBuild...</value> + </data> + <data name="ConvertProgress" xml:space="preserve"> + <value>Converting solution to Qt/MSBuild... +Converting project {0}/{1}: {2}...</value> + </data> + <data name="ConvertCanceled" xml:space="preserve"> + <value>Conversion canceled. {0} projects were not converted.</value> + </data> <data name="ErrorConvertingProject" xml:space="preserve"> <value>Error converting project {0}</value> </data> |