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); }
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); }
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); }
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()); } }
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); } }
/// <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); }
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); }
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); }