diff --git a/src/installer/tests/Assets/TestProjects/RuntimeProperties/Program.cs b/src/installer/tests/Assets/TestProjects/RuntimeProperties/Program.cs index d22677aa617d8..96fa3b2adbad2 100644 --- a/src/installer/tests/Assets/TestProjects/RuntimeProperties/Program.cs +++ b/src/installer/tests/Assets/TestProjects/RuntimeProperties/Program.cs @@ -14,7 +14,14 @@ public static void Main(string[] args) foreach (string propertyName in args) { - Console.WriteLine($"AppContext.GetData({propertyName}) = {System.AppContext.GetData(propertyName)}"); + var propertyValue = (string)System.AppContext.GetData(propertyName); + if (string.IsNullOrEmpty(propertyValue)) + { + Console.WriteLine($"Property '{propertyName}' was not found."); + continue; + } + + Console.WriteLine($"AppContext.GetData({propertyName}) = {propertyValue}"); } } } diff --git a/src/installer/tests/HostActivation.Tests/DotNetBuilder.cs b/src/installer/tests/HostActivation.Tests/DotNetBuilder.cs index 2a99ab5681f75..0a8d54559e227 100644 --- a/src/installer/tests/HostActivation.Tests/DotNetBuilder.cs +++ b/src/installer/tests/HostActivation.Tests/DotNetBuilder.cs @@ -174,6 +174,22 @@ public DotNetBuilder AddFramework( return this; } + public DotNetBuilder AddMockSDK( + string version, + string MNAVersion) + { + string path = Path.Combine(_path, "sdk", version); + Directory.CreateDirectory(path); + + using var _ = File.Create(Path.Combine(path, "dotnet.dll")); + + RuntimeConfig dotnetRuntimeConfig = new RuntimeConfig(Path.Combine(path, "dotnet.runtimeconfig.json")); + dotnetRuntimeConfig.WithFramework(new RuntimeConfig.Framework("Microsoft.NETCore.App", MNAVersion)); + dotnetRuntimeConfig.Save(); + + return this; + } + public DotNetCli Build() { return new DotNetCli(_path); diff --git a/src/installer/tests/HostActivation.Tests/RuntimeProperties.cs b/src/installer/tests/HostActivation.Tests/RuntimeProperties.cs index 6d8949c4132a5..01b5b415ecd26 100644 --- a/src/installer/tests/HostActivation.Tests/RuntimeProperties.cs +++ b/src/installer/tests/HostActivation.Tests/RuntimeProperties.cs @@ -3,6 +3,7 @@ using System; using System.IO; +using Microsoft.DotNet.Cli.Build; using Xunit; namespace Microsoft.DotNet.CoreSetup.Test.HostActivation @@ -25,9 +26,7 @@ public void AppConfigProperty_AppCanGetData() var dotnet = fixture.BuiltDotnet; var appDll = fixture.TestProject.AppDll; dotnet.Exec(appDll, sharedState.AppTestPropertyName) - .EnvironmentVariable("COREHOST_TRACE", "1") - .CaptureStdErr() - .CaptureStdOut() + .EnableTracingAndCaptureOutputs() .Execute() .Should().Pass() .And.HaveStdErrContaining($"Property {sharedState.AppTestPropertyName} = {sharedState.AppTestPropertyValue}") @@ -43,9 +42,7 @@ public void FrameworkConfigProperty_AppCanGetData() var dotnet = fixture.BuiltDotnet; var appDll = fixture.TestProject.AppDll; dotnet.Exec(appDll, sharedState.FrameworkTestPropertyName) - .EnvironmentVariable("COREHOST_TRACE", "1") - .CaptureStdErr() - .CaptureStdOut() + .EnableTracingAndCaptureOutputs() .Execute() .Should().Pass() .And.HaveStdErrContaining($"Property {sharedState.FrameworkTestPropertyName} = {sharedState.FrameworkTestPropertyValue}") @@ -65,15 +62,39 @@ public void DuplicateConfigProperty_AppConfigValueUsed() var dotnet = fixture.BuiltDotnet; var appDll = fixture.TestProject.AppDll; dotnet.Exec(appDll, sharedState.FrameworkTestPropertyName) - .EnvironmentVariable("COREHOST_TRACE", "1") - .CaptureStdErr() - .CaptureStdOut() + .EnableTracingAndCaptureOutputs() .Execute() .Should().Pass() .And.HaveStdErrContaining($"Property {sharedState.FrameworkTestPropertyName} = {sharedState.AppTestPropertyValue}") .And.HaveStdOutContaining($"AppContext.GetData({sharedState.FrameworkTestPropertyName}) = {sharedState.AppTestPropertyValue}"); } + [Fact] + public void HostFxrPathProperty_SetWhenRunningSDKCommand() + { + var dotnet = sharedState.MockSDK; + dotnet.Exec("--info") + .EnableTracingAndCaptureOutputs() + .Execute() + .Should().Pass() + .And.HaveStdErrContaining($"Property {sharedState.HostFxrPathPropertyName} = {dotnet.GreatestVersionHostFxrFilePath}"); + } + + [Fact] + public void HostFxrPathProperty_NotVisibleFromApp() + { + var fixture = sharedState.RuntimePropertiesFixture + .Copy(); + + var dotnet = fixture.BuiltDotnet; + var appDll = fixture.TestProject.AppDll; + dotnet.Exec(appDll, sharedState.HostFxrPathPropertyName) + .EnableTracingAndCaptureOutputs() + .Execute() + .Should().Pass() + .And.HaveStdOutContaining($"Property '{sharedState.HostFxrPathPropertyName}' was not found."); + } + [Fact] public void DuplicateCommonProperty_Fails() { @@ -88,9 +109,7 @@ public void DuplicateCommonProperty_Fails() var dotnet = fixture.BuiltDotnet; var appDll = fixture.TestProject.AppDll; dotnet.Exec(appDll) - .EnvironmentVariable("COREHOST_TRACE", "1") - .CaptureStdErr() - .CaptureStdOut() + .EnableTracingAndCaptureOutputs() .Execute() .Should().Fail() .And.HaveStdErrContaining($"Duplicate runtime property found: {name}"); @@ -100,11 +119,13 @@ public class SharedTestState : IDisposable { public TestProjectFixture RuntimePropertiesFixture { get; } public RepoDirectoriesProvider RepoDirectories { get; } + public DotNetCli MockSDK { get; } public string AppTestPropertyName => "APP_TEST_PROPERTY"; public string AppTestPropertyValue => "VALUE_FROM_APP"; public string FrameworkTestPropertyName => "FRAMEWORK_TEST_PROPERTY"; public string FrameworkTestPropertyValue => "VALUE_FROM_FRAMEWORK"; + public string HostFxrPathPropertyName => "HOSTFXR_PATH"; private readonly string copiedDotnet; @@ -113,6 +134,19 @@ public SharedTestState() copiedDotnet = Path.Combine(TestArtifact.TestArtifactsPath, "runtimeProperties"); SharedFramework.CopyDirectory(Path.Combine(TestArtifact.TestArtifactsPath, "sharedFrameworkPublish"), copiedDotnet); + MockSDK = new DotNetBuilder(copiedDotnet, Path.Combine(TestArtifact.TestArtifactsPath, "sharedFrameworkPublish"), "exe") + .AddMicrosoftNETCoreAppFrameworkMockCoreClr("9999.0.0") + .AddMockSDK("9999.0.0-dev", "9999.0.0") + .Build(); + + File.WriteAllText(Path.Combine(MockSDK.BinPath, "global.json"), + @" +{ + ""sdk"": { + ""version"": ""9999.0.0-dev"" + } +}"); + RepoDirectories = new RepoDirectoriesProvider(builtDotnet: copiedDotnet); RuntimePropertiesFixture = new TestProjectFixture("RuntimeProperties", RepoDirectories) diff --git a/src/native/corehost/fxr/corehost_init.cpp b/src/native/corehost/fxr/corehost_init.cpp index eea9b768f5f90..2d169348fa635 100644 --- a/src/native/corehost/fxr/corehost_init.cpp +++ b/src/native/corehost/fxr/corehost_init.cpp @@ -20,7 +20,8 @@ corehost_init_t::corehost_init_t( const pal::string_t& additional_deps_serialized, const std::vector& probe_paths, const host_mode_t mode, - const fx_definition_vector_t& fx_definitions) + const fx_definition_vector_t& fx_definitions, + const std::vector>& additional_properties) : m_tfm(get_app(fx_definitions).get_runtime_config().get_tfm()) , m_deps_file(deps_file) , m_additional_deps_serialized(additional_deps_serialized) @@ -35,6 +36,12 @@ corehost_init_t::corehost_init_t( { make_cstr_arr(m_probe_paths, &m_probe_paths_cstr); + for (const auto& additional_property : additional_properties) + { + m_clr_keys.push_back(additional_property.first); + m_clr_values.push_back(additional_property.second); + } + size_t fx_count = fx_definitions.size(); m_fx_names.reserve(fx_count); m_fx_dirs.reserve(fx_count); diff --git a/src/native/corehost/fxr/corehost_init.h b/src/native/corehost/fxr/corehost_init.h index 70ea7be46fbf0..6c3148b627496 100644 --- a/src/native/corehost/fxr/corehost_init.h +++ b/src/native/corehost/fxr/corehost_init.h @@ -45,7 +45,8 @@ class corehost_init_t const pal::string_t& additional_deps_serialized, const std::vector& probe_paths, const host_mode_t mode, - const fx_definition_vector_t& fx_definitions); + const fx_definition_vector_t& fx_definitions, + const std::vector>& additional_properties); const host_interface_t& get_host_init_data(); diff --git a/src/native/corehost/fxr/fx_muxer.cpp b/src/native/corehost/fxr/fx_muxer.cpp index 6a20206e2cadb..8647130c18dc1 100644 --- a/src/native/corehost/fxr/fx_muxer.cpp +++ b/src/native/corehost/fxr/fx_muxer.cpp @@ -370,6 +370,7 @@ namespace const pal::string_t &app_candidate, const opt_map_t &opts, host_mode_t mode, + const bool is_sdk_command, /*out*/ pal::string_t &hostpolicy_dir, /*out*/ std::unique_ptr &init) { @@ -473,6 +474,16 @@ namespace } } + std::vector> additional_properties; + if (is_sdk_command) + { + pal::string_t fxr_path; + pal::get_own_module_path(&fxr_path); + + // We pass the loaded hostfxr path to the SDK can load it without relying on dlopen/LoadLibrary to find it. + additional_properties.push_back(std::make_pair(_X("HOSTFXR_PATH"), fxr_path)); + } + const known_options opts_probe_path = known_options::additional_probing_path; std::vector spec_probe_paths = opts.count(opts_probe_path) ? opts.find(opts_probe_path)->second : std::vector(); std::vector probe_realpaths = get_probe_realpaths(fx_definitions, spec_probe_paths); @@ -485,7 +496,7 @@ namespace return StatusCode::CoreHostLibMissingFailure; } - init.reset(new corehost_init_t(host_command, host_info, deps_file, additional_deps_serialized, probe_realpaths, mode, fx_definitions)); + init.reset(new corehost_init_t(host_command, host_info, deps_file, additional_deps_serialized, probe_realpaths, mode, fx_definitions, additional_properties)); return StatusCode::Success; } @@ -498,6 +509,7 @@ namespace int new_argc, const pal::char_t** new_argv, host_mode_t mode, + const bool is_sdk_command, pal::char_t out_buffer[], int32_t buffer_size, int32_t* required_buffer_size) @@ -510,6 +522,7 @@ namespace app_candidate, opts, mode, + is_sdk_command, hostpolicy_dir, init); if (rc != StatusCode::Success) @@ -572,6 +585,7 @@ int fx_muxer_t::execute( argv, new_argoff, mode, + false /*is_sdk_command*/, result_buffer, buffer_size, required_buffer_size); @@ -621,7 +635,8 @@ namespace } const pal::string_t additional_deps_serialized; - init.reset(new corehost_init_t(pal::string_t{}, host_info, deps_file, additional_deps_serialized, probe_realpaths, mode, fx_definitions)); + const std::vector> additional_properties; + init.reset(new corehost_init_t(pal::string_t{}, host_info, deps_file, additional_deps_serialized, probe_realpaths, mode, fx_definitions, additional_properties)); return StatusCode::Success; } @@ -725,6 +740,7 @@ int fx_muxer_t::initialize_for_app( host_info.app_path, opts, mode, + false /*is_sdk_command*/, hostpolicy_dir, init); if (rc != StatusCode::Success) @@ -978,6 +994,7 @@ int fx_muxer_t::handle_exec_host_command( const pal::char_t* argv[], int argoff, host_mode_t mode, + const bool is_sdk_command, pal::char_t result_buffer[], int32_t buffer_size, int32_t* required_buffer_size) @@ -1006,6 +1023,7 @@ int fx_muxer_t::handle_exec_host_command( new_argc, new_argv, mode, + is_sdk_command, result_buffer, buffer_size, required_buffer_size); @@ -1096,6 +1114,7 @@ int fx_muxer_t::handle_cli( new_argv.data(), new_argoff, host_mode_t::muxer, + true /*is_sdk_command*/, nullptr /*result_buffer*/, 0 /*buffer_size*/, nullptr/*required_buffer_size*/); diff --git a/src/native/corehost/fxr/fx_muxer.h b/src/native/corehost/fxr/fx_muxer.h index 6794e2a1c8254..b3a0e0004700a 100644 --- a/src/native/corehost/fxr/fx_muxer.h +++ b/src/native/corehost/fxr/fx_muxer.h @@ -47,6 +47,7 @@ class fx_muxer_t const pal::char_t* argv[], int argoff, host_mode_t mode, + const bool is_sdk_command, pal::char_t result_buffer[], int32_t buffer_size, int32_t* required_buffer_size);