예제 #1
0
        async Task <bool> DownloadBinutils(Context context, string localPackagePath, Uri url)
        {
            if (Utilities.FileExists(localPackagePath))
            {
                Log.StatusLine($"{ProductName} archive already downloaded");
                return(true);
            }

            Log.StatusLine($"Downloading {ProductName} from ", url.ToString(), tailColor: ConsoleColor.White);
            (bool success, ulong size, HttpStatusCode status) = await Utilities.GetDownloadSizeWithStatus(url);

            if (!success)
            {
                if (status == HttpStatusCode.NotFound)
                {
                    Log.ErrorLine($"{ProductName} archive URL not found");
                    return(false);
                }
                Log.WarningLine($"Failed to obtain {ProductName} size. HTTP status code: {status} ({(int)status})");
            }

            DownloadStatus downloadStatus = Utilities.SetupDownloadStatus(context, size, context.InteractiveSession);

            Log.StatusLine($"  {context.Characters.Link} {url}", ConsoleColor.White);
            await Download(context, url, localPackagePath, ProductName, Path.GetFileName(localPackagePath), downloadStatus);

            if (!File.Exists(localPackagePath))
            {
                Log.ErrorLine($"Download of {ProductName} from {url} failed.");
                return(false);
            }

            return(true);
        }
예제 #2
0
        bool HaveAllBinutils(string dir, string?executableExtension = null)
        {
            Log.DebugLine("Checking if all binutils are installed in {dir}");
            string extension = executableExtension ?? String.Empty;

            foreach (var kvp in Configurables.Defaults.AndroidToolchainPrefixes)
            {
                string prefix = kvp.Value;

                foreach (NDKTool tool in Configurables.Defaults.NDKTools)
                {
                    string toolName          = GetToolName(prefix, tool, executableExtension);
                    string toolPath          = Path.Combine(dir, toolName);
                    string versionMarkerPath = GetVersionMarker(toolPath);

                    Log.DebugLine($"Checking {toolName}");
                    if (!Utilities.FileExists(toolPath))
                    {
                        Log.DebugLine($"Binutils tool {toolPath} does not exist");
                        return(false);
                    }

                    if (!Utilities.FileExists(versionMarkerPath))
                    {
                        Log.DebugLine($"Binutils tool {toolPath} exists, but its version is incorrect");
                        return(false);
                    }
                }
            }

            return(true);
        }
예제 #3
0
        protected static string FindProgram(string programName, List <string> directories)
        {
            foreach (string dir in directories)
            {
                string path = Path.Combine(dir, programName);
                if (Utilities.FileExists(path))
                {
                    return(path);
                }
            }

            return(null);
        }
예제 #4
0
        protected override async Task <bool> Execute(Context context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            Uri    nugetUrl       = Configurables.Urls.NugetUri;
            string localNugetPath = Configurables.Paths.LocalNugetPath;

            if (Utilities.FileExists(localNugetPath))
            {
                Log.StatusLine($"NuGet already downloaded ({localNugetPath})");
                return(true);
            }

            Utilities.CreateDirectory(Path.GetDirectoryName(localNugetPath));
            Log.StatusLine("Downloading NuGet");

            (bool success, ulong size, HttpStatusCode status) = await Utilities.GetDownloadSizeWithStatus(nugetUrl);

            if (!success)
            {
                if (status == HttpStatusCode.NotFound)
                {
                    Log.ErrorLine("NuGet URL not found");
                }
                else
                {
                    Log.ErrorLine("Failed to obtain NuGet size. HTTP status code: {status} ({(int)status})");
                }
                return(false);
            }

            DownloadStatus downloadStatus = Utilities.SetupDownloadStatus(context, size, context.InteractiveSession);

            Log.StatusLine($"  {context.Characters.Link} {nugetUrl}", ConsoleColor.White);
            await Download(context, nugetUrl, localNugetPath, "NuGet", Path.GetFileName(localNugetPath), downloadStatus);

            if (!File.Exists(localNugetPath))
            {
                Log.ErrorLine($"Download of NuGet from {nugetUrl} failed");
                return(false);
            }

            return(true);
        }
        public virtual string GetVersion(Context context, string fullProgramPath)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            string programPath = String.IsNullOrEmpty(fullProgramPath) ? ProgramName : fullProgramPath;

            if (Path.IsPathRooted(ProgramName))
            {
                programPath = ProgramName;
            }
            else if (ProgramName.IndexOf(Path.DirectorySeparatorChar) >= 0)
            {
                if (ProgramName [0] == Path.DirectorySeparatorChar)                   // Might be the case on Windows
                {
                    programPath = Path.GetFullPath(ProgramName);
                }
                else
                {
                    programPath = Path.Combine(BuildPaths.XamarinAndroidSourceRoot, ProgramName);
                }
            }
            else
            {
                programPath = context.OS.Which(ProgramName, required: false);
            }

            if (!Utilities.FileExists(programPath))
            {
                Log.DebugLine("File {fullProgramPath} does not exist, unable to obtain version");
                return(DefaultVersionString);
            }

            string versionOutput = Utilities.GetStringFromStdout(programPath, VersionArguments);

            Log.DebugLine($"{programPath} {VersionArguments} returned: {versionOutput}");

            return(ParseVersion(versionOutput));
        }
        protected override async Task <bool> Execute(Context context)
        {
            string xcrun = context.OS.Which("xcrun");

            var libs = new string[] {
                Path.Combine(Configurables.Paths.HostRuntimeDir, Configurables.Paths.UnstrippedLibMonoSgenName),
                Path.Combine(Configurables.Paths.HostRuntimeDir, Configurables.Paths.StrippedLibMonoSgenName),
            };

            bool result = true;

            Log.StatusLine("Changing id for:");
            foreach (string libPath in libs)
            {
                if (!Utilities.FileExists(libPath))
                {
                    Log.StatusLine("    not found", ConsoleColor.Magenta);
                    continue;
                }

                if (!ChangeID(libPath))
                {
                    Log.StatusLine("    failed", ConsoleColor.Magenta);
                    result = false;
                }
            }

            return(result);

            bool ChangeID(string path)
            {
                Log.DebugLine($"Changing dylib id for {path}");
                Log.StatusLine($"  {context.Characters.Bullet} {Utilities.GetRelativePath (BuildPaths.XamarinAndroidSourceRoot, path)}");
                var runner = new ProcessRunner(xcrun, "install_name_tool", "-id", "@loader_path/libmonosgen-2.0.dylib", path);

                return(runner.Run());
            }
        }
예제 #7
0
        protected override async Task <bool> Execute(Context context)
        {
            if (context.ForceRuntimesBuild)
            {
                if (osSupportsMonoBuild)
                {
                    Log.InfoLine("Rebuilding Mono runtimes as requested");
                    return(false);
                }

                Log.InfoLine($"Forced Mono runtimes rebuild requested but rebuilding on {context.OS.Type} is currently not supported.");
            }

            string localPackagePath = Configurables.Paths.BundleArchivePath;

            Log.DebugLine($"Local bundle path: {localPackagePath}");

            if (await Utilities.VerifyArchive(localPackagePath))
            {
                Log.StatusLine("Xamarin.Android Bundle archive already downloaded and valid");
            }
            else
            {
                if (!String.IsNullOrEmpty(context.XABundlePath))
                {
                    // User indicated they wanted to use a specific bundle that's supposed to be on disk. It's not (or
                    // it's invalid) and that means we have no way of getting it - we can't download the default one
                    // since that was not the intention behind overriding the location. Thus, we error out.
                    Log.DebugLine($"Bundle directory from command line: {context.XABundlePath}");
                    throw new InvalidOperationException($"Xamarin.Android bundle indicated on the command line does not exist ({context.XABundlePath})");
                }

                var bundleUrl = new Uri(BundleUriPrefix, BundleFileName);

                Log.StatusLine("Bundle URL: ", $"{bundleUrl}", tailColor: ConsoleColor.Cyan);

                HttpStatusCode status;
                bool           success;
                ulong          size;

                (success, size, status) = await Utilities.GetDownloadSizeWithStatus(bundleUrl);

                if (!success)
                {
                    if (status == HttpStatusCode.NotFound)
                    {
                        if (osSupportsMonoBuild)
                        {
                            Log.StatusLine("   not found, will need to rebuild");
                        }
                        else
                        {
                            Log.ErrorLine($"   not found, rebuilding on {context.OS.Type} is not currently supported");
                        }
                        return(false);
                    }

                    if (String.IsNullOrEmpty(bundle404Message))
                    {
                        throw new InvalidOperationException($"Failed to access bundle at {bundleUrl} (HTTP status: {status})");
                    }
                    else
                    {
                        throw new InvalidOperationException(bundle404Message);
                    }
                }

                DownloadStatus downloadStatus = Utilities.SetupDownloadStatus(context, size, context.InteractiveSession);
                Log.StatusLine($"  {context.Characters.Link} {bundleUrl}", ConsoleColor.White);
                await Download(context, bundleUrl, localPackagePath, "Xamarin.Android Bundle", Path.GetFileName(localPackagePath), downloadStatus);

                if (!File.Exists(localPackagePath))
                {
                    Log.ErrorLine($"Download of Xamarin.Android Bundle from {bundleUrl} failed.");
                    return(false);
                }
            }

            Log.StatusLine($"Unpacking bundle to {Utilities.GetRelativePath (BuildPaths.XamarinAndroidSourceRoot, Configurables.Paths.BundleInstallDir)}");
            string tempDir = $"{Configurables.Paths.BundleInstallDir}-bundle.temp";

            try {
                if (!await Utilities.Unpack(localPackagePath, tempDir, cleanDestinatioBeforeUnpacking: true))
                {
                    Log.WarningLine("Failed to unpack bundle, will need to rebuild");
                    return(false);
                }

                Log.DebugLine($"Moving unpacked bundle from {tempDir} to {Configurables.Paths.BundleInstallDir}");
                Utilities.MoveDirectoryContentsRecursively(tempDir, Configurables.Paths.BundleInstallDir, resetFileTimestamp: true, ignoreDeletionErrors: true);
            } finally {
                Utilities.DeleteDirectorySilent(tempDir);
            }

            string managedRuntime     = context.Properties.GetRequiredValue(KnownProperties.ManagedRuntime);
            bool   haveManagedRuntime = !String.IsNullOrEmpty(managedRuntime);

            if (!await Utilities.BuildRemapRef(context, haveManagedRuntime, managedRuntime))
            {
                return(false);
            }

            Utilities.PropagateXamarinAndroidCecil(context);

            if (String.IsNullOrEmpty(context.XABundleCopyDir))
            {
                return(HaveEverything());
            }

            string destPackagePath = Path.Combine(context.XABundleCopyDir, Path.GetFileName(localPackagePath));

            Log.DebugLine($"Copy of the XA bundle was requested to be created at {destPackagePath}");
            if (Utilities.FileExists(destPackagePath))
            {
                Log.DebugLine("Bundle copy already exists");
                return(HaveEverything());
            }

            // Utilities.FileExists above will return `false` for a dangling symlink at `destPackagePath`, doesn't hurt
            // to remove it here just in case
            Utilities.DeleteFileSilent(destPackagePath);
            Utilities.CopyFile(localPackagePath, destPackagePath);

            return(HaveEverything());

            bool HaveEverything()
            {
                bool ret = MonoRuntimesHelpers.AllBundleItemsPresent(new Runtimes());

                if (!ret)
                {
                    Log.Instance.StatusLine($"Some bundle files are missing, download/rebuild/reinstall forced");
                }
                return(ret);
            }
        }
예제 #8
0
        /// <summary>
        ///   Locate the program indicated in <paramref name="programPath"/> which can be just the base program name
        ///   (without the executable extension for cross-OS compatibility) or a full path to a program (however also
        ///   without the executable extension). In both cases the method tries to find the program at the indicated
        ///   location (if a path is used in <paramref name="programPath"/>) or in the directories found in the
        ///   <c>PATH</c> environment variable, trying all executable extensions (<see cref="ExecutableExtensions"/>)
        ///   until the program file is found. If the file is indeed found, a check is made whether it is executable (by
        ///   calling <see cref="AssertIsExecutable"/>) and the path is returned. If, however, the program is not found
        ///   and <paramref name="required"/> is <c>true</c> then an exception is throw. If <paramref name="required"/>
        ///   is <c>false</c>, however, <c>null</c> is returned.
        /// </summary>
        public virtual string Which(string programPath, bool required = true)
        {
            if (String.IsNullOrEmpty(programPath))
            {
                goto doneAndOut;
            }

            string match;

            // If it's any form of path, just return it as-is, possibly with executable extension added
            if (programPath.IndexOf(Path.DirectorySeparatorChar) >= 0)
            {
                match = GetExecutableWithExtension(programPath, (string ext) => {
                    string fp = $"{programPath}{ext}";
                    if (Utilities.FileExists(fp))
                    {
                        return(fp);
                    }
                    return(null);
                }
                                                   );

                if (match == null && Utilities.FileExists(programPath))
                {
                    match = programPath;
                }

                if (match != null)
                {
                    return(match);
                }
                else if (required)
                {
                    goto doneAndOut;
                }

                return(programPath);
            }

            List <string> extensions  = ExecutableExtensions;
            List <string> directories = GetPathDirectories();

            match = GetExecutableWithExtension(programPath, (string ext) => FindProgram($"{programPath}{ext}", directories));
            if (match != null)
            {
                return(AssertIsExecutable(match));
            }

            match = FindProgram($"{programPath}", directories);
            if (match != null)
            {
                return(AssertIsExecutable(match));
            }

doneAndOut:
            if (required)
            {
                throw new InvalidOperationException($"Required program '{programPath}' could not be found");
            }

            return(null);
        }
예제 #9
0
        async Task <(bool disabled, bool success)> ConfigureBuildAndInstall(Context context, string abiName)
        {
            if (!context.IsHostJitAbiEnabled(abiName))
            {
                Log.DebugLine($"Windows target {abiName} disabled, not building libzip");
                return(true, true);
            }

            bool   sixtyFourBit = context.Is64BitMingwHostAbi(abiName);
            string sourceDir    = context.Properties.GetRequiredValue(KnownProperties.LibZipSourceFullPath);
            string buildDir     = Path.Combine(Configurables.Paths.BuildBinDir, $"libzip-windows-{abiName}");
            string stampFile    = Path.Combine(buildDir, $".build-{context.BuildInfo.FullLibZipHash}");
            string outputPath;

            if (sixtyFourBit)
            {
                outputPath = Path.Combine("x64", LibZipName);
            }
            else
            {
                outputPath = LibZipName;
            }

            string sourceFile = Path.Combine(buildDir, "lib", LibZipName);
            string destFile   = Path.Combine(Configurables.Paths.LibZipOutputPath, outputPath);
            bool   needBuild;

            if (Utilities.FileExists(stampFile) && Utilities.FileExists(sourceFile))
            {
                Log.DebugLine($"LibZip-Windows build stamp file exists: {stampFile}");
                Log.StatusLine($"LibZip for {abiName} already built, skipping compilation");
                needBuild = false;
            }
            else
            {
                needBuild = true;
            }

            if (needBuild)
            {
                Utilities.DeleteDirectorySilent(buildDir);
                Utilities.CreateDirectory(buildDir);
                List <string> arguments = GetCmakeArguments(context, buildDir, sixtyFourBit);

                string logTag = $"libzip-windows-{abiName}";
                var    cmake  = new CMakeRunner(context);
                bool   result = await cmake.Run(
                    logTag : logTag,
                    sourceDirectory : sourceDir,
                    workingDirectory : buildDir,
                    arguments : arguments
                    );

                if (!result)
                {
                    return(false, false);
                }

                var ninja = new NinjaRunner(context);
                result = await ninja.Run(
                    logTag : logTag,
                    workingDirectory : buildDir
                    );

                if (!result)
                {
                    return(false, false);
                }
            }

            Utilities.CopyFile(sourceFile, destFile);

            if (!File.Exists(destFile))
            {
                Log.ErrorLine($"Failed to copy {sourceFile} to {destFile}");
                return(false, false);
            }

            TouchStampFile(stampFile);
            return(false, true);
        }
예제 #10
0
        public bool GatherNDKInfo(Context context)
        {
            string ndkDir = Configurables.Paths.AndroidNdkDirectory;
            string props  = Path.Combine(ndkDir, "source.properties");

            if (!File.Exists(props))
            {
                Log.ErrorLine("NDK properties file does not exist: ", props, tailColor: Log.DestinationColor);
                return(false);
            }

            string[] lines = File.ReadAllLines(props);
            foreach (string l in lines)
            {
                string   line  = l.Trim();
                string[] parts = line.Split(NDKPropertySeparator, 2);
                if (parts.Length != 2)
                {
                    continue;
                }

                if (String.Compare("Pkg.Revision", parts [0].Trim(), StringComparison.Ordinal) != 0)
                {
                    continue;
                }

                string rev = parts [1].Trim();
                NDKRevision = rev;

                Version ver;
                if (!Version.TryParse(rev, out ver))
                {
                    Log.ErrorLine($"Unable to parse NDK revision '{rev}' as a valid version string");
                    return(false);
                }

                NDKVersionMajor = ver.Major.ToString();
                NDKVersionMinor = ver.Minor.ToString();
                NDKVersionMicro = ver.Build.ToString();
                break;
            }

            Log.DebugLine($"Looking for minimum API available in {ndkDir}");
            int minimumApi = Int32.MaxValue;

            foreach (var kvp in Configurables.Defaults.AndroidToolchainPrefixes)
            {
                string dirName   = kvp.Value;
                string platforms = Path.Combine(Configurables.Paths.AndroidToolchainSysrootLibDirectory, dirName);
                Log.DebugLine($"  searching in {platforms}");
                foreach (string p in Directory.EnumerateDirectories(platforms, "*", SearchOption.TopDirectoryOnly))
                {
                    string plibc = Path.Combine(p, "libc.so");
                    if (!Utilities.FileExists(plibc))
                    {
                        continue;
                    }

                    Log.DebugLine($"    found {p}");
                    string pdir = Path.GetFileName(p);
                    int    api;
                    if (!Int32.TryParse(pdir, out api))
                    {
                        continue;
                    }

                    if (api >= minimumApi)
                    {
                        continue;
                    }

                    minimumApi = api;
                }
            }

            Log.DebugLine($"Detected minimum NDK API level: {minimumApi}");
            NDKMinimumApiAvailable = minimumApi.ToString();
            return(true);
        }