Improve Visual Studio solution generation with nested C# project cross-references to properly place projects in group folders
This commit is contained in:
@@ -13,6 +13,22 @@ namespace Flax.Build
|
|||||||
{
|
{
|
||||||
partial class Builder
|
partial class Builder
|
||||||
{
|
{
|
||||||
|
private class ProjectTargetsGroup
|
||||||
|
{
|
||||||
|
public string ProjectName;
|
||||||
|
public ProjectInfo Project;
|
||||||
|
public TargetType Type;
|
||||||
|
public List<Target> Targets;
|
||||||
|
public HashSet<ProjectInfo> ProjectDependencies;
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
if (Project != null)
|
||||||
|
return $"{ProjectName}: {Project.ProjectPath}";
|
||||||
|
return ProjectName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void SetupProjectConfigurations(Project project, ProjectInfo projectInfo)
|
private static void SetupProjectConfigurations(Project project, ProjectInfo projectInfo)
|
||||||
{
|
{
|
||||||
project.Configurations.Clear();
|
project.Configurations.Clear();
|
||||||
@@ -195,7 +211,6 @@ namespace Flax.Build
|
|||||||
if (rootProject == null)
|
if (rootProject == null)
|
||||||
throw new Exception("Missing project.");
|
throw new Exception("Missing project.");
|
||||||
var projectFiles = rootProject.GetAllProjects();
|
var projectFiles = rootProject.GetAllProjects();
|
||||||
var targetGroups = rules.Targets.GroupBy(x => x.ProjectName);
|
|
||||||
var workspaceRoot = rootProject.ProjectFolderPath;
|
var workspaceRoot = rootProject.ProjectFolderPath;
|
||||||
var projectsRoot = Path.Combine(workspaceRoot, "Cache", "Projects");
|
var projectsRoot = Path.Combine(workspaceRoot, "Cache", "Projects");
|
||||||
var projects = new List<Project>();
|
var projects = new List<Project>();
|
||||||
@@ -205,22 +220,57 @@ namespace Flax.Build
|
|||||||
Project mainSolutionProject = null;
|
Project mainSolutionProject = null;
|
||||||
ProjectGenerator nativeProjectGenerator = ProjectGenerator.Create(projectFormat, TargetType.NativeCpp);
|
ProjectGenerator nativeProjectGenerator = ProjectGenerator.Create(projectFormat, TargetType.NativeCpp);
|
||||||
|
|
||||||
|
// Group targets by project name and sort groups based on the project (ensures that referenced plugin source projects are generated firstly before main source projects)
|
||||||
|
var targetGroups = new List<ProjectTargetsGroup>();
|
||||||
|
foreach (var target in rules.Targets)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
for (; i < targetGroups.Count; i++)
|
||||||
|
{
|
||||||
|
if (targetGroups[i].ProjectName == target.ProjectName)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i == targetGroups.Count)
|
||||||
|
{
|
||||||
|
targetGroups.Add(new ProjectTargetsGroup
|
||||||
|
{
|
||||||
|
ProjectName = target.ProjectName,
|
||||||
|
Type = target.Type,
|
||||||
|
Targets = new List<Target>(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
var targetGroup = targetGroups[i];
|
||||||
|
if (targetGroup.Type != target.Type)
|
||||||
|
Log.Error(string.Format($"Invalid targets group. Project {target.ProjectName} uses type {target.Type} from target {targetGroup.Targets[0].Name} but target {target.Name} is type of {target.Type}"));
|
||||||
|
if (targetGroup.Project == null && target is ProjectTarget projectTarget)
|
||||||
|
targetGroup.Project = projectTarget.Project;
|
||||||
|
targetGroup.Targets.Add(target);
|
||||||
|
}
|
||||||
|
foreach (var targetGroup in targetGroups)
|
||||||
|
{
|
||||||
|
if (targetGroup.Project == null)
|
||||||
|
{
|
||||||
|
targetGroup.Project = projectFiles.First(x => targetGroup.Targets[0].FolderPath.Contains(x.ProjectFolderPath));
|
||||||
|
if (targetGroup.Project == null)
|
||||||
|
{
|
||||||
|
Log.Error(string.Format($"Invalid target {targetGroup.ProjectName} has no project to link."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
targetGroup.ProjectDependencies = targetGroup.Project.GetAllProjects();
|
||||||
|
targetGroup.ProjectDependencies.Remove(targetGroup.Project);
|
||||||
|
}
|
||||||
|
targetGroups.Sort((a, b) => a.ProjectDependencies.Count - b.ProjectDependencies.Count);
|
||||||
|
|
||||||
// Setup projects for target groups (before actual generation to handle cross-project references like)
|
// Setup projects for target groups (before actual generation to handle cross-project references like)
|
||||||
foreach (var e in targetGroups)
|
foreach (var e in targetGroups)
|
||||||
{
|
{
|
||||||
var projectName = e.Key;
|
var projectName = e.ProjectName;
|
||||||
using (new ProfileEventScope(projectName))
|
using (new ProfileEventScope(projectName))
|
||||||
{
|
{
|
||||||
var targets = e.ToArray();
|
var targets = e.Targets.ToArray();
|
||||||
if (targets.Length == 0)
|
var type = e.Type;
|
||||||
throw new Exception("No targets in a group " + projectName);
|
var projectInfo = e.Project;
|
||||||
TargetType type = targets[0].Type;
|
|
||||||
for (int i = 1; i < targets.Length; i++)
|
|
||||||
{
|
|
||||||
if (targets[i].Type != type)
|
|
||||||
Log.Error(string.Format($"Invalid targets group. Project {projectName} uses type {type} from target {targets[0].Name} but target {targets[i].Name} is type of {targets[i].Type}"));
|
|
||||||
}
|
|
||||||
var projectInfo = targets[0] is ProjectTarget projectTarget ? projectTarget.Project : projectFiles.First(x => targets[0].FolderPath.Contains(x.ProjectFolderPath));
|
|
||||||
|
|
||||||
// Create project
|
// Create project
|
||||||
Project mainProject;
|
Project mainProject;
|
||||||
@@ -234,7 +284,7 @@ namespace Flax.Build
|
|||||||
project.Type = TargetType.NativeCpp;
|
project.Type = TargetType.NativeCpp;
|
||||||
project.Name = project.BaseName = projectName;
|
project.Name = project.BaseName = projectName;
|
||||||
project.Targets = targets;
|
project.Targets = targets;
|
||||||
project.SearchPaths = new string[0];
|
project.SearchPaths = Array.Empty<string>();
|
||||||
project.WorkspaceRootPath = projectInfo.ProjectFolderPath;
|
project.WorkspaceRootPath = projectInfo.ProjectFolderPath;
|
||||||
if (targets[0].CustomExternalProjectFilePath == null)
|
if (targets[0].CustomExternalProjectFilePath == null)
|
||||||
project.Path = Path.Combine(projectsRoot, project.Name + '.' + generator.ProjectFileExtension);
|
project.Path = Path.Combine(projectsRoot, project.Name + '.' + generator.ProjectFileExtension);
|
||||||
@@ -381,7 +431,7 @@ namespace Flax.Build
|
|||||||
project.Name += ".CSharp"; // Prevent overlapping name with native code project
|
project.Name += ".CSharp"; // Prevent overlapping name with native code project
|
||||||
project.OutputType = TargetOutputType.Library;
|
project.OutputType = TargetOutputType.Library;
|
||||||
project.Targets = targets;
|
project.Targets = targets;
|
||||||
project.SearchPaths = new string[0];
|
project.SearchPaths = Array.Empty<string>();
|
||||||
project.WorkspaceRootPath = mainProject.WorkspaceRootPath;
|
project.WorkspaceRootPath = mainProject.WorkspaceRootPath;
|
||||||
project.GroupName = mainProject.GroupName;
|
project.GroupName = mainProject.GroupName;
|
||||||
if (project.WorkspaceRootPath.StartsWith(workspaceRoot))
|
if (project.WorkspaceRootPath.StartsWith(workspaceRoot))
|
||||||
@@ -491,7 +541,7 @@ namespace Flax.Build
|
|||||||
project.Type = TargetType.DotNetCore;
|
project.Type = TargetType.DotNetCore;
|
||||||
project.Name = project.BaseName = rulesProjectName;
|
project.Name = project.BaseName = rulesProjectName;
|
||||||
project.Targets = new[] { target };
|
project.Targets = new[] { target };
|
||||||
project.SearchPaths = new string[0];
|
project.SearchPaths = Array.Empty<string>();
|
||||||
project.WorkspaceRootPath = workspaceRoot;
|
project.WorkspaceRootPath = workspaceRoot;
|
||||||
project.Path = Path.Combine(projectsRoot, project.Name + '.' + dotNetProjectGenerator.ProjectFileExtension);
|
project.Path = Path.Combine(projectsRoot, project.Name + '.' + dotNetProjectGenerator.ProjectFileExtension);
|
||||||
project.CSharp.OutputPath = Path.Combine(Environment.CurrentDirectory, "Cache", "Intermediate", "Unused");
|
project.CSharp.OutputPath = Path.Combine(Environment.CurrentDirectory, "Cache", "Intermediate", "Unused");
|
||||||
|
|||||||
@@ -200,7 +200,6 @@ namespace Flax.Build.Platforms
|
|||||||
value = null;
|
value = null;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,25 +213,13 @@ namespace Flax.Build.Platforms
|
|||||||
public static bool TryReadInstallDirRegistryKey32(string keySuffix, string valueName, out string dir)
|
public static bool TryReadInstallDirRegistryKey32(string keySuffix, string valueName, out string dir)
|
||||||
{
|
{
|
||||||
if (TryReadDirRegistryKey("HKEY_CURRENT_USER\\SOFTWARE\\" + keySuffix, valueName, out dir))
|
if (TryReadDirRegistryKey("HKEY_CURRENT_USER\\SOFTWARE\\" + keySuffix, valueName, out dir))
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
if (TryReadDirRegistryKey("HKEY_LOCAL_MACHINE\\SOFTWARE\\" + keySuffix, valueName, out dir))
|
if (TryReadDirRegistryKey("HKEY_LOCAL_MACHINE\\SOFTWARE\\" + keySuffix, valueName, out dir))
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
if (TryReadDirRegistryKey("HKEY_CURRENT_USER\\SOFTWARE\\Wow6432Node\\" + keySuffix, valueName, out dir))
|
if (TryReadDirRegistryKey("HKEY_CURRENT_USER\\SOFTWARE\\Wow6432Node\\" + keySuffix, valueName, out dir))
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
if (TryReadDirRegistryKey("HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\" + keySuffix, valueName, out dir))
|
if (TryReadDirRegistryKey("HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\" + keySuffix, valueName, out dir))
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -358,7 +345,6 @@ namespace Flax.Build.Platforms
|
|||||||
{
|
{
|
||||||
sdk10Roots.Add(rootDir);
|
sdk10Roots.Add(rootDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TryReadInstallDirRegistryKey32("Microsoft\\Microsoft SDKs\\Windows\\v10.0", "InstallationFolder", out rootDir))
|
if (TryReadInstallDirRegistryKey32("Microsoft\\Microsoft SDKs\\Windows\\v10.0", "InstallationFolder", out rootDir))
|
||||||
{
|
{
|
||||||
sdk10Roots.Add(rootDir);
|
sdk10Roots.Add(rootDir);
|
||||||
|
|||||||
@@ -203,7 +203,6 @@ namespace Flax.Build.Projects.VisualStudio
|
|||||||
{
|
{
|
||||||
foreach (var folder in project.SourceDirectories)
|
foreach (var folder in project.SourceDirectories)
|
||||||
{
|
{
|
||||||
// TODO: optimize it? make source files searching faster?
|
|
||||||
files.AddRange(Directory.GetFiles(folder, "*", SearchOption.AllDirectories));
|
files.AddRange(Directory.GetFiles(folder, "*", SearchOption.AllDirectories));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user