diff --git a/dotnet/targets/Microsoft.Sdk.R2R.targets b/dotnet/targets/Microsoft.Sdk.R2R.targets index 71c6f4aff0a..0492f48a751 100644 --- a/dotnet/targets/Microsoft.Sdk.R2R.targets +++ b/dotnet/targets/Microsoft.Sdk.R2R.targets @@ -1,6 +1,7 @@ + @@ -134,24 +135,26 @@ - + <_CreateR2RFrameworkDependsOn> _CollectR2RObjectFilesForLinking; - _PrepareR2RFrameworkCreation; - _CreateR2RFrameworkStructure; - _ForceLinkR2RFramework; - _LinkR2RFramework; + _PrepareR2RModules; + _CreateR2RModuleFrameworks; + _GenerateR2RModuleRegistration; - - + <_DesktopFramework Condition="'$(_PlatformName)' == 'macOS' Or '$(_PlatformName)' == 'MacCatalyst'">true @@ -160,81 +163,70 @@ <_R2RFrameworkBinaryInfix Condition="'$(_DesktopFramework)' == 'true'">/Versions/A <_R2RFrameworkResourcesInfix Condition="'$(_DesktopFramework)' == 'true'">/Versions/A/Resources - <_R2RFrameworkIntermediateOutputPath Condition="'$(_R2RFrameworkIntermediateOutputPath)' == ''">$(DeviceSpecificIntermediateOutputPath)r2rframework/ - <_R2RFrameworkName Condition="'$(_R2RFrameworkName)' == ''">$(AssemblyName) - <_R2RFrameworkPath Condition="'$(_R2RFrameworkPath)' == ''">$(_R2RFrameworkIntermediateOutputPath)$(_R2RFrameworkName).framework - <_R2RFrameworkOutput Condition="'$(_R2RFrameworkOutput)' == ''">$(_R2RFrameworkPath)$(_R2RFrameworkBinaryInfix)/$(_R2RFrameworkName) - - <_R2RFrameworkStructureStampFile>$(_R2RFrameworkIntermediateOutputPath)$(_R2RFrameworkName)-structure.stamp - - <_R2RFrameworkInfoPlistPath>$(_R2RFrameworkPath)$(_R2RFrameworkResourcesInfix)/Info.plist - - - - <_R2RFrameworkDirectories Include="$(_R2RFrameworkPath)" /> - - <_R2RFrameworkInputs Include="@(_R2RObjectFilesForLinking)" /> - <_R2RFrameworkLinkerFlags Include="-dynamiclib" /> - <_R2RFrameworkLinkerFlags Include="-Wl,-dead_strip" /> - <_R2RFrameworkLinkerFlags Include="-Wl,-install_name,@rpath/$(_R2RFrameworkName).framework/$(_R2RFrameworkName)" /> - - <_FrameworkNativeReference Include="$(_R2RFrameworkPath)/$(_R2RFrameworkName)" Kind="Framework" /> - - - - <_R2RFrameworkDirectories Include="$(_R2RFrameworkPath)/Versions/A/Resources" /> - - <_R2RFrameworkSymlinks Include="$(_R2RFrameworkPath)/Resources" SymlinkTo="Versions/A/Resources" /> - <_R2RFrameworkSymlinks Include="$(_R2RFrameworkPath)/$(_R2RFrameworkName)" SymlinkTo="Versions/A/$(_R2RFrameworkName)" /> - <_R2RFrameworkSymlinks Include="$(_R2RFrameworkPath)/Versions/Current" SymlinkTo="A" /> - - - - - <_R2RFrameworkCachePath>$(_R2RFrameworkIntermediateOutputPath)cache.txt - <_R2RFrameworkCachePath2>$(_R2RFrameworkCachePath).uptodate + <_R2RModuleIntermediateOutputPath Condition="'$(_R2RModuleIntermediateOutputPath)' == ''">$(DeviceSpecificIntermediateOutputPath)r2rframework/ + <_R2RModuleRegistrationFile>$(_R2RModuleIntermediateOutputPath)r2r_modules.mm - - <_R2RFrameworkCache Include="@(_R2RFrameworkInputs)" /> - <_R2RFrameworkCache Include="@(_R2RFrameworkLinkerFlags)" /> - <_R2RFrameworkCache Include="$(_R2RFrameworkOutput)" /> - <_R2RFrameworkCache Include="$(_MinimumOSVersion)" /> - - - - - - - + - + <_R2RModule Include="@(_ReadyToRunObjectFilesToLink)"> + + $([System.Text.RegularExpressions.Regex]::Replace ('%(Filename)', '\.r2r$', '')) + + $([System.Text.RegularExpressions.Regex]::Replace ($([System.Text.RegularExpressions.Regex]::Replace ('%(Filename)', '\.r2r$', '')), '[^a-zA-Z0-9_]', '_')) + + <_R2RModule Update="@(_R2RModule)"> + RTR_HEADER_%(SanitizedName) + %(NativeLinkerInputPath) + %(ModuleName).r2r + $(_R2RModuleIntermediateOutputPath)%(ModuleName).r2r.framework + $(_R2RModuleIntermediateOutputPath)%(ModuleName).r2r.framework$(_R2RFrameworkBinaryInfix)/%(ModuleName).r2r + $(_R2RModuleIntermediateOutputPath)%(ModuleName).r2r.framework$(_R2RFrameworkResourcesInfix)/Info.plist + $(_R2RModuleIntermediateOutputPath)%(ModuleName).r2r-structure.stamp + $(_R2RModuleIntermediateOutputPath)%(ModuleName).r2r-cache.txt + $(_R2RModuleIntermediateOutputPath)%(ModuleName).r2r-cache.txt.uptodate + $(_R2RModuleIntermediateOutputPath)%(ModuleName).r2r.dylib + $(_R2RModuleIntermediateOutputPath)%(ModuleName).r2r-dylib-cache.txt + $(_R2RModuleIntermediateOutputPath)%(ModuleName).r2r-dylib-cache.txt.uptodate + - + + + + + + - + + + <_CurrentR2RModuleLinkerFlags Remove="@(_CurrentR2RModuleLinkerFlags)" /> + <_CurrentR2RModuleLinkerFlags Include="-dynamiclib" /> + <_CurrentR2RModuleLinkerFlags Include="-Wl,-dead_strip" /> + <_CurrentR2RModuleLinkerFlags Include="-Wl,-alias,_RTR_HEADER,_%(_R2RModule.SymbolName)" /> + <_CurrentR2RModuleLinkerFlags Include="-Wl,-unexported_symbol,_RTR_HEADER" /> + <_CurrentR2RModuleLinkerFlags Include="-Wl,-install_name,@rpath/%(_R2RModule.FrameworkName).framework/%(_R2RModule.FrameworkName)" /> + + + + + + - - - + <_FrameworkNativeReference Include="%(_R2RModule.FrameworkPath)/%(_R2RModule.FrameworkName)" Kind="Framework" /> - - - - - - + + - - + - - - - + - + + + <_CurrentR2RDylibLinkerFlags Remove="@(_CurrentR2RDylibLinkerFlags)" /> + <_CurrentR2RDylibLinkerFlags Include="-dynamiclib" /> + <_CurrentR2RDylibLinkerFlags Include="-Wl,-dead_strip" /> + <_CurrentR2RDylibLinkerFlags Include="-Wl,-alias,_RTR_HEADER,_%(_R2RModule.SymbolName)" /> + <_CurrentR2RDylibLinkerFlags Include="-Wl,-unexported_symbol,_RTR_HEADER" /> + <_CurrentR2RDylibLinkerFlags Include="-Wl,-install_name,@rpath/%(_R2RModule.ModuleName).r2r.dylib" /> + - - - <_CreateR2RDylibDependsOn> - _CollectR2RObjectFilesForLinking; - _PrepareR2RDylibCreation; - _ForceLinkR2RDylib; - _LinkR2RDylib; - - + - - <_R2RDylibIntermediateOutputPath Condition="'$(_R2RFrameworkIntermediateOutputPath)' == ''">$(DeviceSpecificIntermediateOutputPath)r2rdylib/ - <_R2RDylibName Condition="'$(_R2RDylibName)' == ''">$(AssemblyName) - <_R2RDylibPath Condition="'$(_R2RDylibPath)' == ''">$(_R2RDylibIntermediateOutputPath) - <_R2RDylibOutput Condition="'$(_R2RDylibOutput)' == ''">$(_R2RDylibPath)$(_R2RDylibName).r2r.dylib - + MinimumOSVersion="$(_MinimumOSVersion)" + SdkDevPath="$(_SdkDevPath)" + SdkIsSimulator="$(_SdkIsSimulator)" + SdkRoot="$(_SdkRoot)" + TargetArchitectures="$(TargetArchitectures)" + TargetFrameworkMoniker="$(_ComputedTargetFrameworkMoniker)" + /> + - <_R2RDylibInputs Include="@(_R2RObjectFilesForLinking)" /> - <_R2RDylibLinkerFlags Include="-dynamiclib" /> - <_R2RDylibLinkerFlags Include="-Wl,-dead_strip" /> - <_R2RDylibLinkerFlags Include="-Wl,-install_name,@rpath/$(_R2RDylibName).r2r.dylib" /> - - <_FileNativeReference Include="$(_R2RDylibOutput)" Kind="Dynamic" /> + <_FileNativeReference Include="%(_R2RModule.DylibOutput)" Kind="Dynamic" /> - - - <_R2RDylibCachePath>$(_R2RDylibIntermediateOutputPath)cache.txt - <_R2RDylibCachePath2>$(_R2RDylibCachePath).uptodate - - <_R2RDylibCache Include="@(_R2RDylibInputs)" /> - <_R2RDylibCache Include="@(_R2RDylibLinkerFlags)" /> - <_R2RDylibCache Include="$(_R2RDylibOutput)" /> - <_R2RDylibCache Include="$(_MinimumOSVersion)" /> + + - - - + + - + + - + <_MainFile Include="$(_R2RModuleRegistrationFile)" /> - - - - - - + - - + - - + + + <_CreateR2RDylibDependsOn> + _CollectR2RObjectFilesForLinking; + _PrepareR2RModules; + _CreateR2RModuleDylibs; + _GenerateR2RModuleRegistration; + + - + <_PostProcessingItem @@ -2655,11 +2655,11 @@ global using nfloat = global::System.Runtime.InteropServices.NFloat%3B Framework %(Filename).framework.dSYM - + <_PostProcessingItem - Include="$([System.IO.Path]::GetFileName('$(AppBundleDir)'))/$(_AppFrameworksRelativePath)$(_R2RFrameworkName).framework/$(_R2RFrameworkName)" Condition="'$(CreateR2RFramework)' == 'true'"> + Include="@(_R2RModule->'$([System.IO.Path]::GetFileName($(AppBundleDir)))/$(_AppFrameworksRelativePath)%(FrameworkName).framework/%(FrameworkName)')" Condition="'$(CreateR2RFramework)' == 'true'"> Framework - $(_R2RFrameworkName).framework.dSYM + %(FrameworkName).framework.dSYM diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/GenerateR2RModuleRegistration.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/GenerateR2RModuleRegistration.cs new file mode 100644 index 00000000000..47e064eb4e7 --- /dev/null +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/GenerateR2RModuleRegistration.cs @@ -0,0 +1,61 @@ +using System.IO; +using System.Text; + +using Microsoft.Build.Framework; + +#nullable enable + +namespace Xamarin.MacDev.Tasks { + public class GenerateR2RModuleRegistration : XamarinTask { + + #region Inputs + [Required] + public ITaskItem [] R2RModules { get; set; } = []; + + [Required] + public string OutputFile { get; set; } = ""; + #endregion + + public override bool Execute () + { + var sb = new StringBuilder (); + + sb.AppendLine ("#include \"xamarin/xamarin.h\""); + sb.AppendLine (); + + foreach (var module in R2RModules) { + var symbolName = module.GetMetadata ("SymbolName"); + sb.AppendLine ($"extern void* {symbolName};"); + } + + sb.AppendLine (); + sb.AppendLine ("static struct xamarin_r2r_module r2r_module_entries [] = {"); + + foreach (var module in R2RModules) { + var moduleName = module.GetMetadata ("ModuleName"); + var symbolName = module.GetMetadata ("SymbolName"); + sb.AppendLine ($"\t{{ \"{moduleName}\", &{symbolName} }},"); + } + + sb.AppendLine ("};"); + sb.AppendLine (); + + sb.AppendLine ("__attribute__ ((constructor))"); + sb.AppendLine ("static void xamarin_register_r2r_modules ()"); + sb.AppendLine ("{"); + sb.AppendLine ("\txamarin_r2r_modules = r2r_module_entries;"); + sb.AppendLine ("\txamarin_r2r_module_count = sizeof (r2r_module_entries) / sizeof (r2r_module_entries [0]);"); + sb.AppendLine ("}"); + + var content = sb.ToString (); + var outputDir = Path.GetDirectoryName (OutputFile); + if (!string.IsNullOrEmpty (outputDir)) + Directory.CreateDirectory (outputDir); + + if (!File.Exists (OutputFile) || File.ReadAllText (OutputFile) != content) + File.WriteAllText (OutputFile, content); + + return !Log.HasLoggedErrors; + } + } +} diff --git a/runtime/runtime.m b/runtime/runtime.m index 41fbe8ba926..9f727b71abb 100644 --- a/runtime/runtime.m +++ b/runtime/runtime.m @@ -81,6 +81,8 @@ enum XamarinNativeLinkMode xamarin_libmono_native_link_mode = XamarinNativeLinkModeStaticObject; const char **xamarin_runtime_libraries = NULL; void *xamarin_rtr_header = NULL; +struct xamarin_r2r_module *xamarin_r2r_modules = NULL; +int xamarin_r2r_module_count = 0; /* Callbacks */ @@ -2439,9 +2441,25 @@ -(struct NSObjectData*) xamarinGetNSObjectData; if (!context || !data || !context->assembly_path || !context->owner_composite_name) return false; - void* r2r_header = xamarin_rtr_header; + void* r2r_header = NULL; + + // Multi-module: look up by owner_composite_name + if (xamarin_r2r_modules != NULL && xamarin_r2r_module_count > 0) { + for (int i = 0; i < xamarin_r2r_module_count; i++) { + if (strcmp (xamarin_r2r_modules [i].name, context->owner_composite_name) == 0) { + r2r_header = xamarin_r2r_modules [i].header; + break; + } + } + if (r2r_header == NULL) + return false; + } else { + // Single-module fallback for backward compatibility + r2r_header = xamarin_rtr_header; + } + if (r2r_header == NULL) - xamarin_assertion_message ("Failed to find the RTR_HEADER symbol."); + return false; Dl_info info; if (dladdr (r2r_header, &info) == 0) diff --git a/runtime/xamarin/main.h b/runtime/xamarin/main.h index eedfc65f300..4b78e9ebbf6 100644 --- a/runtime/xamarin/main.h +++ b/runtime/xamarin/main.h @@ -129,6 +129,14 @@ extern enum XamarinNativeLinkMode xamarin_libmono_native_link_mode; extern const char** xamarin_runtime_libraries; extern void *xamarin_rtr_header; +struct xamarin_r2r_module { + const char *name; + void *header; +}; + +extern struct xamarin_r2r_module *xamarin_r2r_modules; +extern int xamarin_r2r_module_count; + typedef void (*xamarin_setup_callback) (); typedef int (*xamarin_extension_main_callback) (int argc, char** argv); diff --git a/tools/common/Target.cs b/tools/common/Target.cs index bb864b39db0..33f2b17d52d 100644 --- a/tools/common/Target.cs +++ b/tools/common/Target.cs @@ -344,11 +344,6 @@ void GenerateMainImpl (StringWriter sw, Abi abi) sw.WriteLine (); sw.WriteLine (assembly_externs); - if (app.PublishReadyToRun == true) { - sw.WriteLine ("extern void* RTR_HEADER;"); - sw.WriteLine (); - } - sw.WriteLine ("void xamarin_register_modules_impl ()"); sw.WriteLine ("{"); sw.WriteLine (assembly_aot_modules); @@ -440,8 +435,6 @@ void GenerateMainImpl (StringWriter sw, Abi abi) sw.WriteLine ("\txamarin_runtime_configuration_name = {0};", string.IsNullOrEmpty (app.RuntimeConfigurationFile) ? "NULL" : $"\"{app.RuntimeConfigurationFile}\""); if (app.Registrar == RegistrarMode.ManagedStatic) sw.WriteLine ("\txamarin_set_is_managed_static_registrar (true);"); - if (app.PublishReadyToRun == true) - sw.WriteLine ("\txamarin_rtr_header = &RTR_HEADER;"); sw.WriteLine ("}"); sw.WriteLine (); sw.Write ("int main");