// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved. using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; namespace Flax.Build.Projects.VisualStudio { /// /// The Visual Studio project generator for C# projects (.csproj). /// /// public class CSProjectGenerator : VisualStudioProjectGenerator { /// public CSProjectGenerator(VisualStudioVersion version) : base(version) { } /// public override string ProjectFileExtension => "csproj"; /// public override TargetType? Type => TargetType.DotNet; /// public override void GenerateProject(Project project, string solutionPath) { var csProjectFileContent = new StringBuilder(); var vsProject = (VisualStudioProject)project; var projectFileToolVersion = ProjectFileToolVersion; var projectDirectory = Path.GetDirectoryName(project.Path); var defaultTarget = project.Targets[0]; foreach (var target in project.Targets) { // Pick the Editor-related target if (target.IsEditor) { defaultTarget = target; break; } } var defaultConfiguration = TargetConfiguration.Debug; var defaultArchitecture = TargetArchitecture.AnyCPU; var projectTypes = ProjectTypeGuids.ToOption(ProjectTypeGuids.WindowsCSharp); if (vsProject.CSharp.UseFlaxVS && VisualStudioInstance.HasFlaxVS) projectTypes = ProjectTypeGuids.ToOption(ProjectTypeGuids.FlaxVS) + ';' + projectTypes; // Try to reuse the existing project guid from solution file vsProject.ProjectGuid = GetProjectGuid(solutionPath, vsProject.Name); if (vsProject.ProjectGuid == Guid.Empty) vsProject.ProjectGuid = Guid.NewGuid(); // Header csProjectFileContent.AppendLine(""); csProjectFileContent.AppendLine(string.Format("", projectFileToolVersion)); csProjectFileContent.AppendLine(" "); // Properties csProjectFileContent.AppendLine(" "); csProjectFileContent.AppendLine(string.Format(" {0}", defaultConfiguration)); csProjectFileContent.AppendLine(string.Format(" {0}", defaultArchitecture)); csProjectFileContent.AppendLine(string.Format(" {0}", projectTypes)); csProjectFileContent.AppendLine(string.Format(" {0}", vsProject.ProjectGuid.ToString("B").ToUpperInvariant())); switch (project.OutputType ?? defaultTarget.OutputType) { case TargetOutputType.Executable: csProjectFileContent.AppendLine(" Exe"); break; case TargetOutputType.Library: csProjectFileContent.AppendLine(" Library"); break; default: throw new ArgumentOutOfRangeException(); } csProjectFileContent.AppendLine(string.Format(" {0}", project.BaseName)); csProjectFileContent.AppendLine(string.Format(" {0}.CSharp", project.BaseName)); csProjectFileContent.AppendLine(string.Format(" {0}", "v4.5.2")); csProjectFileContent.AppendLine(" 7.3"); csProjectFileContent.AppendLine(" 512"); csProjectFileContent.AppendLine(" "); if (Version >= VisualStudioVersion.VisualStudio2022) csProjectFileContent.AppendLine(" false"); csProjectFileContent.AppendLine(" "); // Default configuration { var configuration = project.Configurations.First(); foreach (var e in project.Configurations) { if (e.Configuration == defaultConfiguration && e.Target == defaultTarget && e.Platform == Platform.BuildTargetPlatform) { configuration = e; break; } } 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(" ", defaultConfiguration, defaultArchitecture)); csProjectFileContent.AppendLine(" true"); csProjectFileContent.AppendLine(" portable"); csProjectFileContent.AppendLine(string.Format(" {0}", defaultConfiguration == TargetConfiguration.Debug ? "false" : "true")); csProjectFileContent.AppendLine(string.Format(" {0}\\", outputPath)); csProjectFileContent.AppendLine(string.Format(" {0}\\", intermediateOutputPath)); csProjectFileContent.AppendLine(string.Format(" {0}\\", intermediateOutputPath)); csProjectFileContent.AppendLine(string.Format(" {0}", defines)); csProjectFileContent.AppendLine(" prompt"); csProjectFileContent.AppendLine(" 4"); csProjectFileContent.AppendLine(" true"); if (configuration.TargetBuildOptions.ScriptingAPI.IgnoreMissingDocumentationWarnings) csProjectFileContent.AppendLine(" 1591"); csProjectFileContent.AppendLine(string.Format(" {0}\\{1}.CSharp.xml", outputPath, project.BaseName)); csProjectFileContent.AppendLine(" true"); csProjectFileContent.AppendLine(" "); } // 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(" ", configuration.Name)); csProjectFileContent.AppendLine(" true"); csProjectFileContent.AppendLine(" portable"); csProjectFileContent.AppendLine(string.Format(" {0}", configuration.Configuration == TargetConfiguration.Debug ? "false" : "true")); csProjectFileContent.AppendLine(string.Format(" {0}\\", outputPath)); csProjectFileContent.AppendLine(string.Format(" {0}\\", intermediateOutputPath)); csProjectFileContent.AppendLine(string.Format(" {0}\\", intermediateOutputPath)); csProjectFileContent.AppendLine(string.Format(" {0}", defines)); csProjectFileContent.AppendLine(" prompt"); csProjectFileContent.AppendLine(" 4"); csProjectFileContent.AppendLine(" true"); if (configuration.TargetBuildOptions.ScriptingAPI.IgnoreMissingDocumentationWarnings) csProjectFileContent.AppendLine(" 1591"); csProjectFileContent.AppendLine(string.Format(" {0}\\{1}.CSharp.xml", outputPath, project.BaseName)); csProjectFileContent.AppendLine(" true"); csProjectFileContent.AppendLine(" "); } // References csProjectFileContent.AppendLine(" "); foreach (var reference in project.CSharp.SystemReferences) { csProjectFileContent.AppendLine(string.Format(" ", reference)); } foreach (var reference in project.CSharp.FileReferences) { csProjectFileContent.AppendLine(string.Format(" ", Path.GetFileNameWithoutExtension(reference))); csProjectFileContent.AppendLine(string.Format(" {0}", Utilities.MakePathRelativeTo(reference, projectDirectory))); csProjectFileContent.AppendLine(" "); } foreach (var dependency in project.Dependencies) { csProjectFileContent.AppendLine(string.Format(" ", Utilities.MakePathRelativeTo(dependency.Path, projectDirectory))); csProjectFileContent.AppendLine(string.Format(" {0}", ((VisualStudioProject)dependency).ProjectGuid.ToString("B").ToUpperInvariant())); csProjectFileContent.AppendLine(string.Format(" {0}", dependency.BaseName)); csProjectFileContent.AppendLine(" "); } csProjectFileContent.AppendLine(" "); // Files and folders csProjectFileContent.AppendLine(" "); var files = new List(); 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(" "); // End csProjectFileContent.AppendLine(" "); csProjectFileContent.AppendLine(""); if (defaultTarget.CustomExternalProjectFilePath == null) { // Save the files Utilities.WriteFileIfChanged(project.Path, csProjectFileContent.ToString()); } } } }