Example #1
0
        public TypeResources(NPath typeDbOutputDirectory)
        {
            TypeDBOutputDirectory = typeDbOutputDirectory;
            var typeResources = new DotNetAssembly($"{EditorApplication.applicationContentsPath}/Tools/TypeGenerator/TypeGenerator.exe", Framework.Framework471);

            _typeGeneratorExecutable = new DotNetRunnableProgram(typeResources, DotNetRuntime.FindFor(typeResources));
        }
Example #2
0
        public PostProcessor(DotNetAssembly[] processors, NPath outputDirectory)
        {
            OutputDirectory = outputDirectory;

            NPath srcDir = Path.GetFullPath(Path.Combine(Package.PackagePath, "Editor/Unity.Build.Classic.Private/Incremental/ILPostProcessing~"));
            var   processorRunnerProgram = new CSharpProgram()
            {
                FileName = "ILPostProcessorRunner.exe",
                Sources  =
                {
                    srcDir,
                },
                References =
                {
                    EditorApplication.applicationContentsPath + "/Managed/Unity.CompilationPipeline.Common.dll"
                },
                GenerateXmlDoc             = XmlDocMode.Disabled,
                ProjectFilePath            = $"{srcDir}/ILProcessor.gen.csproj",
                CopyReferencesNextToTarget = true,
                Framework = { Framework.Framework471 }
            };

            _processorRunner                    = processorRunnerProgram.SetupDefault();
            _processorRunnableProgram           = new DotNetRunnableProgram(new DotNetAssembly(_processorRunner.Path, Framework.NetStandard20));
            _builtProcessors                    = processors.Select(a => a.DeployTo(Configuration.RootArtifactsPath.Combine("postprocessors"))).ToArray();
            _builtProcessorsDependenciesAndSelf = _builtProcessors.SelectMany(bp => bp.RecursiveRuntimeDependenciesIncludingSelf).Distinct().ToArray();

            _inputFilesFromPostProcessor = _processorRunner.RecursiveRuntimeDependenciesIncludingSelf.Concat(_builtProcessorsDependenciesAndSelf).Select(p => p.Path).ToArray();

            //we are in a funky situation today where user code is compiled against .net standard 2,  but unityengine assemblies are compiled against .net47.  Postprocessors
            //need to be able to deep-resolve any typereference, and it's going to encounter references to both netstandard.dll as well as mscorlib.dll and system.dll. We're going
            //to allow all these typereferences to resolve by resolving against the reference assemblies for both these profiles.
            _bclFiles = Framework471.Singleton.ReferenceAssemblies.Concat(Netstandard20.Singleton.ReferenceAssemblies).Select(a => a.Path).ToArray();
        }
Example #3
0
        static void AddActions(DotNetAssembly[] inputAssemblies, NPath targetDirectory, NativeProgramConfiguration nativeProgramConfiguration)
        {
            var linkerAssembly = new DotNetAssembly(Distribution.Path.Combine("build/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"),
                "--rule-set=experimental", // This will enable modification of method bodies to further reduce size.
                inputAssemblies.Select(a => $"--include-directory={a.Path.Parent.InQuotes()}")
            };

            linkerArguments.AddRange(rootAssemblies.Select(rootAssembly => $"--include-public-assembly={rootAssembly.Path.InQuotes()}"));

//            foreach (var inputDirectory in inputFiles.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}");
            }

            //          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" });
        }
        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);
        }
Example #5
0
    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);
    }
Example #6
0
    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
            );
    }
Example #7
0
        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);
        }
Example #8
0
        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 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);
        }