Ejemplo n.º 1
0
 /// <summary>
 /// Initializes the container with all values.
 /// </summary>
 /// <param name="accessor">Function that returns a value depending on platform/configuration.</param>
 public CollectorContainer(Func <TargetPlatform, TargetConfiguration, T> accessor)
 {
     m_Container = new Dictionary <ushort, T>();
     foreach (var platform in TargetInfo.EnumerateAllPlatforms())
     {
         foreach (var configuration in TargetInfo.EnumerateAllConfigurations())
         {
             m_Container.Add(CompressPlatformConfiguration(platform, configuration), accessor(platform, configuration));
         }
     }
 }
Ejemplo n.º 2
0
 /// <summary>
 /// Accesses the platform/configuration specific value of the container.
 /// </summary>
 /// <param name="platform">One of the target platforms.</param>
 /// <param name="configuration">One of the target configurations.</param>
 public T this[TargetPlatform platform, TargetConfiguration configuration]
 {
     get
     {
         if (platform == TargetPlatform.Any)
         {
             platform = TargetInfo.EnumerateAllPlatforms().First();
         }
         if (configuration == TargetConfiguration.Any)
         {
             configuration = TargetInfo.EnumerateAllConfigurations().First();
         }
         return(m_Container[CompressPlatformConfiguration(platform, configuration)]);
     }
 }
        /// <summary>
        /// Generates solution files for Visual Studio.
        /// </summary>
        /// <param name="solution">Parsed solution object.</param>
        /// <returns>Path to Visual Studio '.sln' file.</returns>
        public sealed override string GenerateSolutionFiles(Solution solution)
        {
            // ==========================================================================================
            // Generating SLN files..
            // ==========================================================================================
            var slnPath = Path.Combine(base.GenerateSolutionFiles(solution), solution.Name + ".sln");

            using (var sln = new StreamWriter(slnPath))
            {
                sln.WriteLine();
                sln.WriteLine("Microsoft Visual Studio Solution File, Format Version 12.00");
                sln.WriteLine("# Generated by GoddamnBuildSystem. Please, do not edit this file manually.");

                // ------------------------------------------------------------------------------------------
                // Caching GUIDs of projects and filters and defining filters.
                // ------------------------------------------------------------------------------------------
                var solutionFiltersGuidCache = new Dictionary <int, string>();
                foreach (var solutionProject in solution.Projects)
                {
                    // Loading the GUID of a build tool..
                    if (solutionProject.IsBuildTool)
                    {
                        // For build tools the best was is to load a GUID from project files: this causes exceptions
                        // in Visual Studio when reloading of solution, and all opened tabs would be terminated..
                        try
                        {
                            solutionProject.Misc.GUID = QueryGuidFromProject(solutionProject.GeneratorOutputPath);
                        }
                        catch (Exception exception)
                        {
                            Console.Error.WriteLine("Unable to load a GUID of C# project \"{0}\". Check this out.", solution.GeneratedSolutionPath);
                            Console.Error.WriteLine(exception.ToString());

                            solutionProject.Misc.GUID = CreateMsBuildGuid();
                        }
                    }

                    // Looking for projects with filters which we have not already cached.
                    if (!string.IsNullOrEmpty(solutionProject.Filter))
                    {
                        var solutionProjectFilterHash = solutionProject.Filter.GetHashCode();
                        if (!solutionFiltersGuidCache.ContainsKey(solutionProjectFilterHash))
                        {
                            // Generating and caching filter GUIDS.
                            solutionProject.Misc.FilterGUID = CreateMsBuildGuid();
                            solutionFiltersGuidCache.Add(solutionProjectFilterHash, solutionProject.Misc.FilterGUID);

                            // E.g. 'Project({Filter-GUID}) = "Name", "Name", "Filter-GUID"'
                            sln.WriteLine("Project(\"{0}\") = \"{1}\", \"{1}\", \"{2}\"", c_SlnFilterProjectGuid, solutionProject.Filter, solutionProject.Misc.FilterGUID);
                            sln.WriteLine("EndProject");
                        }
                        else
                        {
                            solutionProject.Misc.FilterGUID = solutionFiltersGuidCache[solutionProjectFilterHash];
                        }
                    }
                }

                // ------------------------------------------------------------------------------------------
                // Defining Solution projects.
                // ------------------------------------------------------------------------------------------
                foreach (var solutionProject in solution.Projects)
                {
                    // E.g. 'Project({Type-GUID}) = "Name", "Path-ToProject-File", "Project-GUID"'
                    sln.WriteLine("Project(\"{0}\") = \"{1}\", \"{2}\", \"{3}\"",
                                  /* 0 */ solutionProject.IsBuildTool ? c_SlnCsProjProjectGuid : c_SlnVcxProjProjectGuid,
                                  /*1,2*/ solutionProject.Name, solutionProject.GeneratorOutputPath,
                                  /* 3 */ solutionProject.Misc.GUID);
                    // Defining projects this one depends on.
                    sln.WriteLine("\tProjectSection(ProjectDependencies) = postProject");
                    var project = solutionProject;
                    foreach (var solutionDependentProject in solution.Projects)
                    {
                        if (solutionDependentProject.Priority > project.Priority)
                        {
                            // Writing projects with higher priority as ones we depend from.
                            sln.WriteLine("\t\t{0} = {0}", solutionDependentProject.Misc.GUID);
                        }
                    }
                    sln.WriteLine("\tEndProjectSection");
                    sln.WriteLine("EndProject");
                }

                sln.WriteLine("Global");

                // ------------------------------------------------------------------------------------------
                // Linking platforms & configurations.
                // ------------------------------------------------------------------------------------------
                sln.WriteLine("\tGlobalSection(SolutionConfigurationPlatforms) = preSolution");
                foreach (var platform in TargetInfo.EnumerateAllPlatforms())
                {
                    var platformInfo = TargetPlatformInfo.Get(platform);
                    foreach (var configurationInfo in TargetInfo.EnumerateAllConfigurations().Select(TargetConfigurationInfo.Get))
                    {
                        // E.g. \tConfiguration-Name|Platform-Name = Configuration-Name|Platform-Name
                        sln.WriteLine("\t\t{0}|{1} = {0}|{1}", configurationInfo.HumanReadableName, platformInfo.HumanReadableName);
                    }
                }
                sln.WriteLine("\tEndGlobalSection");

                sln.WriteLine("\tGlobalSection(ProjectConfigurationPlatforms) = postSolution");
                foreach (var solutionProject in solution.Projects)
                {
                    foreach (var platform in TargetInfo.EnumerateAllPlatforms())
                    {
                        var platformInfo = TargetPlatformInfo.Get(platform);
                        foreach (var configuration in TargetInfo.EnumerateAllConfigurations())
                        {
                            var configurationInfo = TargetConfigurationInfo.Get(configuration);
                            var platfromConfig    = solutionProject.IsBuildTool
                                ? $"\t\t{solutionProject.Misc.GUID}.{configurationInfo.HumanReadableName}|{platformInfo.HumanReadableName}.* = {(configurationInfo.IsDebug ? "Debug" : "Release")}|Any CPU"
                                : $"\t\t{solutionProject.Misc.GUID}.{configurationInfo.HumanReadableName}|{platformInfo.HumanReadableName}.* = {configuration}{platform}|{ConvertPlatformToMsBuildPlatform(platform)}";

                            sln.WriteLine(platfromConfig.Replace("*", "ActiveCfg"));
                            sln.WriteLine(platfromConfig.Replace("*", "Build.0"));
                        }
                    }
                }
                sln.WriteLine("\tEndGlobalSection");

                sln.WriteLine("\tGlobalSection(SolutionProperties) = postSolution");
                sln.WriteLine("\t\tHideSolutionNode = FALSE");
                sln.WriteLine("\tEndGlobalSection");

                // ------------------------------------------------------------------------------------------
                // Matching projects and filters hierarchy.
                // ------------------------------------------------------------------------------------------
                sln.WriteLine("\tGlobalSection(NestedProjects) = preSolution");
                foreach (var solutionProject in solution.Projects)
                {
                    if (!string.IsNullOrEmpty(solutionProject.Filter))
                    {
                        sln.WriteLine("\t\t{0} = {1}", solutionProject.Misc.GUID, solutionProject.Misc.FilterGUID);
                    }
                }
                sln.WriteLine("\tEndGlobalSection");
                sln.WriteLine("EndGlobal");
            }

            return(slnPath);
        }
        /// <summary>
        /// Generates project files for Visual Studio: '.vcxproj' and '.vcxproj.filter'.
        /// </summary>
        /// <param name="project">Parsed project object.</param>
        /// <returns>Path to Visual Studio '.vcxproj file'.</returns>
        public sealed override string GenerateProjectFiles(Project project)
        {
            var vcxProjPath = Path.Combine(base.GenerateProjectFiles(project), project.Name) + ".vcxproj";

            try
            {
                // For build tools the best was is to load a GUID from project files: this causes exceptions
                // in Visual Studio when reloading of solution, and all opened tabs would be terminated.
                project.Misc.GUID = QueryGuidFromProject(vcxProjPath);
            }
            catch (Exception)
            {
                project.Misc.GUID = CreateMsBuildGuid();
            }

            // ==========================================================================================
            // Generating VCXPROJ files.
            // ==========================================================================================
            using (var vcxProj = new XmlTextWriter(vcxProjPath, null)
            {
                Formatting = Formatting.Indented, Indentation = 1, IndentChar = '\t'
            })
            {
                vcxProj.WriteStartDocument();
                vcxProj.WriteComment("Generated by GoddamnBuildSystem. Please, do not edit this file manually.");
                vcxProj./**/ WriteStartElement("Project", c_MsBuild2003Namespace);
                vcxProj./**//**/ WriteAttributeString("ToolsVersion", c_ToolsVersion);
                vcxProj./**//**/ WriteAttributeString("DefaultTargets", "Build");

                // ------------------------------------------------------------------------------------------
                // Defining list of configurations.
                // ------------------------------------------------------------------------------------------
                vcxProj.WriteStartElement("ItemGroup");
                vcxProj./**/ WriteAttributeString("Label", "ProjectConfigurations");
                foreach (var platform in TargetInfo.EnumerateAllPlatforms())
                {
                    var platformString = ConvertPlatformToMsBuildPlatform(platform);
                    foreach (var configuration in TargetInfo.EnumerateAllConfigurations())
                    {
                        var configurationName = string.Concat(configuration, platform);
                        vcxProj./**/ WriteStartElement("ProjectConfiguration");
                        vcxProj./**//**/ WriteAttributeString("Include", configurationName + '|' + platformString);
                        vcxProj./**//**/ WriteElementString("Configuration", configurationName);
                        vcxProj./**//**/ WriteElementString("Platform", platformString);
                        vcxProj./**/ WriteEndElement();
                    }
                }
                vcxProj.WriteEndElement();

                // ------------------------------------------------------------------------------------------
                // Defining list of source files.
                // ------------------------------------------------------------------------------------------
                foreach (var platform in TargetInfo.EnumerateAllPlatforms())
                {
                    var platformString = ConvertPlatformToMsBuildPlatform(platform);
                    foreach (var configuration in TargetInfo.EnumerateAllConfigurations())
                    {
                        var configurationName = string.Concat(configuration, platform);
                        vcxProj.WriteStartElement("ItemGroup");
                        vcxProj.WriteAttributeStringFormat("Condition", @"'$(Configuration)|$(Platform)'=='{0}|{1}'", configurationName, platformString);
                        foreach (var projectSource in project.Files[platform, configuration])
                        {
                            vcxProj.WriteStartElement(ConvertFileTypeToVcxProjElement(projectSource.FileType));
                            vcxProj.WriteAttributeString("Include", projectSource.FilePath);
                            vcxProj.WriteEndElement();
                        }
                        vcxProj.WriteEndElement();
                    }
                }

                // ------------------------------------------------------------------------------------------
                // Overriding global project properties.
                // ------------------------------------------------------------------------------------------
                vcxProj.WriteStartElement("PropertyGroup");
                vcxProj./**/ WriteElementString("ProjectGuid", project.Misc.GUID);
                vcxProj./**/ WriteElementString("RootNamespace", project.Name);
                vcxProj./**/ WriteElementString("MinimumVisualStudioVersion", "14.0");
                vcxProj.WriteEndElement();
                foreach (var platform in TargetInfo.EnumerateAllPlatforms())
                {
                    var platformString = ConvertPlatformToMsBuildPlatform(platform);
                    foreach (var configuration in TargetInfo.EnumerateAllConfigurations())
                    {
                        var configurationName = string.Concat(configuration, platform);
                        vcxProj.WriteStartElement("PropertyGroup");
                        vcxProj./**/ WriteAttributeStringFormat("Condition", "'$(Configuration)|$(Platform)'=='{0}|{1}'", configurationName, platformString);
                        vcxProj./**/ WriteAttributeString("Label", "Globals");
                        vcxProj./**/ WriteElementString("WindowsTargetPlatformVersion", "10.0.16299.0");
                        if (platform == TargetPlatform.XboxOne)
                        {
                            vcxProj./**/ WriteElementString("AppContainerApplication", "true");
                            vcxProj./**/ WriteElementString("ApplicationType", "Windows Store");
                            vcxProj./**/ WriteElementString("WindowsTargetPlatformVersion", "10.0.16299.0");
                            vcxProj./**/ WriteElementString("WindowsTargetPlatformMinVersion", "10.0.10586.0");
                            vcxProj./**/ WriteElementString("ApplicationTypeRevision", "10");
                        }
                        vcxProj.WriteEndElement();
                    }
                }

                // ------------------------------------------------------------------------------------------
                // Overriding main configuration properties.
                // ------------------------------------------------------------------------------------------
                foreach (var platform in TargetInfo.EnumerateAllPlatforms())
                {
                    var platformString  = ConvertPlatformToMsBuildPlatform(platform);
                    var platformToolset = "v141";

                    foreach (var configuration in TargetInfo.EnumerateAllConfigurations())
                    {
                        var configurationName = string.Concat(configuration, platform);
                        vcxProj.WriteStartElement("PropertyGroup");
                        vcxProj./**/ WriteAttributeStringFormat("Condition", "'$(Configuration)|$(Platform)'=='{0}|{1}'", configurationName, platformString);
                        vcxProj./**/ WriteAttributeString("Label", "Configuration");
                        vcxProj./**/ WriteElementString("PlatformToolset", platformToolset);
                        if (IsPlatformNativelySupported(platform))
                        {
                            vcxProj./**/ WriteElementString("ConfigurationType", project.BuildType[platform, configuration].ToString());
                            vcxProj./**/ WriteElementString("CharacterSet", "Unicode");
                        }
                        else
                        {
                            vcxProj./**/ WriteElementString("ConfigurationType", "Makefile");
                        }
                        vcxProj.WriteEndElement();
                    }
                }

                vcxProj.WriteStartElement("Import");
                vcxProj./**/ WriteAttributeString("Project", @"$(VCTargetsPath)\Microsoft.Cpp.Default.props");
                vcxProj.WriteEndElement();
                vcxProj.WriteStartElement("Import");
                vcxProj./**/ WriteAttributeString("Project", @"$(VCTargetsPath)\Microsoft.Cpp.props");
                vcxProj.WriteEndElement();
                vcxProj.WriteStartElement("ImportGroup");
                vcxProj./**/ WriteAttributeString("Label", "ExtensionSettings");
                vcxProj./**/ WriteStartElement("Import");
                vcxProj./**//**/ WriteAttributeString("Project", @"$(VCTargetsPath)\BuildCustomizations\masm.props");
                vcxProj./**/ WriteEndElement();
                vcxProj.WriteEndElement();
                vcxProj.WriteStartElement("PropertyGroup");
                vcxProj./**/ WriteAttributeString("Label", "UserMacros");
                vcxProj.WriteEndElement();
                vcxProj.WriteStartElement("PropertyGroup");
                vcxProj./**/ WriteElementString("NMakeForcedIncludes", "$(NMakeForcedIncludes)");
                vcxProj./**/ WriteElementString("NMakeAssemblySearchPath", "$(NMakeAssemblySearchPath)");
                vcxProj./**/ WriteElementString("NMakeForcedUsingAssemblies", "$(NMakeForcedUsingAssemblies)");
                vcxProj.WriteEndElement();

                // ------------------------------------------------------------------------------------------
                // Overriding VC++ compiler and linker properties OR NMake commands..
                // ------------------------------------------------------------------------------------------
                foreach (var platform in TargetInfo.EnumerateAllPlatforms())
                {
                    var platformInfo   = TargetPlatformInfo.Get(platform);
                    var platformString = ConvertPlatformToMsBuildPlatform(platform);

                    // Building list of header directories.
                    var includePathes          = project.GenerateIncludePaths(platform, TargetConfiguration.Debug);
                    var standardLibrariesPaths = platformInfo.GenerateStandardIncludePaths();
                    if (string.IsNullOrEmpty(standardLibrariesPaths))
                    {
                        standardLibrariesPaths = "$(NMakeIncludeSearchPath)";
                    }

                    foreach (var configuration in TargetInfo.EnumerateAllConfigurations())
                    {
                        var configurationInfo = TargetConfigurationInfo.Get(configuration);

                        // Defining macros..
                        //var macros = project.GenerateMacros(platform, configuration);
                        //var standardMacros = platformInfo.GenerateStandardMacrosList();
                        //if (string.IsNullOrEmpty(standardMacros))
                        //{
                        //    standardMacros = "$(NMakePreprocessorDefinitions)";
                        //}

                        // Collecting linked libraries..
                        var linkedLibraries         = project.GenerateLinkedLibrariesPaths(platform, configuration);
                        var standardLinkedLibraries = platformInfo.GenerateStandardLinkedLibrariesPaths();
                        if (string.IsNullOrEmpty(standardLinkedLibraries))
                        {
                            standardLinkedLibraries = "";
                        }
                        standardLinkedLibraries += "%(AdditionalDependencies)";

                        var configurationName = string.Concat(configuration, platform);
                        var outputPath        = project.OutputPath[platform, configuration];

                        vcxProj.WriteStartElement("ImportGroup");
                        vcxProj./**/ WriteAttributeStringFormat("Condition", "'$(Configuration)|$(Platform)'=='{0}|{1}'", configurationName, platformString);
                        vcxProj./**/ WriteAttributeString("Label", "PropertySheets");
                        vcxProj./**/ WriteStartElement("Import");
                        vcxProj./**//**/ WriteAttributeString("Project", @"$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props");
                        vcxProj./**//**/ WriteAttributeString("Condition", @"exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')");
                        vcxProj./**//**/ WriteAttributeString("Label", "LocalAppDataPlatform");
                        vcxProj./**/ WriteEndElement();
                        vcxProj.WriteEndElement();

                        if (IsPlatformNativelySupported(platform))
                        {
                            // ------------------------------------------------------------------------------------------
                            // Defining VC++ compiler and linker properties.
                            // ------------------------------------------------------------------------------------------

                            // Include paths..
                            vcxProj.WriteStartElement("PropertyGroup");
                            vcxProj./**/ WriteAttributeStringFormat("Condition", "'$(Configuration)|$(Platform)'=='{0}|{1}'", configurationName, platformString);
                            vcxProj./**/ WriteElementString("IncludePath", includePathes + "$(IncludePath)");
                            vcxProj./**/ WriteElementString("OutDir", Path.GetDirectoryName(outputPath) + Path.DirectorySeparatorChar);
                            vcxProj./**/ WriteElementString("TargetName", Path.GetFileNameWithoutExtension(outputPath));
                            vcxProj.WriteEndElement();

                            // Compiler properties..
                            vcxProj.WriteStartElement("ItemDefinitionGroup");
                            vcxProj./**/ WriteAttributeStringFormat("Condition", "'$(Configuration)|$(Platform)'=='{0}|{1}'", configurationName, platformString);
                            vcxProj./**/ WriteStartElement("ClCompile");
                            vcxProj./**//**/ WriteElementString("FavorSizeOrSpeed", "Speed");
                            vcxProj./**//**/ WriteElementString("PrecompiledHeader", "NotUsing");
                            vcxProj./**//**/ WriteElementString("CallingConvention", "FastCall");
                            vcxProj./**//**/ WriteElementString("WarningLevel", "Level" + TargetCppCompilerInformation.WarningLevel);
                            vcxProj./**//**/ WriteElementString("TreatWarningAsError", TargetCppCompilerInformation.WarningsAreErrors.ToString());
                            //vcxProj./**//**/WriteElementString("PreprocessorDefinitions", macros + "%(PreprocessorDefinition)");
                            vcxProj./**//**/ WriteElementString("Optimization", configurationInfo.Optimize ? "Full" : "Disabled");
                            if (configurationInfo.IsDebug)
                            {
                                vcxProj.WriteElementString("RuntimeLibrary", "MultiThreadedDebugDLL");
                            }
                            if (!platformInfo.RequiresRtti)
                            {
                                vcxProj.WriteElementString("RuntimeTypeInfo", "false");
                            }
                            if (!platformInfo.RequiresExceptions)
                            {
                                //vcxProj.WriteElementString("ExceptionHandling", "false");
                            }
                            vcxProj./**/ WriteEndElement(); // </ VC++ COMPILER PROPERTIES

                            // Linker properties.
                            vcxProj./**/ WriteStartElement("Link");
                            vcxProj./**//**/ WriteElementString("AdditionalDependencies", linkedLibraries + standardLinkedLibraries);
                            vcxProj./**//**/ WriteElementString("GenerateDebugInformation", configurationInfo.GenerateDebugInformation.ToString().ToLowerInvariant());
                            if (project.BuildType[platform, configuration] == ProjectBuildType.DynamicLibrary)
                            {
                                vcxProj./**//**/ WriteElementString("ImportLibrary", project.ImportLibraryOutputPath[platform, configuration]);
                            }
                            vcxProj./**/ WriteEndElement();
                            vcxProj.WriteEndElement();
                        }
                        else
                        {
                            // ------------------------------------------------------------------------------------------
                            // Defining NMake properties..
                            // ------------------------------------------------------------------------------------------

                            var nmakeCommand =
                                $"\"{System.Reflection.Assembly.GetExecutingAssembly().Location}\" --compile-project \"{project.Source}\" {platform} {configuration} ";
                            vcxProj.WriteStartElement("PropertyGroup");
                            vcxProj./**/ WriteAttributeStringFormat("Condition", "'$(Configuration)|$(Platform)'=='{0}|{1}'", configurationName, platformString);
                            vcxProj./**/ WriteElementString("OutDir", Path.GetDirectoryName(outputPath) + Path.DirectorySeparatorChar);
                            vcxProj./**/ WriteElementString("NMakeOutput", outputPath);
                            //vcxProj./**/WriteElementString("NMakePreprocessorDefinitions", macros + standardMacros + ";GD_PLATFORNOT_WINDOWS=1");
                            vcxProj./**/ WriteElementString("NMakeIncludeSearchPath", includePathes + standardLibrariesPaths);
                            vcxProj./**/ WriteElementString("NMakeBuildCommandLine", nmakeCommand);
                            vcxProj./**/ WriteElementString("NMakeReBuildCommandLine", nmakeCommand + "Rebuild");
                            vcxProj./**/ WriteElementString("NMakeCleanCommandLine", nmakeCommand + "Clean");
                            vcxProj.WriteEndElement();
                        }
                    }
                }

                vcxProj.WriteStartElement("Import");
                vcxProj./**/ WriteAttributeString("Project", @"$(VCTargetsPath)\Microsoft.Cpp.targets");
                vcxProj.WriteEndElement();
                vcxProj.WriteStartElement("ImportGroup");
                vcxProj./**/ WriteAttributeString("Label", "ExtensionSettings");
                vcxProj./**/ WriteStartElement("Import");
                vcxProj./**//**/ WriteAttributeString("Project", @"$(VCTargetsPath)\BuildCustomizations\masm.targets");
                vcxProj./**/ WriteEndElement();
                vcxProj.WriteEndElement();

                vcxProj./**/ WriteEndElement();
                vcxProj.WriteEndDocument();
            }

            // ==========================================================================================
            // Generating VCPROJ.FILTERS files.
            // ==========================================================================================
            var vcxProjFiltersPath = vcxProjPath + ".filters";

            using (var vcxProjFilters = new XmlTextWriter(vcxProjFiltersPath, null)
            {
                Formatting = Formatting.Indented, Indentation = 1, IndentChar = '\t'
            })
            {
                vcxProjFilters.WriteStartDocument();
                vcxProjFilters./**/ WriteStartElement("Project", c_MsBuild2003Namespace);
                vcxProjFilters./**/ WriteAttributeString("ToolsVersion", c_ToolsFiltersVersion);

                var projectFoldersCache = new HashSet <string>();
                foreach (var projectSourceFile in project.Files[TargetPlatform.Any, TargetConfiguration.Any])
                {
                    var    projectSourceFileDirectory = Path.GetDirectoryName(projectSourceFile.FilePath);
                    string projectSourceFilter;

                    // Checking if this source can have a filter: it is located in project directory and it not in it's root.
                    // We also add "Source" to each filter to separate configuration and source files.
                    if (projectSourceFileDirectory != null && projectSourceFileDirectory.StartsWith(project.SourcesFilterOrigin, StringComparison.InvariantCultureIgnoreCase) &&
                        projectSourceFileDirectory.Length > project.SourcesFilterOrigin.Length + 1)
                    {
                        projectSourceFilter = "Source\\" + projectSourceFileDirectory.Substring(project.SourcesFilterOrigin.Length + 1);
                        var projectSourceFilterIter = projectSourceFilter;
                        while (!projectFoldersCache.Contains(projectSourceFilterIter) && !string.IsNullOrEmpty(projectSourceFilterIter))
                        {
                            // ------------------------------------------------------------------------------------------
                            // Defining group of filters.
                            // ------------------------------------------------------------------------------------------
                            vcxProjFilters.WriteStartElement("ItemGroup");
                            vcxProjFilters./**/ WriteStartElement("Filter");
                            vcxProjFilters./**//**/ WriteAttributeString("Include", projectSourceFilterIter);
                            vcxProjFilters./**//**/ WriteElementString("UniqueIdentifier", CreateMsBuildGuid());
                            vcxProjFilters./**/ WriteEndElement();
                            vcxProjFilters.WriteEndElement();

                            projectFoldersCache.Add(projectSourceFilterIter);
                            projectSourceFilterIter = Path.GetDirectoryName(projectSourceFilterIter);
                        }
                    }
                    else
                    {
                        projectSourceFilter = "Source";
                    }

                    // ------------------------------------------------------------------------------------------
                    // Defining source's filters.
                    // ------------------------------------------------------------------------------------------
                    vcxProjFilters.WriteStartElement("ItemGroup");
                    vcxProjFilters./**/ WriteStartElement(ConvertFileTypeToVcxProjElement(projectSourceFile.FileType));
                    vcxProjFilters./**//**/ WriteAttributeString("Include", projectSourceFile.FilePath);
                    vcxProjFilters./**//**/ WriteElementString("Filter", projectSourceFilter);
                    vcxProjFilters./**/ WriteEndElement();
                    vcxProjFilters.WriteEndElement();
                }

                vcxProjFilters./**/ WriteEndElement();
                vcxProjFilters.WriteEndDocument();
            }

            return(vcxProjPath);
        }
        }   // class PbxGroup

        /// <summary>
        /// Generates project files for XCode: '.xcodeproj'.
        /// </summary>
        /// <param name="project">Parsed project object.</param>
        /// <returns>Path to XCode '.xcodeproj' file.</returns>
        /// <inheritdoc />
        public sealed override string GenerateProjectFiles(Project project)
        {
            var xcodeProjPath    = Path.Combine(base.GenerateProjectFiles(project), project.Name) + ".xcodeproj";
            var xcodePbxProjPath = Path.Combine(xcodeProjPath, "project.pbxproj");

            Directory.CreateDirectory(xcodeProjPath);

            using (var xcodeProj = new StreamWriter(xcodePbxProjPath))
            {
                // ==========================================================================================
                // Begin .XCODEPROJ.PBXPROJ
                // ==========================================================================================

                var platform = TargetPlatform.MacOS;
                //var configuration = TargetConfiguration.Debug;

                xcodeProj.WriteLine(@"// !$*UTF8*$!
                    // Generated by GoddamnBuildSystem. Please, do not edit this file manually.
                    {
                        archiveVersion = 1;
                        classes = {
                        };
                        objectVersion = 48;
                        objects = {");

                // ------------------------------------------------------------------------------------------
                // Referenced files section.
                // ------------------------------------------------------------------------------------------

                xcodeProj.WriteLine("/* Begin PBXFileReference section */");

                // Writing down product reference..
                string xcodeProductExplicitFileType;
                switch (project.BuildType[platform, TargetConfiguration.Debug])
                {
                case ProjectBuildType.Application:
                    xcodeProductExplicitFileType = "compiled.mach-o.executable";
                    break;

                case ProjectBuildType.StaticLibrary:
                    xcodeProductExplicitFileType = "compiled.mach-o.a";
                    break;

                case ProjectBuildType.DynamicLibrary:
                    xcodeProductExplicitFileType = "compiled.mach-o.dylib";
                    break;

                default:
                    throw new NotSupportedException();
                }

                var xcodeProductRefUUID = new PbxUUID();
                xcodeProj.WriteLine($@"
                    {xcodeProductRefUUID} /*{project.Name}*/ = {{
                        isa = PBXFileReference;
                        explicitFileType = ""{xcodeProductExplicitFileType}"";
                        includeInIndex = 0;
                        path = {project.Name};
                        sourceTree = BUILT_PRODUCTS_DIR;
                    }};");

                // Writing down referenced dependencies..
                foreach (var projectDependency in project.Dependencies[platform, TargetConfiguration.Any])
                {
                    foreach (var projectDependencyFramework in projectDependency.LinkedLibraries[platform, TargetConfiguration.Debug])
                    {
                        string xcodeDependencyRefLastKnownType;
                        switch (projectDependencyFramework.FileType)
                        {
                        case DependencyFileType.StaticLibrary:
                            xcodeDependencyRefLastKnownType = "archive.ar";
                            break;

                        case DependencyFileType.DynamicLibrary:
                            xcodeDependencyRefLastKnownType = "compiled.mach-o.dylib";
                            break;

                        default:
                            throw new NotSupportedException();
                        }

                        projectDependencyFramework.FileMisc.RefUUID = new PbxUUID();
                        xcodeProj.WriteLine($@"
                            {projectDependencyFramework.FileMisc.RefUUID} /*{projectDependencyFramework.FilePath}*/ = {{
                                isa = PBXFileReference;
                                lastKnownFileType = {xcodeDependencyRefLastKnownType};
                                path = {projectDependencyFramework.FilePath};
                                name = {Path.GetFileName(projectDependencyFramework.FilePath)};
                                sourceTree = ""<group>"";
                            }};");
                    }
                }

                // Writing down referenced files..
                foreach (var projectSource in project.Files[platform, TargetConfiguration.Any])
                {
                    string xcodeFileRefLastKnownType;
                    switch (projectSource.FileType)
                    {
                    case ProjectSourceFileType.SourceCode:
                        xcodeFileRefLastKnownType = "sourcecode.cpp.cpp";
                        break;

                    case ProjectSourceFileType.SourceCodeObjective:
                        xcodeFileRefLastKnownType = "sourcecode.cpp.objcpp";
                        break;

                    case ProjectSourceFileType.SourceCodeAssembler:
                        xcodeFileRefLastKnownType = "sourcecode.asm";
                        break;

                    case ProjectSourceFileType.HeaderFile:
                    case ProjectSourceFileType.InlineImplementation:
                        xcodeFileRefLastKnownType = "sourcecode.cpp.h";
                        break;

                    case ProjectSourceFileType.ResourceScript:
                        xcodeFileRefLastKnownType = "file.txt";
                        break;

                    default:
                        throw new NotSupportedException();
                    }

                    projectSource.FileMisc.RefUUID = new PbxUUID();
                    xcodeProj.WriteLine($@"
                        {projectSource.FileMisc.RefUUID} /*{projectSource.FilePath}*/ = {{
                            isa = PBXFileReference;
                            lastKnownFileType = {xcodeFileRefLastKnownType};
                            path = {projectSource.FilePath};
                            name = {Path.GetFileName(projectSource.FilePath)};
                            sourceTree = ""<group>"";
                        }};");
                }

                xcodeProj.WriteLine("/* End PBXFileReference section */\n");

                // ------------------------------------------------------------------------------------------
                // Build Files section.
                // ------------------------------------------------------------------------------------------

                xcodeProj.WriteLine("/* Begin PBXBuildFile section */");

                // Product..
                var xcodeProductBuildUUID = new PbxUUID();
                xcodeProj.WriteLine($@"
                    {xcodeProductBuildUUID} /*{project.Name}*/ = {{
                        isa = PBXBuildFile;
                        fileRef = {xcodeProductRefUUID};
                    }};");

                // Frameworks..
                foreach (var projectDependency in project.Dependencies[platform, TargetConfiguration.Any])
                {
                    foreach (var projectDependencyFramework in projectDependency.LinkedLibraries[platform, TargetConfiguration.Debug])
                    {
                        projectDependencyFramework.FileMisc.BuildUUID = new PbxUUID();
                        xcodeProj.WriteLine($@"
                            {projectDependencyFramework.FileMisc.BuildUUID} /*{projectDependencyFramework.FilePath}*/ = {{
                                isa = PBXBuildFile;
                                fileRef = {projectDependencyFramework.FileMisc.RefUUID};
                            }};");
                    }
                }

                // Source files..
                foreach (var projectSource in project.Files[platform, TargetConfiguration.Any])
                {
                    // Writing down only files that need to be compiled..
                    switch (projectSource.FileType)
                    {
                    case ProjectSourceFileType.SourceCode:
                    case ProjectSourceFileType.SourceCodeObjective:
                    case ProjectSourceFileType.SourceCodeAssembler:
                        break;

                    default:
                        continue;
                    }

                    projectSource.FileMisc.BuildUUID = new PbxUUID();
                    xcodeProj.WriteLine($@"
                        {projectSource.FileMisc.BuildUUID} /*{projectSource.FilePath}*/ = {{
                            isa = PBXBuildFile;
                            fileRef = {projectSource.FileMisc.RefUUID};
                        }};");
                }

                xcodeProj.WriteLine("/* End PBXBuildFile section */\n");

                // ------------------------------------------------------------------------------------------
                // Group section.
                // ------------------------------------------------------------------------------------------

                xcodeProj.WriteLine("/* Begin PBXGroup section */");

                // Generating groups for sources..
                var xcodeGroupSource = new PbxGroup();
                foreach (var projectSource in project.Files[platform, TargetConfiguration.Any])
                {
                    var projectSourceDirectory = Path.GetDirectoryName(projectSource.FilePath);
                    if (projectSourceDirectory != null && projectSourceDirectory.StartsWith(project.SourcesFilterOrigin, StringComparison.Ordinal) &&
                        projectSourceDirectory.Length > project.SourcesFilterOrigin.Length + 1)
                    {
                        // Source would be added to some child group.
                        var projectSourceGroupPath         = projectSourceDirectory.Substring(project.SourcesFilterOrigin.Length + 1);
                        var projectSourceGroupPathSplitted = projectSourceGroupPath.Trim().Split(Path.DirectorySeparatorChar);
                        xcodeGroupSource.Add(projectSourceGroupPathSplitted, projectSource.FileMisc.RefUUID);
                    }
                    else
                    {
                        // Source would be added to the root group.
                        xcodeGroupSource.Add(projectSource.FileMisc.RefUUID);
                    }
                }

                // Writing child groups..
                xcodeGroupSource.Traverse((xcodeProjGroupName, xcodeProjGroup) =>
                {
                    var xcodeGroupChildrenUUIDList = new StringBuilder();
                    foreach (var xcodeProjGroupChildPair in xcodeProjGroup.ChildGroups)
                    {
                        xcodeGroupChildrenUUIDList.Append($"{xcodeProjGroupChildPair.Value.UUID}, ");
                    }
                    foreach (var xcodeProjGroupChildPair in xcodeProjGroup.ChildFileRefs)
                    {
                        xcodeGroupChildrenUUIDList.Append($"{xcodeProjGroupChildPair}, ");
                    }

                    // ReSharper disable once AccessToDisposedClosure
                    xcodeProj.WriteLine($@"
                        {xcodeProjGroup.UUID} = {{
                            isa = PBXGroup;
                            children = (
                                {xcodeGroupChildrenUUIDList}
                            );
                            path = ""{xcodeProjGroupName ?? "Source"}"";
                            sourceTree = ""<group>"";
                        }};");
                });

                // Writing products group..
                var xcodeGroupProductsUUID = new PbxUUID();
                xcodeProj.WriteLine($@"
                    {xcodeGroupProductsUUID} /*Products*/ = {{
                        isa = PBXGroup;
                        children = (
                            {xcodeProductRefUUID} /*{project.Name}*/,
                        );
                        name = Products;
                        sourceTree = ""<group>"";
                    }};");

                // Writing frameworks group..
                var xcodeGroupFrameworksChildrenUUIDList = new StringBuilder();
                foreach (var projectDependency in project.Dependencies[platform, TargetConfiguration.Any])
                {
                    foreach (var projectDependencyFramework in projectDependency.LinkedLibraries[platform, TargetConfiguration.Any])
                    {
                        xcodeGroupFrameworksChildrenUUIDList.Append($"{projectDependencyFramework.FileMisc.RefUUID}, ");
                    }
                }

                var xcodeGroupFrameworksUUID = new PbxUUID();
                xcodeProj.WriteLine($@"
                    {xcodeGroupFrameworksUUID} /*Products*/ = {{
                        isa = PBXGroup;
                        children = (
                            {xcodeGroupFrameworksChildrenUUIDList}
                        );
                        name = Frameworks;
                        sourceTree = ""<group>"";
                    }};");

                // Writing root group..
                var xcodeGroupRootUUID = new PbxUUID();
                xcodeProj.WriteLine($@"
                    {xcodeGroupRootUUID} = {{
                        isa = PBXGroup;
                        children = (
                            {xcodeGroupSource.UUID} /*Source*/,
                            {xcodeGroupProductsUUID} /*Products*/,
                            {xcodeGroupFrameworksUUID} /*Frameworks*/,
                        );
                        sourceTree = ""<group>"";
                        usesTabs = 0;
                    }};");

                xcodeProj.WriteLine("/* End PBXGroup section */\n");

                // ------------------------------------------------------------------------------------------
                // Source build phase section.
                // ------------------------------------------------------------------------------------------

                xcodeProj.WriteLine("/* Begin PBXSourcesBuildPhase section */");

                var xcodeBuildPhaseSourcesUUIDList = new StringBuilder();
                foreach (var projectSource in project.Files[platform, TargetConfiguration.Any])
                {
                    // Writing down only files that need to be compiled..
                    switch (projectSource.FileType)
                    {
                    case ProjectSourceFileType.SourceCode:
                    case ProjectSourceFileType.SourceCodeObjective:
                    case ProjectSourceFileType.SourceCodeAssembler:
                        break;

                    default:
                        continue;
                    }
                    xcodeBuildPhaseSourcesUUIDList.Append($"{projectSource.FileMisc.BuildUUID},");
                }

                var xcodeBuildPhaseSourcesUUID = new PbxUUID();
                xcodeProj.WriteLine($@"
                    {xcodeBuildPhaseSourcesUUID} /*Sources*/ = {{
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
                            {xcodeBuildPhaseSourcesUUIDList}
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                    }};");

                xcodeProj.WriteLine("/* End PBXSourcesBuildPhase section */\n");

                // ------------------------------------------------------------------------------------------
                // Framework build phase section.
                // ------------------------------------------------------------------------------------------

                xcodeProj.WriteLine("/* Begin PBXFrameworksBuildPhase section */");

                var xcodeBuildPhaseFrameworksUUIDList = new StringBuilder();
                foreach (var projectDependency in project.Dependencies[platform, TargetConfiguration.Any])
                {
                    foreach (var projectDependencyFramework in projectDependency.LinkedLibraries[platform, TargetConfiguration.Debug])
                    {
                        xcodeBuildPhaseFrameworksUUIDList.Append($"{projectDependencyFramework.FileMisc.BuildUUID},");
                    }
                }

                var xcodeBuildPhaseFrameworksUUID = new PbxUUID();
                xcodeProj.WriteLine($@"
                    {xcodeBuildPhaseFrameworksUUID} /*Frameworks*/ = {{
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
                            {xcodeBuildPhaseFrameworksUUIDList}
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                    }};");

                xcodeProj.WriteLine("/* End PBXFrameworksBuildPhase section */\n");

                // ------------------------------------------------------------------------------------------
                // Copy files build phase section.
                // ------------------------------------------------------------------------------------------

                xcodeProj.WriteLine("/* Begin PBXCopyFilesBuildPhase section */");

                // TODO: Copy files from dependencies.
                var xcodeBuildPhaseCopyFilesUUID = new PbxUUID();
                xcodeProj.WriteLine($@"
                    {xcodeBuildPhaseCopyFilesUUID} /*Copy Files*/ = {{
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 12;
                        dstPath = ""{Path.GetDirectoryName(project.OutputPath[platform, TargetConfiguration.Debug])}"";
                        dstSubfolderSpec = 0;
                        files = (
                            {xcodeProductBuildUUID}, /*Product*/
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                    }};");

                xcodeProj.WriteLine("/* End PBXCopyFilesBuildPhase section */\n");

                // ------------------------------------------------------------------------------------------
                // Target configuration section.
                // ------------------------------------------------------------------------------------------

                xcodeProj.WriteLine("/* Begin XCBuildConfiguration section */");

                var xcodeConfigurationNativeTargetUUIDList = new StringBuilder();
                var xcodeConfigurationProjectUUIDList      = new StringBuilder();

                foreach (var configuration in TargetInfo.EnumerateAllConfigurations())
                {
                    var xcodeConfigurationNativeTargetUUID = new PbxUUID();
                    xcodeConfigurationNativeTargetUUIDList.Append($"{xcodeConfigurationNativeTargetUUID}, ");

                    // TODO: Configure this shit correctly!
                    xcodeProj.WriteLine($@"
                        {xcodeConfigurationNativeTargetUUID} /*{configuration}*/ = {{
                            isa = XCBuildConfiguration;
                            name = {configuration};
                            buildSettings = {{
                                CODE_SIGN_STYLE = Automatic;
                                HEADER_SEARCH_PATHS = (
                                    {project.GenerateIncludePaths(platform, configuration, ", ")}
                                );
                                LIBRARY_SEARCH_PATHS = (
                                    ""$(inherited)"",
                                    {project.GenerateLinkedLibrariesPaths(platform, configuration, ", ", Path.GetDirectoryName)}
                                );
                                PRODUCT_NAME = ""$(TARGET_NAME)"";
                            }};
                        }};");

                    var xcodeConfigurationProjectUUID = new PbxUUID();
                    xcodeConfigurationProjectUUIDList.Append($"{xcodeConfigurationProjectUUID}, ");

                    // TODO: Configure this shit correctly!
                    xcodeProj.WriteLine($@"
                        {xcodeConfigurationProjectUUID} /*{configuration}*/ = {{
                            isa = XCBuildConfiguration;
                            name = {configuration};
                            buildSettings = {{
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
                                CLANG_CXX_LANGUAGE_STANDARD = ""gnu++14"";
                                CLANG_CXX_LIBRARY = ""libc++"";
                                CLANG_ENABLE_MODULES = YES;
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                CLANG_WARN_COMMA = YES;
                                CLANG_WARN_CONSTANT_CONVERSION = YES;
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
                                CLANG_WARN_EMPTY_BODY = YES;
                                CLANG_WARN_ENUM_CONVERSION = YES;
                                CLANG_WARN_INFINITE_RECURSION = YES;
                                CLANG_WARN_INT_CONVERSION = YES;
                                CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
                                CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
                                CLANG_WARN_STRICT_PROTOTYPES = YES;
                                CLANG_WARN_SUSPICIOUS_MOVE = YES;
                                CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
                                CLANG_WARN_UNREACHABLE_CODE = YES;
                                CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
                                CODE_SIGN_IDENTITY = ""-"";
                                COPY_PHASE_STRIP = NO;
                                DEBUG_INFORMATION_FORMAT = dwarf;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
                                ENABLE_TESTABILITY = YES;
                                GCC_C_LANGUAGE_STANDARD = gnu11;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_OPTIMIZATION_LEVEL = 0;
                                GCC_PREPROCESSOR_DEFINITIONS = (
                                    ""DEBUG=1"",
                                    ""$(inherited)"",
                                );
                                GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
                                GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
                                GCC_WARN_UNUSED_FUNCTION = YES;
                                GCC_WARN_UNUSED_VARIABLE = YES;
                                MACOSX_DEPLOYMENT_TARGET = 10.13;
                                MTL_ENABLE_DEBUG_INFO = YES;
                                ONLY_ACTIVE_ARCH = YES;
                                SDKROOT = macosx;
                            }};
                        }};");
                }
                xcodeProj.WriteLine("/* End XCBuildConfiguration section */\n");

                // ------------------------------------------------------------------------------------------
                // Configuration List section.
                // ------------------------------------------------------------------------------------------

                xcodeProj.WriteLine("/* Begin XCConfigurationList section */");

                var xcodeConfigurationListNativeTarget = new PbxUUID();
                var xcodeConfigurationListProjectUUID  = new PbxUUID();
                xcodeProj.WriteLine($@"
                    {xcodeConfigurationListNativeTarget} /*PBXNativeTarget*/ = {{
                        isa = XCConfigurationList;
                        buildConfigurations = (
                            {xcodeConfigurationNativeTargetUUIDList}
                        );
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = {TargetConfiguration.Release};
                    }};");
                xcodeProj.WriteLine($@"
                    {xcodeConfigurationListProjectUUID} /*PBXProject*/ = {{
                        isa = XCConfigurationList;
                        buildConfigurations = (
                            {xcodeConfigurationProjectUUIDList}
                        );
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = {TargetConfiguration.Release};
                    }};");

                xcodeProj.WriteLine("/* End XCConfigurationList section */\n");

                // ------------------------------------------------------------------------------------------
                // Native Target section.
                // ------------------------------------------------------------------------------------------

                xcodeProj.WriteLine("/* Begin PBXNativeTarget section */");

                string xcodeNativeTargetProductType;
                switch (project.BuildType[TargetPlatform.MacOS, TargetConfiguration.Release])
                {
                case ProjectBuildType.Application:
                    // TODO: Actually, here should be .application.
                    // But this requires to embed a plist.
                    xcodeNativeTargetProductType = "com.apple.product-type.tool";
                    break;

                case ProjectBuildType.StaticLibrary:
                    xcodeNativeTargetProductType = "com.apple.product-type.library.static";
                    break;

                case ProjectBuildType.DynamicLibrary:
                    xcodeNativeTargetProductType = "com.apple.product-type.library.dynamic";
                    break;

                default:
                    throw new NotSupportedException();
                }

                var xcodeNativeTargetUUID = project.Misc.NativeTargetUUID = new PbxUUID();
                xcodeProj.WriteLine($@"
                    {xcodeNativeTargetUUID} /*{project.Name}*/ = {{
                        isa = PBXNativeTarget;
                        buildConfigurationList = {xcodeConfigurationListNativeTarget};
                        buildPhases = (
                            {xcodeBuildPhaseSourcesUUID}, /*Sources*/
                            {xcodeBuildPhaseFrameworksUUID}, /* Frameworks */
                            {xcodeBuildPhaseCopyFilesUUID}, /* Copy Files */
                        );
                        buildRules = (
                        );
                        dependencies = (
                        );
                        name = {project.Name};
                        productName = ""{project.Name}"";
                        productReference = {xcodeProductRefUUID};
                        productType = ""{xcodeNativeTargetProductType}"";
                    }};");

                xcodeProj.WriteLine("/* End PBXNativeTarget section */\n");

                // ------------------------------------------------------------------------------------------
                // Project section.
                // ------------------------------------------------------------------------------------------

                xcodeProj.WriteLine("/* Begin PBXProject section */");

                var xcodeProjectUUID = project.Misc.ProjectUUID = new PbxUUID();
                xcodeProj.WriteLine($@"
                    {xcodeProjectUUID} /*{project.Name}*/ = {{ 
                        isa = PBXProject; 
                        attributes = {{
                            LastUpgradeCheck = 0920;
                            ORGANIZATIONNAME = {Environment.UserName};
                            TargetAttributes = {{
                                7CC50132201C539100AA2808 = {{
                                    CreatedOnToolsVersion = 9.2;
                                    ProvisioningStyle = Automatic;
                                }};
                            }};
                        }};
                        buildConfigurationList = {xcodeConfigurationListProjectUUID};
                        compatibilityVersion = ""Xcode 8.0"";
                        developmentRegion = en;
                        hasScannedForEncodings = 0;
                        knownRegions = (
                            en,
                        );
                        mainGroup = {xcodeGroupRootUUID};
                        productRefGroup = {xcodeGroupProductsUUID};
                        projectDirPath = """";
                        projectRoot = """";
                        targets = (
                            {xcodeNativeTargetUUID} /*PBXNativeTarget*/
                        );
                    }};");

                xcodeProj.WriteLine("/* End PBXProject section */\n");

                // ==========================================================================================
                // End .XCODEPROJ.PBXPROJ
                // ==========================================================================================

                xcodeProj.WriteLine($@"
                    }};
                    rootObject = {xcodeProjectUUID};
                }}");
            }

            return(xcodeProjPath);
        }