private static IEnumerable <NPath> TargetPathsFor(NPath targetDirectory, DotNetAssembly inputAssembly) { yield return(targetDirectory.Combine(inputAssembly.Path.FileName)); if (inputAssembly.DebugSymbolPath != null) { yield return(targetDirectory.Combine(inputAssembly.DebugSymbolPath.FileName)); } }
// Ajout de l'élément /// <summary> /// Alerts listeners that a rule has been used. /// </summary> /// <param name="e">An ElementAddedEventArgs that contains the event data.</param> public override void ElementAdded(ElementAddedEventArgs e) { #region Condition // Test the element DotnetAssemblyShape shape = e.ModelElement as DotnetAssemblyShape; if (shape == null) { return; } // Teste qu'elle est la source qui a générée l'événement if (shape.Store.TransactionManager.CurrentTransaction.TopLevelTransaction.IsSerializing || shape.Store.InUndoRedoOrRollback) { return; } #endregion #region Traitement DotNetAssembly externalAssembly = shape.ModelElement as DotNetAssembly; if (externalAssembly != null && !String.IsNullOrEmpty(externalAssembly.FullName)) { return; } using ( Transaction transaction = externalAssembly.Store.TransactionManager.BeginTransaction("Retrieve assembly infos")) { try { IAssemblySelectorDialog selector = ServiceLocator.Instance.GetService <IAssemblySelectorDialog>(); if (selector.ShowDialog(1)) { externalAssembly.InitFromAssembly(selector.SelectedAssemblies[0], true); transaction.Commit(); } } catch (Exception ex) { ILogger logger = ServiceLocator.Instance.GetService <ILogger>(); if (logger != null) { logger.WriteError("Import assembly", "Reflection error", ex); } transaction.Rollback(); } } #endregion }
private NPath[] SetupIL2CPPConversion(NPath[] linkerOutputFiles, NPath il2cppdata_destinationdir) { var il2cpp = new DotNetAssembly( string.IsNullOrEmpty(CustomIL2CPPLocation) ? $"{EditorApplication.applicationContentsPath}/il2cpp/build/deploy/net471/il2cpp.exe" : $"{CustomIL2CPPLocation}/build/deploy/net471/il2cpp.exe", Framework.Framework471); var netCoreRunRuntime = DotNetRuntime.FindFor(il2cpp); //NetCoreRunRuntime.FromSteve; var il2cppProgram = new DotNetRunnableProgram(il2cpp, netCoreRunRuntime); var extraTypes = new HashSet <string>(); foreach (var extraType in PlayerBuildInterface.ExtraTypesProvider?.Invoke() ?? Array.Empty <string>()) { extraTypes.Add(extraType); } NPath extraTypesFile = Configuration.RootArtifactsPath.Combine("extra-types.txt").MakeAbsolute().WriteAllLines(extraTypes.ToArray()); NPath il2cppOutputDir = Configuration.RootArtifactsPath.Combine("il2cpp"); Backend.Current.AddAction("IL2CPP", Array.Empty <NPath>(), linkerOutputFiles .Concat(il2cpp.Path.Parent.Files()).Concat(netCoreRunRuntime.Inputs) .Concat(new[] { extraTypesFile }) .ToArray(), il2cppProgram.InvocationString, new[] { "--convert-to-cpp", "--emit-null-checks", "--enable-array-bounds-check", "--dotnetprofile=\"unityaot\"", "--libil2cpp-static", $"--extra-types-file={extraTypesFile.InQuotes()}", "--profiler-report", $"--generatedcppdir={il2cppOutputDir.InQuotes(SlashMode.Native)}", $"--directory={linkerOutputFiles.First().Parent.InQuotes(SlashMode.Native)}", }, targetDirectories: new[] { il2cppOutputDir }, allowUnwrittenOutputFiles: true); var il2cppOutputFiles = GuessTargetDirectoryContentsFor(il2cppOutputDir, "dummy.cpp"); var dataDir = il2cppOutputDir.Combine("Data"); foreach (var il2cppdatafile in dataDir.FilesIfExists(recurse: true)) { CopyTool.Instance().Setup(il2cppdata_destinationdir.Combine(il2cppdatafile.RelativeTo(dataDir)), il2cppdatafile); } return(il2cppOutputFiles); }
public static NPath SetupBurst(NPath burstPackage, DotNetAssembly inputAssembly, NPath responseFile, ToolChain toolChain) { var bcl = new DotNetRunnableProgram(new DotNetAssembly(burstPackage.Combine(".Runtime/bcl.exe"), Framework.Framework471)); var targetFile = inputAssembly.Path.Parent.Combine($"burst_output.{toolChain.CppCompiler.ObjectExtension}"); var inputs = Unity.BuildTools.EnumerableExtensions.Append(inputAssembly.RecursiveRuntimeDependenciesIncludingSelf.SelectMany(a => a.Paths), responseFile); Backend.Current.AddAction( "Burst", targetFiles: new[] { targetFile }, inputs: inputs.ToArray(), executableStringFor: bcl.InvocationString, commandLineArguments: new[] { $"--assembly-folder={inputAssembly.Path.Parent}", $"--output={targetFile}", "--keep-intermediate-files", $"@{responseFile.ToString(SlashMode.Native)}" }, allowUnexpectedOutput: false, allowedOutputSubstrings: new[] { "Link succesful", "Method:" }); return(targetFile); }
public void SetupInvocation(DotNetAssembly inputProgram, DotsRuntimeCSharpProgramConfiguration config) { var result = BindGemOutputFor(inputProgram, config); if (result == null) { return; } var assembly = inputProgram; var args = new List <string> { "-v", "-dots", assembly.RuntimeDependencies.Select(rd => $"-r {rd.Path.InQuotes()}"), assembly.RuntimeDependencies.Select(r => BindGemOutputFor(r, config)).ExcludeNulls().Select(bo => $"-cppInclude {bo.Header}"), $"-define_guard BUILD_{assembly.Path.FileName.ToUpper().Replace(".", "_")}", assembly.Path.InQuotes(), "-o", result.Cpp.Parent.Combine(result.Cpp.FileNameWithoutExtension).InQuotes() }; var program = new DotNetRunnableProgram(BuiltBindGemProgram); var inputs = new List <NPath> { BuiltBindGemProgram.Path, assembly.RecursiveRuntimeDependenciesIncludingSelf.Select(d => d.Path) }; // Note: the MakeAbsolute() below also takes care of changing slashes on Windows, // because Windows really hates forward slashes when used as an executable path // to cmd.exe Backend.Current.AddAction( actionName: "BindGem", targetFiles: result.Files, inputs: inputs.ToArray(), executableStringFor: program.InvocationString, commandLineArguments: args.ToArray(), supportResponseFile: false ); }
public DotNetAssembly SetupPostProcessorInvocation(DotNetAssembly inputAsm) { List <DotNetAssembly> inputAssemblyAndReferences; using (new ProfilerMarker(nameof(inputAsm.RecursiveRuntimeDependenciesIncludingSelf)).Auto()) inputAssemblyAndReferences = inputAsm.RecursiveRuntimeDependenciesIncludingSelf.ToList(); var inputFiles = _inputFilesFromPostProcessor.Concat(inputAssemblyAndReferences.Select(p => p.Path)).ToArray(); var result = new DotNetAssembly(OutputDirectory.Combine(inputAsm.Path.FileName), inputAsm.Framework, debugSymbolPath: OutputDirectory.Combine(inputAsm.DebugSymbolPath.FileName)) .WithRuntimeDependencies(inputAsm.RuntimeDependencies.Select(r => _processedAssemblies.TryGetValue(r, out var processed) ? processed : r).ToArray()); var processorPathsArg = _builtProcessors.Select(p => $"-p={p.Path.InQuotes(SlashMode.Native)}"); var referenceAsmPaths = inputAssemblyAndReferences .Where(a => !a.Path.IsChildOf("post_ilprocessing")) .Select(a => a.Path) .Concat(_bclFiles); var args = new List <string> { "-a", inputAsm.Path.InQuotes(SlashMode.Native), $"--outputDir={OutputDirectory.InQuotes(SlashMode.Native)}", processorPathsArg, referenceAsmPaths.Select(r => $"-r={r.InQuotesResolved()}"), "-f=.", }.ToArray(); Backend.Current.AddAction($"ILPostProcessorRunner", result.Paths, inputFiles, executableStringFor: _processorRunnableProgram.InvocationString, args, supportResponseFile: true ); _processedAssemblies.Add(inputAsm, result); return(result); }
public override DotNetAssembly SetupSpecificConfiguration(CSharpProgramConfiguration config) { var nonPatchedUnsafeUtility = base.SetupSpecificConfiguration(config); var builtPatcher = new CSharpProgram() { Path = "artifacts/UnsafeUtilityPatcher/UnsafeUtilityPatcher.exe", Sources = { $"{BuildProgram.LowLevelRoot}/UnsafeUtilityPatcher" }, Defines = { "NDESK_OPTIONS" }, Framework = { Bee.DotNet.Framework.Framework471 }, References = { MonoCecil.Paths, }, LanguageVersion = "7.3" }.SetupDefault(); var outDir = nonPatchedUnsafeUtility.Path.Parent.Combine("patched"); NPath nPath = outDir.Combine(nonPatchedUnsafeUtility.Path.FileName); var builtPatcherProgram = new DotNetRunnableProgram(builtPatcher); var args = new[] { $"--output={nPath}", $"--assembly={nonPatchedUnsafeUtility.Path}", }; var result = new DotNetAssembly(nPath, nonPatchedUnsafeUtility.Framework, nonPatchedUnsafeUtility.DebugFormat, nPath.ChangeExtension("pdb"), nonPatchedUnsafeUtility.RuntimeDependencies, nonPatchedUnsafeUtility.ReferenceAssemblyPath); Backend.Current.AddAction("Patch", result.Paths, nonPatchedUnsafeUtility.Paths.Concat(builtPatcher.Paths).ToArray(), builtPatcherProgram.InvocationString, args); return(result); }
/// <summary> /// Accepts the dot net assembly. /// </summary> /// <param name="assembly">The assembly.</param> private void AcceptDotNetAssembly(DotNetAssembly assembly) { _projectPath.Push(CurrentModelPath); // Si l'assembly est dans le GAC if (assembly.IsInGac) { if (_scope == ReferenceScope.Compilation) { _references.Add(assembly.FullName); } if (_scope != ReferenceScope.Publish) // == Runtime { return; } } string assemblyName = assembly.AssemblyName; string fileName = Path.Combine(_projectPath.Peek(), assemblyName); if (_initialModelIsInSolution && !IsExternalModel) { if (!File.Exists(fileName)) { // 1ère fois - Copie dans le répertoire local Utils.CopyFile(assembly.InitialLocation, fileName); } if (!File.Exists(fileName)) // Toujours pas (même aprés copie éventuelle) { fileName = assembly.AssemblyName; } } _references.Add(fileName); }
private static DotsRuntimeCSharpProgram SetupGame(AsmDefDescription game) { var gameProgram = GetOrMakeDotsRuntimeCSharpProgramFor(game); var configToSetupGame = new Dictionary <DotsRuntimeCSharpProgramConfiguration, DotNetAssembly>(); if (!PerConfigBuildSettings.ContainsKey(game.Name)) { return(null); } var configsToUse = PerConfigBuildSettings[game.Name].Where(config => !CanSkipSetupOf(game.Name, config)); foreach (var config in configsToUse) { var withoutExt = new NPath(new NPath(gameProgram.FileName).FileNameWithoutExtension).Combine(config.Identifier); NPath exportManifest = withoutExt.Combine("export.manifest"); Backend.Current.RegisterFileInfluencingGraph(exportManifest); if (exportManifest.FileExists()) { var dataFiles = exportManifest.MakeAbsolute().ReadAllLines(); foreach (var dataFile in dataFiles.Select(d => new NPath(d))) { gameProgram.SupportFiles.Add( c => c.Equals(config), new DeployableFile(dataFile, GetDeployPathFromExportPath(dataFile))); } } gameProgram.ProjectFile.StartInfo.Add( c => c == config, StartInfoFor(config, EntryPointExecutableFor(gameProgram, config))); gameProgram.ProjectFile.BuildCommand.Add( c => c == config, new BeeBuildCommand(GameDeployBinaryFor(gameProgram, config).ToString(), false, false).ToExecuteArgs()); } foreach (var config in configsToUse) { DotNetAssembly setupGame = gameProgram.SetupSpecificConfiguration(config); if (config.TargetFramework == TargetFramework.Tiny) { var tinyStandard = new DotNetAssembly(Il2Cpp.Distribution.Path.Combine("build/profiles/Tiny/Facades/netstandard.dll"), Framework.FrameworkNone); setupGame = setupGame.WithDeployables(tinyStandard); } var postILProcessedGame = ILPostProcessorTool.SetupInvocation( setupGame, config, gameProgram.Defines.For(config).ToArray()); var postTypeRegGenGame = TypeRegistrationTool.SetupInvocation(postILProcessedGame, config); configToSetupGame[config] = postTypeRegGenGame; } var il2CppOutputProgram = new Il2Cpp.Il2CppOutputProgram(gameProgram.AsmDefDescription.Name); var configToSetupGameBursted = new Dictionary <DotsRuntimeCSharpProgramConfiguration, DotNetAssembly>(); foreach (var kvp in configToSetupGame) { var config = kvp.Key; var setupGame = kvp.Value; if (config.UseBurst) { BurstCompiler burstCompiler = null; if (config.Platform is WindowsPlatform) { burstCompiler = new BurstCompilerForWindows64(); burstCompiler.Link = false; } else if (config.Platform is MacOSXPlatform) { burstCompiler = new BurstCompilerForMac(); burstCompiler.Link = false; } else if (config.Platform is IosPlatform) { burstCompiler = new BurstCompilerForiOS(); burstCompiler.EnableStaticLinkage = true; burstCompiler.ObjectFileExtension = "a"; } else if (config.Platform is LinuxPlatform) { burstCompiler = new BurstCompilerForLinuxWaitingForBurstRelease(); } else if (config.Platform is AndroidPlatform) { burstCompiler = new BurstCompilerForAndroid(); burstCompiler.EnableStaticLinkage = false; burstCompiler.Link = false; burstCompiler.EnableDirectExternalLinking = true; if (config.NativeProgramConfiguration.ToolChain.Architecture is Arm64Architecture) { burstCompiler.TargetArchitecture = "ARMV8A_AARCH64"; } } else if (config.Platform is WebGLPlatform) { burstCompiler = new BurstCompilerForEmscripten(); burstCompiler.EnableStaticLinkage = true; burstCompiler.DisableVectors = false; } // Only generate marshaling info for platforms that require marshalling (e.g. Windows DotNet) // but also if collection checks are enabled (as that is why we need marshalling) burstCompiler.EnableJobMarshalling &= config.EnableUnityCollectionsChecks; burstCompiler.SafetyChecks = config.EnableUnityCollectionsChecks; burstCompiler.DisableWarnings = "BC1370"; // Suppress warning for burst function throwing an exception var outputDir = $"artifacts/{game.Name}/{config.Identifier}_bursted"; var burstLibName = "lib_burst_generated"; DotNetAssembly burstedGame = setupGame; var burstlib = BurstCompiler.SetupBurstCompilationForAssemblies( burstCompiler, setupGame, new NPath(outputDir).Combine("bclobj"), outputDir, burstLibName, out burstedGame); if ((config.Platform is IosPlatform || config.Platform is AndroidPlatform) && config.NativeProgramConfiguration.ToolChain.DynamicLibraryFormat.Extension == "a") // static lib based toolchain { il2CppOutputProgram.Libraries.Add(c => c.Equals(config.NativeProgramConfiguration), burstlib); il2CppOutputProgram.Defines.Add( c => c.Equals(config.NativeProgramConfiguration), $"FORCE_PINVOKE_{burstLibName}_INTERNAL"); } else if (config.Platform is WebGLPlatform) { il2CppOutputProgram.Libraries.Add(c => c.Equals(config.NativeProgramConfiguration), burstlib); } else { var burstDynamicLib = new NativeProgram(burstLibName); burstDynamicLib.Libraries.Add(c => c.Equals(config.NativeProgramConfiguration), burstlib); burstDynamicLib.Libraries.Add( c => c.Equals(config.NativeProgramConfiguration), gameProgram.TransitiveReferencesFor(config) .Where( p => p is DotsRuntimeCSharpProgram && ((DotsRuntimeCSharpProgram)p).NativeProgram != null) .Select( p => new NativeProgramAsLibrary(((DotsRuntimeCSharpProgram)p).NativeProgram) { BuildMode = NativeProgramLibraryBuildMode.Dynamic })); if (config.Platform is IosPlatform || config.Platform is AndroidPlatform) { NativeJobsPrebuiltLibrary.AddToNativeProgram(burstDynamicLib); } DotsRuntimeCSharpProgram.SetupDotsRuntimeNativeProgram(burstLibName, burstDynamicLib); var builtBurstLib = burstDynamicLib.SetupSpecificConfiguration( config.NativeProgramConfiguration, config.NativeProgramConfiguration.ToolChain.DynamicLibraryFormat); burstedGame = burstedGame.WithDeployables(builtBurstLib); } configToSetupGameBursted[config] = burstedGame; } else { configToSetupGameBursted[config] = setupGame; } } var configToSetupGameStripped = new Dictionary <DotsRuntimeCSharpProgramConfiguration, DotNetAssembly>(); foreach (var kvp in configToSetupGameBursted) { var config = kvp.Key; var setupGame = kvp.Value; if (config.ScriptingBackend == ScriptingBackend.TinyIl2cpp) { setupGame = Il2Cpp.UnityLinker.SetupInvocation(setupGame, $"artifacts/{game.Name}/{config.Identifier}_stripped", config.NativeProgramConfiguration); il2CppOutputProgram.SetupConditionalSourcesAndLibrariesForConfig(config, setupGame); configToSetupGameStripped[kvp.Key] = setupGame; } else { configToSetupGameStripped[kvp.Key] = kvp.Value; } } foreach (var kvp in configToSetupGameStripped) { var config = kvp.Key; var setupGame = kvp.Value; NPath deployPath = GameDeployDirectoryFor(gameProgram, config); IDeployable deployedGame; NPath entryPointExecutable = null; if (config.ScriptingBackend == ScriptingBackend.TinyIl2cpp) { var tinyShellFileName = "tiny_shell.html"; NPath tinyShellPath = new NPath(new NPath(gameProgram.FileName).FileNameWithoutExtension).Combine(config.Identifier, "WebTemplate", tinyShellFileName); il2CppOutputProgram.DynamicLinkerSettingsForEmscripten().Add(c => c.WithShellFile(tinyShellPath)); var builtNativeProgram = il2CppOutputProgram.SetupSpecificConfiguration( config.NativeProgramConfiguration, config.NativeProgramConfiguration.ExecutableFormat ) .WithDeployables(setupGame.RecursiveRuntimeDependenciesIncludingSelf.SelectMany(a => a.Deployables.Where(d => !(d is DotNetAssembly) && !(d is StaticLibrary))) .ToArray()); if (builtNativeProgram is IPackagedAppExtension) { (builtNativeProgram as IPackagedAppExtension).SetAppPackagingParameters( gameProgram.AsmDefDescription.Name, config.DotsConfiguration); } if (config.PlatformBuildConfig is WebBuildConfig webBuildConfig) { if (webBuildConfig.SingleFile) { deployedGame = new DeployableFile(GameDeployBinaryFor(gameProgram, config)); CopyTool.Instance().Setup(deployedGame.Path, (builtNativeProgram as EmscriptenExecutable).Path); } else { deployedGame = builtNativeProgram.DeployTo(deployPath); } var webTemplateFolder = webBuildConfig.WebTemplateFolder; if (String.IsNullOrEmpty(webTemplateFolder)) { webTemplateFolder = LowLevelRoot.Combine("WebSupport", "WebTemplates", "Default").ToString(); } if (new NPath(webTemplateFolder).IsRelative) { webTemplateFolder = new NPath("../..").Combine(webTemplateFolder).MakeAbsolute().ToString(); } if (!new NPath(webTemplateFolder).Combine(tinyShellFileName).FileExists()) { throw new InvalidProgramException($"Web template folder \"{webTemplateFolder}\" doesn't contain \"{tinyShellFileName}\" file."); } foreach (var templateFilePath in new NPath(webTemplateFolder).Files(recurse:true)) { string fileRelativePath = templateFilePath.ToString().Substring(webTemplateFolder.Length + 1); if (fileRelativePath == tinyShellFileName) { NPath shellPackager = LowLevelRoot.Combine("WebSupport", "package_shell_file.js"); NPath tinyShellJS = LowLevelRoot.Combine("WebSupport", "tiny_shell.js"); var inputs = new List <NPath> { TinyEmscripten.NodeExe, shellPackager, templateFilePath, tinyShellJS }; var commandLineArguments = new List <string> { shellPackager.ToString(), "--outputHtml", tinyShellPath.ToString(), "--inputShellHtml", templateFilePath.ToString(), "--inputShellJs", tinyShellJS.ToString() }; NPath exportManifest = new NPath(new NPath(gameProgram.FileName).FileNameWithoutExtension).Combine(config.Identifier, "export.manifest"); if (webBuildConfig.SingleFile && exportManifest.FileExists()) { inputs.Add(exportManifest.MakeAbsolute().ReadAllLines().Select(d => new NPath(d))); NPath assetRootDirectory = new NPath(new NPath(gameProgram.FileName).FileNameWithoutExtension).Combine(config.Identifier); commandLineArguments.AddRange(new List <string> { "--assetRootDirectory", assetRootDirectory.ToString(), "--assetManifest", exportManifest.ToString() }); } Backend.Current.AddAction( actionName: "Package Shell File", targetFiles: new NPath[] { tinyShellPath }, inputs: inputs.ToArray(), executableStringFor: TinyEmscripten.NodeExe.InQuotes(), commandLineArguments: commandLineArguments.Select(d => d.InQuotes()).ToArray() ); Backend.Current.AddDependency(deployedGame.Path, tinyShellPath); } else if (!templateFilePath.HasExtension("meta")) { var targetPath = deployPath.Combine(fileRelativePath); CopyTool.Instance().Setup(targetPath, templateFilePath); Backend.Current.AddDependency(deployedGame.Path, targetPath); } } } else { deployedGame = builtNativeProgram.DeployTo(deployPath); } entryPointExecutable = deployedGame.Path; if (config.EnableManagedDebugging && !(builtNativeProgram is IPackagedAppExtension)) { Backend.Current.AddDependency(deployedGame.Path, Il2Cpp.CopyIL2CPPMetadataFile(deployPath, setupGame)); } // make sure http-server gets fetched from stevedore. this should probably go elsewhere, but this is // a convenient quick hack place. if (config.PlatformBuildConfig is WebBuildConfig) { var httpserver = new StevedoreArtifact("http-server"); httpserver.GenerateUnusualPath(); var httpserverpath = httpserver.GetUnusualPath().Combine("bin", "http-server"); Backend.Current.AddDependency(deployedGame.Path, httpserverpath); } } else { deployedGame = setupGame.DeployTo(deployPath); var dotNetAssembly = (DotNetAssembly)deployedGame; //Usually a dotnet runtime game does not have a static void main(), and instead references another "entrypoint asmdef" that provides it. //This is convenient, but what makes it weird is that you have to start YourEntryPoint.exe instead of YourGame.exe. Until we have a better //solution for this, we're going to copy YourEntryPoint.exe to YourGame.exe, so that it's easier to find, and so that when it runs and you look //at the process name you understand what it is. if (deployedGame.Path.HasExtension("dll")) { var to = deployPath.Combine(deployedGame.Path.ChangeExtension("exe").FileName); // Do an explicit check for the entrypoint.exe as a program may refer to other exes as assembly references var from = dotNetAssembly.RecursiveRuntimeDependenciesIncludingSelf.SingleOrDefault(a => a.Path.FileName == "Unity.Runtime.EntryPoint.exe")?.Path; if (from == null) { throw new InvalidProgramException($"Program {dotNetAssembly.Path} is an executable-like thing, but doesn't reference anything with Main"); } Backend.Current.AddDependency(deployedGame.Path, CopyTool.Instance().Setup(to, from)); entryPointExecutable = to; } else { entryPointExecutable = deployedGame.Path; } } //Because we use multidag, and try to not run all the setupcode when we just want to create projectfiles, we have a bit of a challenge. //Projectfiles require exact start and build commands. So we need to have a cheap way to calculate those. However, it's important that they //exactly match the actual place where the buildprogram is going to place our files. If these don't match things break down. The checks //in this block, they compare the "quick way to determine where the binary will be placed, and what the start executable is", with the //actual return values returned from .DeployTo(), when we do run the actual buildcode. NPath deployedGamePath = GameDeployBinaryFor(gameProgram, config); //Identifier with slash means that this is complementary target and we should skip steps which are main target specific. //See comment in DotsConfigs.cs DotsConfigs.MakeConfigs() method for details. if (config.Identifier.IndexOf('/') != -1) { continue; } if (deployedGame.Path != deployedGamePath) { throw new InvalidProgramException($"We expected deployPath to be {deployedGamePath}, but in reality it was {deployedGame.Path}"); } var expectedEntryPointExecutable = EntryPointExecutableFor(gameProgram, config); if (entryPointExecutable != expectedEntryPointExecutable) { throw new InvalidProgramException($"We expected entryPointExecutable to be {expectedEntryPointExecutable}, but in reality it was {entryPointExecutable}"); } Backend.Current.AddAliasDependency(config.Identifier, deployedGamePath); } return(gameProgram); }
public static BagOfObjectFilesLibrary SetupBurstCompilationForAssemblies( BurstCompiler compiler, DotNetAssembly unpatchedInputAssembly, NPath outputDirForObjectFile, NPath outputDirForPatchedAssemblies, string pinvokeName, out DotNetAssembly patchedAssembly) { var objectFile = outputDirForObjectFile.Combine("lib_burst_generated_part_0" + compiler.ObjectFileExtension); patchedAssembly = unpatchedInputAssembly.ApplyDotNetAssembliesPostProcessor( outputDirForPatchedAssemblies, (inputAssemblies, targetDir) => { var inputPaths = inputAssemblies.SelectMany(asm => { var ret = new List <NPath> { asm.Path }; if (asm.DebugSymbolPath != null) { ret.Add(asm.DebugSymbolPath); } return(ret); }); var commandLineArguments = new[] { $"--platform={compiler.TargetPlatform}", $"--backend=burst-llvm", $"--target={compiler.TargetArchitecture}", $"--format={compiler.ObjectFormat}", compiler.SafetyChecks ? "--safety-checks" : "", $"--dump=\"None\"", compiler.DisableVectors ? "--disable-vectors" : "", compiler.Link ? "" : "--nolink", $"--float-precision={compiler.FloatPrecision}", $"--keep-intermediate-files", "--verbose", $"--patch-assemblies-into={outputDirForPatchedAssemblies}", $"--output={objectFile.Parent.Combine(pinvokeName)}", $"--only-static-methods", "--method-prefix=burstedmethod_", $"--pinvoke-name={pinvokeName}" }.Concat(inputAssemblies.Select(asm => $"--root-assembly={asm.Path}")); if (!compiler.UseOwnToolchain) { commandLineArguments = commandLineArguments.Concat(new[] { "--no-native-toolchain" }); } var executableStringFor = HostPlatform.IsWindows ? BurstExecutable.ToString(SlashMode.Native) : "mono"; if (!HostPlatform.IsWindows) { commandLineArguments = new[] { BurstExecutable.ToString(SlashMode.Native) } } .Concat(commandLineArguments); var commandLineArgumentsArray = commandLineArguments.ToArray(); Backend.Current.AddAction( "Burst", //todo: make burst process pdbs inputPaths.Select(p => targetDir.Combine(p.FileName)).Concat(new[] { objectFile }).ToArray(), inputPaths.Concat(new[] { BurstExecutable }).ToArray(), executableStringFor, commandLineArgumentsArray); });
private static DotsRuntimeCSharpProgram SetupGame(AsmDefDescription game) { DotsRuntimeCSharpProgram gameProgram = GetOrMakeDotsRuntimeCSharpProgramFor(game); var withoutExt = new NPath(gameProgram.FileName).FileNameWithoutExtension; NPath exportManifest = new NPath(withoutExt + "/export.manifest"); Backend.Current.RegisterFileInfluencingGraph(exportManifest); if (exportManifest.FileExists()) { var dataFiles = exportManifest.MakeAbsolute().ReadAllLines(); foreach (var dataFile in dataFiles.Select(d => new NPath(d))) { gameProgram.SupportFiles.Add(new DeployableFile(dataFile, "Data/" + dataFile.FileName)); } } var configToSetupGame = DotsConfigs.Configs.ToDictionary(config => config, config => { DotNetAssembly setupGame = gameProgram.SetupSpecificConfiguration(config); return(TypeRegistrationTool.SetupInvocation(setupGame, config)); }); var il2CppOutputProgram = new Il2Cpp.Il2CppOutputProgram(gameProgram.FileName + "_il2cpp"); foreach (var kvp in configToSetupGame) { var config = kvp.Key; var setupGame = kvp.Value; if (config.ScriptingBackend == ScriptingBackend.TinyIl2cpp) { setupGame = Il2Cpp.UnityLinker.SetupInvocation(setupGame, $"artifacts/{game.Name}/{config.Identifier}_stripped", config.NativeProgramConfiguration); il2CppOutputProgram.SetupConditionalSourcesAndLibrariesForConfig(config, setupGame); } } foreach (var kvp in configToSetupGame) { var config = kvp.Key; var setupGame = kvp.Value; NPath deployPath = $"build/{game.Name}/{game.Name}-{config.Identifier}"; IDeployable deployedGame; if (config.ScriptingBackend == ScriptingBackend.TinyIl2cpp) { var builtNativeProgram = il2CppOutputProgram.SetupSpecificConfiguration( config.NativeProgramConfiguration, config.NativeProgramConfiguration.ExecutableFormat ) .WithDeployables(setupGame.RecursiveRuntimeDependenciesIncludingSelf.SelectMany(a => a.Deployables.Where(d => !(d is DotNetAssembly) && !(d is StaticLibrary))) .ToArray()); deployedGame = builtNativeProgram.DeployTo(deployPath); } else { deployedGame = setupGame.DeployTo(deployPath); var dotNetAssembly = (DotNetAssembly)deployedGame; //Usually a dotnet runtime game does not have a static void main(), and instead references another "entrypoint asmdef" that provides it. //This is convenient, but what makes it weird is that you have to start YourEntryPoint.exe instead of YourGame.exe. Until we have a better //solution for this, we're going to copy YourEntryPoint.exe to YourGame.exe, so that it's easier to find, and so that when it runs and you look //at the process name you understand what it is. if (deployedGame.Path.HasExtension("dll")) { var to = deployPath.Combine(deployedGame.Path.ChangeExtension("exe").FileName); var from = dotNetAssembly.RecursiveRuntimeDependenciesIncludingSelf.Single(a => a.Path.HasExtension("exe")).Path; Backend.Current.AddDependency(deployedGame.Path, CopyTool.Instance().Setup(to, from)); } } NPath deployedGamePath = deployedGame.Path; gameProgram.ProjectFile.StartInfo.Add(c => c == config, StartInfoFor(config, deployedGame)); gameProgram.ProjectFile.BuildCommand.Add(c => c == config, new BeeBuildCommand(deployedGamePath.ToString(), false, false).ToExecuteArgs()); Backend.Current.AddAliasDependency($"{game.Name.ToLower()}-{config.Identifier}", deployedGamePath); Backend.Current.AddAliasDependency($"{game.Name.ToLower()}-all", deployedGamePath); } return(gameProgram); }
protected virtual DotNetAssembly SetupNativeProgram(CSharpProgramConfiguration config, DotNetAssembly result) { var dotsConfig = (DotsRuntimeCSharpProgramConfiguration)config; var npc = dotsConfig.NativeProgramConfiguration; if (NativeProgram != null && NativeProgram.Sources.ForAny().Any()) { BuiltNativeProgram setupSpecificConfiguration = NativeProgram.SetupSpecificConfiguration(npc, npc.ToolChain.DynamicLibraryFormat ?? npc.ToolChain.StaticLibraryFormat); result = result.WithDeployables(setupSpecificConfiguration); } return(result); }
protected override DotNetAssembly SetupNativeProgram(CSharpProgramConfiguration config, DotNetAssembly result) { BindGem.Instance().SetupInvocation(result, (DotsRuntimeCSharpProgramConfiguration)config); return(base.SetupNativeProgram(config, result)); }
static void Main() { BeeRootValue = BuildProgramConfigFile.AsmDefDescriptionFor("Unity.Tiny.Text").Path.Parent.Parent.Parent.Combine("DotsPlayer/bee~"); StevedoreGlobalSettings.Instance = new StevedoreGlobalSettings { // Manifest entries always override artifact IDs hard-coded in Bee // Setting EnforceManifest to true will also ensure no artifacts // are used without being listed in a manifest. EnforceManifest = true, Manifest = { BeeRootValue.Combine("manifest.stevedore"), }, }; //The stevedore global manifest will override DownloadableCsc.Csc72 artifacts and use Csc73 CSharpProgram.DefaultConfig = new CSharpProgramConfiguration(CSharpCodeGen.Release, DownloadableCsc.Csc72); UnityLowLevel = new DotsRuntimeCSharpProgram($"{LowLevelRoot}/Unity.LowLevel") { References = { UnsafeUtility.DotNetAssembly }, Unsafe = true }; ZeroJobs = new DotsRuntimeCSharpProgram(BeeRoot.Parent.Combine("ZeroJobs"), "Unity.ZeroJobs") { References = { UnityLowLevel }, Unsafe = true }; var nunit = new StevedoreArtifact("nunit-framework"); Backend.Current.Register(nunit); NUnitLite = new DotNetAssembly(nunit.Path.Combine("bin", "net40", "nunitlite.dll"), Framework.Framework40); NUnitFramework = new DotNetAssembly(nunit.Path.Combine("bin", "net40", "nunit.framework.dll"), Framework.Framework40); //any asmdef that sits next to a .project file we will consider a tiny game. var asmDefDescriptions = BuildProgramConfigFile.AssemblyDefinitions.ToArray(); var gameAsmDefs = asmDefDescriptions.Where(d => d.Path.Parent.Files("*.project").Any()); var gamePrograms = gameAsmDefs.Select(SetupGame).ToArray(); //any asmdef that has .Tests in its name, is going to be our indicator for being a test project for now. var testAsmDefs = asmDefDescriptions.Where(ad => ad.Name.EndsWith(".Tests")); var testPrograms = testAsmDefs.Where(asm => asm.PackageSource != "BuiltIn" && asm.PackageSource != "Registry") .Select(SetupTest) .ExcludeNulls() .ToArray(); var vs = new VisualStudioSolution() { Path = BuildProgramConfigFile.UnityProjectPath.Combine($"{BuildProgramConfigFile.ProjectName}-Dots.sln").RelativeTo(NPath.CurrentDirectory), DefaultSolutionFolderFor = file => (file.Name.Contains("Unity.") || file.Name == "mscorlib") ? "Unity" : "" }; var unityToolsFolder = "Unity/tools"; if (BeeRoot.IsChildOf(BuildProgramConfigFile.UnityProjectPath)) { vs.Projects.Add(new CSharpProjectFileReference("buildprogram.gen.csproj"), unityToolsFolder); } foreach (var gameProgram in gamePrograms) { vs.Projects.Add(gameProgram); } foreach (var testProgram in testPrograms) { vs.Projects.Add(testProgram); } var toolPrograms = new[] { TypeRegistrationTool.EntityBuildUtils, TypeRegistrationTool.TypeRegProgram, BindGem.Instance().Program }; if (BeeRoot.IsChildOf(BuildProgramConfigFile.UnityProjectPath)) { foreach (var p in toolPrograms) { vs.Projects.Add(p, unityToolsFolder); } } foreach (var config in DotsConfigs.Configs) { //we want dotnet to be the default, and we cannot have nice things: https://aras-p.info/blog/2017/03/23/How-does-Visual-Studio-pick-default-config/platform/ var solutionConfigName = config.Identifier == "dotnet" ? "Debug (dotnet)": config.Identifier; vs.Configurations.Add(new SolutionConfiguration(solutionConfigName, (configurations, file) => { var firstOrDefault = configurations.FirstOrDefault(c => c == config); return(new Tuple <IProjectConfiguration, bool>( firstOrDefault ?? configurations.First(), firstOrDefault != null || toolPrograms.Any(t => t.ProjectFile == file))); })); } Backend.Current.AddAliasDependency("ProjectFiles", vs.Setup()); EditorToolsBuildProgram.Setup(BeeRoot); }
public static DotNetAssembly SetupInvocation(DotNetAssembly inputGame, NPath outputPath, NativeProgramConfiguration config) { return(inputGame.ApplyDotNetAssembliesPostProcessor(outputPath, (inputAssemblies, targetDir) => AddActions(inputAssemblies, targetDir, config) )); }
static BindGemResult BindGemOutputFor(DotNetAssembly assembly, DotsRuntimeCSharpProgramConfiguration config) => SupportsBindgem(assembly.Path.FileName) ? MakeBindGemResultFor(assembly.Path.FileName, config) : null;
static void Main() { BeeRootValue = AsmDefConfigFile.AsmDefDescriptionFor("Unity.Runtime.EntryPoint").Path.Parent.Parent.Combine("bee~"); Backend.Current.StevedoreSettings = new StevedoreSettings { // Manifest entries always override artifact IDs hard-coded in Bee // Setting EnforceManifest to true will also ensure no artifacts // are used without being listed in a manifest. EnforceManifest = true, Manifest = { BeeRootValue.Combine("manifest.stevedore"), }, }; // When bee needs to run a second time because the Tundra graph has suggested a need to rerun, // you cannot use LazyStatics or Statics in cases where you construct a program that gets compiled in the first run. // This is because previously bee when it ran a second time would spawn a new process of the buildprogram but in the // new bee we actually run it in the same process which means that you need to construct new programs or clear out old state. TinyIO = null; UnityTinyBurst = null; UnityLowLevel = null; ZeroJobs = null; ILPostProcessorAssemblies = null; ILPostProcessorTool._ilPostProcessorRunnerProgramInternal = null; _cache.Clear(); DotsConfigs.Clear(); CSharpProgram.DefaultConfig = new CSharpProgramConfiguration(CSharpCodeGen.Release); PerConfigBuildSettings = DotsConfigs.MakeConfigs(); foreach (var rootAssemblyName in PerConfigBuildSettings.Keys) { AsmDefConfigFile.AsmDefDescriptionFor(rootAssemblyName).IsTinyRoot = true; } //any asmdef that sits next to a .project file we will consider a tiny game. var asmDefDescriptions = AsmDefConfigFile.AssemblyDefinitions.ToArray(); var burstAsmDef = asmDefDescriptions.First(d => d.Name == "Unity.Burst"); var tinyIOAsmDef = asmDefDescriptions.First(d => d.Name == "Unity.Tiny.IO"); UnityLowLevel = new DotsRuntimeCSharpProgram($"{LowLevelRoot}/Unity.LowLevel") { References = { UnsafeUtility.Program }, Unsafe = true }; UnityLowLevel.NativeProgram.Libraries.Add(IsLinux, new SystemLibrary("dl")); UnityLowLevel.NativeProgram.Libraries.Add(c => c.Platform is AndroidPlatform, new SystemLibrary("log")); TinyIO = GetOrMakeDotsRuntimeCSharpProgramFor(tinyIOAsmDef); UnityTinyBurst = new DotsRuntimeCSharpProgram($"{LowLevelRoot}/Unity.Tiny.Burst") { References = { UnityLowLevel }, Unsafe = true }; ZeroJobs = new DotsRuntimeCSharpProgram($"{LowLevelRoot}/Unity.ZeroJobs") { References = { UnityLowLevel, UnityTinyBurst, GetOrMakeDotsRuntimeCSharpProgramFor(burstAsmDef), TinyIO }, Unsafe = true }; UnityCompilationPipeline = new DotNetAssembly( AsmDefConfigFile.UnityCompilationPipelineAssemblyPath, HackedFrameworkToUseForProjectFilesIfNecessary); var nunit = new StevedoreArtifact("nunit-framework"); NUnitLite = new DotNetAssembly(nunit.Path.Combine("bin", "net40", "nunitlite.dll"), Framework.Framework471); NUnitFramework = new DotNetAssembly(nunit.Path.Combine("bin", "net40", "nunit.framework.dll"), Framework.Framework471); BurstCompiler.BurstExecutable = GetBurstExecutablePath(burstAsmDef).QuoteForProcessStart(); var ilPostProcessorPrograms = asmDefDescriptions .Where(d => d.IsILPostProcessorAssembly) .Select(GetOrMakeDotsRuntimeCSharpProgramFor); ILPostProcessorAssemblies = ilPostProcessorPrograms.Select(p => { /* * We want to compile the ilpp's for hostdotnet, even though we might be compiling the actual game * for something else (e.g. wasm). The ilpp's may reference actual game assemblies, which may have * native code. We do not want to set up the native code for those game assemblies for hostdotnet, * because a) it makes no sense and b) the native toolchains might not be installed, and it would be * dumb to require that to build for an unrelated platform. * * So, set the NativeProgramConfiguration to null, and set up with that. But first, set the platform, * because normally the platform comes from the npc. */ var tmp = DotsConfigs.HostDotnet; tmp.Platform = DotsConfigs.HostDotnet.Platform; tmp.NativeProgramConfiguration = null; var ret = p.SetupSpecificConfiguration(tmp); return(ret); }) .ToArray(); var tinyMainAsmDefs = asmDefDescriptions.Where(a => a.IsTinyRoot); var gameAsmDefs = tinyMainAsmDefs.Union(AsmDefConfigFile.TestableAssemblyDefinitions); foreach (var gameAsmdef in gameAsmDefs) { var gameProgram = GetOrMakeDotsRuntimeCSharpProgramFor(gameAsmdef); if (gameProgram.AsmDefDescription.NeedsEntryPointAdded()) { gameProgram.References.Add( GetOrMakeDotsRuntimeCSharpProgramFor( AsmDefConfigFile.AsmDefDescriptionFor("Unity.Runtime.EntryPoint"))); } } var gamePrograms = gameAsmDefs.Select(SetupGame).ExcludeNulls().ToArray(); var vs = new VisualStudioSolution { Path = AsmDefConfigFile.UnityProjectPath.Combine($"{AsmDefConfigFile.ProjectName}-Dots.sln").RelativeTo(NPath.CurrentDirectory), DefaultSolutionFolderFor = file => (file.Name.Contains("Unity.") || file.Name == "mscorlib") ? "Unity" : "" }; var unityToolsFolder = "Unity/tools"; var unityILPostProcessorsFolder = "Unity/ILPostProcessing"; if (BeeRoot.IsChildOf(AsmDefConfigFile.UnityProjectPath)) { var buildProjRef = new CSharpProjectFileReference("buildprogram.gen.csproj"); vs.Projects.Add(buildProjRef, unityToolsFolder); } foreach (var gameProgram in gamePrograms) { vs.Projects.Add(gameProgram); } var toolPrograms = new[] { TypeRegistrationTool.EntityBuildUtils, TypeRegistrationTool.TypeRegProgram }; foreach (var p in toolPrograms) { vs.Projects.Add(p, unityToolsFolder); } vs.Projects.Add(ILPostProcessorTool.ILPostProcessorRunnerProgram, unityILPostProcessorsFolder); foreach (var p in ilPostProcessorPrograms) { vs.Projects.Add(p, unityILPostProcessorsFolder); } foreach (var config in PerConfigBuildSettings.SelectMany(entry => entry.Value)) { //we want dotnet to be the default, and we cannot have nice things: https://aras-p.info/blog/2017/03/23/How-does-Visual-Studio-pick-default-config/platform/ var solutionConfigName = config.Identifier == "dotnet" ? "Debug (dotnet)": config.Identifier; vs.Configurations.Add(new SolutionConfiguration(solutionConfigName, (configurations, file) => { var firstOrDefault = configurations.FirstOrDefault(c => c == config); return(new Tuple <IProjectConfiguration, bool>( firstOrDefault ?? configurations.First(), firstOrDefault != null || toolPrograms.Any(t => t.ProjectFile == file))); })); } VisualStudioSolution = vs; EditorToolsBuildProgram.Setup(BeeRoot); // Run this before solution setup, to potentially give this a chance to muck with the VisualStudioSolution DotsBuildCustomizer.RunAllCustomizers(); if (!IsRequestedTargetExactlySingleAppSingleConfig()) { Backend.Current.AddAliasDependency("ProjectFiles", vs.Setup()); } }
private static NPath[] SetupLinker(List <NPath> copiedAssemblies, List <DotNetAssembly> postProcessedPlayerAssemblies, BuildTarget buildTarget, NPath workingDirectory) { /* * Invoking UnityLinker with arguments: -out=C:/dots/Samples/Temp/StagingArea/Data/Managed/tempStrip -x=C:/Users/Lucas/AppData/Local/Temp/tmp5eb9e11d.tmp * -x=C:/dots/Samples/Temp/StagingArea/Data/Managed/TypesInScenes.xml -x=C:/dots/Samples/Temp/StagingArea/Data/Managed/DotsStripping.xml * -d=C:/dots/Samples/Temp/StagingArea/Data/Managed --include-unity-root-assembly=C:/dots/Samples/Temp/StagingArea/Data/Managed/Assembly-CSharp.dll * --include-unity-root-assembly=C:/dots/Samples/Temp/StagingArea/Data/Managed/RotateMe.dll --include-unity-root-assembly=C:/dots/Samples/Temp/StagingArea/Data/Managed/Unity.Scenes.Hybrid.dll * --include-unity-root-assembly=C:/dots/Samples/Temp/StagingArea/Data/Managed/Samples.GridPath.dll --include-unity-root-assembly=C:/dots/Samples/Temp/StagingArea/Data/Managed/Unity.Entities.Hybrid.dll * --include-unity-root-assembly=C:/dots/Samples/Temp/StagingArea/Data/Managed/SubsceneWithBuildSettings.dll --include-unity-root-assembly=C:/dots/Samples/Temp/StagingArea/Data/Managed/HelloCube.dll * --include-unity-root-assembly=C:/dots/Samples/Temp/StagingArea/Data/Managed/Samples.Boids.dll --dotnetruntime=il2cpp --dotnetprofile=unityaot --use-editor-options --include-directory=C:/dots/Samples/Temp/StagingArea/Data/Managed * --editor-settings-flag=Development --rule-set=Conservative --editor-data-file=C:/dots/Samples/Temp/StagingArea/Data/Managed/EditorToUnityLinkerData.json --platform=WindowsDesktop * --engine-modules-asset-file=C:/unity/build/WindowsStandaloneSupport/Whitelists/../modules.asset * C:\unity\build\WindowsEditor\Data\il2cpp\build/deploy/net471/UnityLinker.exe exited after 4100 ms. * * "C:\\code\\unity-src-git\\build\\WindowsEditor\\Data\\il2cpp\\build\\deploy\\net471\\UnityLinker.exe --dotnetruntime=mono --dotnetprofile=unityaot * --use-editor-options --include-directory=\"artifacts\\managedassemblies\" --editor-settings-flag=Development --rule-set=conservative --out=\"artifacts\\linkeroutput\" * --include-unity-root-assembly=\"C:/code/dots/Samples/Library/IncrementalClassicBuildPipeline/Win64-LiveLink/artifacts/UnityEngine.UI.dll/Release/UnityEngine.UI.dll\", \"C:/code/dots/Samples/Library/IncrementalClassicBuildPipeline/Win64-LiveLink/artifacts/Unity.Mathematics.dll/Release/Unity.Mathematics.dll\", \"C:/code/dots/Samples/Library/IncrementalClassicBuildPipeline/Win64-LiveLink/artifacts/Unity.Entities.StaticTypeRegistry.dll/Release/Unity.Entities.StaticTypeRegistry.dll\", \"C:/code/dots/Samples/Library/IncrementalClassicBuildPipeline/Win64-LiveLink/artifacts/Unity.Burst.dll/Release/Unity.Burst.dll\", \"C:/code/dots/Samples/Library/IncrementalClassicBuildPipeline/Win64-LiveLink/artifacts/Unity.ScriptableBuildPipeline.dll/Release/Unity.ScriptableBuildPipeline.dll\", \"C:/code/dots/Samples/Library/IncrementalClassicBuildPipeline/Win64-LiveLink/artifacts/Unity.Collections.dll/Release/Unity.Collections.dll\", \"C:/code/dots/Samples/Library/IncrementalClassicBuildPipeline/Win64-LiveLink/artifacts/Unity.Properties.dll/Release/Unity.Properties.dll\", \"C:/code/dots/Samples/Library/IncrementalClassicBuildPipeline/Win64-LiveLink/artifacts/Unity.Jobs.dll/Release/Unity.Jobs.dll\", \"C:/code/dots/Samples/Library/IncrementalClassicBuildPipeline/Win64-LiveLink/artifacts/Unity.Mathematics.Extensions.dll/Release/Unity.Mathematics.Extensions.dll\", \"C:/code/dots/Samples/Library/IncrementalClassicBuildPipeline/Win64-LiveLink/artifacts/Unity.Entities.dll/Release/Unity.Entities.dll\", \"C:/code/dots/Samples/Library/IncrementalClassicBuildPipeline/Win64-LiveLink/artifacts/Unity.Transforms.dll/Release/Unity.Transforms.dll\", \"C:/code/dots/Samples/Library/IncrementalClassicBuildPipeline/Win64-LiveLink/artifacts/Unity.Entities.Determinism.dll/Release/Unity.Entities.Determinism.dll\", \"C:/code/dots/Samples/Library/IncrementalClassicBuildPipeline/Win64-LiveLink/artifacts/Unity.Mathematics.Extensions.Hybrid.dll/Release/Unity.Mathematics.Extensions.Hybrid.dll\", \"C:/code/dots/Samples/Library/IncrementalClassicBuildPipeline/Win64-LiveLink/artifacts/Unity.Entities.Hybrid.dll/Release/Unity.Entities.Hybrid.dll\", \"C:/code/dots/Samples/Library/IncrementalClassicBuildPipeline/Win64-LiveLink/artifacts/Unity.Transforms.Hybrid.dll/Release/Unity.Transforms.Hybrid.dll\", \"C:/code/dots/Samples/Library/IncrementalClassicBuildPipeline/Win64-LiveLink/artifacts/Unity.Scenes.Hybrid.dll/Release/Unity.Scenes.Hybrid.dll\", \"C:/code/dots/Samples/Library/IncrementalClassicBuildPipeline/Win64-LiveLink/artifacts/Unity.Rendering.Hybrid.dll/Release/Unity.Rendering.Hybrid.dll\", \"C:/code/dots/Samples/Library/IncrementalClassicBuildPipeline/Win64-LiveLink/artifacts/Samples.Boids.dll/Release/Samples.Boids.dll\", \"C:/code/dots/Samples/Library/IncrementalClassicBuildPipeline/Win64-LiveLink/artifacts/HelloCube.dll/Release/HelloCube.dll\", \"C:/code/dots/Samples/Library/IncrementalClassicBuildPipeline/Win64-LiveLink/artifacts/Samples.GridPath.dll/Release/Samples.GridPath.dll\", \"C:/code/dots/Samples/Library/IncrementalClassicBuildPipeline/Win64-LiveLink/artifacts/SubsceneWithBuildSettings.dll/Release/SubsceneWithBuildSettings.dll\", \"C:/code/dots/Samples/Library/IncrementalClassicBuildPipeline/Win64-LiveLink/artifacts/Assembly-CSharp.dll/Release/Assembly-CSharp.dll\" * --include-unity-root-assembly=\"C:/code/unity-src-git/build/WindowsStandaloneSupport/Variations/win64_development_mono/Data/Managed/UnityEngine.dll\"", * */ DotNetAssembly linker = new DotNetAssembly( string.IsNullOrEmpty(CustomIL2CPPLocation) ? $"{EditorApplication.applicationContentsPath}/il2cpp/build/deploy/net471/UnityLinker.exe" : $"{CustomIL2CPPLocation}/build/deploy/net471/UnityLinker.exe", Framework.Framework471); var linkerProgram = new DotNetRunnableProgram(linker); var linkXmlFiles = NPath.CurrentDirectory.Combine("Assets").Files("link.xml", true); var unityLinkerProcessors = TypeCacheHelper.ConstructTypesDerivedFrom <IUnityLinkerProcessor>(); var linkerData = new UnityLinkerBuildPipelineData(buildTarget, workingDirectory.ToString()); linkXmlFiles = linkXmlFiles.Concat(unityLinkerProcessors.Select(p => (NPath)p.GenerateAdditionalLinkXmlFile(null, linkerData))).ToArray(); var inputFiles = copiedAssemblies .Concat(postProcessedPlayerAssemblies.Select(p => p.Path)) .Concat(linker.Path.Parent.Files()) .Concat(linkXmlFiles) // .Concat(dotNetRuntime.Inputs) .ToArray(); var searchDirectories = new HashSet <NPath>(); foreach (var file in copiedAssemblies) { searchDirectories.Add(file.Parent); } foreach (var file in postProcessedPlayerAssemblies) { searchDirectories.Add(file.Path.Parent); } searchDirectories.Add(_incrementalClassicSharedData.UnityEngineAssembliesDirectory.ToString()); // Pass along the correct platform names for macOS and Windows desktop targets var platformName = _incrementalClassicSharedData.PlatformName == "Windows" ? "WindowsDesktop" : _incrementalClassicSharedData.PlatformName == "UniversalWindows" ? "WinRT" : _incrementalClassicSharedData.PlatformName; platformName = _incrementalClassicSharedData.PlatformName == "OSX" ? "MacOSX" : platformName; NPath linkerOutputDir = Configuration.RootArtifactsPath.Combine("linkeroutput"); Backend.Current.AddAction("UnityLinker", Array.Empty <NPath>(), inputFiles, linkerProgram.InvocationString, new[] { $"--platform={platformName}", "--dotnetruntime=il2cpp", "--dotnetprofile=unityaot", "--use-editor-options", $"--include-directory={copiedAssemblies.First().Parent.InQuotes(SlashMode.Native)}", "--editor-settings-flag=Development", //if you want to boost up from conservative to aggressive, the linker will start to remove MonoBehaviours. We'd need to add a step that analyzes all assets //in the databuild, and build a list of actually used monobehaviours. this goes very much against the concept of incrementalness. Let's stick to conservative for now.t "--rule-set=Conservative", $"--out={linkerOutputDir.InQuotes(SlashMode.Native)}", $"--search-directory={searchDirectories.Select(d=>d.MakeAbsolute().ToString()).SeparateWithComma()}", $"--include-unity-root-assembly={postProcessedPlayerAssemblies.Where(a => a.Path.FileName != "Unity.Serialization.dll").Select(a => a.Path.MakeAbsolute()).InQuotes().SeparateWithComma()}", $"--engine-modules-asset-file={_incrementalClassicSharedData.PlayerPackageDirectory.Combine("modules.asset").InQuotes(SlashMode.Native)}", linkXmlFiles.Select(f => $"--include-link-xml={f}").SeparateWithSpace(), }, allowUnwrittenOutputFiles: true, supportResponseFile: true, targetDirectories: new[] { linkerOutputDir } ); NPath[] linkerOutputFiles = GuessTargetDirectoryContentsFor(linkerOutputDir, "dummy.dll"); return(linkerOutputFiles); }
private static DotNetAssembly RemovePdbFromStaticTypeRegistry(DotNetAssembly input, DotNetAssembly suggestedOutput) { return(input.Path.FileName == "Unity.Entities.StaticTypeRegistry.dll" ? suggestedOutput.WithDebugSymbolPath(null) : suggestedOutput); }
public (NPath runtimeInitializeOnLoadFile, NPath typeDBfile) SetupTypeDBAndRuntimeInitializeOnLoadFileFor(DotNetAssembly inputAsm) { var searchPathsOneLine = inputAsm.RecursiveRuntimeDependenciesIncludingSelf.Select(x => x.Path.Parent).Distinct().InQuotes().SeparateWithComma(); var inputAssemblyFileName = inputAsm.Path.FileNameWithoutExtension; var args = new[] { "-a", inputAsm.Path.InQuotes(), "-s", searchPathsOneLine, "-o", TypeDBOutputDirectory.InQuotes(), "-n", inputAssemblyFileName.InQuotes(), "-r", "True" }; var runtimeInitializeOnLoadFile = TypeDBOutputDirectory.Combine($"RuntimeInitOnLoad-{inputAssemblyFileName}.json"); var typeDBfile = TypeDBOutputDirectory.Combine($"TypeDb-{inputAssemblyFileName}.json"); Backend.Current.AddAction($"TypeGenerator", new[] { typeDBfile, runtimeInitializeOnLoadFile, }, inputAsm.Paths, executableStringFor: _typeGeneratorExecutable.InvocationString, args, supportResponseFile: true ); return(runtimeInitializeOnLoadFile : runtimeInitializeOnLoadFile, typeDBfile : typeDBfile); }
public void SetupConditionalSourcesAndLibrariesForConfig(DotsRuntimeCSharpProgramConfiguration config, DotNetAssembly setupGame) { NPath[] il2cppGeneratedFiles = SetupInvocation(setupGame); //todo: stop comparing identifier. Sources.Add(npc => ((DotsRuntimeNativeProgramConfiguration)npc).CSharpConfig == config, il2cppGeneratedFiles); Libraries.Add(npc => ((DotsRuntimeNativeProgramConfiguration)npc).CSharpConfig == config, setupGame.RecursiveRuntimeDependenciesIncludingSelf.SelectMany(r => r.Deployables.OfType <StaticLibrary>())); }
public static NPath Il2CppTargetDirForAssembly(DotNetAssembly inputAssembly) { return(inputAssembly.Path.Parent.Combine(inputAssembly.Path.FileName + "-il2cpp-sources")); }
private static DotNetAssembly Clone(NPath outputDir, DotNetAssembly a) { var debugSymbolPath = a.DebugSymbolPath == null ? null : outputDir.Combine(a.DebugSymbolPath.FileName); return(new DotNetAssembly(outputDir.Combine(a.Path.FileName), a.Framework, a.DebugFormat, debugSymbolPath)); }
public static NPath[] SetupInvocation(DotNetAssembly inputAssembly, DotsRuntimeCSharpProgramConfiguration config) { var profile = "unitytiny"; var il2CppTargetDir = Il2CppTargetDirForAssembly(inputAssembly); var args = new List <string>() { "--convert-to-cpp", "--disable-cpp-chunks", // "--directory", $"{InputAssembly.Path.Parent}", "--generatedcppdir", $"{il2CppTargetDir}", // Make settings out of these $"--dotnetprofile={profile}", // Resolve from DotNetAssembly "--libil2cpp-static", "--emit-null-checks=0", "--enable-array-bounds-check=0", "--enable-predictable-output", //"--enable-stacktrace=1" //"--profiler-report", //"--enable-stats", }; if (config.EnableManagedDebugging) { args.Add("--enable-debugger"); } if (config.EnableUnityCollectionsChecks) { args.Add("--development-mode"); } var iarrdis = MoveExeToFront(inputAssembly.RecursiveRuntimeDependenciesIncludingSelf); args.AddRange( iarrdis.SelectMany(a => new[] { "--assembly", a.Path.ToString() })); var sharedFileNames = new List <string> { // static files //"Il2CppComCallableWrappers.cpp", //"Il2CppProjectedComCallableWrapperMethods.cpp", "driver.cpp", "GenericMethods.cpp", "Generics.cpp", "Il2CppGenericComDefinitions.cpp", "ReversePInvokeWrappers.cpp", }; var nonDebuggerExtraFileNames = new[] { "TinyTypes.cpp", "StaticConstructors.cpp", "StringLiterals.cpp", "StaticInitialization.cpp" }; var debuggerExtraFileNames = new[] { "Il2CppGenericClassTable.c", "Il2CppGenericInstDefinitions.c", "Il2CppGenericMethodDefinitions.c", "Il2CppGenericMethodTable.c", "Il2CppMetadataRegistration.c", "Il2CppMetadataUsage.c", "Il2CppTypeDefinitions.c", "Il2CppAttributes.cpp", "Il2CppCodeRegistration.cpp", "Il2CppCompilerCalculateTypeValues.cpp", "Il2CppCompilerCalculateTypeValuesTable.cpp", "Il2CppGenericMethodPointerTable.cpp", "Il2CppInteropDataTable.cpp", "Il2CppInvokerTable.cpp", "Il2CppReversePInvokeWrapperTable.cpp", "UnresolvedVirtualCallStubs.cpp", }; IEnumerable <string> il2cppOutputFileNames = sharedFileNames; if (config.EnableManagedDebugging) { il2cppOutputFileNames = il2cppOutputFileNames.Concat(debuggerExtraFileNames); il2cppOutputFileNames = il2cppOutputFileNames.Concat(iarrdis.Select(asm => asm.Path.FileNameWithoutExtension + "_Debugger.c")); il2cppOutputFileNames = il2cppOutputFileNames.Concat(iarrdis.Select(asm => asm.Path.FileNameWithoutExtension + "_Codegen.c")); } else { il2cppOutputFileNames = il2cppOutputFileNames.Concat(nonDebuggerExtraFileNames); } var il2cppOutputFiles = il2cppOutputFileNames.Concat(iarrdis.Select(asm => asm.Path.FileNameWithoutExtension + ".cpp")) .Select(il2CppTargetDir.Combine).ToArray(); var il2cppInputs = Distribution.GetFileList("build") .Concat(iarrdis.SelectMany(a => a.Paths)) .Concat(new[] { Distribution.Path.Combine("libil2cpptiny", "libil2cpptiny.icalls") }) .Concat(new[] { Il2CppDependencies.GetFileList().First() }); var finalOutputFiles = il2cppOutputFiles; if (config.EnableManagedDebugging) { finalOutputFiles = finalOutputFiles.Concat(new[] { il2CppTargetDir.Combine("Data/Metadata/global-metadata.dat") }).ToArray(); } Backend.Current.AddAction( "Il2Cpp", targetFiles: finalOutputFiles, inputs: il2cppInputs.ToArray(), Il2CppRunnableProgram.InvocationString, args.ToArray()); return(il2cppOutputFiles); }
/// <summary> /// Execute the command /// </summary> public void Exec() { // Affiche la fenetre de dialogue permettant de choisir les assemblies IAssemblySelectorDialog selector = ServiceLocator.Instance.GetService <IAssemblySelectorDialog>(); if (selector.ShowDialog(1)) // Une seule sélection possible { Assembly asm = selector.SelectedAssemblies[0]; using (Transaction transaction = _element.Store.TransactionManager.BeginTransaction("Update model version")) { // Mise à jour de la version du composant et son emplacement initial // et création des nouvelles dépendances (les dépendances actuelles ne seront pas touchées // mais il faudra s'assurer qu'elles soient bien à jour car la procédure ne vérifie que le nom // et ignore la version) _element.InitFromAssembly(asm, true /* creation des nouvelles dépendances*/); transaction.Commit(); } // Vérification si les assemblies existantes possédent la bonne version foreach (AssemblyName assemblyName in asm.GetReferencedAssemblies()) { // On ignore les assemblies systèmes if (Utils.StringCompareEquals(assemblyName.Name, "mscorlib") || assemblyName.Name.StartsWith("System", StringComparison.CurrentCultureIgnoreCase)) { continue; } // On regarde si cette assembly existe déjà dans le modèle DotNetAssembly eam = _element.Component.FindDotNetAssemblyModelFromAssembly(assemblyName); if (eam != null) { if (!assemblyName.Version.Equals((Version)eam.Version)) { using (Transaction transaction = _element.Store.TransactionManager.BeginTransaction("Update assembly version")) { eam.Version = new VersionInfo(assemblyName.Version); transaction.Commit(); } } } else { // Idem pour les composants externes ExternalComponent esm = _element.Component.Model.FindExternalComponentByName(assemblyName.Name); if (esm != null && esm.MetaData != null && esm.MetaData.ComponentType == ComponentType.Library) { if (!assemblyName.Version.Equals((Version)esm.Version)) { // Recherche si il existe un modèle avec la bonne version List <ComponentModelMetadata> versions = RepositoryManager.Instance.ModelsMetadata.Metadatas.GetAllVersions(esm.Id); ComponentModelMetadata metadata = versions.Find(delegate(ComponentModelMetadata m) { return(assemblyName.Version.Equals(m.Version)); }); using (Transaction transaction = _element.Store.TransactionManager.BeginTransaction("Update model version")) { if (metadata != null) { // OK on met a jour esm.Version = metadata.Version; } else // erreur On a pas trouvé de modéle { // Sauvegarde de la bonne version esm.Version = new VersionInfo(assemblyName.Version); // On force à null pour obliger l'utilisateur à sélectionner un // modéle esm.ModelMoniker = Guid.Empty; } transaction.Commit(); } } } } } // Demande si il faut aussi mettre à jour le n° de version du composant if (_element.Visibility == Visibility.Public) { if (MessageBox.Show(String.Format("Do you want to change the current version of the component from {0} to {1}", _element.Component.Model.Version, _element.Version), "Component version change", MessageBoxButtons.YesNo) == DialogResult.Yes) { using (Transaction transaction = _element.Store.TransactionManager.BeginTransaction("Update model version")) { _element.Component.Model.Version = _element.Version; transaction.Commit(); } } } } }
static void AddActions(DotNetAssembly[] inputAssemblies, NPath targetDirectory, NativeProgramConfiguration nativeProgramConfiguration) { var linkerAssembly = new DotNetAssembly(Distribution.Path.Combine("build/deploy/net471/UnityLinker.exe"), Framework.Framework471); var linker = new DotNetRunnableProgram(linkerAssembly); var outputDir = targetDirectory; var isFrameworkNone = inputAssemblies.First().Framework == Framework.FrameworkNone; var rootAssemblies = inputAssemblies.Where(a => a.Path.HasExtension("exe")).Concat(new[] { inputAssemblies.First() }).Distinct(); var linkerArguments = new List <string> { $"--out={outputDir.InQuotes()}", "--use-dots-options", "--dotnetprofile=" + (isFrameworkNone ? "unitytiny" : "unityaot"), }; linkerArguments.AddRange(rootAssemblies.Select(rootAssembly => $"--include-public-assembly={rootAssembly.Path.InQuotes()}")); foreach (var inputDirectory in inputAssemblies.Select(f => f.Path.Parent).Distinct()) { linkerArguments.Add($"--include-directory={inputDirectory.InQuotes()}"); } NPath bclDir = Il2CppDependencies.Path.Combine("MonoBleedingEdge/builds/monodistribution/lib/mono/unityaot"); if (!isFrameworkNone) { linkerArguments.Add($"--search-directory={bclDir.InQuotes()}"); } var targetPlatform = GetTargetPlatformForLinker(nativeProgramConfiguration.Platform); if (!string.IsNullOrEmpty(targetPlatform)) { linkerArguments.Add($"--platform={targetPlatform}"); } var targetArchitecture = GetTargetArchitectureForLinker(nativeProgramConfiguration.ToolChain.Architecture); if (!string.IsNullOrEmpty(targetPlatform)) { linkerArguments.Add($"--architecture={targetArchitecture}"); } if (ManagedDebuggingIsEnabled(nativeProgramConfiguration)) { linkerArguments.Add("--rule-set=aggressive"); // Body modification causes debug symbols to be out of sync linkerArguments.Add("--enable-debugger"); } else { linkerArguments.Add("--rule-set=experimental"); // This will enable modification of method bodies to further reduce size. } // var targetFiles = Unity.BuildTools.EnumerableExtensions.Prepend(nonMainOutputs, mainTargetFile); // targetFiles = targetFiles.Append(bcl); var targetFiles = inputAssemblies.SelectMany(a => a.Paths).Select(i => targetDirectory.Combine(i.FileName)).ToArray(); Backend.Current.AddAction( "UnityLinker", targetFiles: targetFiles, inputs: inputAssemblies.SelectMany(a => a.Paths).Concat(linkerAssembly.Paths).ToArray(), executableStringFor: linker.InvocationString, commandLineArguments: linkerArguments.ToArray(), allowUnwrittenOutputFiles: false, allowUnexpectedOutput: false, allowedOutputSubstrings: new[] { "Output action" }); }
/// <summary> /// Importe des assemblies dans le modèle /// </summary> /// <param name="model">The model.</param> /// <param name="assemblies">Liste des assemblies à importer</param> internal static void ImportAssemblies(CandleModel model, List <Assembly> assemblies) { if (assemblies.Count == 0) { return; } // Si il y a plusieurs assemblies, on va demander lequel est le public Assembly mainAssembly = assemblies[0]; if (assemblies.Count > 1) { if (assemblies.Count > 1) { SelectAssemblyForm form = new SelectAssemblyForm(assemblies); if (form.ShowDialog() == DialogResult.Cancel) { throw new CanceledByUser(); } mainAssembly = form.SelectedAssembly; } } // D'abord le composant BinaryComponent component = model.Component as BinaryComponent; if (component == null) { component = CreateComponent(model, mainAssembly); } else if (component.Assemblies.Count > 0) { // Si il y avait dèjà des assemblies, on n'initialisera pas l'assembly public mainAssembly = null; } // Puis insertion des assemblies, en deux passages car il peut y avoir des dépendances entre assemblies // - Insertion des assemblies // - Création des dépendances // using (Transaction transaction = model.Store.TransactionManager.BeginTransaction("Adding component")) { // Insertion des assemblies internes foreach (Assembly assembly in assemblies) { if (component.FindDotNetAssemblyModelFromAssembly(assembly.GetName()) == null) { DotNetAssembly dotnetAssembly = new DotNetAssembly(model.Store); component.Assemblies.Add(dotnetAssembly); dotnetAssembly.InitFromAssembly(assembly, false); // C'est l'assembly public --> Création d'un port public dotnetAssembly.Visibility = assembly == mainAssembly ? Visibility.Public : Visibility.Private; } } transaction.Commit(); } // Création des dépendances externes using (Transaction transaction = model.Store.TransactionManager.BeginTransaction("Adding references")) { model.Store.TransactionManager.CurrentTransaction.TopLevelTransaction.Context.ContextInfo.Add("Import assemblies", null); foreach (Assembly assembly in assemblies) { DotNetAssembly externalAssembly = component.FindDotNetAssemblyModelFromAssembly(assembly.GetName()); Debug.Assert(externalAssembly != null); externalAssembly.InsertDependencies(assembly); } transaction.Commit(); } }
static void Main() { if (!(Backend.Current is TundraBackend)) { StandaloneBeeDriver.RunBuildProgramInBeeEnvironment("dummy.json", Main); return; } BeeRootValue = AsmDefConfigFile.AsmDefDescriptionFor("Unity.ZeroPlayer.TypeRegGen").Path.Parent.Parent.Combine("bee~"); StevedoreGlobalSettings.Instance = new StevedoreGlobalSettings { // Manifest entries always override artifact IDs hard-coded in Bee // Setting EnforceManifest to true will also ensure no artifacts // are used without being listed in a manifest. EnforceManifest = true, Manifest = { BeeRootValue.Combine("manifest.stevedore"), }, }; //The stevedore global manifest will override DownloadableCsc.Csc72 artifacts and use Csc73 CSharpProgram.DefaultConfig = new CSharpProgramConfiguration(CSharpCodeGen.Release, DownloadableCsc.Csc72); UnityLowLevel = new DotsRuntimeCSharpProgram($"{LowLevelRoot}/Unity.LowLevel") { References = { UnsafeUtility.DotNetAssembly }, Unsafe = true }; UnityLowLevel.NativeProgram.Libraries.Add(IsLinux, new SystemLibrary("dl")); ZeroJobs = new DotsRuntimeCSharpProgram($"{LowLevelRoot}/Unity.ZeroJobs") { References = { UnityLowLevel }, Unsafe = true }; UnityCompilationPipeline = new DotNetAssembly(AsmDefConfigFile.UnityCompilationPipelineAssemblyPath, Framework.NetStandard20); var nunit = new StevedoreArtifact("nunit-framework"); Backend.Current.Register(nunit); NUnitLite = new DotNetAssembly(nunit.Path.Combine("bin", "net40", "nunitlite.dll"), Framework.Framework40); NUnitFramework = new DotNetAssembly(nunit.Path.Combine("bin", "net40", "nunit.framework.dll"), Framework.Framework40); //any asmdef that sits next to a .project file we will consider a tiny game. var asmDefDescriptions = AsmDefConfigFile.AssemblyDefinitions.ToArray(); BurstCompiler.BurstExecutable = asmDefDescriptions.First(d => d.Name == "Unity.Burst") .Path.Parent.Parent.Combine(".Runtime/bcl.exe").QuoteForProcessStart(); var ilPostProcessorPrograms = asmDefDescriptions.Where(d => d.Name.EndsWith(".CodeGen") && !d.DefineConstraints.Contains("!NET_DOTS")).Select(GetOrMakeDotsRuntimeCSharpProgramFor); ILPostProcessorAssemblies = ilPostProcessorPrograms.Select(p => p.SetupSpecificConfiguration(DotsConfigs.HostDotnet)).ToArray(); PerConfigBuildSettings = DotsConfigs.MakeConfigs(); var tinyMainAsmDefs = asmDefDescriptions;//.Where(d => d.NamedReferences.Contains("Unity.Tiny.Main")); var gameAsmDefs = tinyMainAsmDefs.Union(AsmDefConfigFile.TestableAssemblyDefinitions); var gamePrograms = gameAsmDefs.Select(SetupGame).ExcludeNulls().ToArray(); var vs = new VisualStudioSolution { Path = AsmDefConfigFile.UnityProjectPath.Combine($"{AsmDefConfigFile.ProjectName}-Dots.sln").RelativeTo(NPath.CurrentDirectory), DefaultSolutionFolderFor = file => (file.Name.Contains("Unity.") || file.Name == "mscorlib") ? "Unity" : "" }; var unityToolsFolder = "Unity/tools"; var unityILPostProcessorsFolder = "Unity/ILPostProcessing"; if (BeeRoot.IsChildOf(AsmDefConfigFile.UnityProjectPath)) { var buildProjRef = new CSharpProjectFileReference("buildprogram.gen.csproj"); vs.Projects.Add(buildProjRef, unityToolsFolder); vs.Projects.Add(buildProjRef, unityILPostProcessorsFolder); } foreach (var gameProgram in gamePrograms) { vs.Projects.Add(gameProgram); } var toolPrograms = new[] { TypeRegistrationTool.EntityBuildUtils, TypeRegistrationTool.TypeRegProgram }; foreach (var p in toolPrograms) { vs.Projects.Add(p, unityToolsFolder); } vs.Projects.Add(ILPostProcessorTool.ILPostProcessorRunnerProgram, unityILPostProcessorsFolder); foreach (var p in ilPostProcessorPrograms) { vs.Projects.Add(p, unityILPostProcessorsFolder); } foreach (var config in PerConfigBuildSettings.SelectMany(entry => entry.Value)) { //we want dotnet to be the default, and we cannot have nice things: https://aras-p.info/blog/2017/03/23/How-does-Visual-Studio-pick-default-config/platform/ var solutionConfigName = config.Identifier == "dotnet" ? "Debug (dotnet)": config.Identifier; vs.Configurations.Add(new SolutionConfiguration(solutionConfigName, (configurations, file) => { var firstOrDefault = configurations.FirstOrDefault(c => c == config); return(new Tuple <IProjectConfiguration, bool>( firstOrDefault ?? configurations.First(), firstOrDefault != null || toolPrograms.Any(t => t.ProjectFile == file))); })); } VisualStudioSolution = vs; EditorToolsBuildProgram.Setup(BeeRoot); // Run this before solution setup, to potentially give this a chance to muck with the VisualStudioSolution DotsBuildCustomizer.RunAllCustomizers(); if (!IsRequestedTargetExactlySingleAppSingleConfig()) { Backend.Current.AddAliasDependency("ProjectFiles", vs.Setup()); } }
public BurstCompiler(string burstTarget, string burstPlatform, NPath outputDirectory) { BurstTarget = burstTarget; BurstPlatform = burstPlatform; OutputDirectory = outputDirectory; // On macOS the PlatformName is set as OSX in bee but it needs to be macOS for bcl. if (burstPlatform == "OSX") { BurstPlatform = "macOS"; } if (burstPlatform == "IOS" && burstTarget == "ARMV8A_AARCH64") { BurstPlatform = "iOS"; } NPath burstDir = Path.GetFullPath("Packages/com.unity.burst/.Runtime"); var burstFiles = burstDir.Files(recurse: true); bool IsManagedBurstLibrary(NPath f) { if (!f.HasExtension(".dll")) { return(false); } if (f.FileName.StartsWith("burst-llvm-")) { return(false); } // These two libraries are not crossgen-compatible. if (f.FileName == "Unity.Cecil.Rocks.dll" || f.FileName == "Newtonsoft.Json.dll") { return(false); } return(true); } var bclAssembly = new DotNetAssembly(burstDir.Combine("bcl.exe"), Framework.Framework471) .WithRuntimeDependencies(burstFiles .Where(IsManagedBurstLibrary) .Select(f => new DotNetAssembly(f, Framework.Framework471)) .ToArray()); #if BURST_NETCORE //todo: turn this to true. we cannot right now because NetCoreRuntime.SteveDore is implemented through a static field, //which is incompatible with our "create graph in editor, and maybe we will create two graphs during the same domain". the creation //of the steve artifact happens only once, but it needs to be registered in each backend. the fact that it doesn't means you can get into //ugly situations where on second builds the dependencies to netcorerun are not properly setup. bool useNetCore = false; if (useNetCore) { var runtime = NetCoreRunRuntime.FromSteve; _dotnetRuntime = runtime; var useCrossGen = false; if (useCrossGen) { bclAssembly = runtime.SetupAheadOfTimeCompilation(bclAssembly, "artifacts/bcl-crossgen"); bclAssembly = bclAssembly.WithPath(bclAssembly.Path.MakeAbsolute(BeeProjectRoot)); foreach (var file in burstFiles.Where(x => !IsManagedBurstLibrary(x))) { var relative = file.RelativeTo(burstDir); var temp = CopyTool.Instance().Setup(bclAssembly.Path.Parent.Combine(relative), file); Backend.Current.AddDependency(temp, bclAssembly.Path); } } } else #else { _dotnetRuntime = DotNetRuntime.FindFor(bclAssembly); } #endif { _burstRunnableProgram = new DotNetRunnableProgram(bclAssembly, _dotnetRuntime); } _burstCompilerInputFiles = burstFiles; var burstPackageInfo = UnityEditor.PackageManager.PackageInfo.FindForAssetPath("Packages/com.unity.burst/somefile"); var burstPackageRawVersion = burstPackageInfo.version; // Remove everything after '-' if this is a preview package. var parts = burstPackageRawVersion.Split('-'); if (parts.Length > 1) { burstPackageRawVersion = parts[0]; } // Get the preview version number. // Default to max int to signal a very high preview number on release. var previewNumber = int.MaxValue; if (parts.Length > 1) { previewNumber = int.Parse(parts[1].Split('.')[1]); } var burstVersion = Version.Parse(burstPackageRawVersion); var burstVersionWithIncludeRootAssemblyReferencesFeature = new Version(1, 3); _installedBurstSupportsIncludeRootAssemblyReferencesFeature = burstVersion >= burstVersionWithIncludeRootAssemblyReferencesFeature; if (!_installedBurstSupportsIncludeRootAssemblyReferencesFeature) { Debug.Log($"Using burst 1.3 instead of {burstVersion.ToString()} will give much better build times. At the time of this writing it is only available by building manually on your machine."); } _installedBurstSupportsCaching = (burstVersion >= new Version(1, 3) && previewNumber > 7) || burstVersion >= new Version(1, 4); if (!_installedBurstSupportsCaching) { Debug.Log($"Using burst 1.3 preview 8 or above instead of {burstVersion.ToString()} will give much better build times. At the time of this writing it is only available by building manually on your machine."); } _installedBurstIs1_3Preview10OrLater = (burstVersion >= new Version(1, 3) && previewNumber >= 10) || burstVersion >= new Version(1, 4); }
private static DotsRuntimeCSharpProgram SetupGame(AsmDefDescription game) { var gameProgram = GetOrMakeDotsRuntimeCSharpProgramFor(game); var withoutExt = new NPath(gameProgram.FileName).FileNameWithoutExtension; NPath exportManifest = new NPath(withoutExt + "/export.manifest"); Backend.Current.RegisterFileInfluencingGraph(exportManifest); if (exportManifest.FileExists()) { var dataFiles = exportManifest.MakeAbsolute().ReadAllLines(); foreach (var dataFile in dataFiles.Select(d => new NPath(d))) { gameProgram.SupportFiles.Add(new DeployableFile(dataFile, "Data/" + dataFile.FileName)); } } var configToSetupGame = new Dictionary <DotsRuntimeCSharpProgramConfiguration, DotNetAssembly>(); if (!PerConfigBuildSettings.ContainsKey(game.Name)) { return(null); } foreach (var config in PerConfigBuildSettings[game.Name].Where(config => !CanSkipSetupOf(game.Name, config))) { gameProgram.ProjectFile.StartInfo.Add(c => c == config, StartInfoFor(config, EntryPointExecutableFor(gameProgram, config))); gameProgram.ProjectFile.BuildCommand.Add(c => c == config, new BeeBuildCommand(GameDeployBinaryFor(gameProgram, config).ToString(), false, false).ToExecuteArgs()); DotNetAssembly setupGame = gameProgram.SetupSpecificConfiguration(config).WithDeployables(new DotNetAssembly( Il2Cpp.Distribution.Path.Combine("build/profiles/Tiny/Facades/netstandard.dll"), Framework.FrameworkNone)); var postILProcessedGame = ILPostProcessorTool.SetupInvocation(setupGame, config, gameProgram.Defines.For(config).ToArray()); var postTypeRegGenGame = TypeRegistrationTool.SetupInvocation(postILProcessedGame, config); configToSetupGame[config] = postTypeRegGenGame; } ; var il2CppOutputProgram = new Il2Cpp.Il2CppOutputProgram(gameProgram.AsmDefDescription.Name.Replace(".", "-") + ".il2cpp"); var configToSetupGameBursted = new Dictionary <DotsRuntimeCSharpProgramConfiguration, DotNetAssembly>(); BurstCompiler hostBurstCompiler = null; if (HostPlatform.IsWindows) { hostBurstCompiler = new BurstCompilerForWindows64(); hostBurstCompiler.Link = true; hostBurstCompiler.OnlyStaticMethods = true; } else if (HostPlatform.IsOSX) { hostBurstCompiler = new BurstCompilerForMac(); hostBurstCompiler.Link = true; hostBurstCompiler.OnlyStaticMethods = true; } else { Console.WriteLine("Tiny burst not yet supported on linux."); } var webBurstCompiler = new BurstCompilerForEmscripten(); foreach (var kvp in configToSetupGame) { var config = kvp.Key; var setupGame = kvp.Value; if (config.UseBurst) { var outputDir = $"artifacts/{game.Name}/{config.Identifier}_bursted"; var isWebGL = config.Platform is WebGLPlatform; var extension = config.NativeProgramConfiguration.ToolChain.DynamicLibraryFormat.Extension; //burst generates a .bundle on os x. if (config.Platform is MacOSXPlatform) { extension = "bundle"; } var burstlib = BurstCompiler.SetupBurstCompilationAndLinkForAssemblies( isWebGL ? webBurstCompiler : hostBurstCompiler, setupGame, new NPath(outputDir).Combine( $"lib_burst_generated{("."+extension) ?? ""}"), outputDir, out var burstedGame); if (isWebGL) { il2CppOutputProgram.Libraries.Add(c => c.Equals(config.NativeProgramConfiguration), burstlib); } else { burstedGame = burstedGame.WithDeployables(burstlib); } configToSetupGameBursted[config] = burstedGame; } else { configToSetupGameBursted[config] = setupGame; } } var configToSetupGameStripped = new Dictionary <DotsRuntimeCSharpProgramConfiguration, DotNetAssembly>(); foreach (var kvp in configToSetupGameBursted) { var config = kvp.Key; var setupGame = kvp.Value; if (config.ScriptingBackend == ScriptingBackend.TinyIl2cpp) { setupGame = Il2Cpp.UnityLinker.SetupInvocation(setupGame, $"artifacts/{game.Name}/{config.Identifier}_stripped", config.NativeProgramConfiguration); il2CppOutputProgram.SetupConditionalSourcesAndLibrariesForConfig(config, setupGame); configToSetupGameStripped[kvp.Key] = setupGame; } else { configToSetupGameStripped[kvp.Key] = kvp.Value; } } foreach (var kvp in configToSetupGameStripped) { var config = kvp.Key; var setupGame = kvp.Value; NPath deployPath = GameDeployDirectoryFor(gameProgram, config); IDeployable deployedGame; NPath entryPointExecutable = null; if (config.ScriptingBackend == ScriptingBackend.TinyIl2cpp) { var builtNativeProgram = il2CppOutputProgram.SetupSpecificConfiguration( config.NativeProgramConfiguration, config.NativeProgramConfiguration.ExecutableFormat ) .WithDeployables(setupGame.RecursiveRuntimeDependenciesIncludingSelf.SelectMany(a => a.Deployables.Where(d => !(d is DotNetAssembly) && !(d is StaticLibrary))) .ToArray()); if (builtNativeProgram is IPackagedAppExtension) { (builtNativeProgram as IPackagedAppExtension).SetAppPackagingParameters(gameProgram.AsmDefDescription.Name, config.NativeProgramConfiguration.CodeGen, gameProgram.SupportFiles.For(config)); } deployedGame = builtNativeProgram.DeployTo(deployPath); entryPointExecutable = deployedGame.Path; if (config.EnableManagedDebugging) { Backend.Current.AddDependency(deployedGame.Path, Il2Cpp.CopyIL2CPPMetadataFile(deployPath, setupGame)); } } else { deployedGame = setupGame.DeployTo(deployPath); var dotNetAssembly = (DotNetAssembly)deployedGame; //Usually a dotnet runtime game does not have a static void main(), and instead references another "entrypoint asmdef" that provides it. //This is convenient, but what makes it weird is that you have to start YourEntryPoint.exe instead of YourGame.exe. Until we have a better //solution for this, we're going to copy YourEntryPoint.exe to YourGame.exe, so that it's easier to find, and so that when it runs and you look //at the process name you understand what it is. if (deployedGame.Path.HasExtension("dll")) { var to = deployPath.Combine(deployedGame.Path.ChangeExtension("exe").FileName); var from = dotNetAssembly.RecursiveRuntimeDependenciesIncludingSelf.SingleOrDefault(a => a.Path.HasExtension("exe"))?.Path; if (from == null) { throw new InvalidProgramException($"Program {dotNetAssembly.Path} is an executable-like thing, but doesn't reference anything with Main"); } Backend.Current.AddDependency(deployedGame.Path, CopyTool.Instance().Setup(to, from)); entryPointExecutable = to; } else { entryPointExecutable = deployedGame.Path; } } //Because we use multidag, and try to not run all the setupcode when we just want to create projectfiles, we have a bit of a challenge. //Projectfiles require exact start and build commands. So we need to have a cheap way to calculate those. However, it's important that they //exactly match the actual place where the buildprogram is going to place our files. If these don't match things break down. The checks //in this block, they compare the "quick way to determine where the binary will be placed, and what the start executable is", with the //actual return values returned from .DeployTo(), when we do run the actual buildcode. NPath deployedGamePath = GameDeployBinaryFor(gameProgram, config); if (deployedGame.Path != deployedGamePath) { throw new InvalidProgramException($"We expected deployPath to be {deployedGamePath}, but in reality it was {deployedGame.Path}"); } var expectedEntryPointExecutable = EntryPointExecutableFor(gameProgram, config); if (entryPointExecutable != expectedEntryPointExecutable) { throw new InvalidProgramException($"We expected entryPointExecutable to be {expectedEntryPointExecutable}, but in reality it was {entryPointExecutable}"); } Backend.Current.AddAliasDependency(config.Identifier, deployedGamePath); } return(gameProgram); }