private void GenerateProjectReferences()

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);
        }