Example #1
0
        private static AssemblyData AssemblyDataFrom(ScriptAssembly a, ScriptAssembly[] allAssemblies, int index)
        {
            Array.Sort(a.Files, StringComparer.InvariantCulture);
            var references = a.ScriptAssemblyReferences.Select(r => Array.IndexOf(allAssemblies, r)).ToArray();

            Array.Sort(references);
            return(new AssemblyData
            {
                Name = new NPath(a.Filename).FileNameWithoutExtension,
                SourceFiles = a.Files,
                Defines = a.Defines,
                PrebuiltReferences = a.References,
                References = references,
                AllowUnsafeCode = a.CompilerOptions.AllowUnsafeCode,
                RuleSet = a.CompilerOptions.RoslynAnalyzerRulesetPath,
                LanguageVersion = a.CompilerOptions.LanguageVersion,
                Analyzers = a.CompilerOptions.RoslynAnalyzerDllPaths,
                UseDeterministicCompilation = a.CompilerOptions.UseDeterministicCompilation,
                SuppressCompilerWarnings = (a.Flags & AssemblyFlags.SuppressCompilerWarnings) != 0,
                Asmdef = a.AsmDefPath,
                CustomCompilerOptions = a.CompilerOptions.AdditionalCompilerArguments,
                BclDirectories = MonoLibraryHelpers.GetSystemReferenceDirectories(a.CompilerOptions.ApiCompatibilityLevel),
                DebugIndex = index,
                SkipCodeGen = a.SkipCodeGen
            });
        }
        public void SetAllCustomScriptAssemblyJsonContents(string[] paths, string[] contents, string[] guids)
        {
            var assemblies = new List <CustomScriptAssembly>();
            var assemblyLowercaseNamesLookup = new Dictionary <string, CustomScriptAssembly>();
            var exceptions        = new List <Exception>();
            var guidsToAssemblies = new Dictionary <string, CustomScriptAssembly>();
            HashSet <string> predefinedAssemblyNames = null;

            // To check if a path prefix is already being used we use a Dictionary where the key is the prefix and the value is the file path.
            var prefixToFilePathLookup = CustomScriptAssemblyReferences.ToDictionary(x => x.PathPrefix,
                                                                                     x => new List <string> {
                x.FilePath
            }, StringComparer.OrdinalIgnoreCase);

            m_CompilationSetupErrorsTracker.ClearCompilationSetupErrors(CompilationSetupErrors.LoadError);

            // Load first to setup guidsToAssemblies dictionary and convert guids to assembly names
            // before checking for assembly reference errors, so errors emit assembly names instead of guids.
            for (var i = 0; i < paths.Length; ++i)
            {
                var path = paths[i];
                var guid = guids[i];

                string lowerCaseName = null;
                CustomScriptAssembly loadedCustomScriptAssembly = null;

                try
                {
                    var fullPath = AssetPath.IsPathRooted(path)
                        ? AssetPath.GetFullPath(path)
                        : AssetPath.Combine(m_ProjectDirectory, path);

                    loadedCustomScriptAssembly =
                        contents != null
                        ? LoadCustomScriptAssemblyFromJson(fullPath, contents[i], guid)
                        : LoadCustomScriptAssemblyFromJsonPath(fullPath, guid);

                    loadedCustomScriptAssembly.References = loadedCustomScriptAssembly.References ?? new string[0];

                    lowerCaseName = Utility.FastToLower(loadedCustomScriptAssembly.Name);
                    guidsToAssemblies[Utility.FastToLower(guid)] = loadedCustomScriptAssembly;

                    if (!m_SkipCustomScriptAssemblyGraphValidation)
                    {
                        if (predefinedAssemblyNames == null)
                        {
                            predefinedAssemblyNames = new HashSet <string>(EditorBuildRules.PredefinedTargetAssemblyNames);
                            var netfw = MonoLibraryHelpers
                                        .GetSystemLibraryReferences(ApiCompatibilityLevel.NET_Unity_4_8).Select(Path.GetFileNameWithoutExtension);
                            var netstandard21 = MonoLibraryHelpers
                                                .GetSystemLibraryReferences(ApiCompatibilityLevel.NET_Standard).Select(Path.GetFileNameWithoutExtension);
                            predefinedAssemblyNames.UnionWith(netfw);
                            predefinedAssemblyNames.UnionWith(netstandard21);
                        }

                        CheckPredefinedAssemblyNames(
                            predefinedAssemblyNames,
                            assemblyLowercaseNamesLookup,
                            lowerCaseName,
                            prefixToFilePathLookup,
                            ref loadedCustomScriptAssembly);
                    }
                }
                catch (Exception e)
                {
                    m_CompilationSetupErrorsTracker.SetCompilationSetupErrors(CompilationSetupErrors.LoadError);
                    exceptions.Add(e);
                }

                if (loadedCustomScriptAssembly == null || m_SkipCustomScriptAssemblyGraphValidation && assemblyLowercaseNamesLookup.ContainsKey(lowerCaseName))
                {
                    continue;
                }

                loadedCustomScriptAssembly.References       = loadedCustomScriptAssembly.References ?? new string[0];
                assemblyLowercaseNamesLookup[lowerCaseName] = loadedCustomScriptAssembly;
                assemblies.Add(loadedCustomScriptAssembly);

                if (!prefixToFilePathLookup.TryGetValue(loadedCustomScriptAssembly.PathPrefix, out var duplicateFilePaths))
                {
                    duplicateFilePaths = new List <string>();
                    prefixToFilePathLookup[loadedCustomScriptAssembly.PathPrefix] = duplicateFilePaths;
                }

                duplicateFilePaths.Add(loadedCustomScriptAssembly.FilePath);
            }

            ConvertGUIDReferencesToAssemblyNames(assemblies, guidsToAssemblies);

            if (!m_SkipCustomScriptAssemblyGraphValidation)
            {
                CheckForReferenceErrors(assemblies, exceptions);
            }

            CustomScriptAssemblies = assemblies.ToArray();
            Exceptions             = exceptions.ToArray();
        }
        internal static void AddScriptAssemblyReferences(ref ScriptAssembly scriptAssembly, TargetAssembly targetAssembly, ScriptAssemblySettings settings,
                                                         CompilationAssemblies assemblies,
                                                         IDictionary <TargetAssembly, ScriptAssembly> targetToScriptAssembly, ICompilationSetupWarningTracker warningSink)
        {
            var  scriptAssemblyReferences = new List <ScriptAssembly>(targetAssembly.References.Count);
            var  references         = new List <string>();
            bool buildingForEditor  = settings.BuildingForEditor;
            bool noEngineReferences = (targetAssembly.Flags & AssemblyFlags.NoEngineReferences) == AssemblyFlags.NoEngineReferences;

            bool shouldProcessPredefinedCustomTargets = assemblies.CustomTargetAssemblies != null && (targetAssembly.Type & TargetAssemblyType.Predefined) == TargetAssemblyType.Predefined;
            var  predefinedCustomTargetReferences     = Enumerable.Empty <TargetAssembly>();

            if (shouldProcessPredefinedCustomTargets && assemblies.PredefinedAssembliesCustomTargetReferences != null)
            {
                predefinedCustomTargetReferences = assemblies.PredefinedAssembliesCustomTargetReferences;
            }

            var unityReferences = new Dictionary <string, string>();

            // Add Unity assemblies (UnityEngine.dll, UnityEditor.dll) references, as long as the target
            // doesn't specify that it doesn't want them.
            if (!noEngineReferences)
            {
                // Add predefined custom target references in a hash-set for fast lookup
                var predefinedCustomTargetRefs = new HashSet <string>(predefinedCustomTargetReferences.Select(x => x.Filename));
                unityReferences = GetUnityReferences(scriptAssembly, targetAssembly, assemblies.UnityAssemblies, predefinedCustomTargetRefs, settings.CompilationOptions, UnityReferencesOptions.None);
                references.AddRange(unityReferences.Values);
            }

            AddTestRunnerCustomReferences(ref targetAssembly, assemblies.CustomTargetAssemblies);

            // Setup target assembly references
            foreach (var reference in targetAssembly.References)
            {
                ScriptAssembly scriptAssemblyReference;

                // If the assembly already showed up in the unity references, don't reference it here.
                // This can happen when an assembly is configured as a unity assembly override, but
                // overrides are disabled. The Unity assembly should take precedence in that case.
                if (unityReferences.ContainsKey(reference.Filename))
                {
                    continue;
                }

                // Add ScriptAssembly references to other dirty script assemblies that also need to be rebuilt.
                if (targetToScriptAssembly.TryGetValue(reference, out scriptAssemblyReference))
                {
                    System.Diagnostics.Debug.Assert(scriptAssemblyReference != null);
                    scriptAssemblyReferences.Add(scriptAssemblyReference);
                }
            }

            // For predefined target assembly add references to custom target assemblies
            if (shouldProcessPredefinedCustomTargets)
            {
                foreach (var customTargetAssembly in predefinedCustomTargetReferences)
                {
                    ScriptAssembly scriptAssemblyReference;

                    // Only add ScriptAssembly reference if the custom target assembly is dirty, e.g. is in targetToScriptAssembly dictionary
                    // Otherwise just add already compiled custom target assembly as precompiled reference.
                    if (targetToScriptAssembly.TryGetValue(customTargetAssembly, out scriptAssemblyReference))
                    {
                        scriptAssemblyReferences.Add(scriptAssemblyReference);
                    }
                }
            }

            // Add pre-compiled assemblies as references
            var allPrecompiledAssemblies = assemblies.PrecompiledAssemblies ?? new Dictionary <string, PrecompiledAssembly>(0);
            List <PrecompiledAssembly> precompiledReferences = new List <PrecompiledAssembly>(allPrecompiledAssemblies.Count);
            var explicitPrecompiledReferences = new List <PrecompiledAssembly>(targetAssembly.ExplicitPrecompiledReferences.Count);

            if ((targetAssembly.Flags & AssemblyFlags.ExplicitReferences) == AssemblyFlags.ExplicitReferences)
            {
                if (!noEngineReferences)
                {
                    precompiledReferences.AddRange(allPrecompiledAssemblies
                                                   .Where(x => (x.Value.Flags & AssemblyFlags.UserAssembly) != AssemblyFlags.UserAssembly)
                                                   .Select(x => x.Value));
                }

                foreach (var explicitPrecompiledReference in targetAssembly.ExplicitPrecompiledReferences)
                {
                    PrecompiledAssembly assembly;
                    if (allPrecompiledAssemblies.TryGetValue(explicitPrecompiledReference, out assembly))
                    {
                        explicitPrecompiledReferences.Add(assembly);
                    }
                }
            }
            else
            {
                var precompiledAssemblies = allPrecompiledAssemblies.Values.Where(x => (x.Flags & AssemblyFlags.ExplicitlyReferenced) != AssemblyFlags.ExplicitlyReferenced).ToList();

                // if noEngineReferences, add just the non-explicitly-referenced user assemblies
                if (noEngineReferences)
                {
                    precompiledReferences.AddRange(precompiledAssemblies.Where(x => (x.Flags & AssemblyFlags.UserAssembly) == AssemblyFlags.UserAssembly));
                }
                else
                {
                    precompiledReferences.AddRange(precompiledAssemblies);
                }
            }

            AddTestRunnerPrecompiledReferences(targetAssembly, allPrecompiledAssemblies, ref precompiledReferences);

            var precompiledReferenceNames = GetPrecompiledReferences(scriptAssembly, targetAssembly.Type, settings.CompilationOptions, targetAssembly.editorCompatibility, precompiledReferences, explicitPrecompiledReferences, warningSink);

            references.AddRange(precompiledReferenceNames);

            if (buildingForEditor && assemblies.EditorAssemblyReferences != null)
            {
                references.AddRange(assemblies.EditorAssemblyReferences);
            }

            references.AddRange(MonoLibraryHelpers.GetSystemLibraryReferences(scriptAssembly.CompilerOptions.ApiCompatibilityLevel));

            scriptAssembly.ScriptAssemblyReferences = scriptAssemblyReferences.ToArray();
            scriptAssembly.References = references.ToArray();
        }
Example #4
0
        internal static void AddScriptAssemblyReferences(ref ScriptAssembly scriptAssembly, TargetAssembly targetAssembly, ScriptAssemblySettings settings,
                                                         CompilationAssemblies assemblies,
                                                         IDictionary <TargetAssembly, ScriptAssembly> targetToScriptAssembly, string filenameSuffix)
        {
            var  scriptAssemblyReferences = new List <ScriptAssembly>();
            var  references        = new List <string>();
            bool buildingForEditor = settings.BuildingForEditor;

            // Add Unity assemblies (UnityEngine.dll, UnityEditor.dll) referencees.
            var unityReferences = GetUnityReferences(scriptAssembly, assemblies.UnityAssemblies, settings.CompilationOptions);

            references.AddRange(unityReferences);

            // Setup target assembly references
            foreach (var reference in targetAssembly.References)
            {
                ScriptAssembly scriptAssemblyReference;

                // Add ScriptAssembly references to other dirty script assemblies that also need to be rebuilt.
                if (targetToScriptAssembly.TryGetValue(reference, out scriptAssemblyReference))
                {
                    System.Diagnostics.Debug.Assert(scriptAssemblyReference != null);
                    scriptAssemblyReferences.Add(scriptAssemblyReference);
                }
                else
                {
                    // Add string references to other assemblies that do not need to be rebuilt.
                    var assemblyPath = reference.FullPath(settings.OutputDirectory, filenameSuffix);

                    if (File.Exists(assemblyPath))
                    {
                        references.Add(assemblyPath);
                    }
                }
            }

            // For predefined target assembly add references to custom target assemblies
            if (assemblies.CustomTargetAssemblies != null && (targetAssembly.Type & TargetAssemblyType.Predefined) == TargetAssemblyType.Predefined)
            {
                foreach (var customTargetAssembly in assemblies.PredefinedAssembliesCustomTargetReferences ?? Enumerable.Empty <TargetAssembly>())
                {
                    ScriptAssembly scriptAssemblyReference;

                    // Only add ScriptAssembly reference if the custom target assembly is dirty, e.g. is in targetToScriptAssembly dictionary
                    // Otherwise just add already compiled custom target assembly as precompiled reference.
                    if (targetToScriptAssembly.TryGetValue(customTargetAssembly, out scriptAssemblyReference))
                    {
                        scriptAssemblyReferences.Add(scriptAssemblyReference);
                    }
                    else
                    {
                        var customTargetAssemblyPath = customTargetAssembly.FullPath(settings.OutputDirectory, filenameSuffix);

                        // File might not exist if there are no scripts in the custom target assembly folder.
                        if (File.Exists(customTargetAssemblyPath))
                        {
                            references.Add(customTargetAssemblyPath);
                        }
                    }
                }
            }

            // Add pre-compiled assemblies as references
            PrecompiledAssembly[] precompiledAssembliesForReferences = assemblies.PrecompiledAssemblies ?? new PrecompiledAssembly[] {};
            if (settings.OptionalUnityReferences != OptionalUnityReferences.None)
            {
                precompiledAssembliesForReferences = precompiledAssembliesForReferences.Where(x => x.OptionalUnityReferences == OptionalUnityReferences.None || ((targetAssembly.OptionalUnityReferences & x.OptionalUnityReferences & settings.OptionalUnityReferences) != 0)).ToArray();
            }

            var precompiledReferences = GetPrecompiledReferences(scriptAssembly, targetAssembly.Type, settings.CompilationOptions, targetAssembly.editorCompatibility, precompiledAssembliesForReferences);

            references.AddRange(precompiledReferences);

            if (buildingForEditor && assemblies.EditorAssemblyReferences != null)
            {
                references.AddRange(assemblies.EditorAssemblyReferences);
            }

            references.AddRange(MonoLibraryHelpers.GetSystemLibraryReferences(scriptAssembly.ApiCompatibilityLevel, scriptAssembly.BuildTarget, scriptAssembly.Language, buildingForEditor, scriptAssembly.Filename));

            scriptAssembly.ScriptAssemblyReferences = scriptAssemblyReferences.ToArray();
            scriptAssembly.References = references.ToArray();
        }