internal void Link(Builder builder) { if (_dependenciesResolved) { return; } bool hasFastBuildProjectConf = false; foreach (Solution.Configuration solutionConfiguration in Configurations) { // Build SolutionFilesMapping string configurationFile = Path.Combine(solutionConfiguration.SolutionPath, solutionConfiguration.SolutionFileName); var fileConfigurationList = SolutionFilesMapping.GetValueOrAdd(configurationFile, new List <Solution.Configuration>()); fileConfigurationList.Add(solutionConfiguration); // solutionConfiguration.IncludedProjectInfos will be appended // while iterating, but with projects that we already have resolved, // so no need to parse them again int origCount = solutionConfiguration.IncludedProjectInfos.Count; for (int i = 0; i < origCount; ++i) { Configuration.IncludedProjectInfo configurationProject = solutionConfiguration.IncludedProjectInfos[i]; bool projectIsInactive = configurationProject.InactiveProject; Project project = builder.GetProject(configurationProject.Type); Project.Configuration projectConfiguration = project.GetConfiguration(configurationProject.Target); if (projectConfiguration == null) { throw new Error( "Solution {0} for target '{1}' contains project {2} with invalid target '{3}'", GetType().FullName, solutionConfiguration.Target, project.GetType().FullName, configurationProject.Target ); } if (configurationProject.Project == null) { configurationProject.Project = project; } else if (configurationProject.Project != project) { throw new Error("Tried to match more than one project to Project type."); } if (configurationProject.Configuration == null) { configurationProject.Configuration = projectConfiguration; } else if (configurationProject.Configuration != projectConfiguration) { throw new Error("Tried to match more than one Project Configuration to a solution configuration."); } hasFastBuildProjectConf |= projectConfiguration.IsFastBuild; bool build = !projectConfiguration.IsExcludedFromBuild && !configurationProject.InactiveProject; if (build && solutionConfiguration.IncludeOnlyFilterProject && (configurationProject.Project.SourceFilesFiltersCount == 0 || configurationProject.Project.SkipProjectWhenFiltersActive)) { build = false; } if (configurationProject.ToBuild != Configuration.IncludedProjectInfo.Build.YesThroughDependency) { if (build) { configurationProject.ToBuild = Configuration.IncludedProjectInfo.Build.Yes; } else if (configurationProject.ToBuild != Configuration.IncludedProjectInfo.Build.Yes) { configurationProject.ToBuild = Configuration.IncludedProjectInfo.Build.No; } } var dependenciesConfiguration = configurationProject.Configuration.GetRecursiveDependencies(); foreach (Project.Configuration dependencyConfiguration in dependenciesConfiguration) { Project dependencyProject = dependencyConfiguration.Project; Type dependencyProjectType = dependencyProject.GetType(); if (dependencyProjectType.IsDefined(typeof(Export), false)) { continue; } ITarget dependencyProjectTarget = dependencyConfiguration.Target; hasFastBuildProjectConf |= dependencyConfiguration.IsFastBuild; Configuration.IncludedProjectInfo configurationProjectDependency = solutionConfiguration.GetProject(dependencyProjectType); // if that project was not explicitely added to the solution configuration, add it ourselves, as it is needed if (configurationProjectDependency == null) { configurationProjectDependency = new Configuration.IncludedProjectInfo { Type = dependencyProjectType, Project = dependencyProject, Configuration = dependencyConfiguration, Target = dependencyProjectTarget, InactiveProject = projectIsInactive // inherit from the parent: no reason to mark dependencies for build if parent is inactive }; solutionConfiguration.IncludedProjectInfos.Add(configurationProjectDependency); } else if (!projectIsInactive && configurationProjectDependency.InactiveProject) { // if the project we found in the solutionConfiguration is inactive, and the current is not, replace its settings configurationProjectDependency.Type = dependencyProjectType; configurationProjectDependency.Project = dependencyProject; configurationProjectDependency.Configuration = dependencyConfiguration; configurationProjectDependency.Target = dependencyProjectTarget; configurationProjectDependency.InactiveProject = false; } else if (projectIsInactive) { // if the current project is inactive, ignore } else { if (!configurationProjectDependency.Target.IsEqualTo(dependencyProjectTarget)) { throw new Error("In solution configuration (solution: {3}, config: {4}) the parent project {5} generates multiple dependency targets for the same child project {0}: {1} and {2}. Look for all AddPublicDependency() and AddPrivateDependency() calls for the child project and follow the dependency chain.", configurationProjectDependency.Project?.GetType().ToString(), configurationProjectDependency.Target, dependencyProjectTarget, solutionConfiguration.SolutionFileName, solutionConfiguration.Target, project.Name); } if (configurationProjectDependency.Project == null) { configurationProjectDependency.Project = dependencyProject; } else if (configurationProjectDependency.Project != dependencyProject) { throw new Error("Tried to match more than one project to Project type."); } if (configurationProjectDependency.Configuration == null) { configurationProjectDependency.Configuration = dependencyConfiguration; } else if (configurationProjectDependency.Configuration != dependencyConfiguration) { throw new Error("Tried to match more than one Project Configuration to a solution configuration."); } } bool depBuild = !projectIsInactive && !dependencyConfiguration.IsExcludedFromBuild && !configurationProjectDependency.InactiveProject; if (depBuild && solutionConfiguration.IncludeOnlyFilterProject && (dependencyProject.SourceFilesFiltersCount == 0 || dependencyProject.SkipProjectWhenFiltersActive)) { depBuild = false; } if (configurationProjectDependency.ToBuild != Configuration.IncludedProjectInfo.Build.YesThroughDependency) { if (depBuild) { if (projectConfiguration.Output == Project.Configuration.OutputType.Dll || projectConfiguration.Output == Project.Configuration.OutputType.Exe) { configurationProjectDependency.ToBuild = Configuration.IncludedProjectInfo.Build.YesThroughDependency; } else { configurationProjectDependency.ToBuild = Configuration.IncludedProjectInfo.Build.Yes; } } else if (configurationProjectDependency.ToBuild != Configuration.IncludedProjectInfo.Build.Yes) { configurationProjectDependency.ToBuild = Configuration.IncludedProjectInfo.Build.No; } } } } } if (hasFastBuildProjectConf) { MakeFastBuildAllProjectIfNeeded(builder); } _dependenciesResolved = true; }
internal void Link(Builder builder) { if (_dependenciesResolved) { return; } bool hasFastBuildProjectConf = false; var unlinkedConfigurations = new Dictionary <Solution.Configuration, List <Project.Configuration> >(); // This will hold MSBuild -> Fastbuild refs using (builder.CreateProfilingScope("Solution.Link:confs", Configurations.Count)) { foreach (Solution.Configuration solutionConfiguration in Configurations) { // Build SolutionFilesMapping string configurationFile = Path.Combine(solutionConfiguration.SolutionPath, solutionConfiguration.SolutionFileName); var fileConfigurationList = SolutionFilesMapping.GetValueOrAdd(configurationFile, new List <Solution.Configuration>()); fileConfigurationList.Add(solutionConfiguration); var unlinkedList = unlinkedConfigurations.GetValueOrAdd(solutionConfiguration, new List <Project.Configuration>()); // solutionConfiguration.IncludedProjectInfos will be appended // while iterating, but with projects that we already have resolved, // so no need to parse them again int origCount = solutionConfiguration.IncludedProjectInfos.Count; for (int i = 0; i < origCount; ++i) { Configuration.IncludedProjectInfo configurationProject = solutionConfiguration.IncludedProjectInfos[i]; bool projectIsInactive = configurationProject.InactiveProject; Project project = builder.GetProject(configurationProject.Type); Project.Configuration projectConfiguration = project.GetConfiguration(configurationProject.Target); if (projectConfiguration == null) { var messageBuilder = new System.Text.StringBuilder(); messageBuilder.AppendFormat("Resolving dependencies for solution {0}, target '{1}': cannot find target '{3}' in project {2}", GetType().FullName, solutionConfiguration.Target, project.GetType().FullName, configurationProject.Target); messageBuilder.AppendLine(); if (project.Configurations.Any()) { messageBuilder.AppendLine("Project configurations are:"); int confNum = 0; foreach (var conf in project.Configurations) { messageBuilder.AppendLine(++confNum + "/" + project.Configurations.Count + " " + conf.ToString()); } } else { messageBuilder.AppendLine("The project does not contain any configurations!"); } Trace.WriteLine(messageBuilder.ToString()); Debugger.Break(); throw new Error(messageBuilder.ToString()); } if (configurationProject.Project == null) { configurationProject.Project = project; } else if (configurationProject.Project != project) { throw new Error("Tried to match more than one project to Project type."); } if (configurationProject.Configuration == null) { configurationProject.Configuration = projectConfiguration; } else if (configurationProject.Configuration != projectConfiguration) { throw new Error("Tried to match more than one Project Configuration to a solution configuration."); } hasFastBuildProjectConf |= projectConfiguration.IsFastBuild; if (projectConfiguration.IsFastBuild) { projectConfiguration.AddMasterBff(solutionConfiguration.MasterBffFilePath); } bool build = !projectConfiguration.IsExcludedFromBuild && !configurationProject.InactiveProject; if (build && solutionConfiguration.IncludeOnlyFilterProject && (configurationProject.Project.SourceFilesFiltersCount == 0 || configurationProject.Project.SkipProjectWhenFiltersActive)) { build = false; } if (configurationProject.ToBuild != Configuration.IncludedProjectInfo.Build.YesThroughDependency) { if (build) { configurationProject.ToBuild = Configuration.IncludedProjectInfo.Build.Yes; } else if (configurationProject.ToBuild != Configuration.IncludedProjectInfo.Build.Yes) { configurationProject.ToBuild = Configuration.IncludedProjectInfo.Build.No; } } var dependenciesConfiguration = configurationProject.Configuration.GetRecursiveDependencies(); // TODO: Slow LINQ? May be better to create this list as part of GetRecursiveDependencies if (!configurationProject.Configuration.IsFastBuild && configurationProject.Configuration.ResolvedDependencies.Any(d => d.IsFastBuild)) { unlinkedList.Add(configurationProject.Configuration); } unlinkedList.AddRange(dependenciesConfiguration.Where(c => !c.IsFastBuild && c.ResolvedDependencies.Any(d => d.IsFastBuild))); foreach (Project.Configuration dependencyConfiguration in dependenciesConfiguration) { Project dependencyProject = dependencyConfiguration.Project; if (dependencyProject.SharpmakeProjectType == Project.ProjectTypeAttribute.Export) { continue; } Type dependencyProjectType = dependencyProject.GetType(); ITarget dependencyProjectTarget = dependencyConfiguration.Target; hasFastBuildProjectConf |= dependencyConfiguration.IsFastBuild; if (dependencyConfiguration.IsFastBuild) { dependencyConfiguration.AddMasterBff(solutionConfiguration.MasterBffFilePath); } Configuration.IncludedProjectInfo configurationProjectDependency = solutionConfiguration.GetProject(dependencyProjectType); // if that project was not explicitly added to the solution configuration, add it ourselves, as it is needed if (configurationProjectDependency == null) { configurationProjectDependency = new Configuration.IncludedProjectInfo { Type = dependencyProjectType, Project = dependencyProject, Configuration = dependencyConfiguration, Target = dependencyProjectTarget, InactiveProject = projectIsInactive // inherit from the parent: no reason to mark dependencies for build if parent is inactive }; solutionConfiguration.IncludedProjectInfos.Add(configurationProjectDependency); } else if (!projectIsInactive && configurationProjectDependency.InactiveProject) { // if the project we found in the solutionConfiguration is inactive, and the current is not, replace its settings configurationProjectDependency.Type = dependencyProjectType; configurationProjectDependency.Project = dependencyProject; configurationProjectDependency.Configuration = dependencyConfiguration; configurationProjectDependency.Target = dependencyProjectTarget; configurationProjectDependency.InactiveProject = false; } else if (projectIsInactive) { // if the current project is inactive, ignore } else { if (!configurationProjectDependency.Target.IsEqualTo(dependencyProjectTarget)) { throw new Error("In solution configuration (solution: {3}, config: {4}) the parent project {5} generates multiple dependency targets for the same child project {0}: {1} and {2}. Look for all AddPublicDependency() and AddPrivateDependency() calls for the child project and follow the dependency chain.", configurationProjectDependency.Project?.GetType().ToString(), configurationProjectDependency.Target, dependencyProjectTarget, solutionConfiguration.SolutionFileName, solutionConfiguration.Target, project.Name ); } if (configurationProjectDependency.Project == null) { configurationProjectDependency.Project = dependencyProject; } else if (configurationProjectDependency.Project != dependencyProject) { throw new Error("Tried to match more than one project to Project type."); } if (configurationProjectDependency.Configuration == null) { configurationProjectDependency.Configuration = dependencyConfiguration; } else if (configurationProjectDependency.Configuration != dependencyConfiguration) { throw new Error("Tried to match more than one Project Configuration to a solution configuration."); } } if (configurationProjectDependency.ToBuild != Configuration.IncludedProjectInfo.Build.YesThroughDependency) { // If we're finding a Fastbuild dependency of an MSBuild project, we know that it'll need re-linking if the All project is generated. var needsFastbuildRelink = (dependencyConfiguration.IsFastBuild && !configurationProject.Configuration.IsFastBuild && GenerateFastBuildAllProject); var isExcludedSinceNoFilter = solutionConfiguration.IncludeOnlyFilterProject && (configurationProjectDependency.Project.SourceFilesFiltersCount == 0 || configurationProjectDependency.Project.SkipProjectWhenFiltersActive); var skipBuild = dependencyConfiguration.IsExcludedFromBuild || projectIsInactive || configurationProjectDependency.InactiveProject || needsFastbuildRelink || isExcludedSinceNoFilter; if (!skipBuild) { if (projectConfiguration.Output == Project.Configuration.OutputType.Dll || projectConfiguration.Output == Project.Configuration.OutputType.Exe) { configurationProjectDependency.ToBuild = Configuration.IncludedProjectInfo.Build.YesThroughDependency; } else { configurationProjectDependency.ToBuild = Configuration.IncludedProjectInfo.Build.Yes; } } else if (configurationProjectDependency.ToBuild != Configuration.IncludedProjectInfo.Build.Yes) { configurationProjectDependency.ToBuild = Configuration.IncludedProjectInfo.Build.No; } } } } } if (hasFastBuildProjectConf) { MakeFastBuildAllProjectIfNeeded(builder, unlinkedConfigurations); } _dependenciesResolved = true; } }
internal void Link(Builder builder) { if (_dependenciesResolved) { return; } foreach (Solution.Configuration solutionConfiguration in Configurations) { // Build SolutionFilesMapping string configurationFile = Path.Combine(solutionConfiguration.SolutionPath, solutionConfiguration.SolutionFileName); var fileConfigurationList = SolutionFilesMapping.GetValueOrAdd(configurationFile, new List <Solution.Configuration>()); fileConfigurationList.Add(solutionConfiguration); // solutionConfiguration.IncludedProjectInfos will be appended // while iterating, but with projects that we already have resolved, // so no need to parse them again int origCount = solutionConfiguration.IncludedProjectInfos.Count; for (int i = 0; i < origCount; ++i) { Configuration.IncludedProjectInfo configurationProject = solutionConfiguration.IncludedProjectInfos[i]; Project project = builder.GetProject(configurationProject.Type); Project.Configuration projectConfiguration = project.GetConfiguration(configurationProject.Target); if (projectConfiguration == null) { throw new Error( "Solution {0} for target '{1}' contains project {2} with invalid target '{3}'", GetType().FullName, solutionConfiguration.Target, project.GetType().FullName, configurationProject.Target ); } configurationProject.Project = project; configurationProject.Configuration = projectConfiguration; bool build = !projectConfiguration.IsExcludedFromBuild && !configurationProject.InactiveProject; if (configurationProject.ToBuild != Configuration.IncludedProjectInfo.Build.YesThroughDependency) { if (build) { configurationProject.ToBuild = Configuration.IncludedProjectInfo.Build.Yes; } else if (configurationProject.ToBuild != Configuration.IncludedProjectInfo.Build.Yes) { configurationProject.ToBuild = Configuration.IncludedProjectInfo.Build.No; } } var dependenciesConfiguration = configurationProject.Configuration.GetRecursiveDependencies(); foreach (Project.Configuration dependencyConfiguration in dependenciesConfiguration) { Type dependencyProjectType = dependencyConfiguration.Project.GetType(); if (dependencyProjectType.IsDefined(typeof(Export), false)) { continue; } ITarget dependencyProjectTarget = dependencyConfiguration.Target; Configuration.IncludedProjectInfo configurationProjectDependency = solutionConfiguration.GetProject(dependencyProjectType); if (configurationProjectDependency == null) { var dependencyProject = builder.GetProject(dependencyProjectType); configurationProjectDependency = new Configuration.IncludedProjectInfo { Type = dependencyProjectType, Project = dependencyProject, Configuration = dependencyProject.GetConfiguration(dependencyProjectTarget), Target = dependencyProjectTarget, InactiveProject = configurationProject.InactiveProject // inherit from the parent: no reason to mark dependencies for build if parent is inactive }; solutionConfiguration.IncludedProjectInfos.Add(configurationProjectDependency); } else { if (!configurationProjectDependency.Target.IsEqualTo(dependencyProjectTarget)) { throw new Error("In solution configuration (solution: {3}, config: {4}) the parent project {5} generates multiple dependency targets for the same child project {0}: {1} and {2}. Look for all AddPublicDependency() and AddPrivateDependency() calls for the child project and follow the dependency chain.", configurationProjectDependency.Project.GetType().ToString(), configurationProjectDependency.Target, dependencyProjectTarget, solutionConfiguration.SolutionFileName, solutionConfiguration.Target, project.Name); } } bool depBuild = !dependencyConfiguration.IsExcludedFromBuild && !configurationProjectDependency.InactiveProject; if (configurationProjectDependency.ToBuild != Configuration.IncludedProjectInfo.Build.YesThroughDependency) { if (depBuild) { configurationProjectDependency.ToBuild = Configuration.IncludedProjectInfo.Build.YesThroughDependency; } else if (configurationProjectDependency.ToBuild != Configuration.IncludedProjectInfo.Build.Yes) { configurationProjectDependency.ToBuild = Configuration.IncludedProjectInfo.Build.No; } } } } } _dependenciesResolved = true; }