[objcruntime] Refactor `Dlfcn.dlopen` to ease linking (#12002)

* Skip extraneous logic for generated entries where we know the full path is available
  * Update generator to use the internal `_dlopen` that skips the checks
  * This removes the code below (diff) for a simple application

* Use the linker substitution files to remove the warning on release builds
  * If `dlopen` is used then `WarnOnce` method becomes a empty stub and
  * field `warningShown` is also removed

```diff
--- a.cs	2021-06-22 20:59:25.000000000 -0400
+++ b.cs	2021-06-22 20:59:28.000000000 -0400
@@ -2023,44 +2023,14 @@
 	{
 		public static class System
 		{
-			public static readonly IntPtr Handle = Dlfcn.dlopen("/usr/lib/libSystem.dylib", 0);
+			public static readonly IntPtr Handle = Dlfcn._dlopen("/usr/lib/libSystem.dylib", 0);
 		}
 	}
 	public static class Dlfcn
 	{
-		private static bool warningShown;
-
 		[DllImport("/usr/lib/libSystem.dylib", EntryPoint = "dlopen")]
 		internal static extern IntPtr _dlopen(string P_0, int P_1);

-		public static IntPtr dlopen(string P_0, int P_1)
-		{
-			return dlopen(P_0, P_1, true);
-		}
-
-		internal static IntPtr dlopen(string P_0, int P_1, bool P_2)
-		{
-			IntPtr intPtr = _dlopen(P_0, P_1);
-			if (intPtr != IntPtr.Zero)
-			{
-				return intPtr;
-			}
-			if (P_0.IndexOf('/') == -1)
-			{
-				if (!warningShown && P_2)
-				{
-					Runtime.NSLog("You are using dlopen without a full path, retrying by prepending /usr/lib");
-					warningShown = true;
-				}
-				intPtr = _dlopen("/usr/lib/" + P_0, P_1);
-				if (intPtr != IntPtr.Zero)
-				{
-					return intPtr;
-				}
-			}
-			return IntPtr.Zero;
-		}
-
 		[DllImport("/usr/lib/libSystem.dylib")]
 		public static extern IntPtr dlsym(IntPtr P_0, string P_1);
 	}
```

Co-authored-by: Sebastien Pouliot <sebastien.pouliot@microsoft.com>
This commit is contained in:
Sebastien Pouliot 2021-06-23 09:13:42 -04:00 коммит произвёл GitHub
Родитель 096c75f425
Коммит 7b934c811c
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
4 изменённых файлов: 27 добавлений и 14 удалений

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

@ -1,5 +1,8 @@
<linker>
<assembly fullname="Xamarin.iOS">
<type fullname="ObjCRuntime.Dlfcn">
<method signature="System.Void WarnOnce()" body="stub" feature="System.Diagnostics.Debugger.IsSupported" featurevalue="false" />
</type>
<type fullname="ObjCRuntime.Runtime">
<method signature="System.Boolean get_IsCoreCLR()" body="stub" value="false" />
</type>

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

@ -1,5 +1,8 @@
<linker>
<assembly fullname="Xamarin.TVOS">
<type fullname="ObjCRuntime.Dlfcn">
<method signature="System.Void WarnOnce()" body="stub" feature="System.Diagnostics.Debugger.IsSupported" featurevalue="false" />
</type>
<type fullname="ObjCRuntime.Runtime">
<method signature="System.Boolean get_IsCoreCLR()" body="stub" value="false" />
</type>

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

@ -49,20 +49,20 @@ namespace ObjCRuntime {
static partial class Libraries {
#if !COREBUILD
static public class System {
static public readonly IntPtr Handle = Dlfcn.dlopen (Constants.libSystemLibrary, 0);
static public readonly IntPtr Handle = Dlfcn._dlopen (Constants.libSystemLibrary, 0);
}
static public class LibC {
static public readonly IntPtr Handle = Dlfcn.dlopen (Constants.libcLibrary, 0);
static public readonly IntPtr Handle = Dlfcn._dlopen (Constants.libcLibrary, 0);
}
#if HAS_OPENGLES
static public class OpenGLES
{
static public readonly IntPtr Handle = Dlfcn.dlopen (Constants.OpenGLESLibrary, 0);
static public readonly IntPtr Handle = Dlfcn._dlopen (Constants.OpenGLESLibrary, 0);
}
#endif
#if !WATCH
static public class AudioToolbox {
static public readonly IntPtr Handle = Dlfcn.dlopen (Constants.AudioToolboxLibrary, 0);
static public readonly IntPtr Handle = Dlfcn._dlopen (Constants.AudioToolboxLibrary, 0);
}
#endif
#endif
@ -98,10 +98,18 @@ namespace ObjCRuntime {
public static IntPtr dlopen (string path, int mode)
{
return dlopen (path, mode, true);
return dlopen (path, mode, showWarning: true);
}
static bool warningShown;
// the linker can eliminate the body of this method (and the above static variable) on release builds
static void WarnOnce ()
{
if (!warningShown)
Runtime.NSLog ("You are using dlopen without a full path, retrying by prepending /usr/lib");
warningShown = true;
}
internal static IntPtr dlopen (string path, int mode, bool showWarning)
{
var x = _dlopen (path, mode);
@ -112,14 +120,9 @@ namespace ObjCRuntime {
// In iOS >= 9, this fails with:
// "no cache image with name (<top>)"
if (path.IndexOf ('/') == -1){
if (!warningShown && showWarning) {
Runtime.NSLog ("You are using dlopen without a full path, retrying by prepending /usr/lib");
warningShown = true;
}
x = _dlopen ("/usr/lib/" + path, mode);
if (x != IntPtr.Zero)
return x;
if (showWarning)
WarnOnce ();
return dlopen ("/usr/lib/" + path, mode, false);
}
return IntPtr.Zero;
}

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

@ -2745,8 +2745,12 @@ public partial class Generator : IMemberGatherer {
print ("static public readonly IntPtr Handle = Dlfcn.dlopen (null, 0);");
} else if (BindThirdPartyLibrary && library_path != null && IsNotSystemLibrary (library_name)) {
print ($"static public readonly IntPtr Handle = Dlfcn.dlopen (\"{library_path}\", 0);");
} else {
} else if (BindThirdPartyLibrary) {
print ("static public readonly IntPtr Handle = Dlfcn.dlopen (Constants.{0}Library, 0);", library_name);
} else {
// Skip the path check that our managed `dlopen` method does
// This is not required since the path is checked by `IsNotSystemLibrary`
print ("static public readonly IntPtr Handle = Dlfcn._dlopen (Constants.{0}Library, 0);", library_name);
}
indent--; print ("}");
}