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);
    }
Esempio n. 2
0
    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);
    }
Esempio n. 4
0
        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));
        }