From ea500383dae58a597133415d1283a0dbb1265437 Mon Sep 17 00:00:00 2001 From: Rolf Bjarne Kvinge Date: Fri, 3 Oct 2025 13:43:54 +0200 Subject: [PATCH 1/2] [dotnet] Don't overwrite any existing value for DOTNET_DiagnosticPorts when computed through our build logic. Until now, people set the 'DOTNET_DiagnosticPorts' environment variable at launch/runtime to profile or trace an app. When we added support for setting specific MSBuild properties to enable diagnostics (DiagnosticsAddress, DiagnosticsSuspend, etc.), we end up unconditionally setting the DOTNET_DiagnosticPorts environment variable, effectively overwriting any value specified by customers when launching the app. This meant that existing (and fully functioning) profiling/tracing workflows would only work if they set the DOTNET_DiagnosticPorts variable to the defaults we have. Fix this by allowing overriding DOTNET_DiagnosticPorts variable at launch/runtime. --- dotnet/targets/Xamarin.Shared.Sdk.targets | 2 +- msbuild/Xamarin.Shared/Xamarin.Shared.props | 6 +++--- tools/common/Application.cs | 2 +- tools/common/Target.cs | 8 ++++++-- tools/dotnet-linker/LinkerConfiguration.cs | 14 +++++++++++++- 5 files changed, 24 insertions(+), 8 deletions(-) diff --git a/dotnet/targets/Xamarin.Shared.Sdk.targets b/dotnet/targets/Xamarin.Shared.Sdk.targets index 6181d320bed2..2cfdc810086b 100644 --- a/dotnet/targets/Xamarin.Shared.Sdk.targets +++ b/dotnet/targets/Xamarin.Shared.Sdk.targets @@ -590,7 +590,7 @@ DeploymentTarget=$(_MinimumOSVersion) @(_CustomLinkFlags -> 'CustomLinkFlags=%(Identity)') EnableSGenConc=$(EnableSGenConc) - @(_BundlerEnvironmentVariables -> 'EnvironmentVariable=%(Identity)=%(Value)') + @(_BundlerEnvironmentVariables -> 'EnvironmentVariable=Overwrite=%(Overwrite)|%(Identity)=%(Value)') @(_XamarinFrameworkAssemblies -> 'FrameworkAssembly=%(Filename)') Interpreter=$(MtouchInterpreter) IntermediateLinkDir=$(IntermediateLinkDir) diff --git a/msbuild/Xamarin.Shared/Xamarin.Shared.props b/msbuild/Xamarin.Shared/Xamarin.Shared.props index aff250fd1659..4b2c9b8173b7 100644 --- a/msbuild/Xamarin.Shared/Xamarin.Shared.props +++ b/msbuild/Xamarin.Shared/Xamarin.Shared.props @@ -235,9 +235,9 @@ Copyright (C) 2020 Microsoft. All rights reserved. $(DiagnosticConfiguration),suspend $(DiagnosticConfiguration),nosuspend - - $(AppBundleExtraOptions) --setenv=DOTNET_DiagnosticPorts=$(DiagnosticConfiguration) - + + <_BundlerEnvironmentVariables Include="DOTNET_DiagnosticPorts" Value="$(DiagnosticConfiguration)" Overwrite="false" /> + $(IntermediateOutputPath)$(_PlatformName) diff --git a/tools/common/Application.cs b/tools/common/Application.cs index f8901565d8c9..d5baa01bcfbb 100644 --- a/tools/common/Application.cs +++ b/tools/common/Application.cs @@ -151,7 +151,7 @@ public bool AreAnyAssembliesTrimmed { public bool EnableDiagnostics; public bool? DebugTrack; - public Dictionary EnvironmentVariables = new Dictionary (); + public Dictionary EnvironmentVariables = new Dictionary (); public MarshalObjectiveCExceptionMode MarshalObjectiveCExceptions; public MarshalManagedExceptionMode MarshalManagedExceptions; diff --git a/tools/common/Target.cs b/tools/common/Target.cs index def2a09e6bf1..4be7f632de6d 100644 --- a/tools/common/Target.cs +++ b/tools/common/Target.cs @@ -777,8 +777,12 @@ void GenerateIOSMain (StringWriter sw, Abi abi) if (!string.IsNullOrEmpty (app.MonoGCParams)) sw.WriteLine ("\tsetenv (\"MONO_GC_PARAMS\", \"{0}\", 1);", app.MonoGCParams); // Do this last, so that the app developer can override any other environment variable we set. - foreach (var kvp in app.EnvironmentVariables) - sw.WriteLine ("\tsetenv (\"{0}\", \"{1}\", 1);", kvp.Key.Replace ("\"", "\\\""), kvp.Value.Replace ("\"", "\\\"")); + foreach (var kvp in app.EnvironmentVariables) { + var name = kvp.Key; + var value = kvp.Value.Value; + var overwrite = kvp.Value.Overwrite; + sw.WriteLine ("\tsetenv (\"{0}\", \"{1}\", {2});", name.Replace ("\"", "\\\""), value.Replace ("\"", "\\\""), overwrite ? 1 : 0); + } if (app.XamarinRuntime != XamarinRuntime.NativeAOT) sw.WriteLine ("\txamarin_supports_dynamic_registration = {0};", app.DynamicRegistrationSupported ? "TRUE" : "FALSE"); #if NET && !LEGACY_TOOLS diff --git a/tools/dotnet-linker/LinkerConfiguration.cs b/tools/dotnet-linker/LinkerConfiguration.cs index 37cf38c510d8..43896bea6e01 100644 --- a/tools/dotnet-linker/LinkerConfiguration.cs +++ b/tools/dotnet-linker/LinkerConfiguration.cs @@ -173,11 +173,23 @@ public static LinkerConfiguration GetInstance (LinkContext context) Application.EnableSGenConc = string.Equals (value, "true", StringComparison.OrdinalIgnoreCase); break; case "EnvironmentVariable": + var overwrite = true; + var needle = "Overwrite="; + if (value.StartsWith (needle, StringComparison.Ordinal)) { + var pipe = value.IndexOf ('|', needle.Length); + if (pipe > 0 ) { + var overwriteString = value [needle.Length..pipe]; + if (!TryParseOptionalBoolean (overwriteString, out var parsedOverwrite)) + throw new InvalidOperationException ($"Unable to parse the 'Overwrite' value '{overwriteString}' for the environment variable entry '{value}' in {linker_file}"); + overwrite = parsedOverwrite.Value; + value = value [(pipe + 1)..]; + } + } var separators = new char [] { ':', '=' }; var equals = value.IndexOfAny (separators); var name = value.Substring (0, equals); var val = value.Substring (equals + 1); - Application.EnvironmentVariables.Add (name, val); + Application.EnvironmentVariables.Add (name, new (val, overwrite)); break; case "FrameworkAssembly": FrameworkAssemblies.Add (value); From a24f01cf1660f5b54510a25a2ed10ffb21a4a00a Mon Sep 17 00:00:00 2001 From: GitHub Actions Autoformatter Date: Tue, 14 Oct 2025 07:00:14 +0000 Subject: [PATCH 2/2] Auto-format source code --- tools/dotnet-linker/LinkerConfiguration.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/dotnet-linker/LinkerConfiguration.cs b/tools/dotnet-linker/LinkerConfiguration.cs index 43896bea6e01..14424629f368 100644 --- a/tools/dotnet-linker/LinkerConfiguration.cs +++ b/tools/dotnet-linker/LinkerConfiguration.cs @@ -177,7 +177,7 @@ public static LinkerConfiguration GetInstance (LinkContext context) var needle = "Overwrite="; if (value.StartsWith (needle, StringComparison.Ordinal)) { var pipe = value.IndexOf ('|', needle.Length); - if (pipe > 0 ) { + if (pipe > 0) { var overwriteString = value [needle.Length..pipe]; if (!TryParseOptionalBoolean (overwriteString, out var parsedOverwrite)) throw new InvalidOperationException ($"Unable to parse the 'Overwrite' value '{overwriteString}' for the environment variable entry '{value}' in {linker_file}");