Beispiel #1
0
        private void GenerateVcxproj(bool EnableRebuild)
        {
            var VcxprojPath = Path.Combine(OutputDirectory, Project.Name + ".vcxproj");
            var BaseDirPath = Path.GetDirectoryName(Path.GetFullPath(VcxprojPath));

            var xVcxproj = XmlFile.FromString(VcxprojTemplateText);

            Trim(xVcxproj);

            var xn = xVcxproj.Name.Namespace;

            foreach (var ig in xVcxproj.Elements(xn + "ItemGroup").ToArray())
            {
                if (ig.Attribute("Label") != null)
                {
                    continue;
                }

                var None             = ig.Elements().Where(e => e.Name == xn + "None").ToArray();
                var ClInclude        = ig.Elements().Where(e => e.Name == xn + "ClInclude").ToArray();
                var ClCompile        = ig.Elements().Where(e => e.Name == xn + "ClCompile").ToArray();
                var ProjectReference = ig.Elements().Where(e => e.Name == xn + "ProjectReference").ToArray();
                foreach (var e in None)
                {
                    e.Remove();
                }
                foreach (var e in ClInclude)
                {
                    e.Remove();
                }
                foreach (var e in ClCompile)
                {
                    e.Remove();
                }
                foreach (var e in ProjectReference)
                {
                    e.Remove();
                }
                if (!ig.HasElements && !ig.HasAttributes)
                {
                    ig.Remove();
                }
            }

            var GlobalsPropertyGroup = xVcxproj.Elements(xn + "PropertyGroup").Where(e => e.Attribute("Label") != null && e.Attribute("Label").Value == "Globals").FirstOrDefault();

            if (GlobalsPropertyGroup == null)
            {
                GlobalsPropertyGroup = new XElement(xn + "PropertyGroup", new XAttribute("Label", "Globals"));
                xVcxproj.Add(GlobalsPropertyGroup);
            }
            var g = "{" + ProjectId.ToUpper() + "}";

            GlobalsPropertyGroup.SetElementValue(xn + "ProjectGuid", g);
            GlobalsPropertyGroup.SetElementValue(xn + "RootNamespace", Project.Name);

            var ExistingConfigurationTypeAndArchitectures = new Dictionary <KeyValuePair <ConfigurationType, ArchitectureType>, String>();
            var ProjectConfigurations = xVcxproj.Elements(xn + "ItemGroup").Where(e => (e.Attribute("Label") != null) && (e.Attribute("Label").Value == "ProjectConfigurations")).SelectMany(e => e.Elements(xn + "ProjectConfiguration")).Select(e => e.Element(xn + "Configuration").Value + "|" + e.Element(xn + "Platform").Value).ToDictionary(s => s);

            foreach (var Architecture in Enum.GetValues(typeof(ArchitectureType)).Cast <ArchitectureType>())
            {
                foreach (var ConfigurationType in Enum.GetValues(typeof(ConfigurationType)).Cast <ConfigurationType>())
                {
                    var Name = ConfigurationType.ToString() + "|" + GetArchitectureString(Architecture);
                    if (ProjectConfigurations.ContainsKey(Name))
                    {
                        ExistingConfigurationTypeAndArchitectures.Add(new KeyValuePair <ConfigurationType, ArchitectureType>(ConfigurationType, Architecture), Name);
                    }
                }
            }

            foreach (var Pair in ExistingConfigurationTypeAndArchitectures)
            {
                var ConfigurationType = Pair.Key.Key;
                var Architecture      = Pair.Key.Value;
                var Name = Pair.Value;

                var conf = ConfigurationUtils.GetMergedConfiguration(ToolchainType.Windows_VisualC, CompilerType.VisualC, BuildingOperatingSystem, TargetOperatingSystem, ConfigurationType, Architecture, Project.Configurations);

                var PropertyGroup = xVcxproj.Elements(xn + "PropertyGroup").Where(e => (e.Attribute("Condition") != null) && (e.Attribute("Condition").Value == "'$(Configuration)|$(Platform)'=='" + Name + "'")).LastOrDefault();
                if (PropertyGroup == null)
                {
                    PropertyGroup = new XElement(xn + "PropertyGroup", new XAttribute("Condition", "'$(Configuration)|$(Platform)'=='" + Name + "'"));
                }

                if (conf.TargetType == TargetType.Executable)
                {
                    PropertyGroup.SetElementValue(xn + "ConfigurationType", "Application");
                }
                else if (conf.TargetType == TargetType.StaticLibrary)
                {
                    PropertyGroup.SetElementValue(xn + "ConfigurationType", "StaticLibrary");
                }
                else if (conf.TargetType == TargetType.DynamicLibrary)
                {
                    PropertyGroup.SetElementValue(xn + "ConfigurationType", "DynamicLibrary");
                }
                else
                {
                    throw new NotSupportedException("NotSupportedTargetType: " + conf.TargetType.ToString());
                }

                var ItemDefinitionGroup = xVcxproj.Elements(xn + "ItemDefinitionGroup").Where(e => (e.Attribute("Condition") != null) && (e.Attribute("Condition").Value == "'$(Configuration)|$(Platform)'=='" + Name + "'")).LastOrDefault();
                if (ItemDefinitionGroup == null)
                {
                    ItemDefinitionGroup = new XElement(xn + "ItemDefinitionGroup", new XAttribute("Condition", "'$(Configuration)|$(Platform)'=='" + Name + "'"));
                    xVcxproj.Add(ItemDefinitionGroup);
                }
                var ClCompile = ItemDefinitionGroup.Element(xn + "ClCompile");
                if (ClCompile == null)
                {
                    ClCompile = new XElement(xn + "ClCompile");
                    ItemDefinitionGroup.Add(ClCompile);
                }
                var IncludeDirectories = conf.IncludeDirectories.Select(d => FileNameHandling.GetRelativePath(d, BaseDirPath)).ToList();
                if (IncludeDirectories.Count != 0)
                {
                    ClCompile.SetElementValue(xn + "AdditionalIncludeDirectories", String.Join(";", IncludeDirectories) + ";%(AdditionalIncludeDirectories)");
                }
                var Defines = conf.Defines;
                if (Defines.Count != 0)
                {
                    ClCompile.SetElementValue(xn + "PreprocessorDefinitions", String.Join(";", Defines.Select(d => d.Key + (d.Value == null ? "" : "=" + (Regex.IsMatch(d.Value, @"^[0-9]+$") ? d.Value : "\"" + d.Value.Replace("\"", "\"\"") + "\"")))) + ";%(PreprocessorDefinitions)");
                }
                var CompilerFlags = conf.CFlags.Concat(conf.CppFlags).ToList();
                if (CompilerFlags.Count != 0)
                {
                    ClCompile.SetElementValue(xn + "AdditionalOptions", "%(AdditionalOptions) " + String.Join(" ", CompilerFlags.Select(f => (f == null ? "" : Regex.IsMatch(f, @"^[0-9]+$") ? f : "\"" + f.Replace("\"", "\"\"") + "\""))));
                }

                if ((conf.TargetType == TargetType.Executable) || (conf.TargetType == TargetType.DynamicLibrary))
                {
                    var Link = ItemDefinitionGroup.Element(xn + "Link");
                    if (Link == null)
                    {
                        Link = new XElement(xn + "Link");
                        ItemDefinitionGroup.Add(ClCompile);
                    }
                    var LibDirectories = conf.LibDirectories.Select(d => FileNameHandling.GetRelativePath(d, BaseDirPath)).ToList();
                    if (LibDirectories.Count != 0)
                    {
                        Link.SetElementValue(xn + "AdditionalLibraryDirectories", String.Join(";", LibDirectories) + ";%(AdditionalLibraryDirectories)");
                    }
                    var Libs = conf.Libs.Concat(ProjectReferences.Select(p => p.Name + ".lib")).ToList();
                    if (Libs.Count != 0)
                    {
                        Link.SetElementValue(xn + "AdditionalDependencies", String.Join(";", Libs) + ";%(AdditionalDependencies)");
                    }
                    var LinkerFlags = conf.LinkerFlags.ToList();
                    if (LinkerFlags.Count != 0)
                    {
                        ClCompile.SetElementValue(xn + "AdditionalOptions", "%(AdditionalOptions) " + String.Join(" ", LinkerFlags.Select(f => (f == null ? "" : Regex.IsMatch(f, @"^[0-9]+$") ? f : "\"" + f.Replace("\"", "\"\"") + "\""))));
                    }
                }
            }

            var Import = xVcxproj.Elements(xn + "Import").LastOrDefault();

            foreach (var conf in Project.Configurations)
            {
                var FileItemGroup = new XElement(xn + "ItemGroup");
                if (Import != null)
                {
                    Import.AddBeforeSelf(FileItemGroup);
                }
                else
                {
                    xVcxproj.Add(FileItemGroup);
                }
                if ((conf.ConfigurationType != null) || (conf.Architecture != null))
                {
                    var Keys   = new List <String> {
                    };
                    var Values = new List <String> {
                    };
                    if (conf.ConfigurationType != null)
                    {
                        Keys.Add("$(Configuration)");
                        Values.Add(conf.ConfigurationType.ToString());
                    }
                    if (conf.Architecture != null)
                    {
                        Keys.Add("$(Platform)");
                        Values.Add(GetArchitectureString(conf.Architecture.Value));
                    }
                    var Condition = "'" + String.Join("|", Keys) + "' == '" + String.Join("|", Values) + "'";
                    FileItemGroup.Add(new XAttribute("Condition", Condition));
                }
                foreach (var f in conf.Files)
                {
                    var      RelativePath = FileNameHandling.GetRelativePath(f.Path, BaseDirPath);
                    XElement x;
                    if (f.Type == FileType.Header)
                    {
                        x = new XElement(xn + "ClInclude", new XAttribute("Include", RelativePath));
                    }
                    else if (f.Type == FileType.CSource)
                    {
                        x = new XElement(xn + "ClCompile", new XAttribute("Include", RelativePath));
                    }
                    else if (f.Type == FileType.CppSource)
                    {
                        x = new XElement(xn + "ClCompile", new XAttribute("Include", RelativePath));
                        x.Add(new XElement(xn + "ObjectFileName", "$(IntDir)" + RelativePath.Replace("..", "__") + ".obj"));
                    }
                    else
                    {
                        x = new XElement(xn + "None", new XAttribute("Include", RelativePath));
                    }
                    FileItemGroup.Add(x);
                }
                if (!FileItemGroup.HasElements)
                {
                    FileItemGroup.Remove();
                }
            }

            var ProjectItemGroup = new XElement(xn + "ItemGroup");

            if (Import != null)
            {
                Import.AddBeforeSelf(ProjectItemGroup);
            }
            else
            {
                xVcxproj.Add(ProjectItemGroup);
            }
            foreach (var p in ProjectReferences)
            {
                var RelativePath = FileNameHandling.GetRelativePath(p.FilePath, BaseDirPath);
                var x            = new XElement(xn + "ProjectReference", new XAttribute("Include", RelativePath));
                x.Add(new XElement(xn + "Project", "{" + p.Id.ToUpper() + "}"));
                x.Add(new XElement(xn + "Name", "{" + p.Name + "}"));
                ProjectItemGroup.Add(x);
            }
            if (!ProjectItemGroup.HasElements)
            {
                ProjectItemGroup.Remove();
            }

            var sVcxproj = XmlFile.ToString(xVcxproj);

            TextFile.WriteToFile(VcxprojPath, sVcxproj, Encoding.UTF8, !EnableRebuild);
        }
        private void GenerateVcxproj(bool ForceRegenerate)
        {
            var VcxprojPath = OutputDirectory / (Project.Name + ".vcxproj");
            var BaseDirPath = VcxprojPath.Parent;

            var xVcxproj = XmlFile.FromString(VcxprojTemplateText);

            Trim(xVcxproj);

            var xn = xVcxproj.Name.Namespace;

            if (TargetArchitecture != null)
            {
                var rProjectConfigurationInclude = new Regex(@"[^|]+\|(?<Architecture>[^|]+)");
                foreach (var e in xVcxproj.Elements(xn + "ItemGroup").Where(e => (e.Attribute("Label") != null) && (e.Attribute("Label").Value == "ProjectConfigurations")).SelectMany(e => e.Elements(xn + "ProjectConfiguration")).ToArray())
                {
                    var m = rProjectConfigurationInclude.Match(e.Attribute("Include").Value);
                    if (m.Success)
                    {
                        var Architecture = m.Result("${Architecture}");
                        if (Architecture != GetArchitectureString(TargetOperatingSystem, TargetArchitecture.Value))
                        {
                            e.Remove();
                        }
                    }
                }

                var rCondition = new Regex(@"'\$\(Configuration\)\|\$\(Platform\)'=='[^|]+\|(?<Architecture>[^|]+)'");
                foreach (var e in xVcxproj.Elements().ToArray())
                {
                    if (e.Attribute("Condition") != null)
                    {
                        var m = rCondition.Match(e.Attribute("Condition").Value);
                        if (m.Success)
                        {
                            var Architecture = m.Result("${Architecture}");
                            if (Architecture != GetArchitectureString(TargetOperatingSystem, TargetArchitecture.Value))
                            {
                                e.Remove();
                            }
                        }
                    }
                }
            }

            foreach (var ig in xVcxproj.Elements(xn + "ItemGroup").ToArray())
            {
                if (ig.Attribute("Label") != null)
                {
                    continue;
                }

                var None             = ig.Elements().Where(e => e.Name == xn + "None").ToArray();
                var ClInclude        = ig.Elements().Where(e => e.Name == xn + "ClInclude").ToArray();
                var ClCompile        = ig.Elements().Where(e => e.Name == xn + "ClCompile").ToArray();
                var ProjectReference = ig.Elements().Where(e => e.Name == xn + "ProjectReference").ToArray();
                foreach (var e in None)
                {
                    e.Remove();
                }
                foreach (var e in ClInclude)
                {
                    e.Remove();
                }
                foreach (var e in ClCompile)
                {
                    e.Remove();
                }
                foreach (var e in ProjectReference)
                {
                    e.Remove();
                }
                if (!ig.HasElements && !ig.HasAttributes)
                {
                    ig.Remove();
                }
            }

            var GlobalsPropertyGroup = xVcxproj.Elements(xn + "PropertyGroup").Where(e => e.Attribute("Label") != null && e.Attribute("Label").Value == "Globals").FirstOrDefault();

            if (GlobalsPropertyGroup == null)
            {
                GlobalsPropertyGroup = new XElement(xn + "PropertyGroup", new XAttribute("Label", "Globals"));
                xVcxproj.Add(GlobalsPropertyGroup);
            }
            var g = "{" + ProjectId.ToUpper() + "}";

            GlobalsPropertyGroup.SetElementValue(xn + "ProjectGuid", g);
            GlobalsPropertyGroup.SetElementValue(xn + "RootNamespace", Project.Name);
            if (TargetOperatingSystem == OperatingSystemType.Windows)
            {
                GlobalsPropertyGroup.SetElementValue(xn + "WindowsTargetPlatformVersion", GetWindowsTargetPlatformVersion());
                if (WindowsRuntime == WindowsRuntimeType.Win32)
                {
                    GlobalsPropertyGroup.SetElementValue(xn + "Keyword", "Win32Proj");
                }
                else if (WindowsRuntime == WindowsRuntimeType.WinRT)
                {
                    GlobalsPropertyGroup.SetElementValue(xn + "AppContainerApplication", true);
                    GlobalsPropertyGroup.SetElementValue(xn + "ApplicationType", "Windows Store");
                    GlobalsPropertyGroup.SetElementValue(xn + "ApplicationTypeRevision", "10.0");
                }
                else
                {
                    throw new InvalidOperationException();
                }
            }
            else if (TargetOperatingSystem == OperatingSystemType.Linux)
            {
                GlobalsPropertyGroup.SetElementValue(xn + "Keyword", "Linux");
            }
            else
            {
                throw new InvalidOperationException();
            }

            var globalConf = Project.Configurations.Merged(Project.TargetType, HostOperatingSystem, HostArchitecture, TargetOperatingSystem, TargetArchitecture, WindowsRuntime, ToolchainType.VisualStudio, Compiler, CLibrary, CLibraryForm, CppLibrary, CppLibraryForm, null);

            foreach (var o in globalConf.Options)
            {
                var Prefix = "vc.Globals.";
                if (o.Key.StartsWith(Prefix))
                {
                    var Key = o.Key.Substring(Prefix.Length);
                    GlobalsPropertyGroup.SetElementValue(xn + Key, o.Value);
                }
            }

            var ExistingConfigurationTypeAndArchitectures = new Dictionary <KeyValuePair <ConfigurationType, ArchitectureType>, String>();
            var ProjectConfigurations = xVcxproj.Elements(xn + "ItemGroup").Where(e => (e.Attribute("Label") != null) && (e.Attribute("Label").Value == "ProjectConfigurations")).SelectMany(e => e.Elements(xn + "ProjectConfiguration")).Select(e => e.Element(xn + "Configuration").Value + "|" + e.Element(xn + "Platform").Value).ToDictionary(s => s);

            foreach (var Architecture in new ArchitectureType[] { ArchitectureType.x86, ArchitectureType.x64, ArchitectureType.armv7a, ArchitectureType.arm64 })
            {
                foreach (var ConfigurationType in Enum.GetValues(typeof(ConfigurationType)).Cast <ConfigurationType>())
                {
                    var Name = ConfigurationType.ToString() + "|" + GetArchitectureString(TargetOperatingSystem, Architecture);
                    if (ProjectConfigurations.ContainsKey(Name))
                    {
                        ExistingConfigurationTypeAndArchitectures.Add(new KeyValuePair <ConfigurationType, ArchitectureType>(ConfigurationType, Architecture), Name);
                    }
                }
            }

            foreach (var Pair in ExistingConfigurationTypeAndArchitectures)
            {
                var ConfigurationType = Pair.Key.Key;
                var Architecture      = Pair.Key.Value;
                var Name = Pair.Value;

                var conf = Project.Configurations.Merged(Project.TargetType, HostOperatingSystem, HostArchitecture, TargetOperatingSystem, Architecture, WindowsRuntime, ToolchainType.VisualStudio, Compiler, CLibrary, CLibraryForm, CppLibrary, CppLibraryForm, ConfigurationType);

                var PropertyGroupConfiguration = xVcxproj.Elements(xn + "PropertyGroup").Where(e => (e.Attribute("Condition") != null) && (e.Attribute("Condition").Value == "'$(Configuration)|$(Platform)'=='" + Name + "'") && (e.Attribute("Label") != null) && (e.Attribute("Label").Value == "Configuration")).LastOrDefault();
                if (PropertyGroupConfiguration == null)
                {
                    PropertyGroupConfiguration = new XElement(xn + "PropertyGroup", new XAttribute("Condition", "'$(Configuration)|$(Platform)'=='" + Name + "'"), new XAttribute("Label", "Configuration"));
                    xVcxproj.Add(PropertyGroupConfiguration);
                }

                if (!String.IsNullOrEmpty(Project.TargetName) && (Project.TargetName != Project.Name))
                {
                    PropertyGroupConfiguration.SetElementValue(xn + "TargetName", Project.TargetName);
                }
                if (Project.TargetType == TargetType.Executable)
                {
                    PropertyGroupConfiguration.SetElementValue(xn + "ConfigurationType", "Application");
                }
                else if (Project.TargetType == TargetType.StaticLibrary)
                {
                    PropertyGroupConfiguration.SetElementValue(xn + "ConfigurationType", "StaticLibrary");
                }
                else if (Project.TargetType == TargetType.DynamicLibrary)
                {
                    PropertyGroupConfiguration.SetElementValue(xn + "ConfigurationType", "DynamicLibrary");
                }
                else
                {
                    throw new NotSupportedException("NotSupportedTargetType: " + Project.TargetType.ToString());
                }

                if (TargetOperatingSystem == OperatingSystemType.Linux)
                {
                    if (Compiler == CompilerType.gcc)
                    {
                        PropertyGroupConfiguration.SetElementValue(xn + "PlatformToolset", "WSL_1_0");
                    }
                    else if (Compiler == CompilerType.clang)
                    {
                        PropertyGroupConfiguration.SetElementValue(xn + "PlatformToolset", "WSL_Clang_1_0");
                    }
                }

                foreach (var o in conf.Options)
                {
                    var Prefix = "vc.Configuration.";
                    if (o.Key.StartsWith(Prefix))
                    {
                        var Key = o.Key.Substring(Prefix.Length);
                        PropertyGroupConfiguration.SetElementValue(xn + Key, o.Value);
                    }
                }

                var PropertyGroup = xVcxproj.Elements(xn + "PropertyGroup").Where(e => (e.Attribute("Condition") != null) && (e.Attribute("Condition").Value == "'$(Configuration)|$(Platform)'=='" + Name + "'") && (e.Attribute("Label") == null)).LastOrDefault();
                if (PropertyGroup == null)
                {
                    PropertyGroup = new XElement(xn + "PropertyGroup", new XAttribute("Condition", "'$(Configuration)|$(Platform)'=='" + Name + "'"));
                    xVcxproj.Add(PropertyGroup);
                }

                if (conf.OutputDirectory != null)
                {
                    var RelativeOutDir = conf.OutputDirectory.RelativeTo(BuildDirectory);
                    var OutDir         = RelativeOutDir.IsFullPath ? RelativeOutDir.ToString(PathStringStyle.Windows) : "$(SolutionDir)" + RelativeOutDir.ToString(PathStringStyle.Windows);
                    if (!OutDir.EndsWith("\\"))
                    {
                        OutDir += "\\";
                    }
                    PropertyGroup.SetElementValue(xn + "OutDir", OutDir);
                    PropertyGroup.SetElementValue(xn + "DebuggerWorkingDirectory", OutDir);
                }
                else
                {
                    if (TargetArchitecture == null)
                    {
                        PropertyGroup.SetElementValue(xn + "OutDir", $"$(SolutionDir){Architecture}_{ConfigurationType}\\");
                        PropertyGroup.SetElementValue(xn + "DebuggerWorkingDirectory", $"$(SolutionDir){Architecture}_{ConfigurationType}\\");
                    }
                    else
                    {
                        PropertyGroup.SetElementValue(xn + "OutDir", $"$(SolutionDir){ConfigurationType}\\");
                        PropertyGroup.SetElementValue(xn + "DebuggerWorkingDirectory", $"$(SolutionDir){ConfigurationType}\\");
                    }
                }
                if (TargetArchitecture == null)
                {
                    PropertyGroup.SetElementValue(xn + "IntDir", $"$(SolutionDir)projects\\$(ProjectName)\\{Architecture}_{ConfigurationType}\\");
                }
                else
                {
                    PropertyGroup.SetElementValue(xn + "IntDir", $"$(SolutionDir)projects\\$(ProjectName)\\{ConfigurationType}\\");
                }

                if (TargetOperatingSystem == OperatingSystemType.Linux)
                {
                    if (CC != null)
                    {
                        PropertyGroup.SetElementValue(xn + "RemoteCCompileToolExe", CC);
                    }
                    if (CXX != null)
                    {
                        PropertyGroup.SetElementValue(xn + "RemoteCppCompileToolExe", CXX);
                        PropertyGroup.SetElementValue(xn + "RemoteLdToolExe", CXX);
                    }
                    if (AR != null)
                    {
                        PropertyGroup.SetElementValue(xn + "RemoteArToolExe", AR);
                    }
                    PropertyGroup.SetElementValue(xn + "EnableIncrementalBuild", "WithNinja");
                    if (Project.TargetType == TargetType.Executable)
                    {
                        PropertyGroup.SetElementValue(xn + "TargetExt", "");
                    }
                }

                foreach (var o in conf.Options)
                {
                    var Prefix = "vc.PropertyGroup.";
                    if (o.Key.StartsWith(Prefix))
                    {
                        var Key = o.Key.Substring(Prefix.Length);
                        PropertyGroupConfiguration.SetElementValue(xn + Key, o.Value);
                    }
                }

                var ItemDefinitionGroup = xVcxproj.Elements(xn + "ItemDefinitionGroup").Where(e => (e.Attribute("Condition") != null) && (e.Attribute("Condition").Value == "'$(Configuration)|$(Platform)'=='" + Name + "'")).LastOrDefault();
                if (ItemDefinitionGroup == null)
                {
                    ItemDefinitionGroup = new XElement(xn + "ItemDefinitionGroup", new XAttribute("Condition", "'$(Configuration)|$(Platform)'=='" + Name + "'"));
                    xVcxproj.Add(ItemDefinitionGroup);
                }
                var ClCompile = ItemDefinitionGroup.Element(xn + "ClCompile");
                if (ClCompile == null)
                {
                    ClCompile = new XElement(xn + "ClCompile");
                    ItemDefinitionGroup.Add(ClCompile);
                }
                var IncludeDirectories = conf.IncludeDirectories.Select(d => d.FullPath.RelativeTo(BaseDirPath).ToString(PathStringStyle.Windows)).ToList();
                if (IncludeDirectories.Count != 0)
                {
                    ClCompile.SetElementValue(xn + "AdditionalIncludeDirectories", String.Join(";", IncludeDirectories) + ";%(AdditionalIncludeDirectories)");
                }
                var Defines = conf.Defines;
                if (Defines.Count != 0)
                {
                    ClCompile.SetElementValue(xn + "PreprocessorDefinitions", String.Join(";", Defines.Select(d => d.Key + (d.Value == null ? "" : "=" + d.Value))) + ";%(PreprocessorDefinitions)");
                }
                var CompilerFlags = conf.SystemIncludeDirectories.SelectMany(d => new String[] { "/external:I", d.FullPath.RelativeTo(BaseDirPath).ToString(PathStringStyle.Windows) }).Concat(conf.CommonFlags).Concat(conf.CFlags).Concat(conf.CppFlags).ToList();
                if (WindowsRuntime == WindowsRuntimeType.WinRT)
                {
                    CompilerFlags.Add("/Zc:twoPhase-"); //https://docs.microsoft.com/en-us/cpp/build/reference/zc-twophase?view=vs-2019
                }
                if (CompilerFlags.Count != 0)
                {
                    ClCompile.SetElementValue(xn + "AdditionalOptions", "%(AdditionalOptions) " + String.Join(" ", CompilerFlags.Select(f => (f == null ? "" : Regex.IsMatch(f, @"^[0-9]+$") ? f : "\"" + f.Replace("\"", "\"\"\"") + "\""))));
                }

                foreach (var o in conf.Options)
                {
                    var Prefix = "vc.ClCompile.";
                    if (o.Key.StartsWith(Prefix))
                    {
                        ClCompile.SetElementValue(xn + o.Key.Substring(Prefix.Length), o.Value);
                    }
                }

                if (Project.TargetType == TargetType.StaticLibrary)
                {
                    var Lib = ItemDefinitionGroup.Element(xn + "Lib");
                    if (Lib == null)
                    {
                        Lib = new XElement(xn + "Lib");
                        ItemDefinitionGroup.Add(Lib);
                    }

                    foreach (var o in conf.Options)
                    {
                        var Prefix = "vc.Lib.";
                        if (o.Key.StartsWith(Prefix))
                        {
                            Lib.SetElementValue(xn + o.Key.Substring(Prefix.Length), o.Value);
                        }
                    }
                }

                if ((Project.TargetType == TargetType.Executable) || (Project.TargetType == TargetType.DynamicLibrary))
                {
                    var Link = ItemDefinitionGroup.Element(xn + "Link");
                    if (Link == null)
                    {
                        Link = new XElement(xn + "Link");
                        ItemDefinitionGroup.Add(Link);
                    }
                    var LibDirectories = conf.LibDirectories.Select(d => d.FullPath.RelativeTo(BaseDirPath).ToString(PathStringStyle.Windows)).ToList();
                    if (LibDirectories.Count != 0)
                    {
                        Link.SetElementValue(xn + "AdditionalLibraryDirectories", String.Join(";", LibDirectories) + ";%(AdditionalLibraryDirectories)");
                    }
                    if (TargetOperatingSystem == OperatingSystemType.Windows)
                    {
                        var Libs = conf.Libs.Select(Lib => Lib.Parts.Count == 1 ? Lib.ToString(PathStringStyle.Windows) : Lib.RelativeTo(BaseDirPath).ToString(PathStringStyle.Windows)).ToList();
                        if (Libs.Count != 0)
                        {
                            Link.SetElementValue(xn + "AdditionalDependencies", String.Join(";", Libs) + ";%(AdditionalDependencies)");
                        }
                    }
                    else
                    {
                        var Libs = conf.Libs.Select(Lib => Lib.Parts.Count == 1 ? Lib.Extension == "" ? "-l" + Lib.ToString(PathStringStyle.Unix) : "-l:" + Lib.ToString(PathStringStyle.Unix) : Lib.RelativeTo(BaseDirPath).ToString(PathStringStyle.Unix)).ToList();
                        Libs.Add("-Wl,--end-group");
                        if (Libs.Count != 0)
                        {
                            Link.SetElementValue(xn + "AdditionalDependencies", String.Join(";", Libs) + ";%(AdditionalDependencies)");
                        }
                    }
                    var LinkerFlags     = conf.LinkerFlags.Select(f => (f == null ? "" : Regex.IsMatch(f, @"^[0-9]+$") ? f : "\"" + f.Replace("\"", "\"\"") + "\"")).ToList();
                    var PostLinkerFlags = conf.PostLinkerFlags.Select(f => (f == null ? "" : Regex.IsMatch(f, @"^[0-9]+$") ? f : "\"" + f.Replace("\"", "\"\"") + "\"")).ToList();
                    if (TargetOperatingSystem != OperatingSystemType.Windows)
                    {
                        PostLinkerFlags.Add("-Wl,--start-group");
                    }
                    if (LinkerFlags.Count + PostLinkerFlags.Count != 0)
                    {
                        Link.SetElementValue(xn + "AdditionalOptions", String.Join(" ", LinkerFlags.Concat(new List <String> {
                            "%(AdditionalOptions)"
                        }).Concat(PostLinkerFlags)));
                    }

                    foreach (var o in conf.Options)
                    {
                        var Prefix = "vc.Link.";
                        if (o.Key.StartsWith(Prefix))
                        {
                            Link.SetElementValue(xn + o.Key.Substring(Prefix.Length), o.Value);
                        }
                    }
                }
            }

            var Import = xVcxproj.Elements(xn + "Import").LastOrDefault();

            foreach (var gConf in Project.Configurations.Matches(Project.TargetType, HostOperatingSystem, HostArchitecture, TargetOperatingSystem, null, WindowsRuntime, ToolchainType.VisualStudio, Compiler, CLibrary, CLibraryForm, CppLibrary, CppLibraryForm, null).GroupBy(conf => Tuple.Create(conf.MatchingConfigurationTypes, conf.MatchingTargetArchitectures?.Intersect(new ArchitectureType[] { ArchitectureType.x86, ArchitectureType.x64, ArchitectureType.armv7a, ArchitectureType.arm64 }).ToList()), new ConfigurationTypesAndArchitecturesComparer()))
            {
                var MatchingConfigurationTypes  = gConf.Key.Item1;
                var MatchingTargetArchitectures = gConf.Key.Item2;
                if ((MatchingConfigurationTypes != null) && (MatchingConfigurationTypes.Count == 0))
                {
                    continue;
                }
                if ((MatchingTargetArchitectures != null) && (MatchingTargetArchitectures.Count == 0))
                {
                    continue;
                }
                var Conditions = new List <String>();
                Conditions = GetConditions(TargetOperatingSystem, MatchingConfigurationTypes, MatchingTargetArchitectures);

                foreach (var Condition in Conditions)
                {
                    var FileItemGroup = new XElement(xn + "ItemGroup");
                    if (Import != null)
                    {
                        Import.AddBeforeSelf(FileItemGroup);
                    }
                    else
                    {
                        xVcxproj.Add(FileItemGroup);
                    }
                    if (Condition != null)
                    {
                        FileItemGroup.Add(new XAttribute("Condition", Condition));
                    }
                    foreach (var File in gConf.SelectMany(conf => conf.Files))
                    {
                        var      RelativePath    = File.Path.FullPath.RelativeTo(BaseDirPath);
                        var      RelativePathStr = RelativePath.ToString(PathStringStyle.Windows);
                        XElement x;
                        if (File.Type == FileType.Header)
                        {
                            x = new XElement(xn + "ClInclude", new XAttribute("Include", RelativePathStr));
                        }
                        else if ((File.Type == FileType.CSource) || (File.Type == FileType.CppSource))
                        {
                            x = new XElement(xn + "ClCompile", new XAttribute("Include", RelativePathStr));
                            if (Compiler == CompilerType.VisualCpp)
                            {
                                // workaround Visual Studio bug which slows build https://developercommunity.visualstudio.com/idea/586584/vs2017-cc-multi-processor-compilation-does-not-wor.html
                                x.Add(new XElement(xn + "ObjectFileName", "$(IntDir)" + RelativePath.Parent.ToString(PathStringStyle.Windows).Replace("..", "__").Replace(":", "_") + "\\"));
                            }
                            else
                            {
                                x.Add(new XElement(xn + "ObjectFileName", "$(IntDir)" + RelativePath.ToString(PathStringStyle.Windows).Replace("..", "__").Replace(":", "_") + ".o"));
                            }
                        }
                        else if (File.Type == FileType.NatVis)
                        {
                            x = new XElement(xn + "Natvis", new XAttribute("Include", RelativePathStr));
                        }
                        else
                        {
                            x = new XElement(xn + "None", new XAttribute("Include", RelativePathStr));
                        }
                        if ((File.Type == FileType.CSource) || (File.Type == FileType.CppSource))
                        {
                            var fileConfs = File.Configurations.Matches(Project.TargetType, HostOperatingSystem, HostArchitecture, TargetOperatingSystem, null, WindowsRuntime, ToolchainType.VisualStudio, Compiler, CLibrary, CLibraryForm, CppLibrary, CppLibraryForm, null);

                            foreach (var conf in fileConfs)
                            {
                                var FileMatchingConfigurationTypes  = conf.MatchingConfigurationTypes;
                                var FileMatchingTargetArchitectures = conf.MatchingTargetArchitectures;
                                if ((FileMatchingConfigurationTypes != null) && (MatchingConfigurationTypes != null))
                                {
                                    FileMatchingConfigurationTypes = FileMatchingConfigurationTypes.Intersect(MatchingConfigurationTypes).ToList();
                                    if (FileMatchingConfigurationTypes.Count == MatchingConfigurationTypes.Count)
                                    {
                                        FileMatchingConfigurationTypes = null;
                                    }
                                }
                                if ((FileMatchingTargetArchitectures != null) && (MatchingTargetArchitectures != null))
                                {
                                    FileMatchingTargetArchitectures = FileMatchingTargetArchitectures.Intersect(MatchingTargetArchitectures).ToList();
                                    if (FileMatchingTargetArchitectures.Count == MatchingTargetArchitectures.Count)
                                    {
                                        FileMatchingTargetArchitectures = null;
                                    }
                                }
                                var FileConditions = GetConditions(TargetOperatingSystem, FileMatchingConfigurationTypes, FileMatchingTargetArchitectures);

                                foreach (var FileCondition in FileConditions)
                                {
                                    var Attributes = new XAttribute[] { };
                                    if (FileCondition != null)
                                    {
                                        Attributes = new XAttribute[] { new XAttribute("Condition", FileCondition) };
                                    }

                                    var IncludeDirectories = conf.IncludeDirectories.Select(d => d.FullPath.RelativeTo(BaseDirPath).ToString(PathStringStyle.Windows)).ToList();
                                    if (IncludeDirectories.Count != 0)
                                    {
                                        x.Add(new XElement(xn + "AdditionalIncludeDirectories", String.Join(";", IncludeDirectories) + ";%(AdditionalIncludeDirectories)", Attributes));
                                    }
                                    var Defines = conf.Defines;
                                    if (Defines.Count != 0)
                                    {
                                        x.Add(new XElement(xn + "PreprocessorDefinitions", String.Join(";", Defines.Select(d => d.Key + (d.Value == null ? "" : "=" + d.Value))) + ";%(PreprocessorDefinitions)", Attributes));
                                    }
                                    var CompilerFlags = conf.SystemIncludeDirectories.SelectMany(d => new String[] { "/external:I", d.FullPath.RelativeTo(BaseDirPath).ToString(PathStringStyle.Windows) }).Concat(conf.CommonFlags).ToList();
                                    if ((File.Type == FileType.CSource) || (File.Type == FileType.ObjectiveCSource))
                                    {
                                        CompilerFlags = CompilerFlags.Concat(conf.CFlags).ToList();
                                    }
                                    else if ((File.Type == FileType.CppSource) || (File.Type == FileType.ObjectiveCppSource))
                                    {
                                        CompilerFlags = CompilerFlags.Concat(conf.CppFlags).ToList();
                                    }
                                    if (CompilerFlags.Count != 0)
                                    {
                                        x.Add(new XElement(xn + "AdditionalOptions", "%(AdditionalOptions) " + String.Join(" ", CompilerFlags.Select(f => (f == null ? "" : Regex.IsMatch(f, @"^[0-9]+$") ? f : "\"" + f.Replace("\"", "\"\"\"") + "\""))), Attributes));
                                    }

                                    foreach (var o in conf.Options)
                                    {
                                        var Prefix = "vc.ClCompile.";
                                        if (o.Key.StartsWith(Prefix))
                                        {
                                            x.Add(new XElement(xn + o.Key.Substring(Prefix.Length), o.Value, Attributes));
                                        }
                                    }
                                }
                            }
                        }
                        FileItemGroup.Add(x);
                    }
                    if (!FileItemGroup.HasElements)
                    {
                        FileItemGroup.Remove();
                    }
                }
            }

            var ProjectItemGroup = new XElement(xn + "ItemGroup");

            if (Import != null)
            {
                Import.AddBeforeSelf(ProjectItemGroup);
            }
            else
            {
                xVcxproj.Add(ProjectItemGroup);
            }
            foreach (var p in ProjectReferences)
            {
                var RelativePath = p.FilePath.FullPath.RelativeTo(BaseDirPath).ToString(PathStringStyle.Windows);
                var x            = new XElement(xn + "ProjectReference", new XAttribute("Include", RelativePath));
                x.Add(new XElement(xn + "Project", "{" + p.Id.ToUpper() + "}"));
                x.Add(new XElement(xn + "Name", p.Name));
                x.Add(new XElement(xn + "LinkLibraryDependecies", "true"));
                if (WindowsRuntime == WindowsRuntimeType.WinRT)
                {
                    x.Add(new XElement(xn + "ReferenceOutputAssembly", "false"));
                }
                ProjectItemGroup.Add(x);
            }
            if (!ProjectItemGroup.HasElements)
            {
                ProjectItemGroup.Remove();
            }

            //https://developercommunity.visualstudio.com/idea/555602/c-referenced-dlls-copylocal-dosnt-work.html
            if (Project.TargetType == TargetType.DynamicLibrary)
            {
                var OutputCopyItemGroup = new XElement(xn + "ItemGroup");
                xVcxproj.Add(OutputCopyItemGroup);

                OutputCopyItemGroup.Add(new XElement(xn + "Content", new XAttribute("Include", "$(TargetPath)"), new XElement(xn + "Link", "%(Filename)%(Extension)"), new XElement(xn + "CopyToOutputDirectory", "PreserveNewest")));
            }

            var sVcxproj = XmlFile.ToString(xVcxproj);

            TextFile.WriteToFile(VcxprojPath, sVcxproj, Encoding.UTF8, !ForceRegenerate);
        }