/// <summary> /// 初始化英战斗属性 /// </summary> /// <param name="baseHero"></param> /// <param name="inscriptionPage"></param> public void InitBatteryAttibute(BaseHero baseHero, InscriptionPage inscriptionPage) { baseAttibute = CopyTool.DeepCopy <BaseAttribute>(baseHero.baseAttribute); attackAttibute = CopyTool.DeepCopy <AttackAttribute>(baseHero.attackAttribute); defenseAttibute = CopyTool.DeepCopy <DefenseAttribute>(baseHero.defenseAttribute); InitInscriptionAttibute(inscriptionPage); }
public static NPath CopyIL2CPPMetadataFile(NPath destination, DotNetAssembly inputAssembly) { var target = destination.Combine("Data/Metadata/global-metadata.dat"); CopyTool.Instance().Setup(target, Il2CppTargetDirForAssembly(inputAssembly).Combine("Data", "Metadata", "global-metadata.dat")); return(target); }
public void AddRecommendEquipment(BaseEquipment baseEquipment) { BaseEquipment ecop = CopyTool.DeepCopy <BaseEquipment>(baseEquipment); if (_recommendList.ContainsKey(ecop.equipmentId)) { _recommendList.Add(ecop.equipmentId, ecop); } }
private static void CopyAllFilesFrom(NPath fromPath, NPath toPath) { foreach (var file in fromPath.Files(true)) { CopyTool.Instance().Setup( toPath.Combine(file.RelativeTo(fromPath)).MakeAbsolute(), file.MakeAbsolute()); } }
public override BuildResult Run(BuildContext context) { var files = context.GetValue <AdditionallyProvidedFiles>().files; foreach (var entry in files) { CopyTool.Instance().Setup(entry.targetFile, entry.sourceFile); } return(context.Success()); }
public override void DoOtherSetup() { var sprite = skinningCache.GetSprites()[0]; skinningCache.events.selectedSpriteChanged.Invoke(sprite); skinningCache.events.boneSelectionChanged.Invoke(); m_CopyTool = skinningCache.GetTool(Tools.CopyPaste) as CopyTool; EditorGUIUtility.systemCopyBuffer = ""; }
public override void OnInspectorGUI() { CopyTool gen = (CopyTool)target; DrawDefaultInspector(); if (GUILayout.Button("Copy")) { gen.Copy(); } }
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 override void DoOtherSetup() { var sprite = skinningCache.GetSprites()[0]; skinningCache.events.selectedSpriteChanged.Invoke(sprite); skinningCache.events.boneSelectionChanged.Invoke(); m_CopyTool = skinningCache.GetTool(Tools.CopyPaste) as CopyTool; m_CopyStringStore = new StringCopyToolStringStore(); m_CopyStringStore.stringStore = ""; m_CopyTool.copyToolStringStore = m_CopyStringStore; }
private static NPath Copy(NPath from, NPath to, ToolChain toolchain, string subFolderDir) { if (subFolderDir != string.Empty) { to = new NPath($"{pluginDir}/{subFolderDir}").Combine(to.FileName); } else { to = new NPath($"{pluginDir}/{toolchain.LegacyPlatformIdentifier}").Combine(to.FileName); } CopyTool.Instance().Setup(to, from); return(to); }
public void SetTest() { List <string> strList = new List <string> { "test", "test", "test0", "test1" }; Debug.Log("original"); PrintStrList(strList); List <string> strSet = CopyTool.TransStrListToSet(strList); Debug.Log("after"); PrintStrList(strSet); }
private void CopyIcon(NPath destPath, string dpi, string iconName, string configIcon) { if (String.IsNullOrEmpty(configIcon)) { return; } destPath = destPath.Combine($"src/main/res/mipmap-{dpi}", iconName); var srcPath = new NPath(configIcon); if (srcPath.IsRelative) { srcPath = (new NPath("../..")).Combine(srcPath); } m_projectFiles.Add(CopyTool.Instance().Setup(destPath, srcPath)); }
static void SetupGetEditorToolsFromStevedore() { // since this target and `get-editor-tools` target outputs the same files // we cannot have these two targets side by side in the dag. // We need this to generate the only correct target if (CompileEditorToolsFromSourceFileFlag.FileExists()) { return; } var executablesFromEditorTools = new HashSet <string> { "artifacts/Stevedore/dots-editor-tools/images/osx/cwebp", "artifacts/Stevedore/dots-editor-tools/images/osx/moz-cjpeg", "artifacts/Stevedore/dots-editor-tools/images/osx/pngcrush", "artifacts/Stevedore/dots-editor-tools/manager/DotsEditorTools-macos", }; var EditorTools = new StevedoreArtifact("dots-editor-tools"); Backend.Current.Register(EditorTools); var dependencies = new List <NPath>(); foreach (var file in EditorTools.GetFileList()) { var target = new NPath(file.ToString().Replace(EditorTools.Path.ToString(), InstallationDirectory.ToString())); if ((HostPlatform.IsOSX || HostPlatform.IsLinux) && executablesFromEditorTools.Contains(file.ToString())) { Backend.Current.AddAction("copy and chmod +x", new[] { target }, new[] { file }, $"cp {file.InQuotes()} {target.InQuotes()} && chmod +x {target.InQuotes()}", Array.Empty <string>()); } else { CopyTool.Instance().Setup(target, file); } dependencies.Add(target); } Backend.Current.AddAliasDependency("get-editor-tools", dependencies.ToArray()); }
private NPath CopyIcon(NPath srcPath, NPath destPath, string iconName, string configIcon) { const string iconsPath = "Sources/Assets.xcassets/AppIcon.appiconset"; destPath = destPath.Combine(iconsPath, iconName); if (String.IsNullOrEmpty(configIcon)) { srcPath = srcPath.Combine(iconsPath, iconName); } else { srcPath = new NPath(configIcon); if (srcPath.IsRelative) { srcPath = (new NPath("../..")).Combine(srcPath); } } var iconPath = CopyTool.Instance().Setup(destPath, srcPath); m_projectFiles.Add(iconPath); return(iconPath); }
public GraphVisualizationInfoView() { InitializeComponent(); this.shapeInfoShapeMapping = new BidirectionalDictionary <IShapeInfo, IShape>(); this.connectionInfoConnectionMapping = new BidirectionalDictionary <IConnectionInfo, IConnection>(); this.connectionPenStyle = new LinePenStyle(); this.connectionPenStyle.EndCap = LineCap.ArrowAnchor; PasteTool pasteTool = (PasteTool)this.Controller.Tools.Where(t => t.Name == ControllerBase.PasteToolName).FirstOrDefault(); CopyTool copyTool = (CopyTool)this.Controller.Tools.Where(t => t.Name == ControllerBase.CopyToolName).FirstOrDefault(); HeuristicLab.Netron.Controller controller = this.Controller as HeuristicLab.Netron.Controller; if (controller != null) { if (pasteTool != null) { controller.RemoveTool(pasteTool); } if (copyTool != null) { controller.RemoveTool(copyTool); } } }
private void GenerateGradleProject(NPath gradleProjectPath) { var gradleSrcPath = AsmDefConfigFile.AsmDefDescriptionFor("Unity.Build.Android.DotsRuntime").Path.Parent.Combine("AndroidProjectTemplate~/"); var hasGradleDependencies = false; var gradleDependencies = new StringBuilder(); gradleDependencies.AppendLine(" dependencies {"); var hasKotlin = false; foreach (var d in Deployables.Where(d => (d is DeployableFile))) { var f = d as DeployableFile; if (f.Path.Extension == "aar" || f.Path.Extension == "jar") { gradleDependencies.AppendLine($" compile(name:'{f.Path.FileNameWithoutExtension}', ext:'{f.Path.Extension}')"); hasGradleDependencies = true; } else if (f.Path.Extension == "kt") { hasKotlin = true; } } if (hasGradleDependencies) { gradleDependencies.AppendLine(" }"); } else { gradleDependencies.Clear(); } var kotlinClassPath = hasKotlin ? " classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.11'" : ""; var kotlinPlugin = hasKotlin ? "apply plugin: 'kotlin-android'" : ""; var loadLibraries = new StringBuilder(); bool useStaticLib = Deployables.FirstOrDefault(l => l.ToString().Contains("lib_unity_tiny_android.so")) == default(IDeployable); if (useStaticLib) { loadLibraries.AppendLine($" System.loadLibrary(\"{m_gameName}\");"); } else { var rx = new Regex(@".*lib([\w\d_]+)\.so", RegexOptions.Compiled); foreach (var l in Deployables) { var match = rx.Match(l.ToString()); if (match.Success) { loadLibraries.AppendLine($" System.loadLibrary(\"{match.Groups[1].Value}\");"); } } } String abiFilters = ""; if (AndroidApkToolchain.Config.Architectures.Architectures == AndroidArchitecture.ARM64) { abiFilters = "'arm64-v8a'"; } else if (AndroidApkToolchain.Config.Architectures.Architectures == AndroidArchitecture.ARMv7) { abiFilters = "'armeabi-v7a'"; } else if (AndroidApkToolchain.IsFatApk) { abiFilters = "'armeabi-v7a', 'arm64-v8a'"; } else // shouldn't happen { Console.WriteLine($"Tiny android toolchain doesn't support {AndroidApkToolchain.Config.Architectures.Architectures.ToString()} architectures"); } // Android docs say "density" value was added in API level 17, but it doesn't compile with target SDK level lower than 24. string configChanges = ((int)AndroidApkToolchain.Config.APILevels.ResolvedTargetAPILevel > 23) ? AndroidConfigChanges + "|density" : AndroidConfigChanges; var useKeystore = BuildConfiguration.HasComponent <AndroidKeystore>(); var renderOutsideSafeArea = BuildConfiguration.HasComponent <AndroidRenderOutsideSafeArea>(); var icons = AndroidApkToolchain.Config.Icons; var hasBackground = icons.Icons.Any(i => !String.IsNullOrEmpty(i.Background)); var hasCustomIcons = hasBackground || icons.Icons.Any(i => !String.IsNullOrEmpty(i.Foreground) || !String.IsNullOrEmpty(i.Legacy)); var version = AndroidApkToolchain.Config.Settings.Version; var versionFieldCount = version.Revision > 0 ? 4 : 3; var maxRatio = AndroidApkToolchain.Config.AspectRatio.GetMaxAspectRatio(AndroidApkToolchain.Config.APILevels.ResolvedTargetAPILevel); var additionalApplicationMetadata = ""; var additionalPermissions = ""; var additionalFeatures = ""; if (!String.IsNullOrEmpty(maxRatio)) { additionalApplicationMetadata += GetMetaDataString("android.max_aspect", maxRatio); } if (BuildConfiguration.HasComponent <ARCoreSettings>()) { additionalPermissions += GetPermissionString("android.permission.CAMERA"); if (AndroidApkToolchain.Config.ARCore.Requirement == Requirement.Optional) { additionalApplicationMetadata += "\n" + GetMetaDataString("com.google.ar.core", "optional"); } else { additionalApplicationMetadata += "\n" + GetMetaDataString("com.google.ar.core", "required"); additionalFeatures += GetFeatureString("android.hardware.camera.ar", true); } if (AndroidApkToolchain.Config.ARCore.DepthSupport == Requirement.Required) { additionalFeatures += "\n" + GetFeatureString("com.google.ar.core.depth", true); } } var templateStrings = new Dictionary <string, string> { { "**LOADLIBRARIES**", loadLibraries.ToString() }, { "**PACKAGENAME**", AndroidApkToolchain.Config.Identifier.PackageName }, { "**PRODUCTNAME**", AndroidApkToolchain.Config.Settings.ProductName }, { "**VERSIONNAME**", version.ToString(versionFieldCount) }, { "**VERSIONCODE**", AndroidApkToolchain.Config.VersionCode.VersionCode.ToString() }, { "**ORIENTATION**", GetOrientationAttr() }, { "**INSTALLLOCATION**", AndroidApkToolchain.Config.InstallLocation?.PreferredInstallLocationAsString() }, { "**CUTOUTMODE**", AndroidRenderOutsideSafeArea.CutoutMode(renderOutsideSafeArea) }, { "**NOTCHCONFIG**", AndroidRenderOutsideSafeArea.NotchConfig(renderOutsideSafeArea) }, { "**NOTCHSUPPORT**", AndroidRenderOutsideSafeArea.NotchSupport(renderOutsideSafeArea) }, { "**GAMENAME**", m_gameName }, { "**MINSDKVERSION**", ((int)AndroidApkToolchain.Config.APILevels.MinAPILevel).ToString() }, { "**TARGETSDKVERSION**", ((int)AndroidApkToolchain.Config.APILevels.ResolvedTargetAPILevel).ToString() }, { "**CONFIGCHANGES**", configChanges }, { "**ACTIVITY_ASPECT**", String.IsNullOrEmpty(maxRatio) ? "" : $"android:maxAspectRatio=\"{maxRatio}\"" }, { "**ADDITIONAL_APPLICATION_METADATA**", additionalApplicationMetadata }, { "**ADDITIONAL_PERMISSIONS**", additionalPermissions }, { "**ADDITIONAL_FEATURES**", additionalFeatures }, { "**ABIFILTERS**", abiFilters }, { "**SIGN**", AndroidApkToolchain.Config.Keystore.GetSigningConfigs(useKeystore) }, { "**SIGNCONFIG**", AndroidApkToolchain.Config.Keystore.GetSigningConfig(useKeystore) }, { "**DEPENDENCIES**", gradleDependencies.ToString() }, { "**KOTLINCLASSPATH**", kotlinClassPath }, { "**KOTLINPLUGIN**", kotlinPlugin }, { "**ALLOWED_PORTRAIT**", AndroidApkToolchain.AllowedOrientationPortrait ? "true" : "false" }, { "**ALLOWED_REVERSE_PORTRAIT**", AndroidApkToolchain.AllowedOrientationReversePortrait ? "true" : "false" }, { "**ALLOWED_LANDSCAPE**", AndroidApkToolchain.AllowedOrientationLandscape ? "true" : "false" }, { "**ALLOWED_REVERSE_LANDSCAPE**", AndroidApkToolchain.AllowedOrientationReverseLandscape ? "true" : "false" }, { "**BACKGROUND_PATH**", hasBackground ? "mipmap" : "drawable" } }; // copy icon files if (hasCustomIcons) { for (int i = 0; i < icons.Icons.Length; ++i) { var dpi = ((ScreenDPI)i).ToString().ToLower(); if (AndroidApkToolchain.Config.APILevels.TargetSDKSupportsAdaptiveIcons) { CopyIcon(gradleProjectPath, dpi, "ic_launcher_foreground.png", icons.Icons[i].Foreground); CopyIcon(gradleProjectPath, dpi, "ic_launcher_background.png", icons.Icons[i].Background); } CopyIcon(gradleProjectPath, dpi, "app_icon.png", icons.Icons[i].Legacy); } } // copy and patch project files var apiRx = new Regex(@".+res[\\|\/].+-v([0-9]+)$", RegexOptions.Compiled); foreach (var r in gradleSrcPath.Files(true)) { if ((hasCustomIcons && r.HasDirectory("mipmap-mdpi")) || (hasBackground && r.HasDirectory("drawable"))) // skipping icons files if there are custom ones { continue; } if (!AndroidApkToolchain.Config.APILevels.TargetSDKSupportsAdaptiveIcons && r.FileName.StartsWith("ic_launcher_")) { continue; } var match = apiRx.Match(r.Parent.ToString()); if (match.Success) { var api = Int32.Parse(match.Groups[1].Value); if (api > (int)AndroidApkToolchain.Config.APILevels.ResolvedTargetAPILevel) { continue; } } var destPath = gradleProjectPath.Combine(r.RelativeTo(gradleSrcPath)); if (r.Extension == "template") { destPath = destPath.ChangeExtension(""); var code = r.ReadAllText(); foreach (var t in templateStrings) { if (code.IndexOf(t.Key) != -1) { code = code.Replace(t.Key, t.Value); } } Backend.Current.AddWriteTextAction(destPath, code); } else { destPath = CopyTool.Instance().Setup(destPath, r); } m_projectFiles.Add(destPath); } var localProperties = new StringBuilder(); localProperties.AppendLine($"sdk.dir={new NPath(AndroidApkToolchain.Config.ExternalTools.SdkPath).ToString()}"); localProperties.AppendLine($"ndk.dir={new NPath(AndroidApkToolchain.Config.ExternalTools.NdkPath).ToString()}"); var localPropertiesPath = gradleProjectPath.Combine("local.properties"); Backend.Current.AddWriteTextAction(localPropertiesPath, localProperties.ToString()); m_projectFiles.Add(localPropertiesPath); }
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); }
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 NPath PackageApp(NPath buildPath, BuiltNativeProgram mainProgram) { var mainLibPath = mainProgram.Path; m_projectFiles.Add(mainLibPath); m_projectFiles.AddRange(mainProgram.Deployables.Select(d => d.Path)); if (m_apkToolchain == null) { Console.WriteLine($"Error: not Android APK toolchain"); return(buildPath); } if (AndroidApkToolchain.ExportProject) { var deployedPath = buildPath.Combine(m_gameName); GenerateGradleProject(deployedPath); // stub action to have deployedPath in build tree and set correct dependencies Backend.Current.AddAction( actionName: "Gradle project folder", targetFiles: new[] { deployedPath }, inputs: m_projectFiles.ToArray(), executableStringFor: $"echo created", commandLineArguments: Array.Empty <string>(), allowUnexpectedOutput: true, allowUnwrittenOutputFiles: true ); return(deployedPath); } else { var deployedPath = buildPath.Combine(m_gameName + "." + m_apkToolchain.ExecutableFormat.Extension); var gradleProjectPath = mainLibPath.Parent.Parent.Parent.Parent.Parent; GenerateGradleProject(gradleProjectPath); var pathToRoot = new NPath(string.Concat(Enumerable.Repeat("../", gradleProjectPath.Depth))); var javaLaunchPath = new NPath(AndroidApkToolchain.Config.ExternalTools.JavaPath).Combine("bin").Combine("java"); var gradleLaunchPath = AndroidApkToolchain.GetGradleLaunchJarPath(); var releaseBuild = m_config == DotsConfiguration.Release; var gradleCommand = AndroidApkToolchain.BuildAppBundle ? (releaseBuild ? "bundleRelease" : "bundleDebug") : (releaseBuild ? "assembleRelease" : "assembleDebug"); var gradleExecutableString = $"cd {gradleProjectPath.InQuotes()} && {javaLaunchPath.InQuotes()} -classpath {gradleLaunchPath.InQuotes()} org.gradle.launcher.GradleMain {gradleCommand} && cd {pathToRoot.InQuotes()}"; var config = releaseBuild ? "release" : "debug"; var gradleBuildPath = gradleProjectPath.Combine("build/outputs"). Combine(AndroidApkToolchain.BuildAppBundle ? "bundle" : "apk"). Combine($"{config}/gradle-{config}.{(AndroidApkToolchain.BuildAppBundle ? "aab" : "apk")}"); Backend.Current.AddAction( actionName: "Build Gradle project", targetFiles: new[] { gradleBuildPath }, inputs: m_projectFiles.ToArray(), executableStringFor: gradleExecutableString, commandLineArguments: Array.Empty <string>(), allowUnexpectedOutput: false, allowedOutputSubstrings: new[] { ":*", "BUILD SUCCESSFUL in *" } ); return(CopyTool.Instance().Setup(deployedPath, gradleBuildPath)); } }
public NPath PackageApp(NPath buildPath, NPath mainLibPath) { if (m_iosAppToolchain == null) { Console.WriteLine("Error: not IOS App toolchain"); return(mainLibPath); } var iosPlatformPath = AsmDefConfigFile.AsmDefDescriptionFor("Unity.Platforms.iOS").Path.Parent; var xcodeProjectPath = mainLibPath.Parent; var xcodeSrcPath = iosPlatformPath.Combine(TinyProjectName + "~"); var xcodeprojPath = xcodeProjectPath.Combine($"{TinyProjectName}.xcodeproj"); // copy and patch pbxproj file var pbxPath = xcodeprojPath.Combine("project.pbxproj"); var pbxTemplatePath = xcodeSrcPath.Combine($"{TinyProjectName}.xcodeproj", "project.pbxproj"); var exportManifestPath = new NPath(m_gameName).Combine("export.manifest"); var result = SetupXCodeProject(pbxTemplatePath, exportManifestPath.FileExists()); Backend.Current.AddWriteTextAction(pbxPath, result); Backend.Current.AddDependency(pbxPath, mainLibPath); // copy and patch Info.plist file var plistPath = xcodeProjectPath.Combine("Sources", "Info.plist"); var plistTemplatePath = xcodeSrcPath.Combine("Sources", "Info.plist"); result = SetupInfoPlist(plistTemplatePath); Backend.Current.AddWriteTextAction(plistPath, result); Backend.Current.AddDependency(pbxPath, plistPath); // copy xcodeproj files foreach (var r in xcodeSrcPath.Files(true)) { if (r.Extension != "pbxproj" && r.FileName != "Info.plist") { var destPath = xcodeProjectPath.Combine(r.RelativeTo(xcodeSrcPath)); destPath = CopyTool.Instance().Setup(destPath, r); Backend.Current.AddDependency(pbxPath, destPath); } } foreach (var r in m_supportFiles) { if (r.Path.FileName == "testconfig.json") { Backend.Current.AddDependency(pbxPath, CopyTool.Instance().Setup(buildPath.Combine(r.Path.FileName), r.Path)); break; } } // TODO probably it is required to keep previous project since it can be modified by user var outputPath = buildPath.Combine($"{m_gameName}"); Console.WriteLine($"Move project to {outputPath}"); Backend.Current.AddAction( actionName: "Open XCode project folder", targetFiles: new[] { outputPath }, inputs: new[] { pbxPath }, executableStringFor: $"rm -rf {outputPath} && mv {xcodeProjectPath} {outputPath} && open {outputPath}", commandLineArguments: Array.Empty <string>(), allowUnexpectedOutput: true ); return(outputPath); }
public NPath[] Setup(Architecture architecture, DotNetAssembly[] inputAssemblies, int assemblyIndex, string burstLibraryName, Dictionary <string, string> environmentVariables, BurstOutputMode outputMode) { using (new ProfilerMarker("Burst-" + burstLibraryName).Auto()) { NPath intermediateOutputDir = Configuration.RootArtifactsPath.Combine($"bcl/{architecture.Name}/{burstLibraryName}"); var runtimeDependencies = inputAssemblies.SelectMany(i => { return(i.RecursiveRuntimeDependenciesIncludingSelf); }) .Distinct().ToArray(); var args = new List <string> { $"--target={BurstTarget}", $"--platform={BurstPlatform}", //"--log-timings", "--dump=none", $"--output={intermediateOutputDir.Combine(burstLibraryName)}", inputAssemblies.Select(inputAssembly => $"--root-assembly={inputAssembly.Path.InQuotesResolved()}"), runtimeDependencies.Select(r => r.Path.ResolveWithFileSystem().Parent.InQuotes()).Distinct().Select(d => $"--assembly-folder={d}"), }; if (_installedBurstSupportsIncludeRootAssemblyReferencesFeature) { args.Add("--include-root-assembly-references=false"); } if (_installedBurstSupportsCaching) { args.Add("--always-create-output=false"); if (outputMode == BurstOutputMode.LibraryPerJob) { args.Add("--output-mode=LibraryPerJob"); args.Add( $"--cache-directory={NPath.CurrentDirectory.Combine("Library/BurstCache/Incremental")}"); } } if (!_installedBurstIs1_3Preview10OrLater) { args.Add($"--mintarget={BurstTarget}"); } if (_installedBurstIs1_3Preview10OrLater) { args.Add("--debug=Full"); } else { args.Add("--debug"); } Backend.Current.AddAction( "Burst" , new NPath[] { } , runtimeDependencies.Select(p => p.Path).Concat(_dotnetRuntime.Inputs) .Concat(_burstCompilerInputFiles).ToArray() , executableStringFor: _burstRunnableProgram.InvocationString , args.ToArray() , targetDirectories: new[] { intermediateOutputDir } , environmentVariables: environmentVariables ); // This file extension thingy doesn't scale at all NPath[] producedFiles; using (new ProfilerMarker("Globbing produced files").Auto()) { producedFiles = intermediateOutputDir.FilesIfExists("*.dll") .Concat(intermediateOutputDir.FilesIfExists("*.so")) .Concat(intermediateOutputDir.FilesIfExists("*.a")) .Concat(intermediateOutputDir.FilesIfExists("*.bundle")) .ToArray(); } int jobCounter = 0; var targetFiles = new List <NPath>(); foreach (var producedFile in producedFiles) { var targetFile = OutputDirectory.Combine($"lib_burst_{assemblyIndex}_{jobCounter++}").ChangeExtension(producedFile.Extension); targetFiles.Add(CopyTool.Instance().Setup(targetFile, producedFile)); if (BurstPlatform == "Windows" && inputAssemblies.Any(x => x.DebugSymbolPath != null)) { const string debugExtension = ".pdb"; // TODO: Handle other platforms. var producedDebugSymbols = producedFile.ChangeExtension(debugExtension); var targetDebugSymbols = targetFile.ChangeExtension(debugExtension); targetFiles.Add(CopyTool.Instance().Setup(targetDebugSymbols, producedDebugSymbols)); } } return(targetFiles.ToArray()); } }
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); }
static void SetupCompileEditorTools(NPath rootPath) { // since this target and `get-editor-tools` target outputs the same files // we cannot have these two targets side by side in the dag. // We need this to generate the only correct target if (!CompileEditorToolsFromSourceFileFlag.FileExists()) { return; } var editorToolsSourceDirectory = rootPath.Combine("EditorTools/Src"); var env = new Dictionary <string, string>() { { "PATH", $"{NodeDirectory.ToString()}{PathSeparator}{Environment.GetEnvironmentVariable("PATH")}" } }; var dependencies = new List <NPath>(); // Iterate all folders in Tools and process them foreach (var toolDir in editorToolsSourceDirectory.Contents()) { if (toolDir.FileExists("package.json")) { var packageLockJsonFilePath = toolDir.Combine("package-lock.json"); var packageJsonFilePath = toolDir.Combine("package.json"); // Run npm install Backend.Current.AddAction($"npm install", targetFiles: new[] { packageLockJsonFilePath }, inputs: new[] { Node.Path, packageJsonFilePath }, executableStringFor: $"cd {toolDir.InQuotes()} && npm install", commandLineArguments: Array.Empty <string>(), environmentVariables: env, allowUnwrittenOutputFiles: true); dependencies.Add(packageLockJsonFilePath); // Run package var inputs = new List <NPath> { Node.Path, packageLockJsonFilePath }; var indexJsNotInModules = toolDir.Files("index.js", true).Where(p => !p.IsChildOf(toolDir.Combine("node_modules"))); inputs.AddRange(indexJsNotInModules); var toolInstallDir = InstallationDirectory.Combine(toolDir.FileName); Backend.Current.AddAction($"package", targetFiles: new[] { toolInstallDir.Combine($"DotsEditorTools-win.exe"), toolInstallDir.Combine($"DotsEditorTools-macos") }, inputs: inputs.ToArray(), executableStringFor: $"cd {toolDir.InQuotes()} && npm run package -- --out-path {toolInstallDir.InQuotes()} --targets win-x64,macos-x64 .", commandLineArguments: Array.Empty <string>(), environmentVariables: env, allowUnwrittenOutputFiles: true); dependencies.Add(toolInstallDir.Combine($"DotsEditorTools-win.exe")); dependencies.Add(toolInstallDir.Combine($"DotsEditorTools-macos")); } else // Not a node tool, just copy files recursively { foreach (var file in toolDir.Files(true)) { if (file.FileName == "extrabeetmpfile") { continue; } var target = file.ToString().Replace(editorToolsSourceDirectory.ToString(), InstallationDirectory.ToString()); CopyTool.Instance().Setup(target, file); dependencies.Add(target); } } } Backend.Current.AddAliasDependency("compile-editor-tools", dependencies.ToArray()); }
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); }
private NPath GenerateXCodeProject(NPath mainLibPath) { var outputPath = mainLibPath.Parent; var iosPlatformPath = AsmDefConfigFile.AsmDefDescriptionFor("Unity.Build.iOS.DotsRuntime").Path.Parent; var xcodeSrcPath = iosPlatformPath.Combine(TinyProjectName + "~"); var xcodeprojPath = outputPath.Combine($"{TinyProjectName}.xcodeproj"); // copy and patch pbxproj file var pbxPath = xcodeprojPath.Combine("project.pbxproj"); var pbxTemplatePath = xcodeSrcPath.Combine($"{TinyProjectName}.xcodeproj", "project.pbxproj"); var result = SetupXCodeProject(pbxTemplatePath); Backend.Current.AddWriteTextAction(pbxPath, result); m_projectFiles.Add(pbxPath); m_projectFiles.Add(mainLibPath); // copy and patch xcscheme file var xcschemePath = xcodeprojPath.Combine("xcshareddata", "xcschemes", "Tiny-iPhone.xcscheme"); var xcschemeTemplatePath = xcodeSrcPath.Combine($"{TinyProjectName}.xcodeproj", "xcshareddata", "xcschemes", "Tiny-iPhone.xcscheme"); result = SetupXcScheme(xcschemeTemplatePath, m_config == DotsConfiguration.Release); Backend.Current.AddWriteTextAction(xcschemePath, result); m_projectFiles.Add(xcschemePath); // copy and patch Info.plist file var plistPath = outputPath.Combine("Sources", "Info.plist"); var plistTemplatePath = xcodeSrcPath.Combine("Sources", "Info.plist"); result = SetupInfoPlist(plistTemplatePath); Backend.Current.AddWriteTextAction(plistPath, result); m_projectFiles.Add(plistPath); // copy xcodeproj files foreach (var r in xcodeSrcPath.Files(true)) { if (r.Extension != "pbxproj" && r.Extension != "xcscheme" && r.FileName != "Info.plist" && !r.HasDirectory("AppIcon.appiconset")) { var destPath = outputPath.Combine(r.RelativeTo(xcodeSrcPath)); destPath = CopyTool.Instance().Setup(destPath, r); m_projectFiles.Add(destPath); } } // copy icon files var icons = IOSAppToolchain.Config.Icons; CopyIcon(xcodeSrcPath, outputPath, "Icon-iPhone-120.png", icons.iPhone2x); CopyIcon(xcodeSrcPath, outputPath, "Icon-iPhone-180.png", icons.iPhone3x); CopyIcon(xcodeSrcPath, outputPath, "Icon-iPad-152.png", icons.iPad2x); CopyIcon(xcodeSrcPath, outputPath, "Icon-iPad-167.png", icons.iPadPro2x); CopyIcon(xcodeSrcPath, outputPath, "AppStore-1024.png", icons.AppStore); CopyIcon(xcodeSrcPath, outputPath, "Contents.json", null); for (int i = 0; i < Deployables.Length; ++i) { var r = Deployables[i]; if (r is DeployableFile && r.Path.FileName == "testconfig.json") { var path = CopyTool.Instance().Setup(outputPath.Combine(r.Path.FileName), r.Path); m_projectFiles.Add(path); break; } } return(pbxPath); }
private NPath PackageApp(NPath buildPath, NPath mainLibPath) { var deployedPath = buildPath.Combine(m_gameName + ".apk"); if (m_apkToolchain == null) { Console.WriteLine($"Error: not Android APK toolchain"); return(deployedPath); } var gradleProjectPath = mainLibPath.Parent.Parent.Parent.Parent.Parent; var pathToRoot = new NPath(string.Concat(Enumerable.Repeat("../", gradleProjectPath.Depth))); var apkSrcPath = AsmDefConfigFile.AsmDefDescriptionFor("Unity.Platforms.Android").Path.Parent.Combine("AndroidProjectTemplate~/"); var javaLaunchPath = m_apkToolchain.JavaPath.Combine("bin").Combine("java"); var gradleLaunchPath = m_apkToolchain.GetGradleLaunchJarPath(); var releaseApk = m_codeGen == CodeGen.Release; var gradleCommand = releaseApk ? "assembleRelease" : "assembleDebug"; var deleteCommand = Unity.BuildTools.HostPlatform.IsWindows ? $"del /f /q {deployedPath.InQuotes(SlashMode.Native)} 2> nul" : $"rm -f {deployedPath.InQuotes(SlashMode.Native)}"; var gradleExecutableString = $"{deleteCommand} && cd {gradleProjectPath.InQuotes()} && {javaLaunchPath.InQuotes()} -classpath {gradleLaunchPath.InQuotes()} org.gradle.launcher.GradleMain {gradleCommand} && cd {pathToRoot.InQuotes()}"; var apkPath = gradleProjectPath.Combine("build/outputs/apk").Combine(releaseApk ? "release/gradle-release.apk" : "debug/gradle-debug.apk"); Backend.Current.AddAction( actionName: "Build Gradle project", targetFiles: new[] { apkPath }, inputs: m_apkToolchain.RequiredArtifacts.Append(mainLibPath).Concat(m_supportFiles.Select(d => d.Path)).ToArray(), executableStringFor: gradleExecutableString, commandLineArguments: Array.Empty <string>(), allowUnexpectedOutput: false, allowedOutputSubstrings: new[] { ":*", "BUILD SUCCESSFUL in *" } ); var templateStrings = new Dictionary <string, string> { { "**TINYNAME**", m_gameName.Replace("-", "").ToLower() }, { "**GAMENAME**", m_gameName }, }; // copy and patch project files foreach (var r in apkSrcPath.Files(true)) { var destPath = gradleProjectPath.Combine(r.RelativeTo(apkSrcPath)); if (r.Extension == "template") { destPath = destPath.ChangeExtension(""); var code = r.ReadAllText(); foreach (var t in templateStrings) { if (code.IndexOf(t.Key) != -1) { code = code.Replace(t.Key, t.Value); } } Backend.Current.AddWriteTextAction(destPath, code); } else { destPath = CopyTool.Instance().Setup(destPath, r); } Backend.Current.AddDependency(apkPath, destPath); } var localProperties = new StringBuilder(); localProperties.AppendLine($"sdk.dir={m_apkToolchain.SdkPath}"); localProperties.AppendLine($"ndk.dir={m_apkToolchain.Sdk.Path.MakeAbsolute()}"); var localPropertiesPath = gradleProjectPath.Combine("local.properties"); Backend.Current.AddWriteTextAction(localPropertiesPath, localProperties.ToString()); Backend.Current.AddDependency(apkPath, localPropertiesPath); // copy additional resources and Data files // TODO: better to use move from main lib directory foreach (var r in m_supportFiles) { var targetAssetPath = gradleProjectPath.Combine("src/main/assets"); if (r.Path.FileName == "testconfig.json") { targetAssetPath = buildPath.Combine(r.Path.FileName); } else if (r is DeployableFile && (r as DeployableFile).RelativeDeployPath != null) { targetAssetPath = targetAssetPath.Combine((r as DeployableFile).RelativeDeployPath); } else { targetAssetPath = targetAssetPath.Combine(r.Path.FileName); } Backend.Current.AddDependency(apkPath, CopyTool.Instance().Setup(targetAssetPath, r.Path)); } return(CopyTool.Instance().Setup(deployedPath, apkPath)); }