void AssertDynamicLibraryId(ApplePlatform platform, string appPath, string dylibDirectory, string library) { var dylibPath = Path.Combine(appPath, dylibDirectory, library); Assert.That(dylibPath, Does.Exist, "dylib existence"); var invalidLoadCommands = new List <string> (); var appExecutable = GetNativeExecutable(platform, appPath); foreach (var file in MachO.Read(appExecutable)) { foreach (var lc in file.load_commands) { if (lc is DylibLoadCommand loadCommand) { if (!IsValidLoadLibrary(loadCommand.name)) { invalidLoadCommands.Add($"Invalid load library '{loadCommand.name}' in '{file.Filename}'"); } } } } var dylibs = Directory.GetFiles(Path.Combine(appPath, dylibDirectory), "*.dylib"); foreach (var dylib in dylibs) { foreach (var file in MachO.Read(dylib)) { foreach (var lc in file.load_commands) { if (lc is DylibIdCommand loadCommand) { if (!IsValidLoadLibrary(loadCommand.name)) { invalidLoadCommands.Add($"Invalid id '{loadCommand.name}' for library '{file.Filename}'"); } } } } } Assert.That(invalidLoadCommands, Is.Empty); }
public void MinOSVersion(Profile profile, MachO.LoadCommands load_command, MachO.Platform platform, bool device = false) { if (device) { Configuration.AssertDeviceAvailable(); } var machoFiles = Directory.GetFiles(Configuration.GetSdkPath(profile, device), "*", SearchOption.AllDirectories) .Where((v) => { if (v.Contains("dylib.dSYM/Contents/Resources/DWARF")) { // Don't include *.dylib from inside .dSYMs. return(false); } else if (v.Contains("libxammac-classic") || v.Contains("libxammac-system-classic")) { // We don't care about XM Classic, those are binary dependencies. return(false); } var ext = Path.GetExtension(v); return(ext == ".a" || ext == ".dylib"); } ); var failed = new List <string> (); foreach (var machoFile in machoFiles) { var fatfile = MachO.Read(machoFile); foreach (var slice in fatfile) { var any_load_command = false; foreach (var lc in slice.load_commands) { Version lc_min_version; var mincmd = lc as MinCommand; if (mincmd != null) { Assert.AreEqual(load_command, mincmd.Command, "Unexpected min load command"); lc_min_version = mincmd.Version; } else { // starting from iOS SDK 12 the LC_BUILD_VERSION is used instead var buildver = lc as BuildVersionCommand; if (buildver == null) { continue; } var alternativePlatform = (MachO.Platform) 0; switch (platform) { case MachO.Platform.IOSSimulator: alternativePlatform = MachO.Platform.IOS; break; case MachO.Platform.TvOSSimulator: alternativePlatform = MachO.Platform.TvOS; break; case MachO.Platform.WatchOSSimulator: alternativePlatform = MachO.Platform.WatchOS; break; } Assert.That(buildver.Platform, Is.EqualTo(platform).Or.EqualTo(alternativePlatform), $"Unexpected build version command in {machoFile} ({slice.Filename})"); lc_min_version = buildver.MinOS; } Version version; Version alternate_version = null; Version mono_native_compat_version; Version mono_native_unified_version; Version alternate_mono_native_unified_version = null; switch (load_command) { case MachO.LoadCommands.MinMacOSX: version = SdkVersions.MinOSXVersion; mono_native_compat_version = SdkVersions.MinOSXVersion; mono_native_unified_version = new Version(10, 12, 0); break; case MachO.LoadCommands.MiniPhoneOS: version = SdkVersions.MiniOSVersion; if (slice.IsDynamicLibrary && device) { if (version.Major < 7) { version = new Version(7, 0, 0); // dylibs are supported starting with iOS 7. } alternate_version = new Version(8, 0, 0); // some iOS dylibs also have min OS 8.0 (if they're used as frameworks as well). } else if (slice.Architecture == MachO.Architectures.ARM64) { alternate_version = new Version(7, 0, 0); // our arm64 slices has min iOS 7.0. } mono_native_compat_version = version; mono_native_unified_version = new Version(10, 0, 0); break; case MachO.LoadCommands.MintvOS: version = SdkVersions.MinTVOSVersion; mono_native_compat_version = version; mono_native_unified_version = new Version(10, 0, 0); break; case MachO.LoadCommands.MinwatchOS: version = SdkVersions.MinWatchOSVersion; if (device) { alternate_version = new Version(5, 1, 0); // arm64_32 has min OS 5.1 } mono_native_compat_version = version; mono_native_unified_version = new Version(5, 0, 0); if (device) { alternate_mono_native_unified_version = new Version(5, 1, 0); // armv7k has 5.0, arm64_32 has 5.1 } break; default: throw new NotImplementedException(load_command.ToString()); } version = version.WithBuild(); mono_native_compat_version = mono_native_compat_version.WithBuild(); mono_native_unified_version = mono_native_unified_version.WithBuild(); if (alternate_version == null) { alternate_version = version; } if (alternate_mono_native_unified_version == null) { alternate_mono_native_unified_version = mono_native_unified_version; } switch (Path.GetFileName(machoFile)) { case "libmono-native-compat.dylib": case "libmono-native-compat.a": if (mono_native_compat_version != lc_min_version) { failed.Add($"Unexpected minOS version (expected {mono_native_compat_version}, found {lc_min_version}) in {machoFile} ({slice.Filename})."); } break; case "libmono-native-unified.dylib": case "libmono-native-unified.a": if (mono_native_unified_version != lc_min_version && alternate_mono_native_unified_version != lc_min_version) { failed.Add($"Unexpected minOS version (expected {mono_native_unified_version}, found {lc_min_version}) in {machoFile} ({slice.Filename})."); } break; default: if (version != lc_min_version && alternate_version != lc_min_version) { failed.Add($"Unexpected minOS version (expected {version}, alternatively {alternate_version}, found {lc_min_version}) in {machoFile} ({slice.Filename})."); } break; } any_load_command = true; } if (!any_load_command) { failed.Add($"No minOS version found in {machoFile}."); } } } CollectionAssert.IsEmpty(failed, "Failures"); }
public void MinOSVersion(Profile profile, MachO.LoadCommands load_command, bool device = false) { if (device) { Configuration.AssertDeviceAvailable(); } var dylibs = Directory.GetFiles(Configuration.GetSdkPath(profile, device), "*.dylib", SearchOption.AllDirectories) .Where((v) => !v.Contains("dylib.dSYM/Contents/Resources/DWARF")); // Don't include *.dylib from inside .dSYMs. var failed = new List <string> (); foreach (var dylib in dylibs) { var fatfile = MachO.Read(dylib); foreach (var slice in fatfile) { var any_load_command = false; foreach (var lc in slice.load_commands) { var mincmd = lc as MinCommand; if (mincmd == null) { continue; } // Console.WriteLine ($" {mincmd.Command} version: {mincmd.version}=0x{mincmd.version.ToString ("x")}={mincmd.Version} sdk: {mincmd.sdk}=0x{mincmd.sdk.ToString ("x")}={mincmd.Sdk}"); Assert.AreEqual(load_command, mincmd.Command, "Unexpected min load command"); Version version; Version alternate_version = null; switch (load_command) { case MachO.LoadCommands.MinMacOSX: version = SdkVersions.MinOSXVersion; break; case MachO.LoadCommands.MiniPhoneOS: version = SdkVersions.MiniOSVersion; if (device) { if (version.Major < 7) { version = new Version(7, 0, 0); // dylibs are supported starting with iOS 7. } alternate_version = new Version(8, 0, 0); // some iOS dylibs also have min OS 8.0 (if they're used as frameworks as well). } break; case MachO.LoadCommands.MintvOS: version = SdkVersions.MinTVOSVersion; break; case MachO.LoadCommands.MinwatchOS: version = SdkVersions.MinWatchOSVersion; break; default: throw new NotImplementedException(load_command.ToString()); } version = new Version(version.Major, version.Minor, version.Build < 0 ? 0 : version.Build); if (alternate_version == null) { alternate_version = version; } if (version != mincmd.Version && alternate_version != mincmd.Version) { failed.Add($"Unexpected minOS version (expected {version}, alternatively {alternate_version}, found {mincmd.Version}) in {dylib}."); } any_load_command = true; } if (!any_load_command) { failed.Add($"No minOS version found in {dylib}."); } } } CollectionAssert.IsEmpty(failed, "Failures"); }