Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion dotnet/targets/Xamarin.Shared.Sdk.targets
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,6 @@
<InvariantGlobalization Condition="'$(InvariantGlobalization)' == ''">false</InvariantGlobalization>
<!-- Enable HybridGlobalization by default-->
<HybridGlobalization Condition="'$(InvariantGlobalization)' != 'true'">true</HybridGlobalization>
<StartupHookSupport Condition="'$(StartupHookSupport)' == ''">false</StartupHookSupport>
<UseSizeOptimizedLinq Condition="'$(UseSizeOptimizedLinq)' == ''">true</UseSizeOptimizedLinq>
<UseSystemResourceKeys Condition="'$(UseSystemResourceKeys)' == '' And '$(_BundlerDebug)' != 'true'">true</UseSystemResourceKeys>
<UseSystemResourceKeys Condition="'$(UseSystemResourceKeys)' == '' And '$(_BundlerDebug)' == 'true'">false</UseSystemResourceKeys>
Expand All @@ -142,6 +141,12 @@
<DynamicCodeSupport Condition="'$(DynamicCodeSupport)' == '' And ( '$(MtouchInterpreter)' == '' And '$(UseInterpreter)' != 'true' ) And ('$(_PlatformName)' == 'iOS' Or '$(_PlatformName)' == 'tvOS' Or '$(_PlatformName)' == 'MacCatalyst')">false</DynamicCodeSupport>
<_ComObjectDescriptorSupport Condition="'$(_ComObjectDescriptorSupport)' == ''">false</_ComObjectDescriptorSupport>

<!-- StartupHookSupport is used for Hot Reload, so we enable it unless the Optimize flag is set. -->
<!-- When we set StartupHookSupport=true ourselves, suppress the resulting trimmer warning (but not if the developer set it). -->
<_SuppressStartupHookSupportTrimWarning Condition="'$(StartupHookSupport)' == '' And '$(Optimize)' != 'true'">true</_SuppressStartupHookSupportTrimWarning>
<StartupHookSupport Condition="'$(StartupHookSupport)' == '' And '$(Optimize)' != 'true'">true</StartupHookSupport>
<StartupHookSupport Condition="'$(StartupHookSupport)' == ''">false</StartupHookSupport>
Comment on lines +144 to +148
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On Android I also had this in a block for "applications" (that have OutputType=Exe or AndroidApplication=true).

It may not matter, though.


<!-- We don't need to generate reference assemblies for apps or app extensions -->
<ProduceReferenceAssembly Condition="'$(ProduceReferenceAssembly)' == '' And ('$(OutputType)' == 'Exe' Or '$(IsAppExtension)' == 'true')">false</ProduceReferenceAssembly>

Expand Down Expand Up @@ -694,6 +699,7 @@

<ItemGroup>
<!-- Configure linker features -->
<RuntimeHostConfigurationOption Include="ObjCRuntime.SuppressStartupHookTrimWarning" Value="true" Trim="true" Condition="'$(_SuppressStartupHookSupportTrimWarning)' == 'true'" />
<RuntimeHostConfigurationOption Include="ObjCRuntime.AggressiveAttributeTrimming" Value="true" Trim="true" Condition="'$(MobileAggressiveAttributeTrimming)' == 'true'" />
<RuntimeHostConfigurationOption Include="ObjCRuntime.AggressiveAttributeTrimmingMono" Value="true" Trim="true" Condition="'$(MobileAggressiveAttributeTrimming)' == 'true' And '$(_XamarinRuntime)' == 'MonoVM'" />
<RuntimeHostConfigurationOption Include="ObjCRUntime.AggressiveAttributeTrimmingOnlyWithStaticRegistrar" value="true" Trim="true" Condition="'$(MobileAggressiveAttributeTrimming)' == 'true' And ('$(Registrar)' == 'static' Or '$(Registrar)' == 'managed-static')" />
Expand Down Expand Up @@ -1266,6 +1272,7 @@
<_RuntimeConfigReservedProperties Include="NATIVE_DLL_SEARCH_DIRECTORIES" />
<_RuntimeConfigReservedProperties Include="RUNTIME_IDENTIFIER" />
<_RuntimeConfigReservedProperties Include="APP_CONTEXT_BASE_DIRECTORY" />
<_RuntimeConfigReservedProperties Include="STARTUP_HOOKS" />
</ItemGroup>
<RuntimeConfigParserTask
Condition="'$(GenerateRuntimeConfigurationFiles)' == 'true'"
Expand Down
6 changes: 6 additions & 0 deletions runtime/runtime.m
Original file line number Diff line number Diff line change
Expand Up @@ -2406,6 +2406,7 @@ -(struct NSObjectData*) xamarinGetNSObjectData;
char *pinvokeOverride = xamarin_strdup_printf ("%p", &xamarin_pinvoke_override);
char *trusted_platform_assemblies = xamarin_compute_trusted_platform_assemblies ();
char *native_dll_search_directories = xamarin_compute_native_dll_search_directories ();
const char *startupHooks = getenv ("DOTNET_STARTUP_HOOKS");

// All the properties we pass here must also be listed in the _RuntimeConfigReservedProperties item group
// for the _CreateRuntimeConfiguration target in dotnet/targets/Xamarin.Shared.Sdk.targets.
Expand All @@ -2416,6 +2417,7 @@ -(struct NSObjectData*) xamarinGetNSObjectData;
"TRUSTED_PLATFORM_ASSEMBLIES",
"NATIVE_DLL_SEARCH_DIRECTORIES",
"RUNTIME_IDENTIFIER",
"STARTUP_HOOKS", // must be last entry (because we just decrement propertyCount to not pass it if it's not set)
};
const char *propertyValues[] = {
xamarin_get_bundle_path (),
Expand All @@ -2424,10 +2426,14 @@ -(struct NSObjectData*) xamarinGetNSObjectData;
trusted_platform_assemblies,
native_dll_search_directories,
RUNTIMEIDENTIFIER,
startupHooks,
};
static_assert (sizeof (propertyKeys) == sizeof (propertyValues), "The number of keys and values must be the same.");

int propertyCount = (int) (sizeof (propertyValues) / sizeof (propertyValues [0]));
if (startupHooks == NULL || startupHooks [0] == 0)
propertyCount--;

bool rv = xamarin_bridge_vm_initialize (propertyCount, propertyKeys, propertyValues);

xamarin_free (pinvokeOverride);
Expand Down
11 changes: 11 additions & 0 deletions src/TrimAttributes.LinkDescription.xml
Original file line number Diff line number Diff line change
Expand Up @@ -290,4 +290,15 @@
</attribute>
</type>
</assembly>
<!-- Suppress the IL2026 warning from System.StartupHookProvider.ProcessStartupHooks when we're the ones enabling StartupHookSupport -->
<assembly fullname="System.Private.CoreLib" feature="ObjCRuntime.SuppressStartupHookTrimWarning" featurevalue="true">
<type fullname="System.StartupHookProvider">
<method name="ProcessStartupHooks">
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
<argument>ILLink</argument>
<argument>IL2026</argument>
</attribute>
</method>
</type>
</assembly>
</linker>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)-maccatalyst</TargetFramework>
</PropertyGroup>
<Import Project="..\shared.csproj" />
</Project>

17 changes: 17 additions & 0 deletions tests/dotnet/StartupHookLibrary/StartupHook.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System;

using Foundation;


class StartupHook {
public static void Initialize ()
{
Console.WriteLine ("STARTUP");

StartupStatus.Initialized = true;
}
}

public static class StartupStatus {
public static bool Initialized { get; internal set; }
}
8 changes: 8 additions & 0 deletions tests/dotnet/StartupHookLibrary/iOS/StartupHookLibrary.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)-ios</TargetFramework>
</PropertyGroup>
<Import Project="..\shared.csproj" />
</Project>

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)-macos</TargetFramework>
</PropertyGroup>
<Import Project="..\shared.csproj" />
</Project>

6 changes: 6 additions & 0 deletions tests/dotnet/StartupHookLibrary/shared.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project>
<ItemGroup>
<Compile Include="../*.cs" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)-tvos</TargetFramework>
</PropertyGroup>
<Import Project="..\shared.csproj" />
</Project>

35 changes: 35 additions & 0 deletions tests/dotnet/StartupHookTest/AppDelegate.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System;
using System.Runtime.InteropServices;

using Foundation;

namespace MySimpleApp {
public class Program {
static int Main (string [] args)
{
GC.KeepAlive (typeof (NSObject)); // prevent linking away the platform assembly

Console.WriteLine (Environment.GetEnvironmentVariable ("MAGIC_WORD"));
Console.WriteLine ($"Startup.Initialized: {StartupHook.Initialized}");
Console.WriteLine ($"StartupStatus.Initialized: {StartupStatus.Initialized}");

var rv = 0;

if (!StartupHook.Initialized)
rv += 1;

if (!StartupStatus.Initialized)
rv += 2;

return rv;
}
}
}

class StartupHook {
Comment thread
rolfbjarne marked this conversation as resolved.
public static bool Initialized { get; private set; }
public static void Initialize ()
{
Initialized = true;
}
}
1 change: 1 addition & 0 deletions tests/dotnet/StartupHookTest/MacCatalyst/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include ../shared.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)-maccatalyst</TargetFramework>
</PropertyGroup>
<Import Project="..\shared.csproj" />
</Project>
2 changes: 2 additions & 0 deletions tests/dotnet/StartupHookTest/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
TOP=../../..
include $(TOP)/tests/common/shared-dotnet-test.mk
1 change: 1 addition & 0 deletions tests/dotnet/StartupHookTest/iOS/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include ../shared.mk
7 changes: 7 additions & 0 deletions tests/dotnet/StartupHookTest/iOS/StartupHookTest.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)-ios</TargetFramework>
</PropertyGroup>
<Import Project="..\shared.csproj" />
</Project>
1 change: 1 addition & 0 deletions tests/dotnet/StartupHookTest/macOS/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include ../shared.mk
7 changes: 7 additions & 0 deletions tests/dotnet/StartupHookTest/macOS/StartupHookTest.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)-macos</TargetFramework>
</PropertyGroup>
<Import Project="..\shared.csproj" />
</Project>
17 changes: 17 additions & 0 deletions tests/dotnet/StartupHookTest/shared.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<Project>
<PropertyGroup>
<OutputType>Exe</OutputType>

<ApplicationTitle>StartupHookTest</ApplicationTitle>
<ApplicationId>com.xamarin.startuphooktest</ApplicationId>
</PropertyGroup>

<Import Project="../../common/shared-dotnet.csproj" />

<ItemGroup>
<Compile Include="../*.cs" />

<ProjectReference Include="../../StartupHookLibrary/$(_PlatformName)/StartupHookLibrary.csproj" />
</ItemGroup>
</Project>
3 changes: 3 additions & 0 deletions tests/dotnet/StartupHookTest/shared.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
TOP=../../../..
TESTNAME=StartupHookTest
include $(TOP)/tests/common/shared-dotnet.mk
1 change: 1 addition & 0 deletions tests/dotnet/StartupHookTest/tvOS/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include ../shared.mk
7 changes: 7 additions & 0 deletions tests/dotnet/StartupHookTest/tvOS/StartupHookTest.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)-tvos</TargetFramework>
</PropertyGroup>
<Import Project="..\shared.csproj" />
</Project>
114 changes: 114 additions & 0 deletions tests/dotnet/UnitTests/StartupHookTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
#nullable enable

namespace Xamarin.Tests {
[TestFixture]
public class StartupHookTest : TestBaseClass {
const string project = "StartupHookTest";

[TestCase (ApplePlatform.MacOSX, "osx-arm64")]
[TestCase (ApplePlatform.MacCatalyst, "maccatalyst-x64")]
public void EnabledForDebug (ApplePlatform platform, string runtimeIdentifiers)
{
Configuration.IgnoreIfIgnoredPlatform (platform);

var configuration = "Debug";
var project_path = GetProjectPath (project, runtimeIdentifiers: runtimeIdentifiers, platform: platform, out var appPath, configuration: configuration);
Clean (project_path);

var properties = GetDefaultProperties (runtimeIdentifiers);
properties ["Configuration"] = configuration;
DotNet.AssertBuild (project_path, properties);

if (CanExecute (platform, properties)) {
var appExecutable = GetNativeExecutable (platform, appPath);
var env = new Dictionary<string, string?> {
{ "DOTNET_STARTUP_HOOKS", "StartupHookTest:StartupHookLibrary" },
};
ExecuteWithMagicWordAndAssert (appExecutable, env);

env = new Dictionary<string, string?> {
{ "DOTNET_STARTUP_HOOKS", "StartupHookLibrary" },
};
ExecuteWithMagicWordAndAssert (appExecutable, env, expectedExitCode: 1); // this should fail

env = new Dictionary<string, string?> {
{ "DOTNET_STARTUP_HOOKS", "StartupHookTest" },
};
ExecuteWithMagicWordAndAssert (appExecutable, env, expectedExitCode: 2); // this should fail
}
}

[TestCase (ApplePlatform.MacOSX, "osx-arm64")]
[TestCase (ApplePlatform.MacCatalyst, "maccatalyst-x64")]
public void DisabledForRelease (ApplePlatform platform, string runtimeIdentifiers)
{
Configuration.IgnoreIfIgnoredPlatform (platform);

var configuration = "Release";
var project_path = GetProjectPath (project, runtimeIdentifiers: runtimeIdentifiers, platform: platform, out var appPath, configuration: configuration);
Clean (project_path);

var properties = GetDefaultProperties (runtimeIdentifiers);
properties ["Configuration"] = configuration;
DotNet.AssertBuild (project_path, properties);

if (CanExecute (platform, properties)) {
var appExecutable = GetNativeExecutable (platform, appPath);
var env = new Dictionary<string, string?> {
{ "DOTNET_STARTUP_HOOKS", "StartupHookTest:StartupHookLibrary" },
};
ExecuteWithMagicWordAndAssert (appExecutable, env, expectedExitCode: 3); // this should fail

env = new Dictionary<string, string?> ();
ExecuteWithMagicWordAndAssert (appExecutable, env, expectedExitCode: 3); // this should fail

env = new Dictionary<string, string?> {
{ "DOTNET_STARTUP_HOOKS", "StartupHookLibrary" },
};
ExecuteWithMagicWordAndAssert (appExecutable, env, expectedExitCode: 3); // this should fail

env = new Dictionary<string, string?> {
{ "DOTNET_STARTUP_HOOKS", "StartupHookTest" },
};
ExecuteWithMagicWordAndAssert (appExecutable, env, expectedExitCode: 3); // this should fail
}
}

[TestCase (ApplePlatform.MacOSX, "osx-arm64")]
[TestCase (ApplePlatform.MacCatalyst, "maccatalyst-x64")]
public void Enableable (ApplePlatform platform, string runtimeIdentifiers)
{
Configuration.IgnoreIfIgnoredPlatform (platform);

var configuration = "Release";
var project_path = GetProjectPath (project, runtimeIdentifiers: runtimeIdentifiers, platform: platform, out var appPath, configuration: configuration);
Clean (project_path);

var properties = GetDefaultProperties (runtimeIdentifiers);
properties ["Configuration"] = configuration;
properties ["StartupHookSupport"] = "true";
DotNet.AssertBuild (project_path, properties);

if (CanExecute (platform, properties)) {
var appExecutable = GetNativeExecutable (platform, appPath);
var env = new Dictionary<string, string?> {
{ "DOTNET_STARTUP_HOOKS", "StartupHookTest:StartupHookLibrary" },
};
ExecuteWithMagicWordAndAssert (appExecutable, env); // this should work

env = new Dictionary<string, string?> ();
ExecuteWithMagicWordAndAssert (appExecutable, env, expectedExitCode: 3); // this should fail

env = new Dictionary<string, string?> {
{ "DOTNET_STARTUP_HOOKS", "StartupHookLibrary" },
};
ExecuteWithMagicWordAndAssert (appExecutable, env, expectedExitCode: 1); // this should fail
Comment thread
rolfbjarne marked this conversation as resolved.

env = new Dictionary<string, string?> {
{ "DOTNET_STARTUP_HOOKS", "StartupHookTest" },
};
ExecuteWithMagicWordAndAssert (appExecutable, env, expectedExitCode: 2); // this should fail
}
}
}
}
6 changes: 3 additions & 3 deletions tests/dotnet/UnitTests/TestBaseClass.cs
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ protected string ExecuteWithMagicWordAndAssert (ApplePlatform platform, string r
return ExecuteWithMagicWordAndAssert (executable, environment);
}

protected string ExecuteWithMagicWordAndAssert (string executable, Dictionary<string, string?>? environment = null)
protected string ExecuteWithMagicWordAndAssert (string executable, Dictionary<string, string?>? environment = null, int expectedExitCode = 0)
{
if (Environment.OSVersion.Platform == PlatformID.Win32NT) {
Console.WriteLine ($"Not executing '{executable}' because we're on Windows.");
Expand All @@ -395,8 +395,8 @@ protected string ExecuteWithMagicWordAndAssert (string executable, Dictionary<st

var rv = Execute (executable, out var output, out string magicWord, environment);
var outputString = output.ToString ();
if (rv.ExitCode != 0) {
var msg = $"'{executable}' exited with exit code {rv.ExitCode} (timed out: {rv.TimedOut} timeout: {rv.Timeout}):" +
if (rv.ExitCode != expectedExitCode) {
var msg = $"'{executable}' exited with exit code {rv.ExitCode} (expected exit code {expectedExitCode}) (timed out: {rv.TimedOut} timeout: {rv.Timeout}):" +
"\t" + outputString.Replace ("\n", "\n\t").TrimEnd (new char [] { '\n', '\t' });
Console.WriteLine (msg);
Assert.Fail (msg);
Expand Down
Loading