diff options
author | Alexander Köplinger <alex.koeplinger@outlook.com> | 2018-03-24 01:56:02 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-03-24 01:56:02 +0300 |
commit | 506fc0b522fde4d71621c94cb6495c07c07f720b (patch) | |
tree | 4231feb331a3b0309173938f205c5f628ac963a2 /msvc | |
parent | 331f3d9f27e667e31ffddac26644b24e76f0e11c (diff) |
[genproj] Deduplication of sources (#7810)
This implements a simple deduplication of source files in the .csproj's.
A postprocessing step opens the files and grabs all ItemGroups with sources
and then does an intersection. It then moves files that are common
across all platforms into a separate ItemGroup.
Diffstat (limited to 'msvc')
-rw-r--r-- | msvc/scripts/csproj.tmpl | 1 | ||||
-rw-r--r-- | msvc/scripts/genproj.cs | 86 |
2 files changed, 87 insertions, 0 deletions
diff --git a/msvc/scripts/csproj.tmpl b/msvc/scripts/csproj.tmpl index 32f186fd228..4ca9b2be8b3 100644 --- a/msvc/scripts/csproj.tmpl +++ b/msvc/scripts/csproj.tmpl @@ -51,6 +51,7 @@ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+<!-- @COMMON_SOURCES@ -->
<!-- @ALL_SOURCES@ -->
<!-- @ALL_REFERENCES@ -->
diff --git a/msvc/scripts/genproj.cs b/msvc/scripts/genproj.cs index 47d1fabccac..7efbaa446b9 100644 --- a/msvc/scripts/genproj.cs +++ b/msvc/scripts/genproj.cs @@ -1337,6 +1337,12 @@ public class Driver { } } + foreach (var csprojFile in projects.Values.Select (x => x.GetProjectFilename ()).Distinct ()) + { + Console.WriteLine ("Deduplicating: " + csprojFile); + DeduplicateSources (csprojFile); + } + Func<MsbuildGenerator.VsCsproj, bool> additionalFilter; additionalFilter = fullSolutions ? (Func<MsbuildGenerator.VsCsproj, bool>)null : IsCommonLibrary; @@ -1382,6 +1388,86 @@ public class Driver { //WriteSolution (build_sln_gen, "mcs_build.sln"); } + static void DeduplicateSources (string csprojFilename) + { + XmlDocument doc = new XmlDocument (); + doc.Load (csprojFilename); + XmlNamespaceManager mgr = new XmlNamespaceManager (doc.NameTable); + mgr.AddNamespace ("x", "http://schemas.microsoft.com/developer/msbuild/2003"); + + XmlNode root = doc.DocumentElement; + var allSources = new Dictionary<string, List<string>> (); + + // grab all sources across all platforms + ProcessCompileItems (mgr, root, (source, platform) => + { + if (!allSources.ContainsKey (platform)) + allSources[platform] = new List<string> (); + allSources[platform].Add (source.Attributes["Include"].Value); + }); + + if (allSources.Count > 1) + { + // find the sources which are common across all platforms + var commonSources = allSources.Values.First (); + foreach (var l in allSources.Values.Skip (1)) + commonSources = commonSources.Intersect (l).ToList (); + + if (commonSources.Count > 0) + { + // remove common sources from the individual platforms + ProcessCompileItems (mgr, root, (source, platform) => + { + var parent = source.ParentNode; + if (commonSources.Contains (source.Attributes["Include"].Value)) + parent.RemoveChild (source); + + if (!parent.HasChildNodes) + parent.ParentNode.RemoveChild (parent); + }); + + // add common sources as ItemGroup + XmlNode commonSourcesComment = root.SelectSingleNode ("//comment()[. = ' @COMMON_SOURCES@ ']"); + XmlElement commonSourcesElement = doc.CreateElement ("ItemGroup", root.NamespaceURI); + + foreach (var s in commonSources) + { + var c = doc.CreateElement ("Compile", root.NamespaceURI); + var v = doc.CreateAttribute ("Include"); + v.Value = s; + c.Attributes.Append (v); + + commonSourcesElement.AppendChild (c); + } + root.ReplaceChild (commonSourcesElement, commonSourcesComment); + } + } + + doc.Save (csprojFilename); + } + + static void ProcessCompileItems (XmlNamespaceManager mgr, XmlNode x, Action<XmlNode, string> action) + { + foreach (XmlNode n in x.SelectNodes("//x:ItemGroup[@Condition]", mgr)) + { + if (n.Attributes.Count == 0) + continue; + + var platform = n.Attributes["Condition"].Value; + + if (!platform.Contains("$(Platform)")) + continue; + + var compileItems = n.SelectNodes("./x:Compile[@Include]", mgr); + + if (compileItems.Count == 0) + continue; + + foreach (XmlNode source in compileItems) + action(source, platform); + } + } + // Rebases a path, assuming that execution is taking place in the "class" subdirectory, // so it strips ../class/ from a path, which is a no-op static string RebaseToClassDirectory (string path) |