in Sharpmake.Generators/VisualStudio/Vcxproj.cs [918:1136]
private void GenerateProjectReferences(
IVcxprojGenerationContext context,
IFileGenerator fileGenerator,
bool fastbuildOnly)
{
var firstConf = context.ProjectConfigurations.First();
if (!fastbuildOnly)
{
if (context.Builder.Diagnostics)
{
// check consistency
foreach (var conf in context.ProjectConfigurations)
{
if (firstConf.ReferencesByName.SortedValues.ToString() != conf.ReferencesByName.SortedValues.ToString())
throw new Error("ReferencesByName in " + FileName + ProjectExtension + " are different between configurations. Please fix, or split the vcxproj.");
if (firstConf.ReferencesByPath.SortedValues.ToString() != conf.ReferencesByPath.SortedValues.ToString())
throw new Error("ReferencesByPath in " + FileName + ProjectExtension + " are different between configurations. Please fix, or split the vcxproj.");
}
}
if (firstConf.ReferencesByName.Count != 0)
{
fileGenerator.Write(Template.Project.ItemGroupBegin);
foreach (var referenceName in firstConf.ReferencesByName)
{
bool copyLocal = (firstConf.Project.DependenciesCopyLocal.HasFlag(Project.DependenciesCopyLocalTypes.DotNetReferences));
using (fileGenerator.Declare("include", referenceName))
using (fileGenerator.Declare("private", copyLocal.ToString().ToLower())) //ToString().ToLower() as told by msdn for booleans in xml files
{
if (copyLocal)
fileGenerator.Write(Template.Project.ReferenceByName);
else
fileGenerator.Write(Template.Project.SingleReferenceByName);
}
}
fileGenerator.Write(Template.Project.ItemGroupEnd);
}
}
var projectFilesWriter = new FileGenerator(fileGenerator.Resolver);
if (!fastbuildOnly)
{
foreach( var conf in context.ProjectConfigurations)
{
string externalReferencesCopyLocal = conf.Project.DependenciesCopyLocal.HasFlag(Project.DependenciesCopyLocalTypes.ExternalReferences)
? "true"
: FileGeneratorUtilities.RemoveLineTag;
using (projectFilesWriter.Declare("platformName", Util.GetToolchainPlatformString(conf.Platform, conf.Project, conf.Target)))
using (projectFilesWriter.Declare("conf", conf))
{
foreach (var reference in conf.ReferencesByPath)
{
string nameWithExtension = reference.Split(Util.WindowsSeparator).Last();
string name = nameWithExtension.Substring(0, nameWithExtension.LastIndexOf('.'));
using (projectFilesWriter.Declare("include", name))
using (projectFilesWriter.Declare("hintPath", reference))
using (projectFilesWriter.Declare("private", externalReferencesCopyLocal))
{
projectFilesWriter.Write(Template.Project.ReferenceByPath);
}
}
}
}
}
// Write dotNet dependencies references
{
// The behavior should be the same than for csproj...
string projectDependenciesCopyLocal = firstConf.Project.DependenciesCopyLocal.HasFlag(Project.DependenciesCopyLocalTypes.ProjectReferences).ToString().ToLower();
Options.ExplicitOptions options = new Options.ExplicitOptions();
options["CopyLocalSatelliteAssemblies"] = FileGeneratorUtilities.RemoveLineTag;
options["UseLibraryDependencyInputs"] = FileGeneratorUtilities.RemoveLineTag;
// The check for the blobbed is so we add references to blobed projects over non blobed projects.
var publicDotNetDependenciesConf = context.ProjectConfigurations.Where(x => x.IsBlobbed).FirstOrDefault(x => x.DotNetPublicDependencies.Count > 0) ??
context.ProjectConfigurations.FirstOrDefault(x => x.DotNetPublicDependencies.Count > 0);
var privateDotNetDependenciesConf = context.ProjectConfigurations.Where(x => x.IsBlobbed).FirstOrDefault(x => x.DotNetPrivateDependencies.Count > 0) ??
context.ProjectConfigurations.FirstOrDefault(x => x.DotNetPrivateDependencies.Count > 0);
var dotNetDependenciesLists = new List<IEnumerable<DotNetDependency>>();
if (publicDotNetDependenciesConf != null)
dotNetDependenciesLists.Add(publicDotNetDependenciesConf.DotNetPublicDependencies);
if (privateDotNetDependenciesConf != null)
dotNetDependenciesLists.Add(privateDotNetDependenciesConf.DotNetPrivateDependencies);
foreach (var dotNetDependencies in dotNetDependenciesLists)
{
foreach (var dotNetDependency in dotNetDependencies)
{
var dependency = dotNetDependency.Configuration;
// Don't add any Fastbuild deps to fastbuild projects, that's already handled
if (fastbuildOnly && dependency.IsFastBuild)
continue;
if (dependency.Project.SharpmakeProjectType == Project.ProjectTypeAttribute.Export)
continue; // Can't generate a project dependency for export projects(the project doesn't exist!!).
string include = Util.PathGetRelative(firstConf.ProjectPath, dependency.ProjectFullFileNameWithExtension);
// If dependency project is marked as [Compile], read the GUID from the project file
if (string.IsNullOrEmpty(dependency.ProjectGuid) || dependency.ProjectGuid == Guid.Empty.ToString())
{
if (dependency.Project.SharpmakeProjectType == Project.ProjectTypeAttribute.Compile)
dependency.ProjectGuid = ReadGuidFromProjectFile(dependency);
}
bool? linkLibraryDependencies = dotNetDependency.ReferenceOutputAssembly;
// avoid linking with .lib from a dependency that doesn't create a lib
if (dependency.Output == Project.Configuration.OutputType.DotNetClassLibrary && !dependency.CppCliExportsNativeLib)
{
linkLibraryDependencies = false;
}
options["ReferenceOutputAssembly"] = (dotNetDependency.ReferenceOutputAssembly == false) ? "false" : FileGeneratorUtilities.RemoveLineTag;
options["LinkLibraryDependencies"] = (linkLibraryDependencies == false) ? "false" : FileGeneratorUtilities.RemoveLineTag;
using (projectFilesWriter.Declare("include", include))
using (projectFilesWriter.Declare("projectGUID", dependency.ProjectGuid ?? FileGeneratorUtilities.RemoveLineTag))
using (projectFilesWriter.Declare("projectRefName", dependency.ProjectName))
using (projectFilesWriter.Declare("private", projectDependenciesCopyLocal))
using (projectFilesWriter.Declare("options", options))
{
projectFilesWriter.Write(Template.Project.ProjectReference);
}
}
}
}
WriteProjectReferencesByPath(context, projectFilesWriter);
if (context.Builder.Diagnostics
&& context.Project.AllowInconsistentDependencies == false
&& context.ProjectConfigurations.Any(c => ConfigurationNeedReferences(c)))
{
CheckReferenceDependenciesConsistency(context);
}
bool addDependencies = context.Project.AllowInconsistentDependencies
? context.ProjectConfigurations.Any(c => ConfigurationNeedReferences(c))
: ConfigurationNeedReferences(firstConf);
if (addDependencies)
{
var dependencies = new UniqueList<ProjectDependencyInfo>();
foreach (var configuration in context.ProjectConfigurations)
{
var configDeps = new UniqueList<Project.Configuration>();
configDeps.AddRange(configuration.ConfigurationDependencies);
configDeps.AddRange(configuration.BuildOrderDependencies);
foreach (var configurationDependency in configDeps)
{
// Ignore projects marked as Export
if (configurationDependency.Project.SharpmakeProjectType == Project.ProjectTypeAttribute.Export)
continue;
// Ignore exe and utility outputs
if (configurationDependency.Output == Project.Configuration.OutputType.Exe ||
configurationDependency.Output == Project.Configuration.OutputType.Utility)
continue;
// Ignore FastBuild projects if this is already a FastBuild project.
if (configurationDependency.IsFastBuild && fastbuildOnly)
continue;
ProjectDependencyInfo depInfo;
depInfo.ProjectFullFileNameWithExtension = configurationDependency.ProjectFullFileNameWithExtension;
// If dependency project is marked as [Compile], read the GUID from the project file
depInfo.ProjectGuid = configurationDependency.Project.SharpmakeProjectType == Project.ProjectTypeAttribute.Compile ? ReadGuidFromProjectFile(configurationDependency) : configurationDependency.ProjectGuid;
depInfo.ContainsASM = configurationDependency.Project.ContainsASM;
dependencies.Add(depInfo);
}
}
Options.ExplicitOptions options = context.ProjectConfigurationOptions[firstConf];
foreach (var dependencyInfo in dependencies.OrderBy(project => project.ProjectGuid))
{
string include = Util.PathGetRelative(context.ProjectDirectory, dependencyInfo.ProjectFullFileNameWithExtension);
string backupUseLibraryDependencyInputs = options["UseLibraryDependencyInputs"];
if (dependencyInfo.ContainsASM)
{
// Work around ms-build bug
// Obj files generated in referenced projects by MASM are not linked automatically when "Use Library Dependency Inputs" is set to true
// https://connect.microsoft.com/VisualStudio/feedback/details/679267/obj-files-generated-in-referenced-projects-by-masm-are-not-linked-automatically-when-use-library-dependency-inputs-is-set-to-true
options["UseLibraryDependencyInputs"] = "false";
}
using (projectFilesWriter.Declare("include", include))
using (projectFilesWriter.Declare("projectGUID", dependencyInfo.ProjectGuid))
using (projectFilesWriter.Declare("projectRefName", FileGeneratorUtilities.RemoveLineTag)) // not needed it seems
using (projectFilesWriter.Declare("private", FileGeneratorUtilities.RemoveLineTag)) // TODO: check the conditions for a reference to be private
using (projectFilesWriter.Declare("options", options))
{
projectFilesWriter.Write(Template.Project.ProjectReference);
}
options["UseLibraryDependencyInputs"] = backupUseLibraryDependencyInputs;
}
}
if (!projectFilesWriter.IsEmpty())
{
fileGenerator.Write(Template.Project.ProjectFilesBegin);
projectFilesWriter.WriteTo(fileGenerator);
fileGenerator.Write(Template.Project.ProjectFilesEnd);
}
foreach (var platforms in context.PresentPlatforms.Values)
platforms.GeneratePlatformReferences(context, fileGenerator);
}