Example #1
0
        public void TestNdkUtil()
        {
            var log = new TaskLoggingHelper(engine, TestName);

            using (var builder = new Builder()) {
                var ndkDir = AndroidNdkPath;
                var sdkDir = AndroidSdkPath;
                MonoAndroidHelper.AndroidSdk = new AndroidSdkInfo((arg1, arg2) => { }, sdkDir, ndkDir, AndroidSdkResolver.GetJavaSdkPath());
                NdkUtil.Init(log, ndkDir);
                var platforms = NdkUtil.GetSupportedPlatforms(log, ndkDir);
                Assert.AreNotEqual(0, platforms.Count(), "No platforms found");
                var arch = AndroidTargetArch.X86;
                Assert.IsTrue(NdkUtil.ValidateNdkPlatform(log, ndkDir, arch, enableLLVM: false));
                Assert.AreEqual(0, errors.Count, "NdkUtil.ValidateNdkPlatform should not have returned false.");
                int level    = NdkUtil.GetMinimumApiLevelFor(arch, ndkDir);
                int expected = 16;
                Assert.AreEqual(expected, level, $"Min Api Level for {arch} should be {expected}.");
                var compilerNoQuotes = NdkUtil.GetNdkTool(ndkDir, arch, "gcc", level);
                Assert.AreEqual(0, errors.Count, "NdkUtil.GetNdkTool should not have errored.");
                Assert.NotNull(compilerNoQuotes, "NdkUtil.GetNdkTool returned null.");
                var gas = NdkUtil.GetNdkTool(ndkDir, arch, "as", level);
                Assert.AreEqual(0, errors.Count, "NdkUtil.GetNdkTool should not have errored.");
                Assert.NotNull(gas, "NdkUtil.GetNdkTool returned null.");
                var inc = NdkUtil.GetNdkPlatformIncludePath(ndkDir, arch, level);
                Assert.NotNull(inc, " NdkUtil.GetNdkPlatformIncludePath should not return null");
                var libPath = NdkUtil.GetNdkPlatformLibPath(ndkDir, arch, level);
                Assert.NotNull(libPath, "NdkUtil.GetNdkPlatformLibPath  should not return null");
                string ld = NdkUtil.GetNdkTool(ndkDir, arch, "ld", level);
                Assert.AreEqual(0, errors.Count, "NdkUtil.GetNdkTool should not have errored.");
                Assert.NotNull(ld, "NdkUtil.GetNdkTool returned null.");
            }
        }
Example #2
0
        bool DoExecute()
        {
            var    results    = new List <ITaskItem>();
            string bundlepath = Path.Combine(TempOutputPath, "bundles");

            if (!Directory.Exists(bundlepath))
            {
                Directory.CreateDirectory(bundlepath);
            }
            else if (ProduceStub && Link)
            {
                Directory.Delete(bundlepath, true);
            }
            foreach (var abi in SupportedAbis)
            {
                AndroidTargetArch arch = AndroidTargetArch.Other;
                switch (abi)
                {
                case "arm64":
                case "arm64-v8a":
                case "aarch64":
                    arch = AndroidTargetArch.Arm64;
                    break;

                case "armeabi-v7a":
                    arch = AndroidTargetArch.Arm;
                    break;

                case "x86":
                    arch = AndroidTargetArch.X86;
                    break;

                case "x86_64":
                    arch = AndroidTargetArch.X86_64;
                    break;

                case "mips":
                    arch = AndroidTargetArch.Mips;
                    break;
                }

                if (!NdkUtil.ValidateNdkPlatform(Log, AndroidNdkDirectory, arch, enableLLVM: false))
                {
                    return(false);
                }

                var    clb     = new CommandLineBuilder();
                var    proc    = new Process();
                var    outpath = Path.Combine(bundlepath, abi);
                int    level   = NdkUtil.GetMinimumApiLevelFor(arch, AndroidNdkDirectory);
                string windowsCompilerSwitches = NdkUtil.GetCompilerTargetParameters(AndroidNdkDirectory, arch, level);
                var    compilerNoQuotes        = NdkUtil.GetNdkTool(AndroidNdkDirectory, arch, "gcc", level);
                var    compiler = $"\"{compilerNoQuotes}\" {windowsCompilerSwitches}".Trim();
                if (ProduceStub)
                {
                    if (!Directory.Exists(outpath))
                    {
                        Directory.CreateDirectory(outpath);
                    }

                    clb.AppendSwitch("--dos2unix=false");
                    clb.AppendSwitch("--nomain");
                    clb.AppendSwitch("--i18n none");
                    clb.AppendSwitch("--bundled-header");
                    clb.AppendSwitch("--mono-api-struct-path");
                    clb.AppendFileNameIfNotNull(BundleApiPath);
                    clb.AppendSwitch("--style");
                    clb.AppendSwitch("linux");
                    clb.AppendSwitch("-c");
                    clb.AppendSwitch("-v");
                    clb.AppendSwitch("-o");
                    clb.AppendFileNameIfNotNull(Path.Combine(outpath, "temp.c"));
                    clb.AppendSwitch("-oo");
                    clb.AppendFileNameIfNotNull(Path.Combine(outpath, "assemblies.o"));
                    if (AutoDeps)
                    {
                        clb.AppendSwitch("--autodeps");
                    }
                    if (KeepTemp)
                    {
                        clb.AppendSwitch("--keeptemp");
                    }
                    clb.AppendSwitch("-z"); // Compress
                    clb.AppendFileNamesIfNotNull(Assemblies, " ");
                    var psi = new ProcessStartInfo()
                    {
                        FileName               = MkbundlePath,
                        Arguments              = clb.ToString(),
                        UseShellExecute        = false,
                        RedirectStandardOutput = true,
                        RedirectStandardError  = true,
                        CreateNoWindow         = true,
                        WindowStyle            = ProcessWindowStyle.Hidden,
                    };
                    var gas = '"' + NdkUtil.GetNdkTool(AndroidNdkDirectory, arch, "as", level) + '"';
                    psi.EnvironmentVariables["CC"] = compiler;
                    psi.EnvironmentVariables["AS"] = gas;
                    Log.LogDebugMessage("CC=" + compiler);
                    Log.LogDebugMessage("AS=" + gas);
                    Log.LogDebugMessage("[mkbundle] " + psi.FileName + " " + clb);
                    proc.OutputDataReceived += OnMkbundleOutputData;
                    proc.ErrorDataReceived  += OnMkbundleErrorData;
                    proc.StartInfo           = psi;
                    proc.Start();
                    proc.BeginOutputReadLine();
                    proc.BeginErrorReadLine();
                    proc.WaitForExit();
                    if (proc.ExitCode != 0)
                    {
                        Log.LogCodedError("XA5102", "Conversion from assembly to native code failed. Exit code {0}", proc.ExitCode);
                        return(false);
                    }
                }
                // then compile temp.c into temp.o and ...

                if (Link)
                {
                    clb = new CommandLineBuilder();

                    // See NdkUtils.GetNdkTool for reasons why
                    if (!String.IsNullOrEmpty(windowsCompilerSwitches))
                    {
                        clb.AppendTextUnquoted(windowsCompilerSwitches);
                    }

                    clb.AppendSwitch("-c");

                    // This is necessary only when unified headers are in use but it won't hurt to have it
                    // defined even if we don't use them
                    clb.AppendSwitch($"-D__ANDROID_API__={level}");

                    // This is necessary because of the injected code, which is reused between libmonodroid
                    // and the bundle
                    clb.AppendSwitch("-DANDROID");

                    clb.AppendSwitch("-o");
                    clb.AppendFileNameIfNotNull(Path.Combine(outpath, "temp.o"));
                    if (!string.IsNullOrWhiteSpace(IncludePath))
                    {
                        clb.AppendSwitch("-I");
                        clb.AppendFileNameIfNotNull(IncludePath);
                    }

                    string asmIncludePath = NdkUtil.GetNdkAsmIncludePath(AndroidNdkDirectory, arch, level);
                    if (!String.IsNullOrEmpty(asmIncludePath))
                    {
                        clb.AppendSwitch("-I");
                        clb.AppendFileNameIfNotNull(asmIncludePath);
                    }

                    clb.AppendSwitch("-I");
                    clb.AppendFileNameIfNotNull(NdkUtil.GetNdkPlatformIncludePath(AndroidNdkDirectory, arch, level));
                    clb.AppendFileNameIfNotNull(Path.Combine(outpath, "temp.c"));
                    Log.LogDebugMessage("[CC] " + compiler + " " + clb);
                    if (MonoAndroidHelper.RunProcess(compilerNoQuotes, clb.ToString(), OnCcOutputData, OnCcErrorData) != 0)
                    {
                        Log.LogCodedError("XA5103", "NDK C compiler resulted in an error. Exit code {0}", proc.ExitCode);
                        return(false);
                    }

                    // ... link temp.o and assemblies.o into app.so

                    clb = new CommandLineBuilder();
                    clb.AppendSwitch("--shared");
                    clb.AppendFileNameIfNotNull(Path.Combine(outpath, "temp.o"));
                    clb.AppendFileNameIfNotNull(Path.Combine(outpath, "assemblies.o"));

                    // API23+ requires that the shared library has its soname set or it won't load
                    clb.AppendSwitch("-soname");
                    clb.AppendSwitch(BundleSharedLibraryName);
                    clb.AppendSwitch("-o");
                    clb.AppendFileNameIfNotNull(Path.Combine(outpath, BundleSharedLibraryName));
                    clb.AppendSwitch("-L");
                    clb.AppendFileNameIfNotNull(NdkUtil.GetNdkPlatformLibPath(AndroidNdkDirectory, arch, level));
                    clb.AppendSwitch("-lc");
                    clb.AppendSwitch("-lm");
                    clb.AppendSwitch("-ldl");
                    clb.AppendSwitch("-llog");
                    clb.AppendSwitch("-lz"); // Compress
                    string ld = NdkUtil.GetNdkTool(AndroidNdkDirectory, arch, "ld", level);
                    Log.LogMessage(MessageImportance.Normal, "[LD] " + ld + " " + clb);
                    if (MonoAndroidHelper.RunProcess(ld, clb.ToString(), OnLdOutputData, OnLdErrorData) != 0)
                    {
                        Log.LogCodedError("XA5201", "NDK Linker resulted in an error. Exit code {0}", proc.ExitCode);
                        return(false);
                    }
                    results.Add(new TaskItem(Path.Combine(outpath, "libmonodroid_bundle_app.so")));
                }
            }
            OutputNativeLibraries = results.ToArray();
            return(true);
        }