diff --git a/eng/testing/tests.ioslike.targets b/eng/testing/tests.ioslike.targets
index df77a1481fcc7..d4dfbe3ebe1e4 100644
--- a/eng/testing/tests.ioslike.targets
+++ b/eng/testing/tests.ioslike.targets
@@ -10,13 +10,14 @@
- <_AOTBuildCommand>export PATH=$HELIX_CORRELATION_PAYLOAD/build/cmake/cmake-3.16.4-Darwin-x86_64/CMake.app/Contents/bin:$PATH &&
+ <_AOTBuildCommand>export PATH=$HELIX_CORRELATION_PAYLOAD/build/cmake/cmake-3.28.0-macos-universal/CMake.app/Contents/bin:$PATH &&
<_AOTBuildCommand>$(_AOTBuildCommand) dotnet msbuild publish/ProxyProjectForAOTOnHelix.proj /bl:$XHARNESS_OUT/AOTBuild.binlog
<_AOTBuildCommand Condition="'$(ContinuousIntegrationBuild)' != 'true'">$(_AOTBuildCommand) /p:RuntimeSrcDir=$(RepoRoot) /p:RuntimeConfig=$(Configuration)
<_AOTBuildCommand>$(_AOTBuildCommand) /p:XHARNESS_EXECUTION_DIR="$XHARNESS_EXECUTION_DIR" /p:RunAOTCompilation=$(RunAOTCompilation) /p:UseNativeAOTRuntime=$(UseNativeAOTRuntime) /p:TargetOS=$(TargetOS) /p:TargetArchitecture=$(TargetArchitecture) /p:MonoForceInterpreter=$(MonoForceInterpreter) /p:MonoEnableLLVM=true /p:DevTeamProvisioning=$(DevTeamProvisioning) /p:UsePortableRuntimePack=true /p:Configuration=$(Configuration)
+ <_AOTBuildCommand Condition="'$(NativeLib)' != ''">$(_AOTBuildCommand) /p:NativeLib=$(NativeLib) /p:BundlesResources=$(BundlesResources) /p:ForceLibraryModeGenerateAppBundle=$(ForceLibraryModeGenerateAppBundle)
<_AOTBuildCommand>$(_AOTBuildCommand)
<_ResetSimulatorSwitch Condition="('$(TargetOS)' == 'iossimulator' or '$(TargetOS)' == 'tvossimulator') and '$(IncludesTestRunner)' == 'true'">--reset-simulator
diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets
index 256b344888cc0..3202fcf43a776 100644
--- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets
+++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets
@@ -105,8 +105,8 @@
<_symbolExt Condition="'$(OS)' != 'Windows_NT'">$(NativeBinaryExt)$(NativeSymbolExt)
<_symbolSourcePath>$(NativeOutputPath)$(TargetName)$(_symbolExt)
<_symbolTargetPath>$(PublishDir)\$(TargetName)$(_symbolExt)
-
- <_symbolIsFile Condition="'$(NativeSymbolExt)' == '.dsym'">false
+
+ <_symbolIsFile Condition="'$(NativeSymbolExt)' == '.dSYM'">false
<_symbolIsFile Condition="'$(_symbolIsFile)' == ''">true
diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets
index 107f750af7290..ec91635d8fb1d 100644
--- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets
+++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets
@@ -33,7 +33,7 @@ The .NET Foundation licenses this file to you under the MIT license.
libRuntime.ServerGC
- $(RuntimeIdentifier)
+ $(RuntimeIdentifier)
x86_64
@@ -57,6 +57,48 @@ The .NET Foundation licenses this file to you under the MIT license.
libstandalonegc-enabled
+
+ 13.5
+ 14.2
+ 11.0
+
+ <_AppleSdkName Condition="'$(_targetOS)' == 'ios'">iphoneos
+ <_AppleSdkName Condition="'$(_targetOS)' == 'iossimulator'">iphonesimulator
+ <_AppleSdkName Condition="'$(_targetOS)' == 'tvos'">appletvos
+ <_AppleSdkName Condition="'$(_targetOS)' == 'tvossimulator'">appletvsimulator
+ <_AppleSdkName Condition="'$(_targetOS)' == 'maccatalyst'">macosx
+
+ <_AppleTripleOS Condition="'$(_targetOS)' == 'maccatalyst' or $(_targetOS.StartsWith('ios'))">ios
+ <_AppleTripleOS Condition="$(_targetOS.StartsWith('tvos'))">tvos
+
+ <_AppleTripleAbi Condition="'$(_targetOS)' == 'ios' or '$(_targetOS)' == 'tvos'">macho
+ <_AppleTripleAbi Condition="'$(_targetOS)' == 'maccatalyst'">macabi
+ <_AppleTripleAbi Condition="$(_targetOS.EndsWith('simulator'))">simulator
+
+ $(CrossCompileArch)-apple-$(_AppleTripleOS)$(AppleMinOSVersion)-$(_AppleTripleAbi)
+ @rpath/$(TargetName)$(NativeBinaryExt)
+
+
+
+
+
+ xcrun
+ <_WhereXcrun>0
+
+
+
+
+
+
+
+
+
+
+
+
@@ -130,13 +172,15 @@ The .NET Foundation licenses this file to you under the MIT license.
-
-
+
+
+
+
diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets
index e54323ccb4040..c9ff464334c49 100644
--- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets
+++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets
@@ -71,7 +71,7 @@ The .NET Foundation licenses this file to you under the MIT license.
.lib
.a
- .dsym
+ .dSYM
.pdb
.dbg
diff --git a/src/libraries/sendtohelix-mobile.targets b/src/libraries/sendtohelix-mobile.targets
index 1d207919aa51f..b003014bdcd26 100644
--- a/src/libraries/sendtohelix-mobile.targets
+++ b/src/libraries/sendtohelix-mobile.targets
@@ -53,7 +53,7 @@
$([MSBuild]::NormalizeDirectory('$(RepoRoot)', 'src', 'mono', 'msbuild', 'common'))
$(TargetOS)-
- https://netcorenativeassets.blob.core.windows.net/resource-packages/external/macos/cmake/cmake-3.16.4-Darwin-x86_64.tar.gz
+ https://netcorenativeassets.blob.core.windows.net/resource-packages/external/macos/cmake/cmake-3.28.0-macos-universal.tar.gz
<_XHarnessAppleCustomCommand Condition="'$(NeedsiOSSDK)' == 'true'">
source build-apple-app.sh
@@ -64,6 +64,7 @@
+
diff --git a/src/mono/msbuild/apple/build/AppleBuild.props b/src/mono/msbuild/apple/build/AppleBuild.props
index 211b35e7004e1..b910c6c395728 100644
--- a/src/mono/msbuild/apple/build/AppleBuild.props
+++ b/src/mono/msbuild/apple/build/AppleBuild.props
@@ -5,7 +5,7 @@
-
+
true
@@ -19,7 +19,8 @@
- <_IsLibraryMode Condition="'$(UseNativeAOTRuntime)' != 'true' and '$(NativeLib)' != ''">true
+
+ <_IsLibraryMode Condition="('$(UseNativeAOTRuntime)' != 'true' and '$(NativeLib)' != '') or ('$(UseNativeAOTRuntime)' == 'true' and '$(NativeLib)' == 'Shared')">true
<_AotCompileTargetName Condition="'$(UseNativeAOTRuntime)' == 'true'">_AppleNativeAotCompile
<_AotCompileTargetName Condition="'$(UseNativeAOTRuntime)' != 'true'">_AppleAotCompile
diff --git a/src/mono/msbuild/apple/build/AppleBuild.targets b/src/mono/msbuild/apple/build/AppleBuild.targets
index df0bf82e95bd5..914351a5cee4d 100644
--- a/src/mono/msbuild/apple/build/AppleBuild.targets
+++ b/src/mono/msbuild/apple/build/AppleBuild.targets
@@ -4,7 +4,7 @@
true
false
- <_ProcessRuntimeComponentsForLibraryMode Condition="'$(_IsLibraryMode)' == 'true'">_ProcessRuntimeComponentsForLibraryMode
+ <_ProcessRuntimeComponentsForLibraryMode Condition="'$(_IsLibraryMode)' == 'true' and '$(UseNativeAOTRuntime)' != 'true'">_ProcessRuntimeComponentsForLibraryMode
false
@@ -267,7 +267,7 @@
+ DependsOnTargets="SetupProperties;ComputeIlcCompileInputs;IlcCompile;$(_IlcLibraryBuildDependsOn)" />
+
+
-
+
-
-
-
+
+
<_LinkerFlagsToDrop Include="@(NativeFramework->'-framework %(Identity)')" />
diff --git a/src/mono/msbuild/apple/data/ProxyProjectForAOTOnHelix.proj b/src/mono/msbuild/apple/data/ProxyProjectForAOTOnHelix.proj
index fe64069b485fb..e1a82cd4f7c28 100644
--- a/src/mono/msbuild/apple/data/ProxyProjectForAOTOnHelix.proj
+++ b/src/mono/msbuild/apple/data/ProxyProjectForAOTOnHelix.proj
@@ -11,20 +11,36 @@
- $(OriginalPublishDir)
false
true
- static
- true
- false
+ <_UseNativeAOTLibraryModeBundling Condition="'$(NativeLib)' == 'Shared'">true
+
<_IsApplePlatform>true
true
<_targetOS>$(TargetOS)
-
+
true
+
+
+ $(OriginalPublishDir)
+ static
+ true
+ false
+
+
+
+ false
+ $(BaseIntermediateOutputPath)
+ $([MSBuild]::NormalizeDirectory($(TestRootDir), '..', 'bin'))
+ $(OriginalPublishDir)
+ <_IlcLibraryBuildDependsOn>LinkNative;CopyNativeBinary
+
+ false
+
+
@@ -57,6 +73,13 @@
+
+
+
+
127.0.0.1:9000,nosuspend,listen
diff --git a/src/tasks/AppleAppBuilder/Templates/CMakeLists-librarymode.txt.template b/src/tasks/AppleAppBuilder/Templates/CMakeLists-librarymode.txt.template
index edb0989f2bdf7..2b40c6dd1b4ef 100644
--- a/src/tasks/AppleAppBuilder/Templates/CMakeLists-librarymode.txt.template
+++ b/src/tasks/AppleAppBuilder/Templates/CMakeLists-librarymode.txt.template
@@ -5,22 +5,18 @@ enable_language(OBJC ASM)
set(APP_RESOURCES
%AppResources%
-lib%ProjectName%.dylib
)
add_executable(
%ProjectName%
%MainSource%
${APP_RESOURCES}
+ util.h
+ util.m
+ runtime-librarymode.h
+ runtime-librarymode.m
)
-if(NOT %UseNativeAOTRuntime%)
- target_sources(
- %ProjectName%
- PRIVATE
- runtime.m)
-endif()
-
%Defines%
if(NOT %UseNativeAOTRuntime%)
@@ -36,6 +32,7 @@ set_target_properties(%ProjectName% PROPERTIES
XCODE_EMBED_FRAMEWORKS "%DYLIB_PATH%"
XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@executable_path/Frameworks"
XCODE_ATTRIBUTE_SUPPORTS_MACCATALYST "YES"
+ XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY "YES"
RESOURCE "${APP_RESOURCES}"
)
diff --git a/src/tasks/AppleAppBuilder/Templates/main-console.m b/src/tasks/AppleAppBuilder/Templates/main-console.m
index 5bad15ff67de1..bd3a9e78ca0e1 100644
--- a/src/tasks/AppleAppBuilder/Templates/main-console.m
+++ b/src/tasks/AppleAppBuilder/Templates/main-console.m
@@ -2,13 +2,18 @@
// The .NET Foundation licenses this file to you under the MIT license.
#import
+
+#if !USE_LIBRARY_MODE
#if !USE_NATIVE_AOT
#import "runtime.h"
#else
#import
#import "util.h"
extern int __managed__Main(int argc, char* argv[]);
-#endif
+#endif // !USE_NATIVE_AOT
+#else
+#import "runtime-librarymode.h"
+#endif // !USE_LIBRARY_MODE
@interface ViewController : UIViewController
@end
@@ -69,19 +74,23 @@ - (void)viewDidLoad {
[self.view addSubview:summaryLabel];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+#if !USE_LIBRARY_MODE
#if !USE_NATIVE_AOT
mono_ios_runtime_init ();
#else
#if INVARIANT_GLOBALIZATION
setenv ("DOTNET_SYSTEM_GLOBALIZATION_INVARIANT", "1", TRUE);
-#endif
+#endif // INVARIANT_GLOBALIZATION
char **managed_argv;
int managed_argc = get_managed_args (&managed_argv);
int ret_val = __managed__Main (managed_argc, managed_argv);
free_managed_args (&managed_argv, managed_argc);
os_log_info (OS_LOG_DEFAULT, EXIT_CODE_TAG ": %d", ret_val);
exit (ret_val);
-#endif
+#endif // !USE_NATIVE_AOT
+#else
+ library_mode_init();
+#endif //!USE_LIBRARY_MODE
});
}
diff --git a/src/tasks/AppleAppBuilder/Templates/runtime-librarymode.h b/src/tasks/AppleAppBuilder/Templates/runtime-librarymode.h
new file mode 100644
index 0000000000000..16b57d15f4897
--- /dev/null
+++ b/src/tasks/AppleAppBuilder/Templates/runtime-librarymode.h
@@ -0,0 +1,9 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#ifndef runtime_librarymode_h
+#define runtime_librarymode_h
+
+void library_mode_init (void);
+
+#endif /* runtime_librarymode_h */
diff --git a/src/tasks/AppleAppBuilder/Templates/runtime-librarymode.m b/src/tasks/AppleAppBuilder/Templates/runtime-librarymode.m
index 274d9a5414c16..a4cef0ad029c2 100644
--- a/src/tasks/AppleAppBuilder/Templates/runtime-librarymode.m
+++ b/src/tasks/AppleAppBuilder/Templates/runtime-librarymode.m
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
#import
+#if !USE_NATIVE_AOT
#include
#include
#include
@@ -13,6 +14,7 @@
#include
#include
#include
+#endif
#include
#import
#include
@@ -49,7 +51,7 @@ int invoke_netlibrary_entrypoints (void)
}
void
-mono_ios_runtime_init (void)
+library_mode_init (void)
{
#if INVARIANT_GLOBALIZATION
setenv ("DOTNET_SYSTEM_GLOBALIZATION_INVARIANT", "1", TRUE);
@@ -59,17 +61,19 @@ int invoke_netlibrary_entrypoints (void)
setenv ("DOTNET_SYSTEM_GLOBALIZATION_HYBRID", "1", TRUE);
#endif
-#if ENABLE_RUNTIME_LOGGING
+#if ENABLE_RUNTIME_LOGGING && !USE_NATIVE_AOT
setenv ("MONO_LOG_LEVEL", "debug", TRUE);
setenv ("MONO_LOG_MASK", "all", TRUE);
#endif
+#if !USE_NATIVE_AOT
// build using DiagnosticPorts property in AppleAppBuilder
// or set DOTNET_DiagnosticPorts env via mlaunch, xharness when undefined.
// NOTE, using DOTNET_DiagnosticPorts requires app build using AppleAppBuilder and RuntimeComponents to include 'diagnostics_tracing' component
#ifdef DIAGNOSTIC_PORTS
setenv ("DOTNET_DiagnosticPorts", DIAGNOSTIC_PORTS, true);
#endif
+#endif // !USE_NATIVE_AOT
// When not bundling, this will make sure the runtime can access all the assemblies
const char* bundle = get_bundle_path ();
diff --git a/src/tasks/AppleAppBuilder/Xcode.cs b/src/tasks/AppleAppBuilder/Xcode.cs
index e3c4d8149249c..a9bf648f8129a 100644
--- a/src/tasks/AppleAppBuilder/Xcode.cs
+++ b/src/tasks/AppleAppBuilder/Xcode.cs
@@ -259,6 +259,18 @@ public string GenerateCMake(
{
// bundle everything as resources excluding native files
var predefinedExcludes = new List { ".dll.o", ".dll.s", ".dwarf", ".m", ".h", ".a", ".bc", "libmonosgen-2.0.dylib", "libcoreclr.dylib", "icudt*" };
+
+ // TODO: All of these exclusions shouldn't be needed once we carefully construct the publish folder on Helix
+ if (useNativeAOTRuntime)
+ {
+ predefinedExcludes.Add(".dll");
+ predefinedExcludes.Add(".pdb");
+ predefinedExcludes.Add(".json");
+ predefinedExcludes.Add(".txt");
+ predefinedExcludes.Add(".bin");
+ predefinedExcludes.Add(".dSYM");
+ }
+
predefinedExcludes = predefinedExcludes.Concat(excludes).ToList();
if (!preferDylibs)
{
@@ -278,7 +290,7 @@ public string GenerateCMake(
{
// use built-in main.m (with default UI) if it's not set
nativeMainSource = Path.Combine(binDir, "main.m");
- File.WriteAllText(nativeMainSource, Utils.GetEmbeddedResource(useConsoleUiTemplate ? "main-console.m" : "main-simple.m"));
+ File.WriteAllText(nativeMainSource, Utils.GetEmbeddedResource((useConsoleUiTemplate || isLibraryMode) ? "main-console.m" : "main-simple.m"));
}
else
{
@@ -330,8 +342,30 @@ public string GenerateCMake(
if (isLibraryMode)
{
- string dylibName = $"lib{projectName}.dylib";
- cmakeLists = cmakeLists.Replace("%DYLIB_PATH%", $"{Path.Combine(binDir, dylibName)}");
+ string libraryPath;
+ // TODO: unify MonoAOT and NativeAOT library paths
+ // Current differences:
+ // - NativeAOT produces {ProjectName}.dylib, while MonoAOT produces lib{ProjectName}.dylib
+ // - NativeAOT places the library in the 'workspace' location ie 'publish' folder, while MonoAOT places it in 'binDir' ie 'AppBundle'
+ if (useNativeAOTRuntime)
+ {
+ libraryPath = Path.Combine(workspace, $"{projectName}.dylib");
+ }
+ else
+ {
+ libraryPath = Path.Combine(binDir, $"lib{projectName}.dylib");
+ }
+
+ if (!File.Exists(libraryPath))
+ {
+ throw new Exception($"Library not found at: {libraryPath} when building in the library mode.");
+ }
+
+ cmakeLists = cmakeLists.Replace("%DYLIB_PATH%", libraryPath);
+
+ // pass the shared library to the linker for dynamic linking
+ if (useNativeAOTRuntime)
+ toLink += $" {libraryPath}{Environment.NewLine}";
}
else
{
@@ -409,7 +443,8 @@ public string GenerateCMake(
}
string appLinkLibraries = $" {frameworks}{Environment.NewLine}";
- string extraLinkerArgsConcat = $"\"{string.Join('\n', extraLinkerArgs)}\"";
+ string extraLinkerArgsConcatEscapeQuotes = string.Join('\n', extraLinkerArgs).Replace("\"", "\\\"");
+ string extraLinkerArgsConcat = $"\"{extraLinkerArgsConcatEscapeQuotes}\"";
cmakeLists = cmakeLists.Replace("%NativeLibrariesToLink%", toLink);
cmakeLists = cmakeLists.Replace("%APP_LINK_LIBRARIES%", appLinkLibraries);
@@ -454,6 +489,11 @@ public string GenerateCMake(
defines.AppendLine("add_definitions(-DUSE_NATIVE_AOT=1)");
}
+ if (isLibraryMode)
+ {
+ defines.AppendLine("add_definitions(-DUSE_LIBRARY_MODE=1)");
+ }
+
cmakeLists = cmakeLists.Replace("%Defines%", defines.ToString());
string plist = Utils.GetEmbeddedResource("Info.plist.template")
@@ -477,7 +517,12 @@ public string GenerateCMake(
File.WriteAllText(Path.Combine(binDir, "app.entitlements"), entitlementsTemplate.Replace("%Entitlements%", ent.ToString()));
}
- if (!useNativeAOTRuntime)
+ if (isLibraryMode)
+ {
+ File.WriteAllText(Path.Combine(binDir, "runtime-librarymode.h"), Utils.GetEmbeddedResource("runtime-librarymode.h"));
+ File.WriteAllText(Path.Combine(binDir, "runtime-librarymode.m"), Utils.GetEmbeddedResource("runtime-librarymode.m"));
+ }
+ else if (!useNativeAOTRuntime)
{
File.WriteAllText(Path.Combine(binDir, "runtime.h"),
Utils.GetEmbeddedResource("runtime.h"));
@@ -496,9 +541,8 @@ public string GenerateCMake(
pinvokeOverrides.AppendLine($" \"System.Globalization.Native\",");
- string runtimeTemplateName = (isLibraryMode) ? "runtime-librarymode.m" : "runtime.m";
File.WriteAllText(Path.Combine(binDir, "runtime.m"),
- Utils.GetEmbeddedResource(runtimeTemplateName)
+ Utils.GetEmbeddedResource("runtime.m")
.Replace("//%PInvokeOverrideLibraries%", pinvokeOverrides.ToString())
.Replace("//%APPLE_RUNTIME_IDENTIFIER%", RuntimeIdentifier)
.Replace("%EntryPointLibName%", Path.GetFileName(entryPointLib)));
diff --git a/src/tests/FunctionalTests/iOS/Simulator/LibraryMode/Program.cs b/src/tests/FunctionalTests/iOS/Device/LibraryMode/ClassLibrary.cs
similarity index 55%
rename from src/tests/FunctionalTests/iOS/Simulator/LibraryMode/Program.cs
rename to src/tests/FunctionalTests/iOS/Device/LibraryMode/ClassLibrary.cs
index 75b4fa4f6d751..078eb84c4d608 100644
--- a/src/tests/FunctionalTests/iOS/Simulator/LibraryMode/Program.cs
+++ b/src/tests/FunctionalTests/iOS/Device/LibraryMode/ClassLibrary.cs
@@ -6,24 +6,12 @@
using System.Threading.Tasks;
using System.Runtime.InteropServices;
-public static class Program
+public static class ClassLibrary
{
- [DllImport("__Internal")]
- public static extern void mono_ios_set_summary (string value);
-
[UnmanagedCallersOnly(EntryPoint = nameof(SayHello))]
public static int SayHello()
{
Console.WriteLine("Called from native! Hello!");
return 42;
}
-
- public static async Task Main(string[] args)
- {
- mono_ios_set_summary($"Starting functional test");
- Console.WriteLine("Done!");
- await Task.Delay(5000);
-
- return 42;
- }
}
diff --git a/src/tests/FunctionalTests/iOS/Device/LibraryMode/ILLink.Descriptors.xml b/src/tests/FunctionalTests/iOS/Device/LibraryMode/ILLink.Descriptors.xml
new file mode 100644
index 0000000000000..599ada98f3ba5
--- /dev/null
+++ b/src/tests/FunctionalTests/iOS/Device/LibraryMode/ILLink.Descriptors.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/tests/FunctionalTests/iOS/Device/LibraryMode/iOS.Device.LibraryMode.Test.csproj b/src/tests/FunctionalTests/iOS/Device/LibraryMode/iOS.Device.LibraryMode.Test.csproj
new file mode 100644
index 0000000000000..7f33aa52c112d
--- /dev/null
+++ b/src/tests/FunctionalTests/iOS/Device/LibraryMode/iOS.Device.LibraryMode.Test.csproj
@@ -0,0 +1,52 @@
+
+
+
+ Library
+ true
+ $(NetCoreAppCurrent)
+ $(TargetOS)-$(TargetArchitecture)
+ ios
+ false
+ 42
+ true
+ true
+ true
+ shared
+ false
+ true
+
+
+
+ true
+ true
+ iOS.Device.LibraryMode.Test.dll
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+ $(CoreClrProjectRoot)nativeaot/BuildIntegration/Microsoft.DotNet.ILCompiler.SingleEntry.targets
+ $(ToolsProjectRoot)illink/src/ILLink.Tasks/build/Microsoft.NET.ILLink.targets
+ $([MSBuild]::NormalizeDirectory('$(RepoRoot)', 'artifacts', 'bin', 'coreclr', '$(TargetOS).$(TargetArchitecture).$(CoreCLRConfiguration)', 'ilc-published', 'netstandard'))
+ $(IlcBuildTasksDir)ILCompiler.Build.Tasks.dll
+
+
+
+
+
+ $(CoreCLRCrossILCompilerDir)
+ $(CoreCLRAotSdkDir)
+ $(LibrariesAllBinArtifactsPath)
+ $(LibrariesAllBinArtifactsPath)
+
+
+
+
diff --git a/src/tests/FunctionalTests/iOS/Simulator/LibraryMode/ClassLibrary.cs b/src/tests/FunctionalTests/iOS/Simulator/LibraryMode/ClassLibrary.cs
new file mode 100644
index 0000000000000..078eb84c4d608
--- /dev/null
+++ b/src/tests/FunctionalTests/iOS/Simulator/LibraryMode/ClassLibrary.cs
@@ -0,0 +1,17 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Runtime.InteropServices;
+
+public static class ClassLibrary
+{
+ [UnmanagedCallersOnly(EntryPoint = nameof(SayHello))]
+ public static int SayHello()
+ {
+ Console.WriteLine("Called from native! Hello!");
+ return 42;
+ }
+}
diff --git a/src/tests/FunctionalTests/iOS/Simulator/LibraryMode/ILLink.Descriptors.xml b/src/tests/FunctionalTests/iOS/Simulator/LibraryMode/ILLink.Descriptors.xml
index 407eecfd7968c..f6ecff2f1ff37 100644
--- a/src/tests/FunctionalTests/iOS/Simulator/LibraryMode/ILLink.Descriptors.xml
+++ b/src/tests/FunctionalTests/iOS/Simulator/LibraryMode/ILLink.Descriptors.xml
@@ -1,6 +1,6 @@
-
+
diff --git a/src/tests/FunctionalTests/iOS/Simulator/LibraryMode/iOS.Simulator.LibraryMode.Test.csproj b/src/tests/FunctionalTests/iOS/Simulator/LibraryMode/iOS.Simulator.LibraryMode.Test.csproj
index 0454742254a2c..843f82e1555ab 100644
--- a/src/tests/FunctionalTests/iOS/Simulator/LibraryMode/iOS.Simulator.LibraryMode.Test.csproj
+++ b/src/tests/FunctionalTests/iOS/Simulator/LibraryMode/iOS.Simulator.LibraryMode.Test.csproj
@@ -1,29 +1,52 @@
- Exe
- false
- true
+ Library
true
$(NetCoreAppCurrent)
+ $(TargetOS)-$(TargetArchitecture)
iossimulator
- iOS.Simulator.LibraryMode.Test.dll
false
42
- true
- true
true
shared
false
- false
+ true
+
+ true
+ true
+ iOS.Simulator.LibraryMode.Test.dll
+ false
+ true
+ false
+
-
+
+
+
+
+ $(CoreClrProjectRoot)nativeaot/BuildIntegration/Microsoft.DotNet.ILCompiler.SingleEntry.targets
+ $(ToolsProjectRoot)illink/src/ILLink.Tasks/build/Microsoft.NET.ILLink.targets
+ $([MSBuild]::NormalizeDirectory('$(RepoRoot)', 'artifacts', 'bin', 'coreclr', '$(TargetOS).$(TargetArchitecture).$(CoreCLRConfiguration)', 'ilc-published', 'netstandard'))
+ $(IlcBuildTasksDir)ILCompiler.Build.Tasks.dll
+
+
+
+
+
+ $(CoreCLRCrossILCompilerDir)
+ $(CoreCLRAotSdkDir)
+ $(LibrariesAllBinArtifactsPath)
+ $(LibrariesAllBinArtifactsPath)
+
+
+