예제 #1
0
        /// <inheritdoc />
        public override void GenerateProject(Project project)
        {
            var csProjectFileContent = new StringBuilder();

            var vsProject = (VisualStudioProject)project;
            var projectFileToolVersion = ProjectFileToolVersion;
            var projectDirectory       = Path.GetDirectoryName(project.Path);
            var defaultTarget          = project.Targets[0];
            var defaultConfiguration   = defaultTarget.Configurations.First();
            var defaultArchitecture    = defaultTarget.Architectures.First();
            var projectTypes           = ProjectTypeGuids.ToOption(ProjectTypeGuids.WindowsCSharp);

            if (vsProject.CSharp.UseFlaxVS && VisualStudioInstance.HasFlaxVS)
            {
                projectTypes = ProjectTypeGuids.ToOption(ProjectTypeGuids.FlaxVS) + ';' + projectTypes;
            }

            // Header

            csProjectFileContent.AppendLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
            csProjectFileContent.AppendLine(string.Format("<Project DefaultTargets=\"Build\" ToolsVersion=\"{0}\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">", projectFileToolVersion));
            csProjectFileContent.AppendLine("  <Import Project=\"$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')\" />");

            // Properties

            csProjectFileContent.AppendLine("  <PropertyGroup>");

            csProjectFileContent.AppendLine(string.Format("    <Configuration Condition=\" '$(Configuration)' == '' \">{0}</Configuration>", defaultConfiguration));
            csProjectFileContent.AppendLine(string.Format("    <Platform Condition=\" '$(Platform)' == '' \">{0}</Platform>", defaultArchitecture));
            csProjectFileContent.AppendLine(string.Format("    <ProjectTypeGuids>{0}</ProjectTypeGuids>", projectTypes));
            csProjectFileContent.AppendLine(string.Format("    <ProjectGuid>{0}</ProjectGuid>", vsProject.ProjectGuid.ToString("B").ToUpperInvariant()));

            switch (project.OutputType ?? defaultTarget.OutputType)
            {
            case TargetOutputType.Executable:
                csProjectFileContent.AppendLine("    <OutputType>Exe</OutputType>");
                break;

            case TargetOutputType.Library:
                csProjectFileContent.AppendLine("    <OutputType>Library</OutputType>");
                break;

            default: throw new ArgumentOutOfRangeException();
            }

            csProjectFileContent.AppendLine(string.Format("    <RootNamespace>{0}</RootNamespace>", project.Name));
            csProjectFileContent.AppendLine(string.Format("    <AssemblyName>{0}.CSharp</AssemblyName>", project.Name));
            csProjectFileContent.AppendLine(string.Format("    <TargetFrameworkVersion>{0}</TargetFrameworkVersion>", "v4.5"));
            csProjectFileContent.AppendLine("    <LangVersion>7.3</LangVersion>");
            csProjectFileContent.AppendLine("    <FileAlignment>512</FileAlignment>");
            csProjectFileContent.AppendLine("    <TargetFrameworkProfile />");

            csProjectFileContent.AppendLine("  </PropertyGroup>");

            // Configurations
            foreach (var configuration in project.Configurations)
            {
                var defines = string.Join(";", project.Defines);
                if (configuration.TargetBuildOptions.ScriptingAPI.Defines.Count != 0)
                {
                    if (defines.Length != 0)
                    {
                        defines += ";";
                    }
                    defines += string.Join(";", configuration.TargetBuildOptions.ScriptingAPI.Defines);
                }
                var outputPath             = Utilities.MakePathRelativeTo(project.CSharp.OutputPath ?? configuration.TargetBuildOptions.OutputFolder, projectDirectory);
                var intermediateOutputPath = Utilities.MakePathRelativeTo(project.CSharp.IntermediateOutputPath ?? Path.Combine(configuration.TargetBuildOptions.IntermediateFolder, "CSharp"), projectDirectory);

                csProjectFileContent.AppendLine(string.Format("  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == '{0}' \">", configuration.Name));
                csProjectFileContent.AppendLine("    <DebugSymbols>true</DebugSymbols>");
                csProjectFileContent.AppendLine("    <DebugType>portable</DebugType>");
                csProjectFileContent.AppendLine(string.Format("    <Optimize>{0}</Optimize>", configuration.Configuration == TargetConfiguration.Debug ? "false" : "true"));
                csProjectFileContent.AppendLine(string.Format("    <OutputPath>{0}\\</OutputPath>", outputPath));
                csProjectFileContent.AppendLine(string.Format("    <BaseIntermediateOutputPath>{0}\\</BaseIntermediateOutputPath>", intermediateOutputPath));
                csProjectFileContent.AppendLine(string.Format("    <IntermediateOutputPath>{0}\\</IntermediateOutputPath>", intermediateOutputPath));
                csProjectFileContent.AppendLine(string.Format("    <DefineConstants>{0}</DefineConstants>", defines));
                csProjectFileContent.AppendLine("    <ErrorReport>prompt</ErrorReport>");
                csProjectFileContent.AppendLine("    <WarningLevel>4</WarningLevel>");
                csProjectFileContent.AppendLine("    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>");
                if (configuration.TargetBuildOptions.ScriptingAPI.IgnoreMissingDocumentationWarnings)
                {
                    csProjectFileContent.AppendLine("    <NoWarn>1591</NoWarn>");
                }
                csProjectFileContent.AppendLine(string.Format("    <DocumentationFile>{0}\\{1}.CSharp.xml</DocumentationFile>", outputPath, project.Name));
                csProjectFileContent.AppendLine("    <UseVSHostingProcess>true</UseVSHostingProcess>");
                csProjectFileContent.AppendLine("  </PropertyGroup>");
            }

            // References

            csProjectFileContent.AppendLine("  <ItemGroup>");

            foreach (var reference in project.CSharp.SystemReferences)
            {
                csProjectFileContent.AppendLine(string.Format("    <Reference Include=\"{0}\" />", reference));
            }

            foreach (var reference in project.CSharp.FileReferences)
            {
                csProjectFileContent.AppendLine(string.Format("    <Reference Include=\"{0}\">", Path.GetFileNameWithoutExtension(reference)));
                csProjectFileContent.AppendLine(string.Format("      <HintPath>{0}</HintPath>", Utilities.MakePathRelativeTo(reference, projectDirectory)));
                csProjectFileContent.AppendLine("    </Reference>");
            }

            foreach (var dependency in project.Dependencies)
            {
                csProjectFileContent.AppendLine(string.Format("    <ProjectReference Include=\"{0}\">", Utilities.MakePathRelativeTo(dependency.Path, projectDirectory)));
                csProjectFileContent.AppendLine(string.Format("      <Project>{0}</Project>", ((VisualStudioProject)dependency).ProjectGuid.ToString("B").ToUpperInvariant()));
                csProjectFileContent.AppendLine(string.Format("      <Name>{0}</Name>", dependency.Name));
                csProjectFileContent.AppendLine("    </ProjectReference>");
            }

            csProjectFileContent.AppendLine("  </ItemGroup>");

            // Files and folders

            csProjectFileContent.AppendLine("  <ItemGroup>");

            var files = new List <string>();

            if (project.SourceFiles != null)
            {
                files.AddRange(project.SourceFiles);
            }
            if (project.SourceDirectories != null)
            {
                foreach (var folder in project.SourceDirectories)
                {
                    files.AddRange(Directory.GetFiles(folder, "*", SearchOption.AllDirectories));
                }
            }

            foreach (var file in files)
            {
                string fileType;
                if (file.EndsWith(".cs", StringComparison.OrdinalIgnoreCase))
                {
                    fileType = "Compile";
                }
                else
                {
                    fileType = "None";
                }

                var projectPath = Utilities.MakePathRelativeTo(file, projectDirectory);
                csProjectFileContent.AppendLine(string.Format("    <{0} Include=\"{1}\" />", fileType, projectPath));
            }

            if (project.GeneratedSourceFiles != null)
            {
                foreach (var file in project.GeneratedSourceFiles)
                {
                    string fileType;
                    if (file.EndsWith(".cs", StringComparison.OrdinalIgnoreCase))
                    {
                        fileType = "Compile";
                    }
                    else
                    {
                        fileType = "None";
                    }

                    csProjectFileContent.AppendLine(string.Format("    <{0} Visible=\"false\" Include =\"{1}\" />", fileType, file));
                }
            }

            csProjectFileContent.AppendLine("  </ItemGroup>");

            // End

            csProjectFileContent.AppendLine("  <Import Project=\"$(MSBuildToolsPath)\\Microsoft.CSharp.targets\" />");
            csProjectFileContent.AppendLine("</Project>");

            if (defaultTarget.CustomExternalProjectFilePath == null)
            {
                // Save the files
                Utilities.WriteFileIfChanged(project.Path, csProjectFileContent.ToString());
            }
        }
예제 #2
0
        /// <inheritdoc />
        public override void GenerateSolution(Solution solution)
        {
            // Try to extract info from the existing solution file to make random IDs stable
            var solutionId = Guid.NewGuid();
            var folderIds  = new Dictionary <string, Guid>();

            if (File.Exists(solution.Path))
            {
                try
                {
                    var contents = File.ReadAllText(solution.Path);

                    var solutionIdMatch = Regex.Match(contents, "SolutionGuid = \\{(.*?)\\}");
                    if (solutionIdMatch.Success)
                    {
                        var value = solutionIdMatch.Value;
                        solutionId = Guid.ParseExact(value.Substring(15), "B");
                    }

                    var folderIdsMatch = Regex.Match(contents, "Project\\(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\"\\) = \"(.*?)\", \"(.*?)\", \"{(.*?)}\"");
                    if (folderIdsMatch.Success)
                    {
                        foreach (Capture capture in folderIdsMatch.Captures)
                        {
                            var value    = capture.Value.Substring("Project(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"".Length);
                            var folder   = value.Substring(0, value.IndexOf('\"'));
                            var folderId = Guid.ParseExact(value.Substring(folder.Length * 2 + "\", \"".Length + "\", \"".Length, 38), "B");
                            folderIds["Source\\" + folder] = folderId;
                        }
                    }
                }
                catch (Exception ex)
                {
                    Log.Warning("Failed to restore solution and solution folders identifiers from existing file.");
                    Log.Exception(ex);
                }
            }

            StringBuilder vcSolutionFileContent = new StringBuilder();
            var           solutionDirectory     = Path.GetDirectoryName(solution.Path);
            var           projects = solution.Projects.Cast <VisualStudioProject>().ToArray();

            // Header
            if (Version == VisualStudioVersion.VisualStudio2019)
            {
                //vcSolutionFileContent.AppendLine();
                vcSolutionFileContent.AppendLine("Microsoft Visual Studio Solution File, Format Version 12.00");
                vcSolutionFileContent.AppendLine("# Visual Studio Version 16");
                vcSolutionFileContent.AppendLine("VisualStudioVersion = 16.0.28315.86");
                vcSolutionFileContent.AppendLine("MinimumVisualStudioVersion = 10.0.40219.1");
            }
            else if (Version == VisualStudioVersion.VisualStudio2017)
            {
                //vcSolutionFileContent.AppendLine();
                vcSolutionFileContent.AppendLine("Microsoft Visual Studio Solution File, Format Version 12.00");
                vcSolutionFileContent.AppendLine("# Visual Studio 15");
                vcSolutionFileContent.AppendLine("VisualStudioVersion = 15.0.25807.0");
                vcSolutionFileContent.AppendLine("MinimumVisualStudioVersion = 10.0.40219.1");
            }
            else if (Version == VisualStudioVersion.VisualStudio2015)
            {
                //vcSolutionFileContent.AppendLine();
                vcSolutionFileContent.AppendLine("Microsoft Visual Studio Solution File, Format Version 12.00");
                vcSolutionFileContent.AppendLine("# Visual Studio 14");
                vcSolutionFileContent.AppendLine("VisualStudioVersion = 14.0.22310.1");
                vcSolutionFileContent.AppendLine("MinimumVisualStudioVersion = 10.0.40219.1");
            }
            else
            {
                throw new Exception("Unsupported solution file format.");
            }

            // Solution folders
            var folderNames = new HashSet <string>();

            {
                // Move projects to subfolders based on group names including subfolders to match the location of the source in the workspace
                foreach (var project in projects)
                {
                    var folder = project.GroupName;

                    if (project.SourceDirectories != null && project.SourceDirectories.Count == 1)
                    {
                        var subFolder = Utilities.MakePathRelativeTo(Path.GetDirectoryName(project.SourceDirectories[0]), project.WorkspaceRootPath);
                        if (subFolder.StartsWith("Source\\"))
                        {
                            subFolder = subFolder.Substring(7);
                        }
                        if (subFolder.Length != 0)
                        {
                            if (folder.Length != 0)
                            {
                                folder += '\\';
                            }
                            folder += subFolder;
                        }
                    }

                    if (string.IsNullOrEmpty(folder))
                    {
                        continue;
                    }

                    var folderParents = folder.Split('\\');
                    for (int i = 0; i < folderParents.Length; i++)
                    {
                        var folderPath = folderParents[0];
                        for (int j = 1; j <= i; j++)
                        {
                            folderPath += '\\' + folderParents[j];
                        }

                        if (folderNames.Contains(folderPath))
                        {
                            project.FolderGuid = folderIds[folderPath];
                        }
                        else
                        {
                            if (!folderIds.TryGetValue(folderPath, out project.FolderGuid))
                            {
                                project.FolderGuid = Guid.NewGuid();
                                folderIds.Add(folderPath, project.FolderGuid);
                            }
                            folderNames.Add(folderPath);
                        }
                    }
                }

                foreach (var folder in folderNames)
                {
                    var folderGuid = folderIds[folder].ToString("B").ToUpperInvariant();
                    var typeGuid   = ProjectTypeGuids.ToOption(ProjectTypeGuids.SolutionFolder);
                    var lastSplit  = folder.LastIndexOf('\\');
                    var name       = lastSplit != -1 ? folder.Substring(lastSplit + 1) : folder;

                    vcSolutionFileContent.AppendLine(string.Format("Project(\"{0}\") = \"{1}\", \"{2}\", \"{3}\"", typeGuid, name, name, folderGuid));
                    vcSolutionFileContent.AppendLine("EndProject");
                }
            }

            // Solution projects
            foreach (var project in projects)
            {
                var projectId = project.ProjectGuid.ToString("B").ToUpperInvariant();
                var typeGuid  = ProjectTypeGuids.ToOption(project.ProjectTypeGuid);

                vcSolutionFileContent.AppendLine(string.Format("Project(\"{0}\") = \"{1}\", \"{2}\", \"{3}\"", typeGuid, project.Name, Utilities.MakePathRelativeTo(project.Path, solutionDirectory), projectId));

                if (project.Dependencies.Count > 0)
                {
                    vcSolutionFileContent.AppendLine("\tProjectSection(ProjectDependencies) = postProject");
                    foreach (var dependency in project.Dependencies.Cast <VisualStudioProject>())
                    {
                        string dependencyId = dependency.ProjectGuid.ToString("B").ToUpperInvariant();
                        vcSolutionFileContent.AppendLine("\t\t" + dependencyId + " = " + dependencyId);
                    }

                    vcSolutionFileContent.AppendLine("\tEndProjectSection");
                }

                vcSolutionFileContent.AppendLine("EndProject");
            }

            // Global configuration
            {
                vcSolutionFileContent.AppendLine("Global");

                // Collect all unique configurations
                var configurations = new HashSet <SolutionConfiguration>();
                foreach (var project in projects)
                {
                    if (project.Configurations == null || project.Configurations.Count == 0)
                    {
                        throw new Exception("Missing configurations for project " + project.Name);
                    }

                    foreach (var configuration in project.Configurations)
                    {
                        configurations.Add(new SolutionConfiguration(configuration));
                    }
                }

                // Add missing configurations (Visual Studio needs all permutations of configuration/platform pair)
                var configurationNames = configurations.Select(x => x.Configuration).Distinct().ToArray();
                var platformNames      = configurations.Select(x => x.Platform).Distinct().ToArray();
                foreach (var configurationName in configurationNames)
                {
                    foreach (var platformName in platformNames)
                    {
                        configurations.Add(new SolutionConfiguration(configurationName, platformName));
                    }
                }

                // Sort configurations
                var configurationsSorted = new List <SolutionConfiguration>(configurations);
                configurationsSorted.Sort();

                // Global configurations
                {
                    vcSolutionFileContent.AppendLine("	GlobalSection(SolutionConfigurationPlatforms) = preSolution");

                    foreach (var configuration in configurationsSorted)
                    {
                        vcSolutionFileContent.AppendLine("		"+ configuration.Name + " = " + configuration.Name);
                    }

                    vcSolutionFileContent.AppendLine("	EndGlobalSection");
                }

                // Per-project configurations mapping
                {
                    vcSolutionFileContent.AppendLine("	GlobalSection(ProjectConfigurationPlatforms) = postSolution");

                    foreach (var project in projects)
                    {
                        string projectId = project.ProjectGuid.ToString("B").ToUpperInvariant();

                        foreach (var configuration in configurationsSorted)
                        {
                            SolutionConfiguration projectConfiguration;
                            bool build = false;
                            int  firstFullMatch = -1, firstPlatformMatch = -1;
                            for (int i = 0; i < project.Configurations.Count; i++)
                            {
                                var e = new SolutionConfiguration(project.Configurations[i]);
                                if (e.Name == configuration.Name)
                                {
                                    firstFullMatch = i;
                                    break;
                                }
                                if (firstPlatformMatch == -1 && e.Platform == configuration.Platform)
                                {
                                    firstPlatformMatch = i;
                                }
                            }
                            if (firstFullMatch != -1)
                            {
                                projectConfiguration = configuration;
                                build = solution.MainProject == project || (solution.MainProject == null && project.Name == solution.Name);
                            }
                            else if (firstPlatformMatch != -1)
                            {
                                projectConfiguration = new SolutionConfiguration(project.Configurations[firstPlatformMatch]);
                            }
                            else
                            {
                                projectConfiguration = new SolutionConfiguration(project.Configurations[0]);
                            }

                            vcSolutionFileContent.AppendLine(string.Format("		{0}.{1}.ActiveCfg = {2}", projectId, configuration.Name, projectConfiguration.OriginalName));
                            if (build)
                            {
                                vcSolutionFileContent.AppendLine(string.Format("		{0}.{1}.Build.0 = {2}", projectId, configuration.Name, projectConfiguration.OriginalName));
                            }
                        }
                    }

                    vcSolutionFileContent.AppendLine("	EndGlobalSection");
                }

                // Always show solution root node
                {
                    vcSolutionFileContent.AppendLine("	GlobalSection(SolutionProperties) = preSolution");
                    vcSolutionFileContent.AppendLine("		HideSolutionNode = FALSE");
                    vcSolutionFileContent.AppendLine("	EndGlobalSection");
                }

                // Solution directory hierarchy
                {
                    vcSolutionFileContent.AppendLine("	GlobalSection(NestedProjects) = preSolution");

                    // Write nested folders hierarchy
                    foreach (var folder in folderNames)
                    {
                        var lastSplit = folder.LastIndexOf('\\');
                        if (lastSplit != -1)
                        {
                            var folderGuid       = folderIds[folder].ToString("B").ToUpperInvariant();
                            var parentFolder     = folder.Substring(0, lastSplit);
                            var parentFolderGuid = folderIds[parentFolder].ToString("B").ToUpperInvariant();
                            vcSolutionFileContent.AppendLine(string.Format("		{0} = {1}", folderGuid, parentFolderGuid));
                        }
                    }

                    // Write mapping for projectId - folderId
                    foreach (var project in projects)
                    {
                        if (project.FolderGuid != Guid.Empty)
                        {
                            var projectGuidString = project.ProjectGuid.ToString("B").ToUpperInvariant();
                            var folderGuidString  = project.FolderGuid.ToString("B").ToUpperInvariant();
                            vcSolutionFileContent.AppendLine(string.Format("		{0} = {1}", projectGuidString, folderGuidString));
                        }
                    }

                    vcSolutionFileContent.AppendLine("	EndGlobalSection");
                }

                // Solution identifier
                {
                    vcSolutionFileContent.AppendLine("	GlobalSection(ExtensibilityGlobals) = postSolution");
                    vcSolutionFileContent.AppendLine(string.Format("		SolutionGuid = {0}", solutionId.ToString("B").ToUpperInvariant()));
                    vcSolutionFileContent.AppendLine("	EndGlobalSection");
                }

                vcSolutionFileContent.AppendLine("EndGlobal");
            }

            // Save the file
            Utilities.WriteFileIfChanged(solution.Path, vcSolutionFileContent.ToString());
        }