diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.cs index 419820f56..93fe10c0b 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; using Flax.Build.NativeCpp; using BuildData = Flax.Build.Builder.BuildData; @@ -58,11 +57,8 @@ namespace Flax.Build.Bindings private static ModuleInfo ParseModuleInner(BuildData buildData, Module module, BuildOptions moduleOptions = null) { - if (buildData.ModulesInfo.TryGetValue(module, out var moduleInfo)) - return moduleInfo; - // Setup bindings module info descriptor - moduleInfo = new ModuleInfo + var moduleInfo = new ModuleInfo { Module = module, Name = module.BinaryModuleName, @@ -81,26 +77,35 @@ namespace Flax.Build.Bindings throw new Exception($"Cannot parse module {module.Name} without options."); // Collect all header files that can have public symbols for API - var headerFiles = moduleOptions.SourceFiles.Where(x => x.EndsWith(".h")).ToList(); - - // Skip if no header files to process + var headerFiles = new List(moduleOptions.SourceFiles.Count / 2); + for (int i = 0; i < moduleOptions.SourceFiles.Count; i++) + { + if (moduleOptions.SourceFiles[i].EndsWith(".h", StringComparison.OrdinalIgnoreCase)) + headerFiles.Add(moduleOptions.SourceFiles[i]); + } if (headerFiles.Count == 0) return moduleInfo; + if (module.Name == "Core") + { + // Special case for Core module to ignore API tags defines + for (int i = 0; i < headerFiles.Count; i++) + { + if (headerFiles[i].EndsWith("Config.h", StringComparison.Ordinal)) + { + headerFiles.RemoveAt(i); + break; + } + } + } - // TODO: use aynsc tasks or thread pool to load and parse multiple header files at once using multi-threading + // TODO: use async tasks or thread pool to load and parse multiple header files at once using multi-threading // Find and load files with API tags string[] headerFilesContents = null; - //using (new ProfileEventScope("LoadHeaderFiles")) + using (new ProfileEventScope("LoadHeaderFiles")) { - var anyApi = false; for (int i = 0; i < headerFiles.Count; i++) { - // Skip scripting tags definitions file - if (headerFiles[i].Replace('\\', '/').EndsWith("Engine/Core/Config.h", StringComparison.Ordinal)) - continue; - - // Check if file contains any valid API tag var contents = File.ReadAllText(headerFiles[i]); for (int j = 0; j < ApiTokens.SearchTags.Length; j++) { @@ -109,15 +114,13 @@ namespace Flax.Build.Bindings if (headerFilesContents == null) headerFilesContents = new string[headerFiles.Count]; headerFilesContents[i] = contents; - anyApi = true; break; } } } - - if (!anyApi) - return moduleInfo; } + if (headerFilesContents == null) + return moduleInfo; // Skip if none of the headers was modified after last time generated C++ file was edited // TODO: skip parsing if module has API cache file -> then load it from disk diff --git a/Source/Tools/Flax.Build/Build/Builder.Rules.cs b/Source/Tools/Flax.Build/Build/Builder.Rules.cs index 9982e3601..1c4609c2e 100644 --- a/Source/Tools/Flax.Build/Build/Builder.Rules.cs +++ b/Source/Tools/Flax.Build/Build/Builder.Rules.cs @@ -12,12 +12,31 @@ namespace Flax.Build partial class Builder { private static RulesAssembly _rules; + private static Type[] _buildTypes; /// /// The build configuration files postfix. /// public static string BuildFilesPostfix = ".Build.cs"; + /// + /// The cached list of types from Flax.Build assembly. Reused by other build tool utilities to improve performance. + /// + internal static Type[] BuildTypes + { + get + { + if (_buildTypes == null) + { + using (new ProfileEventScope("CacheBuildTypes")) + { + _buildTypes = typeof(Program).Assembly.GetTypes(); + } + } + return _buildTypes; + } + } + /// /// The rules assembly data. /// @@ -128,7 +147,7 @@ namespace Flax.Build using (new ProfileEventScope("InitInBuildPlugins")) { - foreach (var type in typeof(Program).Assembly.GetTypes().Where(x => !x.IsAbstract && x.IsSubclassOf(typeof(Plugin)))) + foreach (var type in BuildTypes.Where(x => x.IsClass && !x.IsAbstract && x.IsSubclassOf(typeof(Plugin)))) { var plugin = (Plugin)Activator.CreateInstance(type); plugin.Init(); @@ -176,67 +195,74 @@ namespace Flax.Build // Prepare targets and modules objects Type[] types; - Target[] targetObjects; - Module[] moduleObjects; - Plugin[] pluginObjects; + var targetObjects = new List(16); + var moduleObjects = new List(256); + var pluginObjects = new List(); using (new ProfileEventScope("GetTypes")) { types = assembly.GetTypes(); - targetObjects = types.Where(x => !x.IsAbstract && x.IsSubclassOf(typeof(Target))).Select(type => + for (var i = 0; i < types.Length; i++) { - var target = (Target)Activator.CreateInstance(type); - - var targetFilename = target.Name + BuildFilesPostfix; - target.FilePath = files.FirstOrDefault(path => string.Equals(Path.GetFileName(path), targetFilename, StringComparison.OrdinalIgnoreCase)); - if (target.FilePath == null) + var type = types[i]; + if (!type.IsClass || type.IsAbstract) + continue; + if (type.IsSubclassOf(typeof(Target))) { - targetFilename = target.Name + "Target" + BuildFilesPostfix; + var target = (Target)Activator.CreateInstance(type); + + var targetFilename = target.Name + BuildFilesPostfix; target.FilePath = files.FirstOrDefault(path => string.Equals(Path.GetFileName(path), targetFilename, StringComparison.OrdinalIgnoreCase)); if (target.FilePath == null) { - if (target.Name.EndsWith("Target")) - { - targetFilename = target.Name.Substring(0, target.Name.Length - "Target".Length) + BuildFilesPostfix; - target.FilePath = files.FirstOrDefault(path => string.Equals(Path.GetFileName(path), targetFilename, StringComparison.OrdinalIgnoreCase)); - } + targetFilename = target.Name + "Target" + BuildFilesPostfix; + target.FilePath = files.FirstOrDefault(path => string.Equals(Path.GetFileName(path), targetFilename, StringComparison.OrdinalIgnoreCase)); if (target.FilePath == null) { - throw new Exception(string.Format("Failed to find source file path for {0}", target)); + if (target.Name.EndsWith("Target")) + { + targetFilename = target.Name.Substring(0, target.Name.Length - "Target".Length) + BuildFilesPostfix; + target.FilePath = files.FirstOrDefault(path => string.Equals(Path.GetFileName(path), targetFilename, StringComparison.OrdinalIgnoreCase)); + } + if (target.FilePath == null) + { + throw new Exception(string.Format("Failed to find source file path for {0}", target)); + } } } + target.FolderPath = Path.GetDirectoryName(target.FilePath); + target.Init(); + targetObjects.Add(target); } - target.FolderPath = Path.GetDirectoryName(target.FilePath); - target.Init(); - return target; - }).ToArray(); - moduleObjects = types.Where(x => !x.IsAbstract && x.IsSubclassOf(typeof(Module))).Select(type => - { - var module = (Module)Activator.CreateInstance(type); - - var moduleFilename = module.Name + BuildFilesPostfix; - module.FilePath = files.FirstOrDefault(path => string.Equals(Path.GetFileName(path), moduleFilename, StringComparison.OrdinalIgnoreCase)); - if (module.FilePath == null) + else if (type.IsSubclassOf(typeof(Module))) { - moduleFilename = module.Name + "Module" + BuildFilesPostfix; + var module = (Module)Activator.CreateInstance(type); + + var moduleFilename = module.Name + BuildFilesPostfix; module.FilePath = files.FirstOrDefault(path => string.Equals(Path.GetFileName(path), moduleFilename, StringComparison.OrdinalIgnoreCase)); if (module.FilePath == null) { - throw new Exception(string.Format("Failed to find source file path for {0}", module)); + moduleFilename = module.Name + "Module" + BuildFilesPostfix; + module.FilePath = files.FirstOrDefault(path => string.Equals(Path.GetFileName(path), moduleFilename, StringComparison.OrdinalIgnoreCase)); + if (module.FilePath == null) + { + throw new Exception(string.Format("Failed to find source file path for {0}", module)); + } } + module.FolderPath = Path.GetDirectoryName(module.FilePath); + module.Init(); + moduleObjects.Add(module); } - module.FolderPath = Path.GetDirectoryName(module.FilePath); - module.Init(); - return module; - }).ToArray(); - pluginObjects = types.Where(x => !x.IsAbstract && x.IsSubclassOf(typeof(Plugin))).Select(type => - { - var plugin = (Plugin)Activator.CreateInstance(type); - plugin.Init(); - return plugin; - }).ToArray(); + else if (type.IsSubclassOf(typeof(Plugin))) + { + var plugin = (Plugin)Activator.CreateInstance(type); + + plugin.Init(); + pluginObjects.Add(plugin); + } + } } - _rules = new RulesAssembly(assembly, targetObjects, moduleObjects, pluginObjects); + _rules = new RulesAssembly(assembly, targetObjects.ToArray(), moduleObjects.ToArray(), pluginObjects.ToArray()); } return _rules; diff --git a/Source/Tools/Flax.Build/Build/NativeCpp/Builder.NativeCpp.cs b/Source/Tools/Flax.Build/Build/NativeCpp/Builder.NativeCpp.cs index 70d3722fb..af50cfe1e 100644 --- a/Source/Tools/Flax.Build/Build/NativeCpp/Builder.NativeCpp.cs +++ b/Source/Tools/Flax.Build/Build/NativeCpp/Builder.NativeCpp.cs @@ -330,7 +330,12 @@ namespace Flax.Build } // Collect all files to compile - var cppFiles = moduleOptions.SourceFiles.Where(x => x.EndsWith(".cpp")).ToList(); + var cppFiles = new List(moduleOptions.SourceFiles.Count / 2); + for (int i = 0; i < moduleOptions.SourceFiles.Count; i++) + { + if (moduleOptions.SourceFiles[i].EndsWith(".cpp", StringComparison.OrdinalIgnoreCase)) + cppFiles.Add(moduleOptions.SourceFiles[i]); + } if (!string.IsNullOrEmpty(module.BinaryModuleName)) { diff --git a/Source/Tools/Flax.Build/Build/Platform.cs b/Source/Tools/Flax.Build/Build/Platform.cs index 07a18a2a9..15addce27 100644 --- a/Source/Tools/Flax.Build/Build/Platform.cs +++ b/Source/Tools/Flax.Build/Build/Platform.cs @@ -157,7 +157,7 @@ namespace Flax.Build if (_platforms == null) { using (new ProfileEventScope("GetPlatforms")) - _platforms = typeof(Platform).Assembly.GetTypes().Where(x => !x.IsAbstract && x.IsSubclassOf(typeof(Platform))).Select(Activator.CreateInstance).Cast().ToArray(); + _platforms = Builder.BuildTypes.Where(x => x.IsClass && !x.IsAbstract && x.IsSubclassOf(typeof(Platform))).Select(Activator.CreateInstance).Cast().ToArray(); } foreach (var platform in _platforms) diff --git a/Source/Tools/Flax.Build/Build/Sdk.cs b/Source/Tools/Flax.Build/Build/Sdk.cs index 450d8f43f..5c7044705 100644 --- a/Source/Tools/Flax.Build/Build/Sdk.cs +++ b/Source/Tools/Flax.Build/Build/Sdk.cs @@ -68,7 +68,7 @@ namespace Flax.Build using (new ProfileEventScope("GetSdks")) { _sdks = new Dictionary(); - var types = typeof(Sdk).Assembly.GetTypes().Where(x => !x.IsAbstract && x.IsSubclassOf(typeof(Sdk))); + var types = Builder.BuildTypes.Where(x => !x.IsAbstract && x.IsSubclassOf(typeof(Sdk))); foreach (var type in types) { object instance = null; diff --git a/Source/Tools/Flax.Build/Deps/DepsBuilder.cs b/Source/Tools/Flax.Build/Deps/DepsBuilder.cs index 7ac4b0d69..6d6eaf5b3 100644 --- a/Source/Tools/Flax.Build/Deps/DepsBuilder.cs +++ b/Source/Tools/Flax.Build/Deps/DepsBuilder.cs @@ -51,7 +51,7 @@ namespace Flax.Deps } // Get all deps - var dependencies = typeof(DepsBuilder).Assembly.GetTypes().Where(x => x.IsSubclassOf(typeof(Dependency))).Select(Activator.CreateInstance).Cast().ToArray(); + var dependencies = Builder.BuildTypes.Where(x => x.IsSubclassOf(typeof(Dependency))).Select(Activator.CreateInstance).Cast().ToArray(); if (dependencies.Length == 0) Log.Warning("No dependencies found!"); for (var i = 0; i < dependencies.Length; i++)