[src] Fix the library for a few P/Invokes. (#12715)

This matters because we use the library defined by the P/Invoke to determine
which frameworks to link with, and if we get it wrong, things like this may
happen:

    Undefined symbols for architecture arm64:
      "_AudioObjectGetPropertyData", referenced from:
          wrapper_managed_to_native_AudioUnit_AudioUnit_AudioObjectGetPropertyData_uint_AudioUnit_AudioObjectPropertyAddress__uint__intptr__uint__uint_ in Xamarin.MacCatalyst.dll.o

because we though that the AudioObjectGetPropertyData function was in the
AudioUnit framework, and not in CoreAudio where it really is, and thus we
didn't link with the CoreAudio framework.

Also add an introspection test to verify that the library our P/Invokes point
to is correct.
This commit is contained in:
Rolf Bjarne Kvinge 2021-09-15 11:05:59 +02:00 коммит произвёл GitHub
Родитель 67fa841aa5
Коммит 2a3bb286f0
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
4 изменённых файлов: 100 добавлений и 6 удалений

Просмотреть файл

@ -906,7 +906,7 @@ namespace AudioUnit
#else
[SupportedOSPlatform ("maccatalyst15.0")]
#endif
[DllImport (Constants.AudioUnitLibrary)]
[DllImport (Constants.CoreAudioLibrary)]
static extern int AudioObjectGetPropertyData (
uint inObjectID,
ref AudioObjectPropertyAddress inAddress,

Просмотреть файл

@ -239,7 +239,7 @@ namespace CoreFoundation {
[Obsolete ("Starting with macos12.0 use 'Network.framework' instead.", DiagnosticId = "BI1234", UrlFormat = "https://github.com/xamarin/xamarin-macios/wiki/Obsolete")]
#endif
#endif
[DllImport (Constants.CFNetworkLibrary)]
[DllImport (Constants.CoreFoundationLibrary)]
internal extern static void CFStreamCreatePairWithPeerSocketSignature (/* CFAllocatorRef */ IntPtr allocator,
/* CFSocketSignature* */ ref CFSocketSignature sig,
/* CFReadStreamRef* */ out IntPtr readStream, /* CFWriteStreamRef* */ out IntPtr writeStream);
@ -365,7 +365,7 @@ namespace CoreFoundation {
[Obsolete ("Starting with macos12.0 use 'Network.framework' instead.", DiagnosticId = "BI1234", UrlFormat = "https://github.com/xamarin/xamarin-macios/wiki/Obsolete")]
#endif
#endif
[DllImport (Constants.CFNetworkLibrary)]
[DllImport (Constants.CoreFoundationLibrary)]
internal extern static void CFStreamCreatePairWithSocketToHost (/* CFAllocatorRef */ IntPtr allocator,
/* CFStringRef */ IntPtr host, /* UInt32 */ int port,
/* CFReadStreamRef* */ out IntPtr readStream, /* CFWriteStreamRef* */ out IntPtr writeStream);
@ -486,7 +486,7 @@ namespace CoreFoundation {
}
#endif
[DllImport (Constants.CFNetworkLibrary)]
[DllImport (Constants.CoreFoundationLibrary)]
internal extern static void CFStreamCreateBoundPair (/* CFAllocatorRef */ IntPtr alloc,
/* CFReadStreamRef* */ out IntPtr readStream, /* CFWriteStreamRef* */ out IntPtr writeStream,
/* CFIndex */ nint transferBufferSize);

Просмотреть файл

@ -292,7 +292,7 @@ namespace CoreGraphics {
ToCTFont() overloads where attributes is CTFontDescriptorRef
#endif // TODO
[DllImport (Constants.CoreTextLibrary, EntryPoint="CGFontGetTypeID")]
[DllImport (Constants.CoreGraphicsLibrary, EntryPoint="CGFontGetTypeID")]
public extern static /* CFTypeID */ nint GetTypeID ();
#endif // !COREBUILD
}

Просмотреть файл

@ -238,8 +238,26 @@ namespace Introspection
var lib = Dlfcn.dlopen (path, 0);
var h = Dlfcn.dlsym (lib, name);
if (h == IntPtr.Zero)
if (h == IntPtr.Zero) {
ReportError ("Could not find the symbol '{0}' in {1} for the P/Invoke {2}.{3} in {4}", name, path, t.FullName, m.Name, a.GetName ().Name);
} else if (path != null) {
// Verify that the P/Invoke points to the right library.
Dl_info info = default (Dl_info);
var found = dladdr (h, out info);
if (found != 0) {
// Resolve symlinks in both cases
var dllImportPath = ResolveLibrarySymlinks (path);
var foundLibrary = ResolveLibrarySymlinks (Marshal.PtrToStringAuto (info.dli_fname));
if (Skip (name, ref dllImportPath, ref foundLibrary)) {
// Skipped
} else if (foundLibrary != dllImportPath) {
ReportError ($"Found the symbol '{name}' in the library '{foundLibrary}', but the P/Invoke {t.FullName}.{m.Name} in {a.GetName ().Name} claims it's in '{dllimport.Value}'.");
}
} else {
Console.WriteLine ($"Unable to find the library for the symbol '{name}' claimed to be in {path} for the P/Invoke {t.FullName}.{m.Name} in {a.GetName ().Name} (rv: {found})");
}
}
Dlfcn.dlclose (lib);
n++;
}
@ -247,6 +265,82 @@ namespace Introspection
Assert.AreEqual (0, Errors, "{0} errors found in {1} symbol lookups{2}", Errors, n, Errors == 0 ? string.Empty : ":\n" + ErrorData.ToString () + "\n");
}
protected string ResolveLibrarySymlinks (string path)
{
var resolved = ((NSString) path).ResolveSymlinksInPath ().ToString ();
// ResolveSymlinksInPath will return the input if something goes wrong.
// Something usually goes wrong with system libraries: they don't actually exist on disk :/
// So add some custom logic to handle those cases.
resolved = resolved.Replace ("/Versions/A/", "/");
resolved = resolved.Replace ("/Versions/C/", "/");
resolved = resolved.Replace (".A.dylib", ".dylib");
return resolved;
}
protected virtual bool Skip (string symbol, ref string dllImportLibrary, ref string nativeLibrary)
{
// We only care about system libraries for this test.
if (!nativeLibrary.StartsWith ("/System", StringComparison.Ordinal))
return true;
// Assume that if the symbol is in a private framework, then the DllImport is pointing
// to the corresponding public/official location, and that we're just running into an
// implementation detail.
if (nativeLibrary.Contains ("/PrivateFrameworks/", StringComparison.Ordinal))
return true;
// System libraries in /usr/lib/system/ have public/official entry points in other
// libraries, so skip those too.
if (nativeLibrary.StartsWith ("/usr/lib/system/", StringComparison.Ordinal))
return true;
switch (nativeLibrary) {
case "/usr/lib/libnetwork.dylib":
return dllImportLibrary == "/System/Library/Frameworks/Network.framework/Network";
case "/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/LaunchServices":
switch (dllImportLibrary) {
case "/System/Library/Frameworks/MobileCoreServices.framework/MobileCoreServices":
case "/System/Library/Frameworks/CoreServices.framework/CoreServices":
return true;
}
break;
case "/System/Library/Frameworks/CoreServices.framework/Frameworks/FSEvents.framework/FSEvents":
return dllImportLibrary == "/System/Library/Frameworks/CoreServices.framework/CoreServices";
#if __MACOS__
case "/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics":
// Years ago, CoreGraphics was somewhere else on macOS
return dllImportLibrary == "/System/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreGraphics.framework/CoreGraphics";
#endif
case "/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib":
return dllImportLibrary == "/System/Library/Frameworks/OpenGL.framework/OpenGL";
case "/System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework/CarbonCore":
return dllImportLibrary == "/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon";
case "/System/Library/Frameworks/MetalPerformanceShaders.framework/Frameworks/MPSCore.framework/MPSCore":
// Check the umbrella framework
nativeLibrary = "/System/Library/Frameworks/MetalPerformanceShaders.framework/MetalPerformanceShaders";
return false;
}
#if __MACCATALYST__
if (nativeLibrary.StartsWith ("/System/iOSSupport/", StringComparison.Ordinal))
nativeLibrary = nativeLibrary.Substring ("/System/iOSSupport".Length);
#endif
return false;
}
[DllImport (Constants.libcLibrary)]
static extern int dladdr (IntPtr addr, out Dl_info info);
struct Dl_info
{
internal IntPtr dli_fname; /* Pathname of shared object */
internal IntPtr dli_fbase; /* Base address of shared object */
internal IntPtr dli_sname; /* Name of nearest symbol */
internal IntPtr dli_saddr; /* Address of nearest symbol */
}
protected abstract bool SkipAssembly (Assembly a);
// Note: this looks very similar to the "SymbolExists" test above (and it is)