public AsmDefBasedDotsRuntimeCSharpProgram(AsmDefDescription asmDefDescription) : base(asmDefDescription.Directory, deferConstruction: true ) { AsmDefDescription = asmDefDescription; ReferencedPrograms = AsmDefDescription.References.Select(BuildProgram.GetOrMakeDotsRuntimeCSharpProgramFor).ToArray(); var referencesEntryPoint = ReferencedPrograms.Any(r => r.FileName.EndsWith(".exe")); var isExe = asmDefDescription.DefineConstraints.Contains("UNITY_DOTS_ENTRYPOINT") || (asmDefDescription.Path.Parent.Files("*.project").Any() && !referencesEntryPoint) || asmDefDescription.OptionalUnityReferences.Contains("TestAssemblies"); Construct(asmDefDescription.Name, isExe); ProjectFile.AdditionalFiles.Add(asmDefDescription.Path); IncludePlatforms = AsmDefDescription.IncludePlatforms; ExcludePlatforms = AsmDefDescription.ExcludePlatforms; Unsafe = AsmDefDescription.Unsafe; References.Add(config => { if (config is DotsRuntimeCSharpProgramConfiguration dotsConfig) { return(ReferencedPrograms.Where(rp => rp.IsSupportedOn(dotsConfig.NativeProgramConfiguration.ToolChain.Platform))); } //this codepath will be hit for the bindgem invocation return(ReferencedPrograms); }); if (BuildProgram.ZeroJobs != null) { References.Add(BuildProgram.ZeroJobs); } if (BuildProgram.UnityLowLevel != null) { References.Add(BuildProgram.UnityLowLevel); } if (IsTestAssembly) { References.Add(BuildProgram.NUnitFramework); var nunitLiteMain = BuildProgram.BeeRoot.Combine("CSharpSupport/NUnitLiteMain.cs"); Sources.Add(nunitLiteMain); ProjectFile.AddCustomLinkRoot(nunitLiteMain.Parent, "TestRunner"); References.Add(BuildProgram.NUnitLite); References.Add(BuildProgram.GetOrMakeDotsRuntimeCSharpProgramFor(BuildProgramConfigFile.AsmDefDescriptionFor("Unity.Entities"))); } BindGem.ConfigureNativeProgramFor(this); }
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); }
protected void Construct(string name, bool isExe) { FileName = name + (isExe ? ".exe" : ".dll"); Framework.Add(c => ShouldTargetTinyCorlib(c, this), Bee.DotNet.Framework.FrameworkNone); References.Add(c => ShouldTargetTinyCorlib(c, this), Il2Cpp.TinyCorlib); Framework.Add(c => !ShouldTargetTinyCorlib(c, this), Bee.DotNet.Framework.Framework471); References.Add(c => !ShouldTargetTinyCorlib(c, this), new SystemReference("System")); ProjectFile.Path = new NPath(FileName).ChangeExtension(".csproj"); ProjectFile.ReferenceModeCallback = arg => { if (arg == Il2Cpp.TinyCorlib) { return(ProjectFile.ReferenceMode.ByCSProj); } //most projects are AsmDefBasedDotsRuntimeCSharpProgram. The remained are things like ZeroJobs. For them we'll look up their packagestatus by the fact that we know //it's in the same package as Unity.Entities.CPlusPlus var asmdefDotsProgram = (arg as AsmDefBasedDotsRuntimeCSharpProgram)?.AsmDefDescription ?? BuildProgramConfigFile.AsmDefDescriptionFor("Unity.Entities.CPlusPlus"); switch (asmdefDotsProgram.PackageSource) { case "NoPackage": case "Embedded": case "Local": return(ProjectFile.ReferenceMode.ByCSProj); default: return(ProjectFile.ReferenceMode.ByDotNetAssembly); } }; LanguageVersion = "7.3"; Defines.Add( "UNITY_2018_3_OR_NEWER", "UNITY_DOTSPLAYER", "UNITY_ZEROPLAYER", //<-- this was used for a while, let's keep it around to not break people's incoming PR's. "NET_TINY", "NET_DOTS", "UNITY_USE_TINYMATH", "UNITY_BINDGEM" ); Defines.Add(c => (c as DotsRuntimeCSharpProgramConfiguration)?.Platform is WebGLPlatform, "UNITY_WEBGL"); Defines.Add(c => (c as DotsRuntimeCSharpProgramConfiguration)?.Platform is WindowsPlatform, "UNITY_WINDOWS"); Defines.Add(c => (c as DotsRuntimeCSharpProgramConfiguration)?.Platform is MacOSXPlatform, "UNITY_MACOSX"); Defines.Add(c => (c as DotsRuntimeCSharpProgramConfiguration)?.Platform is LinuxPlatform, "UNITY_LINUX"); Defines.Add(c => (c as DotsRuntimeCSharpProgramConfiguration)?.Platform is IosPlatform, "UNITY_IOS"); Defines.Add(c => (c as DotsRuntimeCSharpProgramConfiguration)?.Platform is AndroidPlatform, "UNITY_ANDROID"); CopyReferencesNextToTarget = false; WarningsAsErrors = false; //hack, fix this in unity.mathematics if (SourcePath.FileName == "Unity.Mathematics") { Sources.Add(SourcePath.Files("*.cs", true).Where(f => f.FileName != "math_unity_conversion.cs" && f.FileName != "PropertyAttributes.cs")); } else { var csFilesForDirectory = CSFilesForDirectory(SourcePath).ToList(); if (csFilesForDirectory.Count == 0) { csFilesForDirectory.Add(BuildProgram.BeeRoot.Combine("CSharpSupport/PlaceHolderForEmptyProject.cs")); } Sources.Add(csFilesForDirectory); } var cppFolder = SourcePath.Combine("cpp~"); var prejsFolder = SourcePath.Combine("prejs~"); var jsFolder = SourcePath.Combine("js~"); var postjsFolder = SourcePath.Combine("postjs~"); var beeFolder = SourcePath.Combine("bee~"); var includeFolder = cppFolder.Combine("include"); NPath[] cppFiles = Array.Empty <NPath>(); if (cppFolder.DirectoryExists()) { cppFiles = cppFolder.Files("*.c*", true); ProjectFile.AdditionalFiles.AddRange(cppFolder.Files(true)); GetOrMakeNativeProgram().Sources.Add(cppFiles); } if (prejsFolder.DirectoryExists()) { var jsFiles = prejsFolder.Files("*.js", true); ProjectFile.AdditionalFiles.AddRange(prejsFolder.Files(true)); GetOrMakeNativeProgram().Libraries.Add(jsFiles.Select(jsFile => new PreJsLibrary(jsFile))); } //todo: get rid of having both a regular js and a prejs folder if (jsFolder.DirectoryExists()) { var jsFiles = jsFolder.Files("*.js", true); ProjectFile.AdditionalFiles.AddRange(jsFolder.Files(true)); GetOrMakeNativeProgram().Libraries.Add(jsFiles.Select(jsFile => new JavascriptLibrary(jsFile))); } if (postjsFolder.DirectoryExists()) { var jsFiles = postjsFolder.Files("*.js", true); ProjectFile.AdditionalFiles.AddRange(postjsFolder.Files(true)); GetOrMakeNativeProgram().Libraries.Add(jsFiles.Select(jsFile => new PostJsLibrary(jsFile))); } if (beeFolder.DirectoryExists()) { ProjectFile.AdditionalFiles.AddRange(beeFolder.Files("*.cs")); } if (includeFolder.DirectoryExists()) { GetOrMakeNativeProgram().PublicIncludeDirectories.Add(includeFolder); } SupportFiles.Add(SourcePath.Files().Where(f => f.HasExtension("jpg", "png", "wav", "mp3", "jpeg", "mp4", "webm", "ogg"))); Defines.Add(c => c.CodeGen == CSharpCodeGen.Debug, "DEBUG"); Defines.Add(c => ((DotsRuntimeCSharpProgramConfiguration)c).EnableUnityCollectionsChecks, "ENABLE_UNITY_COLLECTIONS_CHECKS"); Defines.Add( c => (c as DotsRuntimeCSharpProgramConfiguration)?.ScriptingBackend == ScriptingBackend.TinyIl2cpp, "UNITY_DOTSPLAYER_IL2CPP"); Defines.Add(c => (c as DotsRuntimeCSharpProgramConfiguration)?.ScriptingBackend == ScriptingBackend.Dotnet, "UNITY_DOTSPLAYER_DOTNET"); ProjectFile.RedirectMSBuildBuildTargetToBee = true; ProjectFile.AddCustomLinkRoot(SourcePath, "."); ProjectFile.RootNameSpace = ""; DotsRuntimeCSharpProgramCustomizer.RunAllCustomizersOn(this); }
private NPath PackageApp(NPath buildPath, NPath mainLibPath) { var deployedPath = buildPath.Combine(m_gameName.Replace(".", "-") + ".apk"); if (m_apkToolchain == null) { Console.WriteLine($"Error: not Android APK toolchain"); return(deployedPath); } var gradleProjectPath = buildPath.Combine("gradle/"); var pathToRoot = new NPath(string.Concat(Enumerable.Repeat("../", gradleProjectPath.Depth))); var apkSrcPath = BuildProgramConfigFile.AsmDefDescriptionFor("Unity.Platforms.Android").Path.Parent.Combine("AndroidProjectTemplate~/"); var javaLaunchPath = pathToRoot.Combine(m_apkToolchain.JavaPath).Combine("bin").Combine("java"); var gradleLaunchPath = pathToRoot.Combine(m_apkToolchain.GradlePath).Combine("lib").Combine("gradle-launcher-4.6.jar"); var releaseApk = m_codeGen == CodeGen.Release; var gradleCommand = releaseApk ? "assembleRelease" : "assembleDebug"; var deleteCommand = 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: new[] { mainLibPath, m_apkToolchain.SdkPath, m_apkToolchain.JavaPath, m_apkToolchain.GradlePath }, executableStringFor: gradleExecutableString, commandLineArguments: Array.Empty <string>(), allowUnexpectedOutput: false, allowedOutputSubstrings: new[] { ":*", "BUILD SUCCESSFUL in *" } ); var templateStrings = new Dictionary <string, string> { { "**TINYNAME**", m_gameName.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.MakeAbsolute()}"); 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 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)); }