private void AddDependencies(AssetItem assetItem, HashSet <BuildDependencyInfo> typesToInclude, HashSet <Type> typesToExclude) { // for now we use the dependency manager itself to resolve runtime dependencies, in the future we might want to unify the builddependency manager with the dependency manager var dependencies = assetItem.Package.Session.DependencyManager.ComputeDependencies(assetItem.Id, AssetDependencySearchOptions.Out); if (dependencies != null) { foreach (var assetDependency in dependencies.LinksOut) { var assetType = assetDependency.Item.Asset.GetType(); if (!typesToExclude.Contains(assetType)) //filter out what we do not need { foreach (var input in typesToInclude.Where(x => x.AssetType == assetType)) { var node = buildDependencyManager.FindOrCreateNode(assetDependency.Item, input.CompilationContext); var link = new BuildAssetLink(this, node, input.DependencyType); references.TryAdd(link, link); if (link.HasOne(BuildDependencyType.CompileAsset)) { // When we have a CompileAsset type of dependency, we want to analyze this asset and extract other assets that it references and are needed by this asset. AddDependencies(assetDependency.Item, typesToInclude, typesToExclude); } } } } } }
/// <summary> /// Performs analysis on the asset to figure out all the needed dependencies /// </summary> /// <param name="context">The compiler context</param> /// <returns>True if the node was updated, false otherwise.</returns> public bool Analyze(AssetCompilerContext context) { var assetVersion = AssetItem.Version; if (Interlocked.Exchange(ref version, assetVersion) == assetVersion) { // This node is up-to-date. Let's check if CompileAsset links are also up-to-date. // Otherwise we need to refresh this node since this kind of link can bring additional dependencies. var upToDate = true; foreach (var node in References) { if (node.HasOne(BuildDependencyType.CompileAsset)) { if (node.Target.Analyze(context)) { upToDate = false; } } } if (upToDate) { return(false); // Same version, skip analysis, do not clear links } } var mainCompiler = BuildDependencyManager.AssetCompilerRegistry.GetCompiler(AssetItem.Asset.GetType(), CompilationContext); if (mainCompiler == null) { return(false); // Scripts and such don't have compiler } var typesToInclude = new HashSet <BuildDependencyInfo>(mainCompiler.GetInputTypes(AssetItem)); var typesToExclude = new HashSet <Type>(mainCompiler.GetInputTypesToExclude(AssetItem)); // Clean up our references references.Clear(); // DependencyManager check AddDependencies(AssetItem, typesToInclude, typesToExclude); // Input files required foreach (var inputFile in new HashSet <ObjectUrl>(mainCompiler.GetInputFiles(AssetItem))) //directly resolve by input files, in the future we might just want this pass { if (inputFile.Type == UrlType.Content) { var asset = AssetItem.Package.Session.FindAsset(inputFile.Path); //this will search all packages if (asset == null) { continue; //this might be an error tho... but in the end compilation might fail so we let the build engine do the error reporting if it really was a issue } if (!typesToExclude.Contains(asset.GetType())) { // TODO: right now, we consider that assets returned by GetInputFiles must be compiled in AssetCompilationContext. At some point, we might need to be able to specify a custom context. var dependencyType = inputFile.Type == UrlType.Content ? BuildDependencyType.CompileContent : BuildDependencyType.CompileAsset; //Content means we need to load the content, the rest is just asset dependency var node = buildDependencyManager.FindOrCreateNode(asset, typeof(AssetCompilationContext)); var link = new BuildAssetLink(this, node, dependencyType); references.TryAdd(link, link); } } } bool shouldVisitTypes; context.Properties.TryGet(VisitRuntimeTypes, out shouldVisitTypes); if (shouldVisitTypes || mainCompiler.AlwaysCheckRuntimeTypes) { var collector = new RuntimeDependenciesCollector(mainCompiler.GetRuntimeTypes(AssetItem)); var deps = collector.GetDependencies(AssetItem); foreach (var reference in deps) { var asset = AssetItem.Package.FindAsset(reference.Id); if (asset != null) { // TODO: right now, we consider that assets found with RuntimeDependenciesCollector must be compiled in AssetCompilationContext. At some point, we might need to be able to specify a custom context. var dependencyType = BuildDependencyType.Runtime; var node = buildDependencyManager.FindOrCreateNode(asset, typeof(AssetCompilationContext)); var link = new BuildAssetLink(this, node, dependencyType); references.TryAdd(link, link); } } } return(true); }
/// <summary> /// Performs analysis on the asset to figure out all the needed dependencies /// </summary> /// <param name="context">The compiler context</param> public void Analyze(AssetCompilerContext context) { var assetVersion = AssetItem.Version; if (Interlocked.Exchange(ref version, assetVersion) == assetVersion) { return; //same version, skip analysis, do not clear links } var mainCompiler = BuildDependencyManager.AssetCompilerRegistry.GetCompiler(AssetItem.Asset.GetType(), CompilationContext); if (mainCompiler == null) { return; //scripts and such don't have compiler } var typesToInclude = new HashSet <BuildDependencyInfo>(mainCompiler.GetInputTypes(AssetItem)); var typesToExclude = new HashSet <Type>(mainCompiler.GetInputTypesToExclude(AssetItem)); //clean up our references references.Clear(); //DependencyManager check //for now we use the dependency manager itself to resolve runtime dependencies, in the future we might want to unify the builddependency manager with the dependency manager var dependencies = AssetItem.Package.Session.DependencyManager.ComputeDependencies(AssetItem.Id, AssetDependencySearchOptions.Out); if (dependencies != null) { foreach (var assetDependency in dependencies.LinksOut) { var assetType = assetDependency.Item.Asset.GetType(); if (!typesToExclude.Contains(assetType)) //filter out what we do not need { foreach (var input in typesToInclude.Where(x => x.AssetType == assetType)) { var node = buildDependencyManager.FindOrCreateNode(assetDependency.Item, input.CompilationContext); var link = new BuildAssetLink(this, node, input.DependencyType); references.TryAdd(link, link); } } } } //Input files required foreach (var inputFile in new HashSet <ObjectUrl>(mainCompiler.GetInputFiles(AssetItem))) //directly resolve by input files, in the future we might just want this pass { if (inputFile.Type == UrlType.Content || inputFile.Type == UrlType.ContentLink) { var asset = AssetItem.Package.Session.FindAsset(inputFile.Path); //this will search all packages if (asset == null) { continue; //this might be an error tho... but in the end compilation might fail so we let the build engine do the error reporting if it really was a issue } if (!typesToExclude.Contains(asset.GetType())) { // TODO: right now, we consider that assets returned by GetInputFiles must be compiled in AssetCompilationContext. At some point, we might need to be able to specify a custom context. var dependencyType = inputFile.Type == UrlType.Content ? BuildDependencyType.CompileContent : BuildDependencyType.CompileAsset; //Content means we need to load the content, the rest is just asset dependency var node = buildDependencyManager.FindOrCreateNode(asset, typeof(AssetCompilationContext)); var link = new BuildAssetLink(this, node, dependencyType); references.TryAdd(link, link); } } } bool shouldVisitTypes; context.Properties.TryGet(VisitRuntimeTypes, out shouldVisitTypes); if (shouldVisitTypes || mainCompiler.AlwaysCheckRuntimeTypes) { var collector = new RuntimeDependenciesCollector(mainCompiler.GetRuntimeTypes(AssetItem)); var deps = collector.GetDependencies(AssetItem); foreach (var reference in deps) { var asset = AssetItem.Package.FindAsset(reference.Id); if (asset != null) { // TODO: right now, we consider that assets found with RuntimeDependenciesCollector must be compiled in AssetCompilationContext. At some point, we might need to be able to specify a custom context. var dependencyType = BuildDependencyType.Runtime; var node = buildDependencyManager.FindOrCreateNode(asset, typeof(AssetCompilationContext)); var link = new BuildAssetLink(this, node, dependencyType); references.TryAdd(link, link); } } } }