[runtime] Set the current directory to the root directory of the app bundle for all platforms in .NET. (#12104)
To have consistent behavior in .NET, set the current directory to the root of the app bundle for all platforms. This is a breaking change for legacy Xamarin.Mac, which used to set the current directory to the Contents/Resources subdirectory, but there's a simple workaround for customers that depend on the old behavior (change it in Main themselves), and I believe the consistent experience across platforms warrants this change. Note that we already had a breaking change here for macOS/.NET: we were (unintentionally) setting the current directory to the Contents/MonoBundle directory, which neither matched mobile platforms, nor the legacy Xamarin.Mac behavior. This solves the problem of what to do for Mac Catalyst apps, because there's no need to choose between the macOS or the mobile behavior, since they're the same. This required changing the launch of macOS apps using CoreCLR to pass the full path to the entry assembly, since the entry assembly isn't in the current directory anymore.
This commit is contained in:
Родитель
a202354c71
Коммит
fc8fb4818c
|
@ -602,18 +602,18 @@ mono_jit_exec (MonoDomain * domain, MonoAssembly * assembly, int argc, const cha
|
||||||
{
|
{
|
||||||
unsigned int exitCode = 0;
|
unsigned int exitCode = 0;
|
||||||
|
|
||||||
char *assemblyName = xamarin_bridge_get_assembly_name (assembly->gchandle);
|
char *assemblyPath = xamarin_bridge_get_assembly_location (assembly->gchandle);
|
||||||
|
|
||||||
LOG_CORECLR (stderr, "mono_jit_exec (%p, %p, %i, %p) => EXECUTING %s\n", domain, assembly, argc, argv, assemblyName);
|
LOG_CORECLR (stderr, "mono_jit_exec (%p, %p, %i, %p) => EXECUTING %s\n", domain, assembly, argc, argv, assemblyPath);
|
||||||
for (int i = 0; i < argc; i++) {
|
for (int i = 0; i < argc; i++) {
|
||||||
LOG_CORECLR (stderr, " Argument #%i: %s\n", i + 1, argv [i]);
|
LOG_CORECLR (stderr, " Argument #%i: %s\n", i + 1, argv [i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
int rv = coreclr_execute_assembly (coreclr_handle, coreclr_domainId, argc, argv, assemblyName, &exitCode);
|
int rv = coreclr_execute_assembly (coreclr_handle, coreclr_domainId, argc, argv, assemblyPath, &exitCode);
|
||||||
|
|
||||||
LOG_CORECLR (stderr, "mono_jit_exec (%p, %p, %i, %p) => EXECUTING %s rv: %i exitCode: %i\n", domain, assembly, argc, argv, assemblyName, rv, exitCode);
|
LOG_CORECLR (stderr, "mono_jit_exec (%p, %p, %i, %p) => EXECUTING %s rv: %i exitCode: %i\n", domain, assembly, argc, argv, assemblyPath, rv, exitCode);
|
||||||
|
|
||||||
xamarin_free (assemblyName);
|
xamarin_free (assemblyPath);
|
||||||
|
|
||||||
if (rv != 0)
|
if (rv != 0)
|
||||||
xamarin_assertion_message ("mono_jit_exec failed: %i\n", rv);
|
xamarin_assertion_message ("mono_jit_exec failed: %i\n", rv);
|
||||||
|
|
|
@ -383,6 +383,13 @@
|
||||||
OnlyCoreCLR = true,
|
OnlyCoreCLR = true,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
new XDelegate ("char *", "IntPtr", "xamarin_bridge_get_assembly_location",
|
||||||
|
"GCHandle", "IntPtr", "gchandle"
|
||||||
|
) {
|
||||||
|
WrappedManagedFunction = "GetAssemblyLocation",
|
||||||
|
OnlyCoreCLR = true,
|
||||||
|
},
|
||||||
|
|
||||||
new XDelegate ("MonoObject *", "MonoObject *", "xamarin_bridge_create_exception",
|
new XDelegate ("MonoObject *", "MonoObject *", "xamarin_bridge_create_exception",
|
||||||
"enum XamarinExceptionTypes", "Runtime.ExceptionType", "type",
|
"enum XamarinExceptionTypes", "Runtime.ExceptionType", "type",
|
||||||
"const char *", "IntPtr", "arg0"
|
"const char *", "IntPtr", "arg0"
|
||||||
|
|
|
@ -270,8 +270,11 @@ xamarin_main (int argc, char *argv[], enum XamarinLaunchMode launch_mode)
|
||||||
|
|
||||||
MonoAssembly *assembly;
|
MonoAssembly *assembly;
|
||||||
GCHandle exception_gchandle = NULL;
|
GCHandle exception_gchandle = NULL;
|
||||||
const char *c_bundle_path = xamarin_get_bundle_path ();
|
|
||||||
|
|
||||||
|
// For legacy Xamarin.Mac, we used to chdir to $appdir/Contents/Resources (I'm not sure where this comes from, earliest commit I could find was this: https://github.com/xamarin/maccore/commit/20045dd7f85cb038cea673a9281bb6131711069c)
|
||||||
|
// For mobile platforms, we chdir to $appdir
|
||||||
|
// In .NET, we always chdir to $appdir, so that we're consistent
|
||||||
|
const char *c_bundle_path = xamarin_get_app_bundle_path ();
|
||||||
chdir (c_bundle_path);
|
chdir (c_bundle_path);
|
||||||
|
|
||||||
setenv ("DYLD_BIND_AT_LAUNCH", "1", 1);
|
setenv ("DYLD_BIND_AT_LAUNCH", "1", 1);
|
||||||
|
|
|
@ -1318,6 +1318,23 @@ xamarin_initialize ()
|
||||||
MONO_EXIT_GC_UNSAFE;
|
MONO_EXIT_GC_UNSAFE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *x_app_bundle_path = NULL;
|
||||||
|
const char *
|
||||||
|
xamarin_get_app_bundle_path ()
|
||||||
|
{
|
||||||
|
if (x_app_bundle_path != NULL)
|
||||||
|
return x_app_bundle_path;
|
||||||
|
|
||||||
|
NSBundle *main_bundle = [NSBundle mainBundle];
|
||||||
|
|
||||||
|
if (main_bundle == NULL)
|
||||||
|
xamarin_assertion_message ("Could not find the main bundle in the app ([NSBundle mainBundle] returned nil)");
|
||||||
|
|
||||||
|
x_app_bundle_path = strdup ([[[main_bundle bundlePath] stringByStandardizingPath] UTF8String]);
|
||||||
|
|
||||||
|
return x_app_bundle_path;
|
||||||
|
}
|
||||||
|
|
||||||
static char *x_bundle_path = NULL;
|
static char *x_bundle_path = NULL;
|
||||||
const char *
|
const char *
|
||||||
xamarin_get_bundle_path ()
|
xamarin_get_bundle_path ()
|
||||||
|
|
|
@ -154,9 +154,12 @@ void xamarin_initialize ();
|
||||||
void xamarin_initialize_embedded (); /* Public API, must not change - this is used by the embeddinator */
|
void xamarin_initialize_embedded (); /* Public API, must not change - this is used by the embeddinator */
|
||||||
|
|
||||||
void xamarin_assertion_message (const char *msg, ...) __attribute__((__noreturn__));
|
void xamarin_assertion_message (const char *msg, ...) __attribute__((__noreturn__));
|
||||||
|
// Gets the bundle path (where the managed executable is). This is *not* the path of the app bundle (.app/.appex).
|
||||||
const char * xamarin_get_bundle_path (); /* Public API */
|
const char * xamarin_get_bundle_path (); /* Public API */
|
||||||
// Sets the bundle path (where the managed executable is). By default APP/Contents/MonoBundle.
|
// Sets the bundle path (where the managed executable is). By default APP/Contents/MonoBundle.
|
||||||
void xamarin_set_bundle_path (const char *path); /* Public API */
|
void xamarin_set_bundle_path (const char *path); /* Public API */
|
||||||
|
// Gets the app bundle path (.app/.appex).
|
||||||
|
const char * xamarin_get_app_bundle_path ();
|
||||||
MonoObject * xamarin_get_managed_object_for_ptr_fast (id self, GCHandle *exception_gchandle);
|
MonoObject * xamarin_get_managed_object_for_ptr_fast (id self, GCHandle *exception_gchandle);
|
||||||
void xamarin_check_for_gced_object (MonoObject *obj, SEL sel, id self, MonoMethod *method, GCHandle *exception_gchandle);
|
void xamarin_check_for_gced_object (MonoObject *obj, SEL sel, id self, MonoMethod *method, GCHandle *exception_gchandle);
|
||||||
unsigned long xamarin_objc_type_size (const char *type);
|
unsigned long xamarin_objc_type_size (const char *type);
|
||||||
|
|
|
@ -407,6 +407,12 @@ namespace ObjCRuntime {
|
||||||
return Marshal.StringToHGlobalAuto (Path.GetFileName (asm.Location));
|
return Marshal.StringToHGlobalAuto (Path.GetFileName (asm.Location));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static IntPtr GetAssemblyLocation (IntPtr gchandle)
|
||||||
|
{
|
||||||
|
var asm = (Assembly) GetGCHandleTarget (gchandle);
|
||||||
|
return Marshal.StringToHGlobalAuto (asm.Location);
|
||||||
|
}
|
||||||
|
|
||||||
static void SetFlagsForNSObject (IntPtr gchandle, byte flags)
|
static void SetFlagsForNSObject (IntPtr gchandle, byte flags)
|
||||||
{
|
{
|
||||||
var obj = (NSObject) GetGCHandleTarget (gchandle);
|
var obj = (NSObject) GetGCHandleTarget (gchandle);
|
||||||
|
|
|
@ -847,5 +847,15 @@ Additional information:
|
||||||
handles [i].Free ();
|
handles [i].Free ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void CurrentDirectory ()
|
||||||
|
{
|
||||||
|
#if NET || !MONOMAC
|
||||||
|
Assert.AreEqual (Environment.CurrentDirectory, NSBundle.MainBundle.BundlePath, "Current directory at launch");
|
||||||
|
#else
|
||||||
|
Assert.AreEqual (Environment.CurrentDirectory, NSBundle.MainBundle.ResourcePath, "Current directory at launch");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче