From 80826c19eb2c1d59420d6c7359e383106645981d Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Tue, 19 Mar 2019 18:20:28 -0700 Subject: [PATCH 01/12] Empty implementation of nethost --- signing/sign.proj | 3 ++ src/corehost/Windows/gen-buildsys-win.bat | 4 +- src/corehost/build.proj | 19 ++++---- src/corehost/build.sh | 4 +- src/corehost/cli/CMakeLists.txt | 1 + src/corehost/cli/nethost/CMakeLists.txt | 29 ++++++++++++ src/corehost/cli/nethost/nethost.cpp | 15 +++++++ src/corehost/cli/nethost/nethost.h | 54 +++++++++++++++++++++++ 8 files changed, 117 insertions(+), 12 deletions(-) create mode 100644 src/corehost/cli/nethost/CMakeLists.txt create mode 100644 src/corehost/cli/nethost/nethost.cpp create mode 100644 src/corehost/cli/nethost/nethost.h diff --git a/signing/sign.proj b/signing/sign.proj index ef80e07e33..170fd30c31 100644 --- a/signing/sign.proj +++ b/signing/sign.proj @@ -40,6 +40,9 @@ $(CertificateId) + + $(CertificateId) + diff --git a/src/corehost/Windows/gen-buildsys-win.bat b/src/corehost/Windows/gen-buildsys-win.bat index ff97131b58..db57de4cf5 100644 --- a/src/corehost/Windows/gen-buildsys-win.bat +++ b/src/corehost/Windows/gen-buildsys-win.bat @@ -41,8 +41,8 @@ for /f "delims=" %%a in ('powershell -NoProfile -ExecutionPolicy ByPass "& .\Win popd :DoGen -echo "%CMakePath%" %__sourceDir% %__SDKVersion% "-DCLI_CMAKE_RUNTIME_ID:STRING=%cm_BaseRid%" "-DCLI_CMAKE_HOST_VER:STRING=%__HostVersion%" "-DCLI_CMAKE_APPHOST_VER:STRING=%__AppHostVersion%" "-DCLI_CMAKE_COMHOST_VER:STRING=%__AppHostVersion%" "-DCLI_CMAKE_IJWHOST_VER:STRING=%__AppHostVersion%" "-DCLI_CMAKE_HOST_FXR_VER:STRING=%__HostFxrVersion%" "-DCLI_CMAKE_HOST_POLICY_VER:STRING=%__HostPolicyVersion%" "-DCLI_CMAKE_PKG_RID:STRING=%cm_BaseRid%" "-DCLI_CMAKE_COMMIT_HASH:STRING=%__LatestCommit%" "-DCLI_CMAKE_PLATFORM_ARCH_%cm_Arch%=1" "-DCMAKE_INSTALL_PREFIX=%__CMakeBinDir%" "-DCLI_CMAKE_RESOURCE_DIR:STRING=%__ResourcesDir%" -G "Visual Studio %__VSString%" %__ExtraCmakeParams% -"%CMakePath%" %__sourceDir% %__SDKVersion% "-DCLI_CMAKE_RUNTIME_ID:STRING=%cm_BaseRid%" "-DCLI_CMAKE_HOST_VER:STRING=%__HostVersion%" "-DCLI_CMAKE_APPHOST_VER:STRING=%__AppHostVersion%" "-DCLI_CMAKE_COMHOST_VER:STRING=%__AppHostVersion%" "-DCLI_CMAKE_IJWHOST_VER:STRING=%__AppHostVersion%" "-DCLI_CMAKE_HOST_FXR_VER:STRING=%__HostFxrVersion%" "-DCLI_CMAKE_HOST_POLICY_VER:STRING=%__HostPolicyVersion%" "-DCLI_CMAKE_PKG_RID:STRING=%cm_BaseRid%" "-DCLI_CMAKE_COMMIT_HASH:STRING=%__LatestCommit%" "-DCLI_CMAKE_PLATFORM_ARCH_%cm_Arch%=1" "-DCMAKE_INSTALL_PREFIX=%__CMakeBinDir%" "-DCLI_CMAKE_RESOURCE_DIR:STRING=%__ResourcesDir%" -G "Visual Studio %__VSString%" %__ExtraCmakeParams% +echo "%CMakePath%" %__sourceDir% %__SDKVersion% "-DCLI_CMAKE_RUNTIME_ID:STRING=%cm_BaseRid%" "-DCLI_CMAKE_HOST_VER:STRING=%__HostVersion%" "-DCLI_CMAKE_APPHOST_VER:STRING=%__AppHostVersion%" "-DCLI_CMAKE_COMHOST_VER:STRING=%__AppHostVersion%" "-DCLI_CMAKE_IJWHOST_VER:STRING=%__AppHostVersion%" "-DCLI_CMAKE_NETHOST_VER:STRING=%__AppHostVersion%" "-DCLI_CMAKE_HOST_FXR_VER:STRING=%__HostFxrVersion%" "-DCLI_CMAKE_HOST_POLICY_VER:STRING=%__HostPolicyVersion%" "-DCLI_CMAKE_PKG_RID:STRING=%cm_BaseRid%" "-DCLI_CMAKE_COMMIT_HASH:STRING=%__LatestCommit%" "-DCLI_CMAKE_PLATFORM_ARCH_%cm_Arch%=1" "-DCMAKE_INSTALL_PREFIX=%__CMakeBinDir%" "-DCLI_CMAKE_RESOURCE_DIR:STRING=%__ResourcesDir%" -G "Visual Studio %__VSString%" %__ExtraCmakeParams% +"%CMakePath%" %__sourceDir% %__SDKVersion% "-DCLI_CMAKE_RUNTIME_ID:STRING=%cm_BaseRid%" "-DCLI_CMAKE_HOST_VER:STRING=%__HostVersion%" "-DCLI_CMAKE_APPHOST_VER:STRING=%__AppHostVersion%" "-DCLI_CMAKE_COMHOST_VER:STRING=%__AppHostVersion%" "-DCLI_CMAKE_IJWHOST_VER:STRING=%__AppHostVersion%" "-DCLI_CMAKE_NETHOST_VER:STRING=%__AppHostVersion%" "-DCLI_CMAKE_HOST_FXR_VER:STRING=%__HostFxrVersion%" "-DCLI_CMAKE_HOST_POLICY_VER:STRING=%__HostPolicyVersion%" "-DCLI_CMAKE_PKG_RID:STRING=%cm_BaseRid%" "-DCLI_CMAKE_COMMIT_HASH:STRING=%__LatestCommit%" "-DCLI_CMAKE_PLATFORM_ARCH_%cm_Arch%=1" "-DCMAKE_INSTALL_PREFIX=%__CMakeBinDir%" "-DCLI_CMAKE_RESOURCE_DIR:STRING=%__ResourcesDir%" -G "Visual Studio %__VSString%" %__ExtraCmakeParams% endlocal GOTO :DONE diff --git a/src/corehost/build.proj b/src/corehost/build.proj index 51793842be..260a712711 100644 --- a/src/corehost/build.proj +++ b/src/corehost/build.proj @@ -7,7 +7,7 @@ - + true @@ -19,11 +19,11 @@ DependsOnTargets="GetLatestCommitHash;GenerateVersionSourceFile"> $(IntermediateOutputRootPath)corehost\cmake\ - + --configuration $(ConfigurationGroup) --arch $(TargetArchitecture) --apphostver $(AppHostVersion) --hostver $(HostVersion) --fxrver $(HostResolverVersion) --policyver $(HostPolicyVersion) --commithash $(LatestCommit) - $(BuildArgs) -portable - $(BuildArgs) --cross - $(BuildArgs) --stripsymbols + $(BuildArgs) -portable + $(BuildArgs) --cross + $(BuildArgs) --stripsymbols @@ -51,15 +51,18 @@ .NET Core IJW Host + + .NET Core Component Host + - + $(ConfigurationGroup) $(TargetArchitecture) apphostver $(AppHostVersion) hostver $(HostVersion) fxrver $(HostResolverVersion) policyver $(HostPolicyVersion) commit $(LatestCommit) rid $(OutputRid) - $(BuildArgs) portable + $(BuildArgs) portable $(BuildArgs) incremental-native-build diff --git a/src/corehost/build.sh b/src/corehost/build.sh index 572e8270c9..843ab7fd03 100755 --- a/src/corehost/build.sh +++ b/src/corehost/build.sh @@ -263,9 +263,9 @@ if [ $__CrossBuild == 1 ]; then fi export TARGET_BUILD_ARCH=$__build_arch_lowcase export __DistroRid=$__rid_plat - cmake "$DIR" -G "Unix Makefiles" $__cmake_defines -DCLI_CMAKE_HOST_VER:STRING=$__host_ver -DCLI_CMAKE_APPHOST_VER:STRING=$__apphost_ver -DCLI_CMAKE_HOST_FXR_VER:STRING=$__fxr_ver -DCLI_CMAKE_HOST_POLICY_VER:STRING=$__policy_ver -DCLI_CMAKE_PKG_RID:STRING=$__base_rid -DCLI_CMAKE_COMMIT_HASH:STRING=$__commit_hash -DCMAKE_INSTALL_PREFIX=$__cmake_bin_prefix -DCMAKE_TOOLCHAIN_FILE=$DIR/../../cross/toolchain.cmake + cmake "$DIR" -G "Unix Makefiles" $__cmake_defines -DCLI_CMAKE_HOST_VER:STRING=$__host_ver -DCLI_CMAKE_APPHOST_VER:STRING=$__apphost_ver -DCLI_CMAKE_NETHOST_VER:STRING=$__apphost_ver -DCLI_CMAKE_HOST_FXR_VER:STRING=$__fxr_ver -DCLI_CMAKE_HOST_POLICY_VER:STRING=$__policy_ver -DCLI_CMAKE_PKG_RID:STRING=$__base_rid -DCLI_CMAKE_COMMIT_HASH:STRING=$__commit_hash -DCMAKE_INSTALL_PREFIX=$__cmake_bin_prefix -DCMAKE_TOOLCHAIN_FILE=$DIR/../../cross/toolchain.cmake else - cmake "$DIR" -G "Unix Makefiles" $__cmake_defines -DCLI_CMAKE_HOST_VER:STRING=$__host_ver -DCLI_CMAKE_APPHOST_VER:STRING=$__apphost_ver -DCLI_CMAKE_HOST_FXR_VER:STRING=$__fxr_ver -DCLI_CMAKE_HOST_POLICY_VER:STRING=$__policy_ver -DCLI_CMAKE_PKG_RID:STRING=$__base_rid -DCLI_CMAKE_COMMIT_HASH:STRING=$__commit_hash -DCMAKE_INSTALL_PREFIX=$__cmake_bin_prefix + cmake "$DIR" -G "Unix Makefiles" $__cmake_defines -DCLI_CMAKE_HOST_VER:STRING=$__host_ver -DCLI_CMAKE_APPHOST_VER:STRING=$__apphost_ver -DCLI_CMAKE_NETHOST_VER:STRING=$__apphost_ver -DCLI_CMAKE_HOST_FXR_VER:STRING=$__fxr_ver -DCLI_CMAKE_HOST_POLICY_VER:STRING=$__policy_ver -DCLI_CMAKE_PKG_RID:STRING=$__base_rid -DCLI_CMAKE_COMMIT_HASH:STRING=$__commit_hash -DCMAKE_INSTALL_PREFIX=$__cmake_bin_prefix fi popd diff --git a/src/corehost/cli/CMakeLists.txt b/src/corehost/cli/CMakeLists.txt index 50bd771f9f..4d307fc080 100644 --- a/src/corehost/cli/CMakeLists.txt +++ b/src/corehost/cli/CMakeLists.txt @@ -2,6 +2,7 @@ add_subdirectory(apphost) add_subdirectory(dotnet) add_subdirectory(fxr) add_subdirectory(hostpolicy) +add_subdirectory(nethost) add_subdirectory(test_fx_ver) add_subdirectory(test) diff --git a/src/corehost/cli/nethost/CMakeLists.txt b/src/corehost/cli/nethost/CMakeLists.txt new file mode 100644 index 0000000000..fde6e19d80 --- /dev/null +++ b/src/corehost/cli/nethost/CMakeLists.txt @@ -0,0 +1,29 @@ +# Copyright (c) .NET Foundation and contributors. All rights reserved. +# Licensed under the MIT license. See LICENSE file in the project root for full license information. + +cmake_minimum_required (VERSION 2.6) +project(nethost) + +set(DOTNET_PROJECT_NAME "nethost") + +# Include directories +include_directories(../fxr) + +# CMake does not recommend using globbing since it messes with the freshness checks +set(SOURCES + nethost.cpp +) + +include(../lib.cmake) + +add_definitions(-DFEATURE_LIBHOST=1) +add_definitions(-DNETHOST_EXPORT) + +if("${CLI_CMAKE_NETHOST_VER}" STREQUAL "") + message(FATAL_ERROR "nethost version is not specified") +else() + add_definitions(-DLIBHOST_PKG_VER="${CLI_CMAKE_NETHOST_VER}") +endif() + +install(TARGETS nethost DESTINATION corehost) +install_symbols(nethost corehost) \ No newline at end of file diff --git a/src/corehost/cli/nethost/nethost.cpp b/src/corehost/cli/nethost/nethost.cpp new file mode 100644 index 0000000000..c05ca58be7 --- /dev/null +++ b/src/corehost/cli/nethost/nethost.cpp @@ -0,0 +1,15 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include "nethost.h" +#include +#include +#include + +NETHOST_API int STDMETHODCALLTYPE nethost_get_hostfxr_path( + nethost_get_hostfxr_path_result_fn result, + const char_t * assembly_path) +{ + result(assembly_path != nullptr ? assembly_path : _X("")); + return StatusCode::Success; +} \ No newline at end of file diff --git a/src/corehost/cli/nethost/nethost.h b/src/corehost/cli/nethost/nethost.h new file mode 100644 index 0000000000..843e025526 --- /dev/null +++ b/src/corehost/cli/nethost/nethost.h @@ -0,0 +1,54 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#ifndef __NETHOST_H__ +#define __NETHOST_H__ + +#if defined(_WIN32) + #ifdef NETHOST_EXPORT + #define NETHOST_API __declspec(dllexport) + #else + #define NETHOST_API __declspec(dllimport) + #endif + + #define NETHOST_CALLTYPE __stdcall + #ifdef _WCHAR_T_DEFINED + using char_t = wchar_t; + #else + using char_t = unsigned short; + #endif +#else + #ifdef NETHOST_EXPORT + #define NETHOST_API __attribute__((__visibility__("default"))) + #else + #define NETHOST_API + #endif + + #define NETHOST_CALLTYPE + using char_t = char; +#endif + +using nethost_get_hostfxr_path_result_fn = void(*)(const char_t * hostfxr_path); + +// +// Get the path to the hostfxr library +// +// Parameters: +// result +// Callback invoked to return the hostfxr path. String passed in is valid for +// the duration of the call. +// +// assembly_path +// Optional. Path to the compenent's assembly. Whether or not this is specified +// determines the behaviour for locating the hostfxr library. +// If nullptr, hostfxr will be located as if the running executable is the muxer +// If specified, hostfxr will be located as if the assembly_path is the apphost +// +// Return value: +// 0 on success, otherwise failure +// +extern "C" NETHOST_API int NETHOST_CALLTYPE nethost_get_hostfxr_path( + nethost_get_hostfxr_path_result_fn result, + const char_t * assembly_path); + +#endif // __NETHOST_H__ \ No newline at end of file From a84045559bf1be2aa3b45959da662669c227ace6 Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Tue, 19 Mar 2019 20:35:57 -0700 Subject: [PATCH 02/12] Implement nethost_get_hostfxr_path --- Documentation/design-docs/host-components.md | 2 +- src/corehost/cli/comhost/comhost.cpp | 6 +- src/corehost/cli/fxr_resolver.cpp | 147 ++++++++++--------- src/corehost/cli/fxr_resolver.h | 6 +- src/corehost/cli/ijwhost/ijwhost.cpp | 4 +- src/corehost/cli/nethost/CMakeLists.txt | 2 + src/corehost/cli/nethost/nethost.cpp | 27 +++- src/corehost/corehost.cpp | 10 +- 8 files changed, 126 insertions(+), 78 deletions(-) diff --git a/Documentation/design-docs/host-components.md b/Documentation/design-docs/host-components.md index c9870c501d..21252a6472 100644 --- a/Documentation/design-docs/host-components.md +++ b/Documentation/design-docs/host-components.md @@ -9,7 +9,7 @@ The .NET Core default hosting setup consists of several components which are des * `comhost` (library) - which is used to enable COM server hosting. Component which wants to expose COM server objects will be built with this dynamic library in its output. The `comhost` then acts as the main entry point for the OS. The executable does just one thing, it finds the `hostfxr` library and passes control to it. It also exposes the right entry points for its purpose (so the "main" for `dotnet` and `apphost`, the COM exports for `comhost` and so on). -* `dotnet` host - `hostfxr` is obtained from the `./shared/host/fxr` folder (relative to the location of the `dotnet` host). +* `dotnet` host - `hostfxr` is obtained from the `./host/fxr` folder (relative to the location of the `dotnet` host). * `apphost` and `comhost` - `hostfxr` is located by 1. The app's folder is searched first. This is either the folder where the `apphost` or `comhost` lives or in case of `apphost` it is the path it has embedded in it as the app path. 1. If the `DOTNET_ROOT` environment variable is defined, that path is searched diff --git a/src/corehost/cli/comhost/comhost.cpp b/src/corehost/cli/comhost/comhost.cpp index 7bad50f3bc..6c016d0643 100644 --- a/src/corehost/cli/comhost/comhost.cpp +++ b/src/corehost/cli/comhost/comhost.cpp @@ -62,7 +62,7 @@ namespace { get_comhost_error_stream() << msg; } - + int get_com_activation_delegate(pal::string_t *app_path, com_activation_fn *delegate) { pal::string_t host_path; @@ -74,7 +74,7 @@ namespace pal::string_t dotnet_root; pal::string_t fxr_path; - if (!resolve_fxr_path(get_directory(host_path), &dotnet_root, &fxr_path)) + if (!fxr_resolver::try_get_path(host_mode_t::libhost, get_directory(host_path), &dotnet_root, &fxr_path)) { return StatusCode::CoreHostLibMissingFailure; } @@ -130,7 +130,7 @@ COM_API HRESULT STDMETHODCALLTYPE DllGetClassObject( { trace::setup(); reset_comhost_error_stream(); - + error_writer_scope_t writer_scope(comhost_error_writer); int ec = get_com_activation_delegate(&app_path, &act); diff --git a/src/corehost/cli/fxr_resolver.cpp b/src/corehost/cli/fxr_resolver.cpp index d7f1d6f905..771d299c07 100644 --- a/src/corehost/cli/fxr_resolver.cpp +++ b/src/corehost/cli/fxr_resolver.cpp @@ -2,15 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#include "pal.h" +#include #include "fxr_resolver.h" -#include "error_codes.h" -#include "fx_ver.h" -#include "trace.h" -#include "utils.h" +#include +#include +#include namespace -{ +{ bool get_latest_fxr(pal::string_t fxr_root, pal::string_t* out_fxr_path) { trace::info(_X("Reading fx resolver directory=[%s]"), fxr_root.c_str()); @@ -54,80 +53,90 @@ namespace } } -bool resolve_fxr_path(const pal::string_t& root_path, pal::string_t* out_dotnet_root, pal::string_t* out_fxr_path) +bool fxr_resolver::try_get_path(const host_mode_t mode, const pal::string_t& root_path, pal::string_t* out_dotnet_root, pal::string_t* out_fxr_path) { pal::string_t fxr_dir; -#if FEATURE_APPHOST || FEATURE_LIBHOST - // If a hostfxr exists in app_root, then assume self-contained. - if (library_exists_in_dir(root_path, LIBFXR_NAME, out_fxr_path)) + assert(mode != host_mode_t::invalid); + switch (mode) { - trace::info(_X("Resolved fxr [%s]..."), out_fxr_path->c_str()); - out_dotnet_root->assign(root_path); - return true; - } + case host_mode_t::apphost: + case host_mode_t::libhost: + { + // If a hostfxr exists in app_root, then assume self-contained. + if (library_exists_in_dir(root_path, LIBFXR_NAME, out_fxr_path)) + { + trace::info(_X("Resolved fxr [%s]..."), out_fxr_path->c_str()); + out_dotnet_root->assign(root_path); + return true; + } - // For framework-dependent apps, use DOTNET_ROOT + // For framework-dependent apps, use DOTNET_ROOT - pal::string_t default_install_location; - pal::string_t dotnet_root_env_var_name = get_dotnet_root_env_var_name(); - if (get_file_path_from_env(dotnet_root_env_var_name.c_str(), out_dotnet_root)) - { - trace::info(_X("Using environment variable %s=[%s] as runtime location."), dotnet_root_env_var_name.c_str(), out_dotnet_root->c_str()); - } - else - { - if (pal::get_dotnet_self_registered_dir(&default_install_location) || pal::get_default_installation_dir(&default_install_location)) - { - trace::info(_X("Using global installation location [%s] as runtime location."), default_install_location.c_str()); - out_dotnet_root->assign(default_install_location); - } - else - { - trace::error(_X("A fatal error occurred, the default install location cannot be obtained.")); - return false; - } - trace::info(_X("Using default installation location [%s] as runtime location."), default_install_location.c_str()); - out_dotnet_root->assign(default_install_location); - } + pal::string_t default_install_location; + pal::string_t dotnet_root_env_var_name = get_dotnet_root_env_var_name(); + if (get_file_path_from_env(dotnet_root_env_var_name.c_str(), out_dotnet_root)) + { + trace::info(_X("Using environment variable %s=[%s] as runtime location."), dotnet_root_env_var_name.c_str(), out_dotnet_root->c_str()); + } + else + { + if (pal::get_dotnet_self_registered_dir(&default_install_location) || pal::get_default_installation_dir(&default_install_location)) + { + trace::info(_X("Using global installation location [%s] as runtime location."), default_install_location.c_str()); + out_dotnet_root->assign(default_install_location); + } + else + { + trace::error(_X("A fatal error occurred, the default install location cannot be obtained.")); + return false; + } + } - fxr_dir = *out_dotnet_root; - append_path(&fxr_dir, _X("host")); - append_path(&fxr_dir, _X("fxr")); - if (!pal::directory_exists(fxr_dir)) - { - if (default_install_location.empty()) - { - pal::get_dotnet_self_registered_dir(&default_install_location); + fxr_dir = *out_dotnet_root; + append_path(&fxr_dir, _X("host")); + append_path(&fxr_dir, _X("fxr")); + if (!pal::directory_exists(fxr_dir)) + { + if (default_install_location.empty()) + { + pal::get_dotnet_self_registered_dir(&default_install_location); + } + if (default_install_location.empty()) + { + pal::get_default_installation_dir(&default_install_location); + } + + trace::error(_X("A fatal error occurred. The required library %s could not be found.\n" + "If this is a self-contained application, that library should exist in [%s].\n" + "If this is a framework-dependent application, install the runtime in the global location [%s] or use the %s environment variable to specify the runtime location."), + LIBFXR_NAME, + root_path.c_str(), + default_install_location.c_str(), + dotnet_root_env_var_name.c_str()); + return false; + } + break; } - if (default_install_location.empty()) + case host_mode_t::muxer: { - pal::get_default_installation_dir(&default_install_location); - } - - trace::error(_X("A fatal error occurred. The required library %s could not be found.\n" - "If this is a self-contained application, that library should exist in [%s].\n" - "If this is a framework-dependent application, install the runtime in the global location [%s] or use the %s environment variable to specify the runtime location."), - LIBFXR_NAME, - root_path.c_str(), - default_install_location.c_str(), - dotnet_root_env_var_name.c_str()); - return false; - } -#else // !FEATURE_APPHOST && !FEATURE_LIBHOST - pal::string_t host_dir; - host_dir.assign(get_directory(root_path)); + pal::string_t host_dir; + host_dir.assign(get_directory(root_path)); - out_dotnet_root->assign(host_dir); + out_dotnet_root->assign(host_dir); - fxr_dir = *out_dotnet_root; - append_path(&fxr_dir, _X("host")); - append_path(&fxr_dir, _X("fxr")); - if (!pal::directory_exists(fxr_dir)) - { - trace::error(_X("A fatal error occurred. The folder [%s] does not exist"), fxr_dir.c_str()); - return false; + fxr_dir = *out_dotnet_root; + append_path(&fxr_dir, _X("host")); + append_path(&fxr_dir, _X("fxr")); + if (!pal::directory_exists(fxr_dir)) + { + trace::error(_X("A fatal error occurred. The folder [%s] does not exist"), fxr_dir.c_str()); + return false; + } + break; + } + default: + return false; } -#endif // !FEATURE_APPHOST && !FEATURE_LIBHOST if (!get_latest_fxr(std::move(fxr_dir), out_fxr_path)) return false; diff --git a/src/corehost/cli/fxr_resolver.h b/src/corehost/cli/fxr_resolver.h index de8dd7fff6..2e76713e62 100644 --- a/src/corehost/cli/fxr_resolver.h +++ b/src/corehost/cli/fxr_resolver.h @@ -6,7 +6,11 @@ #define _COREHOST_CLI_FXR_RESOLVER_H_ #include +#include "host_interface.h" -bool resolve_fxr_path(const pal::string_t& host_path, pal::string_t* out_dotnet_root, pal::string_t* out_fxr_path); +namespace fxr_resolver +{ + bool try_get_path(const host_mode_t mode, const pal::string_t& root_path, pal::string_t* out_dotnet_root, pal::string_t* out_fxr_path); +} #endif //_COREHOST_CLI_FXR_RESOLVER_H_ diff --git a/src/corehost/cli/ijwhost/ijwhost.cpp b/src/corehost/cli/ijwhost/ijwhost.cpp index a4337eaf1e..9e9bb88150 100644 --- a/src/corehost/cli/ijwhost/ijwhost.cpp +++ b/src/corehost/cli/ijwhost/ijwhost.cpp @@ -34,7 +34,7 @@ pal::hresult_t get_load_in_memory_assembly_delegate(pal::dll_t handle, load_in_m pal::string_t dotnet_root; pal::string_t fxr_path; - if (!resolve_fxr_path(get_directory(host_path), &dotnet_root, &fxr_path)) + if (!fxr_resolver::try_get_path(host_mode_t::libhost, get_directory(host_path), &dotnet_root, &fxr_path)) { return StatusCode::CoreHostLibMissingFailure; } @@ -61,7 +61,7 @@ pal::hresult_t get_load_in_memory_assembly_delegate(pal::dll_t handle, load_in_m trace::error(_X("Failed to resolve full path of the current mixed-mode module [%s]"), host_path.c_str()); return StatusCode::LibHostCurExeFindFailure; } - + return get_delegate_from_hostfxr(host_path.c_str(), dotnet_root.c_str(), app_path.c_str(), hostfxr_delegate_type::load_in_memory_assembly, (void**)delegate); } diff --git a/src/corehost/cli/nethost/CMakeLists.txt b/src/corehost/cli/nethost/CMakeLists.txt index fde6e19d80..cd3404a551 100644 --- a/src/corehost/cli/nethost/CMakeLists.txt +++ b/src/corehost/cli/nethost/CMakeLists.txt @@ -12,6 +12,8 @@ include_directories(../fxr) # CMake does not recommend using globbing since it messes with the freshness checks set(SOURCES nethost.cpp + ../fxr_resolver.cpp + ../fxr/fx_ver.cpp ) include(../lib.cmake) diff --git a/src/corehost/cli/nethost/nethost.cpp b/src/corehost/cli/nethost/nethost.cpp index c05ca58be7..862d9d7e1b 100644 --- a/src/corehost/cli/nethost/nethost.cpp +++ b/src/corehost/cli/nethost/nethost.cpp @@ -3,13 +3,38 @@ #include "nethost.h" #include +#include +#include #include #include +#include NETHOST_API int STDMETHODCALLTYPE nethost_get_hostfxr_path( nethost_get_hostfxr_path_result_fn result, const char_t * assembly_path) { - result(assembly_path != nullptr ? assembly_path : _X("")); + host_mode_t mode = host_mode_t::invalid; + pal::string_t root_path; + if (assembly_path == nullptr) + { + mode = host_mode_t::muxer; + if (!pal::get_own_executable_path(&root_path) || !pal::realpath(&root_path)) + { + trace::error(_X("Failed to resolve full path of the current executable [%s]"), root_path.c_str()); + return StatusCode::CoreHostCurHostFindFailure; + } + } + else + { + mode = host_mode_t::libhost; + root_path = get_directory(assembly_path); + } + + pal::string_t dotnet_root; + pal::string_t fxr_path; + if(!fxr_resolver::try_get_path(mode, root_path, &dotnet_root, &fxr_path)) + return StatusCode::CoreHostLibMissingFailure; + + result(fxr_path.c_str()); return StatusCode::Success; } \ No newline at end of file diff --git a/src/corehost/corehost.cpp b/src/corehost/corehost.cpp index fa85473405..b74cdfd609 100644 --- a/src/corehost/corehost.cpp +++ b/src/corehost/corehost.cpp @@ -154,9 +154,17 @@ int exe_start(const int argc, const pal::char_t* argv[]) app_path.append(_X(".dll")); #endif + host_mode_t mode; +#if FEATURE_APPHOST + mode = host_mode_t::apphost; +#elif FEATURE_LIBHOST + mode = host_mode_t::libhost; +#else + mode = host_mode_t::muxer; +#endif pal::string_t dotnet_root; pal::string_t fxr_path; - if (!resolve_fxr_path(app_root, &dotnet_root, &fxr_path)) + if (!fxr_resolver::try_get_path(mode, app_root, &dotnet_root, &fxr_path)) { return StatusCode::CoreHostLibMissingFailure; } From bfff90fd82a1dc914ceb0a64609aa17b8c05eb8a Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Wed, 20 Mar 2019 19:41:12 -0700 Subject: [PATCH 03/12] Add basic test for nethost --- src/corehost/cli/test/CMakeLists.txt | 1 + .../cli/test/nativehost/CMakeLists.txt | 18 +++ .../cli/test/nativehost/nativehost.cpp | 63 +++++++++ src/corehost/cli/test/testexe.cmake | 13 ++ .../NativeHosting/Nethost.cs | 121 ++++++++++++++++++ 5 files changed, 216 insertions(+) create mode 100644 src/corehost/cli/test/nativehost/CMakeLists.txt create mode 100644 src/corehost/cli/test/nativehost/nativehost.cpp create mode 100644 src/corehost/cli/test/testexe.cmake create mode 100644 src/test/HostActivationTests/NativeHosting/Nethost.cs diff --git a/src/corehost/cli/test/CMakeLists.txt b/src/corehost/cli/test/CMakeLists.txt index bc83dc16ce..c898a2919c 100644 --- a/src/corehost/cli/test/CMakeLists.txt +++ b/src/corehost/cli/test/CMakeLists.txt @@ -1 +1,2 @@ add_subdirectory(mockhostpolicy) +add_subdirectory(nativehost) \ No newline at end of file diff --git a/src/corehost/cli/test/nativehost/CMakeLists.txt b/src/corehost/cli/test/nativehost/CMakeLists.txt new file mode 100644 index 0000000000..eec4a44ca4 --- /dev/null +++ b/src/corehost/cli/test/nativehost/CMakeLists.txt @@ -0,0 +1,18 @@ +# Copyright (c) .NET Foundation and contributors. All rights reserved. +# Licensed under the MIT license. See LICENSE file in the project root for full license information. + +cmake_minimum_required (VERSION 2.6) +project(nativehost) + +set(DOTNET_PROJECT_NAME "nativehost") + +include_directories(${CMAKE_CURRENT_LIST_DIR}/../../nethost) + +set(SOURCES + ./nativehost.cpp +) + +include(../testexe.cmake) + +set_common_libs("exe") +target_link_libraries(${DOTNET_PROJECT_NAME} nethost) \ No newline at end of file diff --git a/src/corehost/cli/test/nativehost/nativehost.cpp b/src/corehost/cli/test/nativehost/nativehost.cpp new file mode 100644 index 0000000000..d3f070eacf --- /dev/null +++ b/src/corehost/cli/test/nativehost/nativehost.cpp @@ -0,0 +1,63 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include +#include +#include + +namespace +{ + pal::string_t fxr_path; + void hostfxr_path_callback(const char_t *hostfxr_path) + { + fxr_path.assign(hostfxr_path); + } + + std::vector tostr(const pal::string_t &value) + { + std::vector vect; + pal::pal_utf8string(value, &vect); + return vect; + } +} + +#if defined(_WIN32) +int __cdecl wmain(const int argc, const pal::char_t *argv[]) +#else +int main(const int argc, const pal::char_t *argv[]) +#endif +{ + if (argc < 2) + { + std::cerr << "Invalid arguments" << std::endl; + return -1; + } + + const pal::char_t *command = argv[1]; + if (pal::strcmp(command, _X("nethost_get_hostfxr_path")) == 0) + { + const pal::char_t *assembly_path = nullptr; + if (argc >= 3) + assembly_path = argv[2]; + + int res = nethost_get_hostfxr_path(hostfxr_path_callback, assembly_path); + if (res == 0) + { + std::cout << "nethost_get_hostfxr_path succeeded" << std::endl; + std::cout << "hostfxr_path: " << tostr(pal::to_lower(fxr_path)).data() << std::endl; + } + else + { + std::cout << "nethost_get_hostfxr_path failed: " << std::hex << std::showbase << res << std::endl; + } + + return res; + } + else + { + std::cerr << "Invalid arguments" << std::endl; + return -1; + } + + return 0; +} \ No newline at end of file diff --git a/src/corehost/cli/test/testexe.cmake b/src/corehost/cli/test/testexe.cmake new file mode 100644 index 0000000000..1c0908fa10 --- /dev/null +++ b/src/corehost/cli/test/testexe.cmake @@ -0,0 +1,13 @@ +# Copyright (c) .NET Foundation and contributors. All rights reserved. +# Licensed under the MIT license. See LICENSE file in the project root for full license information. + +project(${DOTNET_PROJECT_NAME}) + +set(SKIP_VERSIONING 1) + +include(${CMAKE_CURRENT_LIST_DIR}/../common.cmake) + +add_executable(${DOTNET_PROJECT_NAME} ${SOURCES}) + +install(TARGETS ${DOTNET_PROJECT_NAME} DESTINATION corehost_test) +install_symbols(${DOTNET_PROJECT_NAME} corehost_test) \ No newline at end of file diff --git a/src/test/HostActivationTests/NativeHosting/Nethost.cs b/src/test/HostActivationTests/NativeHosting/Nethost.cs new file mode 100644 index 0000000000..ee995af514 --- /dev/null +++ b/src/test/HostActivationTests/NativeHosting/Nethost.cs @@ -0,0 +1,121 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.DotNet.Cli.Build; +using Microsoft.DotNet.Cli.Build.Framework; +using System; +using System.IO; +using Xunit; + +namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.NativeHosting +{ + public class Nethost : IClassFixture + { + private const string GetHostFxrPath = "nethost_get_hostfxr_path"; + + private readonly SharedTestState sharedState; + private readonly DotNetCli dotNetCli; + + public Nethost(SharedTestState sharedTestState) + { + sharedState = sharedTestState; + dotNetCli = new DotNetCli(Path.Combine(TestArtifact.TestArtifactsPath, "sharedFrameworkPublish")); + } + + [Fact] + public void GetHostFxrPath_NoAssemblyPath_NoFxr() + { + Command.Create(sharedState.NativeHostPath, GetHostFxrPath) + .CaptureStdErr() + .CaptureStdOut() + .Execute() + .Should().Fail(); + } + + [Fact] + public void GetHostFxrPath_NoAssemblyPath_FxrSubdirectory() + { + string copiedHostPath = Path.Combine(Path.GetDirectoryName(sharedState.NativeHostPath), "host"); + SharedFramework.CopyDirectory(Path.Combine(dotNetCli.BinPath, "host"), copiedHostPath); + CommandResult result = Command.Create(sharedState.NativeHostPath, GetHostFxrPath) + .CaptureStdErr() + .CaptureStdOut() + .Execute(); + Directory.Delete(copiedHostPath, true); + + string expectedFxrPath = Path.Combine( + copiedHostPath, + "fxr", + Path.GetFileName(dotNetCli.GreatestVersionHostFxrPath), + RuntimeInformationExtensions.GetSharedLibraryFileNameForCurrentPlatform("hostfxr")); + result.Should().Pass() + .And.HaveStdOutContaining($"hostfxr_path: {expectedFxrPath}".ToLower()); + } + + [Fact] + public void GetHostFxrPath_WithAssemblyPath_AppLocalFxr() + { + TestProjectFixture fixture = sharedState.StandaloneAppFixture; + Command.Create(sharedState.NativeHostPath, $"{GetHostFxrPath} {fixture.TestProject.AppDll}") + .CaptureStdErr() + .CaptureStdOut() + .Execute() + .Should().Pass() + .And.HaveStdOutContaining($"hostfxr_path: {fixture.TestProject.HostFxrDll}".ToLower()); + } + + [Fact] + public void GetHostFxrPath_WithAssemblyPath_DotNetRootEnvironment() + { + string expectedFxrPath = Path.Combine( + dotNetCli.GreatestVersionHostFxrPath, + RuntimeInformationExtensions.GetSharedLibraryFileNameForCurrentPlatform("hostfxr")); + Command.Create(sharedState.NativeHostPath, $"{GetHostFxrPath} {sharedState.NativeHostPath}") + .CaptureStdErr() + .CaptureStdOut() + .EnvironmentVariable("DOTNET_ROOT", dotNetCli.BinPath) + .Execute() + .Should().Pass() + .And.HaveStdOutContaining($"hostfxr_path: {expectedFxrPath}".ToLower()); + } + + public class SharedTestState : IDisposable + { + public RepoDirectoriesProvider RepoDirectories { get; } + public TestProjectFixture StandaloneAppFixture { get; } + public string NativeHostPath { get; } + + private readonly string baseDir; + + public SharedTestState() + { + RepoDirectories = new RepoDirectoriesProvider(); + + baseDir = SharedFramework.CalculateUniqueTestDirectory(Path.Combine(TestArtifact.TestArtifactsPath, "nativeHosting")); + Directory.CreateDirectory(baseDir); + + string nativeHostName = RuntimeInformationExtensions.GetExeFileNameForCurrentPlatform("nativehost"); + NativeHostPath = Path.Combine(baseDir, nativeHostName); + + // Copy over native host and nethost + string nethostName = RuntimeInformationExtensions.GetSharedLibraryFileNameForCurrentPlatform("nethost"); + File.Copy(Path.Combine(RepoDirectories.CorehostPackages, nethostName), Path.Combine(baseDir, nethostName)); + File.Copy(Path.Combine(RepoDirectories.Artifacts, "corehost_test", nativeHostName), NativeHostPath); + + var standaloneAppFixture = new TestProjectFixture("StandaloneApp", RepoDirectories); + StandaloneAppFixture = standaloneAppFixture + .EnsureRestoredForRid(standaloneAppFixture.CurrentRid, RepoDirectories.CorehostPackages) + .PublishProject(runtime: standaloneAppFixture.CurrentRid); + } + + public void Dispose() + { + StandaloneAppFixture.Dispose(); + if (!TestArtifact.PreserveTestRuns() && Directory.Exists(baseDir)) + { + Directory.Delete(baseDir, true); + } + } + } + } +} From 986153bc645ffbe7b5962ec9c28b13ef0f0a0c97 Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Thu, 21 Mar 2019 10:31:28 -0700 Subject: [PATCH 04/12] Set rpath --- src/corehost/cli/test/nativehost/CMakeLists.txt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/corehost/cli/test/nativehost/CMakeLists.txt b/src/corehost/cli/test/nativehost/CMakeLists.txt index eec4a44ca4..03bf576355 100644 --- a/src/corehost/cli/test/nativehost/CMakeLists.txt +++ b/src/corehost/cli/test/nativehost/CMakeLists.txt @@ -1,11 +1,19 @@ # Copyright (c) .NET Foundation and contributors. All rights reserved. # Licensed under the MIT license. See LICENSE file in the project root for full license information. -cmake_minimum_required (VERSION 2.6) +cmake_minimum_required (VERSION 2.8.12) project(nativehost) set(DOTNET_PROJECT_NAME "nativehost") +set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) +set(MACOSX_RPATH ON) +if (CMAKE_SYSTEM_NAME STREQUAL Darwin) + set(CMAKE_INSTALL_RPATH "@loader_path") +else() + set(CMAKE_INSTALL_RPATH "\$ORIGIN") +endif() + include_directories(${CMAKE_CURRENT_LIST_DIR}/../../nethost) set(SOURCES From 7501fd8aa570d4ee87986ea987dc64cb2c8f9f01 Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Thu, 21 Mar 2019 14:05:03 -0700 Subject: [PATCH 05/12] Update licence header --- src/corehost/cli/nethost/CMakeLists.txt | 5 +++-- src/corehost/cli/nethost/nethost.cpp | 5 +++-- src/corehost/cli/nethost/nethost.h | 5 +++-- src/corehost/cli/test/nativehost/CMakeLists.txt | 5 +++-- src/corehost/cli/test/nativehost/nativehost.cpp | 5 +++-- src/corehost/cli/test/testexe.cmake | 5 +++-- src/test/HostActivationTests/NativeHosting/Nethost.cs | 5 +++-- 7 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/corehost/cli/nethost/CMakeLists.txt b/src/corehost/cli/nethost/CMakeLists.txt index cd3404a551..cbda07da74 100644 --- a/src/corehost/cli/nethost/CMakeLists.txt +++ b/src/corehost/cli/nethost/CMakeLists.txt @@ -1,5 +1,6 @@ -# Copyright (c) .NET Foundation and contributors. All rights reserved. -# Licensed under the MIT license. See LICENSE file in the project root for full license information. +# Licensed to the .NET Foundation under one or more agreements. +# The .NET Foundation licenses this file to you under the MIT license. +# See the LICENSE file in the project root for more information. cmake_minimum_required (VERSION 2.6) project(nethost) diff --git a/src/corehost/cli/nethost/nethost.cpp b/src/corehost/cli/nethost/nethost.cpp index 862d9d7e1b..731dff13a1 100644 --- a/src/corehost/cli/nethost/nethost.cpp +++ b/src/corehost/cli/nethost/nethost.cpp @@ -1,5 +1,6 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. #include "nethost.h" #include diff --git a/src/corehost/cli/nethost/nethost.h b/src/corehost/cli/nethost/nethost.h index 843e025526..9db7cf681a 100644 --- a/src/corehost/cli/nethost/nethost.h +++ b/src/corehost/cli/nethost/nethost.h @@ -1,5 +1,6 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. #ifndef __NETHOST_H__ #define __NETHOST_H__ diff --git a/src/corehost/cli/test/nativehost/CMakeLists.txt b/src/corehost/cli/test/nativehost/CMakeLists.txt index 03bf576355..ce7a956cfb 100644 --- a/src/corehost/cli/test/nativehost/CMakeLists.txt +++ b/src/corehost/cli/test/nativehost/CMakeLists.txt @@ -1,5 +1,6 @@ -# Copyright (c) .NET Foundation and contributors. All rights reserved. -# Licensed under the MIT license. See LICENSE file in the project root for full license information. +# Licensed to the .NET Foundation under one or more agreements. +# The .NET Foundation licenses this file to you under the MIT license. +# See the LICENSE file in the project root for more information. cmake_minimum_required (VERSION 2.8.12) project(nativehost) diff --git a/src/corehost/cli/test/nativehost/nativehost.cpp b/src/corehost/cli/test/nativehost/nativehost.cpp index d3f070eacf..8e7e30c010 100644 --- a/src/corehost/cli/test/nativehost/nativehost.cpp +++ b/src/corehost/cli/test/nativehost/nativehost.cpp @@ -1,5 +1,6 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. #include #include diff --git a/src/corehost/cli/test/testexe.cmake b/src/corehost/cli/test/testexe.cmake index 1c0908fa10..0a49f990d9 100644 --- a/src/corehost/cli/test/testexe.cmake +++ b/src/corehost/cli/test/testexe.cmake @@ -1,5 +1,6 @@ -# Copyright (c) .NET Foundation and contributors. All rights reserved. -# Licensed under the MIT license. See LICENSE file in the project root for full license information. +# Licensed to the .NET Foundation under one or more agreements. +# The .NET Foundation licenses this file to you under the MIT license. +# See the LICENSE file in the project root for more information. project(${DOTNET_PROJECT_NAME}) diff --git a/src/test/HostActivationTests/NativeHosting/Nethost.cs b/src/test/HostActivationTests/NativeHosting/Nethost.cs index ee995af514..cacb5a724e 100644 --- a/src/test/HostActivationTests/NativeHosting/Nethost.cs +++ b/src/test/HostActivationTests/NativeHosting/Nethost.cs @@ -1,5 +1,6 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using Microsoft.DotNet.Cli.Build; using Microsoft.DotNet.Cli.Build.Framework; From e728a62c670ec575d23a5433c3548e02fc8bb3bc Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Thu, 21 Mar 2019 19:07:53 -0700 Subject: [PATCH 06/12] Collapse CLI_CMAKE_APP/COM/IJW/NETHOST_VER to CLI_CMAKE_COMMON_HOST_VER --- src/corehost/Windows/gen-buildsys-win.bat | 4 ++-- src/corehost/build.sh | 4 ++-- src/corehost/cli/comhost/CMakeLists.txt | 7 ------- src/corehost/cli/ijwhost/CMakeLists.txt | 7 ------- src/corehost/cli/nethost/CMakeLists.txt | 6 ------ src/corehost/cli/nethost/nethost.cpp | 2 +- src/corehost/cli/setup.cmake | 6 +++--- src/corehost/corehost.cpp | 2 +- 8 files changed, 9 insertions(+), 29 deletions(-) diff --git a/src/corehost/Windows/gen-buildsys-win.bat b/src/corehost/Windows/gen-buildsys-win.bat index db57de4cf5..58a18cd30f 100644 --- a/src/corehost/Windows/gen-buildsys-win.bat +++ b/src/corehost/Windows/gen-buildsys-win.bat @@ -41,8 +41,8 @@ for /f "delims=" %%a in ('powershell -NoProfile -ExecutionPolicy ByPass "& .\Win popd :DoGen -echo "%CMakePath%" %__sourceDir% %__SDKVersion% "-DCLI_CMAKE_RUNTIME_ID:STRING=%cm_BaseRid%" "-DCLI_CMAKE_HOST_VER:STRING=%__HostVersion%" "-DCLI_CMAKE_APPHOST_VER:STRING=%__AppHostVersion%" "-DCLI_CMAKE_COMHOST_VER:STRING=%__AppHostVersion%" "-DCLI_CMAKE_IJWHOST_VER:STRING=%__AppHostVersion%" "-DCLI_CMAKE_NETHOST_VER:STRING=%__AppHostVersion%" "-DCLI_CMAKE_HOST_FXR_VER:STRING=%__HostFxrVersion%" "-DCLI_CMAKE_HOST_POLICY_VER:STRING=%__HostPolicyVersion%" "-DCLI_CMAKE_PKG_RID:STRING=%cm_BaseRid%" "-DCLI_CMAKE_COMMIT_HASH:STRING=%__LatestCommit%" "-DCLI_CMAKE_PLATFORM_ARCH_%cm_Arch%=1" "-DCMAKE_INSTALL_PREFIX=%__CMakeBinDir%" "-DCLI_CMAKE_RESOURCE_DIR:STRING=%__ResourcesDir%" -G "Visual Studio %__VSString%" %__ExtraCmakeParams% -"%CMakePath%" %__sourceDir% %__SDKVersion% "-DCLI_CMAKE_RUNTIME_ID:STRING=%cm_BaseRid%" "-DCLI_CMAKE_HOST_VER:STRING=%__HostVersion%" "-DCLI_CMAKE_APPHOST_VER:STRING=%__AppHostVersion%" "-DCLI_CMAKE_COMHOST_VER:STRING=%__AppHostVersion%" "-DCLI_CMAKE_IJWHOST_VER:STRING=%__AppHostVersion%" "-DCLI_CMAKE_NETHOST_VER:STRING=%__AppHostVersion%" "-DCLI_CMAKE_HOST_FXR_VER:STRING=%__HostFxrVersion%" "-DCLI_CMAKE_HOST_POLICY_VER:STRING=%__HostPolicyVersion%" "-DCLI_CMAKE_PKG_RID:STRING=%cm_BaseRid%" "-DCLI_CMAKE_COMMIT_HASH:STRING=%__LatestCommit%" "-DCLI_CMAKE_PLATFORM_ARCH_%cm_Arch%=1" "-DCMAKE_INSTALL_PREFIX=%__CMakeBinDir%" "-DCLI_CMAKE_RESOURCE_DIR:STRING=%__ResourcesDir%" -G "Visual Studio %__VSString%" %__ExtraCmakeParams% +echo "%CMakePath%" %__sourceDir% %__SDKVersion% "-DCLI_CMAKE_RUNTIME_ID:STRING=%cm_BaseRid%" "-DCLI_CMAKE_HOST_VER:STRING=%__HostVersion%" "-DCLI_CMAKE_COMMON_HOST_VER:STRING=%__AppHostVersion%" "-DCLI_CMAKE_HOST_FXR_VER:STRING=%__HostFxrVersion%" "-DCLI_CMAKE_HOST_POLICY_VER:STRING=%__HostPolicyVersion%" "-DCLI_CMAKE_PKG_RID:STRING=%cm_BaseRid%" "-DCLI_CMAKE_COMMIT_HASH:STRING=%__LatestCommit%" "-DCLI_CMAKE_PLATFORM_ARCH_%cm_Arch%=1" "-DCMAKE_INSTALL_PREFIX=%__CMakeBinDir%" "-DCLI_CMAKE_RESOURCE_DIR:STRING=%__ResourcesDir%" -G "Visual Studio %__VSString%" %__ExtraCmakeParams% +"%CMakePath%" %__sourceDir% %__SDKVersion% "-DCLI_CMAKE_RUNTIME_ID:STRING=%cm_BaseRid%" "-DCLI_CMAKE_HOST_VER:STRING=%__HostVersion%" "-DCLI_CMAKE_COMMON_HOST_VER:STRING=%__AppHostVersion%" "-DCLI_CMAKE_HOST_FXR_VER:STRING=%__HostFxrVersion%" "-DCLI_CMAKE_HOST_POLICY_VER:STRING=%__HostPolicyVersion%" "-DCLI_CMAKE_PKG_RID:STRING=%cm_BaseRid%" "-DCLI_CMAKE_COMMIT_HASH:STRING=%__LatestCommit%" "-DCLI_CMAKE_PLATFORM_ARCH_%cm_Arch%=1" "-DCMAKE_INSTALL_PREFIX=%__CMakeBinDir%" "-DCLI_CMAKE_RESOURCE_DIR:STRING=%__ResourcesDir%" -G "Visual Studio %__VSString%" %__ExtraCmakeParams% endlocal GOTO :DONE diff --git a/src/corehost/build.sh b/src/corehost/build.sh index 843ab7fd03..f64b6b62fb 100755 --- a/src/corehost/build.sh +++ b/src/corehost/build.sh @@ -263,9 +263,9 @@ if [ $__CrossBuild == 1 ]; then fi export TARGET_BUILD_ARCH=$__build_arch_lowcase export __DistroRid=$__rid_plat - cmake "$DIR" -G "Unix Makefiles" $__cmake_defines -DCLI_CMAKE_HOST_VER:STRING=$__host_ver -DCLI_CMAKE_APPHOST_VER:STRING=$__apphost_ver -DCLI_CMAKE_NETHOST_VER:STRING=$__apphost_ver -DCLI_CMAKE_HOST_FXR_VER:STRING=$__fxr_ver -DCLI_CMAKE_HOST_POLICY_VER:STRING=$__policy_ver -DCLI_CMAKE_PKG_RID:STRING=$__base_rid -DCLI_CMAKE_COMMIT_HASH:STRING=$__commit_hash -DCMAKE_INSTALL_PREFIX=$__cmake_bin_prefix -DCMAKE_TOOLCHAIN_FILE=$DIR/../../cross/toolchain.cmake + cmake "$DIR" -G "Unix Makefiles" $__cmake_defines -DCLI_CMAKE_HOST_VER:STRING=$__host_ver -DCLI_CMAKE_COMMON_HOST_VER:STRING=$__apphost_ver -DCLI_CMAKE_HOST_FXR_VER:STRING=$__fxr_ver -DCLI_CMAKE_HOST_POLICY_VER:STRING=$__policy_ver -DCLI_CMAKE_PKG_RID:STRING=$__base_rid -DCLI_CMAKE_COMMIT_HASH:STRING=$__commit_hash -DCMAKE_INSTALL_PREFIX=$__cmake_bin_prefix -DCMAKE_TOOLCHAIN_FILE=$DIR/../../cross/toolchain.cmake else - cmake "$DIR" -G "Unix Makefiles" $__cmake_defines -DCLI_CMAKE_HOST_VER:STRING=$__host_ver -DCLI_CMAKE_APPHOST_VER:STRING=$__apphost_ver -DCLI_CMAKE_NETHOST_VER:STRING=$__apphost_ver -DCLI_CMAKE_HOST_FXR_VER:STRING=$__fxr_ver -DCLI_CMAKE_HOST_POLICY_VER:STRING=$__policy_ver -DCLI_CMAKE_PKG_RID:STRING=$__base_rid -DCLI_CMAKE_COMMIT_HASH:STRING=$__commit_hash -DCMAKE_INSTALL_PREFIX=$__cmake_bin_prefix + cmake "$DIR" -G "Unix Makefiles" $__cmake_defines -DCLI_CMAKE_HOST_VER:STRING=$__host_ver -DCLI_CMAKE_COMMON_HOST_VER:STRING=$__apphost_ver -DCLI_CMAKE_HOST_FXR_VER:STRING=$__fxr_ver -DCLI_CMAKE_HOST_POLICY_VER:STRING=$__policy_ver -DCLI_CMAKE_PKG_RID:STRING=$__base_rid -DCLI_CMAKE_COMMIT_HASH:STRING=$__commit_hash -DCMAKE_INSTALL_PREFIX=$__cmake_bin_prefix fi popd diff --git a/src/corehost/cli/comhost/CMakeLists.txt b/src/corehost/cli/comhost/CMakeLists.txt index ecd2289fed..c80db1e2e6 100644 --- a/src/corehost/cli/comhost/CMakeLists.txt +++ b/src/corehost/cli/comhost/CMakeLists.txt @@ -36,13 +36,6 @@ endif() include(../lib.cmake) -# Move to setup.cmake if COMHOST is ever built on non-Windows -if("${CLI_CMAKE_COMHOST_VER}" STREQUAL "") - message(FATAL_ERROR "comhost version is not specified") -else() - add_definitions(-DLIBHOST_PKG_VER="${CLI_CMAKE_COMHOST_VER}") -endif() - add_definitions(-DFEATURE_LIBHOST=1) # Specify non-default Windows libs to be used for Arm/Arm64 builds diff --git a/src/corehost/cli/ijwhost/CMakeLists.txt b/src/corehost/cli/ijwhost/CMakeLists.txt index f07d9aad61..f706e040bc 100644 --- a/src/corehost/cli/ijwhost/CMakeLists.txt +++ b/src/corehost/cli/ijwhost/CMakeLists.txt @@ -29,13 +29,6 @@ if(WIN32) Exports.def) endif() -# Move to setup.cmake if IJWHOST is ever built on non-Windows -if("${CLI_CMAKE_IJWHOST_VER}" STREQUAL "") - message(FATAL_ERROR "ijwhost version is not specified") -else() - add_definitions(-DLIBHOST_PKG_VER="${CLI_CMAKE_IJWHOST_VER}") -endif() - set (ASM_HELPERS_SOURCES ${ARCH_SPECIFIC_FOLDER_NAME}/asmhelpers.asm) diff --git a/src/corehost/cli/nethost/CMakeLists.txt b/src/corehost/cli/nethost/CMakeLists.txt index cbda07da74..30d749f1bd 100644 --- a/src/corehost/cli/nethost/CMakeLists.txt +++ b/src/corehost/cli/nethost/CMakeLists.txt @@ -22,11 +22,5 @@ include(../lib.cmake) add_definitions(-DFEATURE_LIBHOST=1) add_definitions(-DNETHOST_EXPORT) -if("${CLI_CMAKE_NETHOST_VER}" STREQUAL "") - message(FATAL_ERROR "nethost version is not specified") -else() - add_definitions(-DLIBHOST_PKG_VER="${CLI_CMAKE_NETHOST_VER}") -endif() - install(TARGETS nethost DESTINATION corehost) install_symbols(nethost corehost) \ No newline at end of file diff --git a/src/corehost/cli/nethost/nethost.cpp b/src/corehost/cli/nethost/nethost.cpp index 731dff13a1..0b9062e190 100644 --- a/src/corehost/cli/nethost/nethost.cpp +++ b/src/corehost/cli/nethost/nethost.cpp @@ -10,7 +10,7 @@ #include #include -NETHOST_API int STDMETHODCALLTYPE nethost_get_hostfxr_path( +NETHOST_API int NETHOST_CALLTYPE nethost_get_hostfxr_path( nethost_get_hostfxr_path_result_fn result, const char_t * assembly_path) { diff --git a/src/corehost/cli/setup.cmake b/src/corehost/cli/setup.cmake index 983f968a1a..0d6a1cdb12 100644 --- a/src/corehost/cli/setup.cmake +++ b/src/corehost/cli/setup.cmake @@ -24,10 +24,10 @@ else() add_definitions(-DHOST_PKG_VER="${CLI_CMAKE_HOST_VER}") endif() -if("${CLI_CMAKE_APPHOST_VER}" STREQUAL "") - message(FATAL_ERROR "apphost version is not specified") +if("${CLI_CMAKE_COMMON_HOST_VER}" STREQUAL "") + message(FATAL_ERROR "Common host version is not specified") else() - add_definitions(-DAPPHOST_PKG_VER="${CLI_CMAKE_APPHOST_VER}") + add_definitions(-DCOMMON_HOST_PKG_VER="${CLI_CMAKE_COMMON_HOST_VER}") endif() if("${CLI_CMAKE_PKG_RID}" STREQUAL "") diff --git a/src/corehost/corehost.cpp b/src/corehost/corehost.cpp index b74cdfd609..8bbcfc5e19 100644 --- a/src/corehost/corehost.cpp +++ b/src/corehost/corehost.cpp @@ -12,7 +12,7 @@ #if FEATURE_APPHOST #define CURHOST_TYPE _X("apphost") -#define CUREXE_PKG_VER APPHOST_PKG_VER +#define CUREXE_PKG_VER COMMON_HOST_PKG_VER #define CURHOST_EXE /** From e371f6edf0670a049c666d60643d065c9ee732f7 Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Fri, 22 Mar 2019 15:12:28 -0700 Subject: [PATCH 07/12] Stop using muxer behaviour in nethost_get_hostfxr_path - Look at environment variable and global locations when called without an assembly path (app/libhost behaviour minus app-local search) - Switch back to preprocessor conditions for getting fxr path now that nethost doesn't need different behaviours - Update/add tests for changed behaviour --- src/corehost/cli/comhost/comhost.cpp | 2 +- src/corehost/cli/fxr_resolver.cpp | 135 +++++++-------- src/corehost/cli/fxr_resolver.h | 3 +- src/corehost/cli/ijwhost/ijwhost.cpp | 2 +- src/corehost/cli/nethost/nethost.cpp | 19 +-- src/corehost/cli/nethost/nethost.h | 4 +- .../cli/test/nativehost/nativehost.cpp | 10 ++ src/corehost/corehost.cpp | 10 +- .../NativeHosting/Nethost.cs | 159 +++++++++++------- 9 files changed, 181 insertions(+), 163 deletions(-) diff --git a/src/corehost/cli/comhost/comhost.cpp b/src/corehost/cli/comhost/comhost.cpp index 6c016d0643..0798b18ddf 100644 --- a/src/corehost/cli/comhost/comhost.cpp +++ b/src/corehost/cli/comhost/comhost.cpp @@ -74,7 +74,7 @@ namespace pal::string_t dotnet_root; pal::string_t fxr_path; - if (!fxr_resolver::try_get_path(host_mode_t::libhost, get_directory(host_path), &dotnet_root, &fxr_path)) + if (!fxr_resolver::try_get_path(get_directory(host_path), &dotnet_root, &fxr_path)) { return StatusCode::CoreHostLibMissingFailure; } diff --git a/src/corehost/cli/fxr_resolver.cpp b/src/corehost/cli/fxr_resolver.cpp index 771d299c07..4757972d41 100644 --- a/src/corehost/cli/fxr_resolver.cpp +++ b/src/corehost/cli/fxr_resolver.cpp @@ -53,90 +53,77 @@ namespace } } -bool fxr_resolver::try_get_path(const host_mode_t mode, const pal::string_t& root_path, pal::string_t* out_dotnet_root, pal::string_t* out_fxr_path) +bool fxr_resolver::try_get_path(const pal::string_t& root_path, pal::string_t* out_dotnet_root, pal::string_t* out_fxr_path) { pal::string_t fxr_dir; - assert(mode != host_mode_t::invalid); - switch (mode) +#if FEATURE_APPHOST || FEATURE_LIBHOST + // If a hostfxr exists in root_path, then assume self-contained. + if (root_path.length() > 0 && library_exists_in_dir(root_path, LIBFXR_NAME, out_fxr_path)) { - case host_mode_t::apphost: - case host_mode_t::libhost: - { - // If a hostfxr exists in app_root, then assume self-contained. - if (library_exists_in_dir(root_path, LIBFXR_NAME, out_fxr_path)) - { - trace::info(_X("Resolved fxr [%s]..."), out_fxr_path->c_str()); - out_dotnet_root->assign(root_path); - return true; - } - - // For framework-dependent apps, use DOTNET_ROOT + trace::info(_X("Resolved fxr [%s]..."), out_fxr_path->c_str()); + out_dotnet_root->assign(root_path); + return true; + } - pal::string_t default_install_location; - pal::string_t dotnet_root_env_var_name = get_dotnet_root_env_var_name(); - if (get_file_path_from_env(dotnet_root_env_var_name.c_str(), out_dotnet_root)) - { - trace::info(_X("Using environment variable %s=[%s] as runtime location."), dotnet_root_env_var_name.c_str(), out_dotnet_root->c_str()); - } - else - { - if (pal::get_dotnet_self_registered_dir(&default_install_location) || pal::get_default_installation_dir(&default_install_location)) - { - trace::info(_X("Using global installation location [%s] as runtime location."), default_install_location.c_str()); - out_dotnet_root->assign(default_install_location); - } - else - { - trace::error(_X("A fatal error occurred, the default install location cannot be obtained.")); - return false; - } - } + // For framework-dependent apps, use DOTNET_ROOT + pal::string_t default_install_location; + pal::string_t dotnet_root_env_var_name = get_dotnet_root_env_var_name(); + if (get_file_path_from_env(dotnet_root_env_var_name.c_str(), out_dotnet_root)) + { + trace::info(_X("Using environment variable %s=[%s] as runtime location."), dotnet_root_env_var_name.c_str(), out_dotnet_root->c_str()); + } + else + { + if (pal::get_dotnet_self_registered_dir(&default_install_location) || pal::get_default_installation_dir(&default_install_location)) + { + trace::info(_X("Using global installation location [%s] as runtime location."), default_install_location.c_str()); + out_dotnet_root->assign(default_install_location); + } + else + { + trace::error(_X("A fatal error occurred, the default install location cannot be obtained.")); + return false; + } + } - fxr_dir = *out_dotnet_root; - append_path(&fxr_dir, _X("host")); - append_path(&fxr_dir, _X("fxr")); - if (!pal::directory_exists(fxr_dir)) - { - if (default_install_location.empty()) - { - pal::get_dotnet_self_registered_dir(&default_install_location); - } - if (default_install_location.empty()) - { - pal::get_default_installation_dir(&default_install_location); - } - - trace::error(_X("A fatal error occurred. The required library %s could not be found.\n" - "If this is a self-contained application, that library should exist in [%s].\n" - "If this is a framework-dependent application, install the runtime in the global location [%s] or use the %s environment variable to specify the runtime location."), - LIBFXR_NAME, - root_path.c_str(), - default_install_location.c_str(), - dotnet_root_env_var_name.c_str()); - return false; - } - break; + fxr_dir = *out_dotnet_root; + append_path(&fxr_dir, _X("host")); + append_path(&fxr_dir, _X("fxr")); + if (!pal::directory_exists(fxr_dir)) + { + if (default_install_location.empty()) + { + pal::get_dotnet_self_registered_dir(&default_install_location); } - case host_mode_t::muxer: + if (default_install_location.empty()) { - pal::string_t host_dir; - host_dir.assign(get_directory(root_path)); + pal::get_default_installation_dir(&default_install_location); + } + + trace::error(_X("A fatal error occurred. The required library %s could not be found.\n" + "If this is a self-contained application, that library should exist in [%s].\n" + "If this is a framework-dependent application, install the runtime in the global location [%s] or use the %s environment variable to specify the runtime location."), + LIBFXR_NAME, + root_path.c_str(), + default_install_location.c_str(), + dotnet_root_env_var_name.c_str()); + return false; + } +#else // !FEATURE_APPHOST && !FEATURE_LIBHOST + pal::string_t host_dir; + host_dir.assign(get_directory(root_path)); - out_dotnet_root->assign(host_dir); + out_dotnet_root->assign(host_dir); - fxr_dir = *out_dotnet_root; - append_path(&fxr_dir, _X("host")); - append_path(&fxr_dir, _X("fxr")); - if (!pal::directory_exists(fxr_dir)) - { - trace::error(_X("A fatal error occurred. The folder [%s] does not exist"), fxr_dir.c_str()); - return false; - } - break; - } - default: - return false; + fxr_dir = *out_dotnet_root; + append_path(&fxr_dir, _X("host")); + append_path(&fxr_dir, _X("fxr")); + if (!pal::directory_exists(fxr_dir)) + { + trace::error(_X("A fatal error occurred. The folder [%s] does not exist"), fxr_dir.c_str()); + return false; } +#endif // !FEATURE_APPHOST && !FEATURE_LIBHOST if (!get_latest_fxr(std::move(fxr_dir), out_fxr_path)) return false; diff --git a/src/corehost/cli/fxr_resolver.h b/src/corehost/cli/fxr_resolver.h index 2e76713e62..30dfc29f85 100644 --- a/src/corehost/cli/fxr_resolver.h +++ b/src/corehost/cli/fxr_resolver.h @@ -6,11 +6,10 @@ #define _COREHOST_CLI_FXR_RESOLVER_H_ #include -#include "host_interface.h" namespace fxr_resolver { - bool try_get_path(const host_mode_t mode, const pal::string_t& root_path, pal::string_t* out_dotnet_root, pal::string_t* out_fxr_path); + bool try_get_path(const pal::string_t& root_path, pal::string_t* out_dotnet_root, pal::string_t* out_fxr_path); } #endif //_COREHOST_CLI_FXR_RESOLVER_H_ diff --git a/src/corehost/cli/ijwhost/ijwhost.cpp b/src/corehost/cli/ijwhost/ijwhost.cpp index 9e9bb88150..18943424d1 100644 --- a/src/corehost/cli/ijwhost/ijwhost.cpp +++ b/src/corehost/cli/ijwhost/ijwhost.cpp @@ -34,7 +34,7 @@ pal::hresult_t get_load_in_memory_assembly_delegate(pal::dll_t handle, load_in_m pal::string_t dotnet_root; pal::string_t fxr_path; - if (!fxr_resolver::try_get_path(host_mode_t::libhost, get_directory(host_path), &dotnet_root, &fxr_path)) + if (!fxr_resolver::try_get_path(get_directory(host_path), &dotnet_root, &fxr_path)) { return StatusCode::CoreHostLibMissingFailure; } diff --git a/src/corehost/cli/nethost/nethost.cpp b/src/corehost/cli/nethost/nethost.cpp index 0b9062e190..ea57b8958b 100644 --- a/src/corehost/cli/nethost/nethost.cpp +++ b/src/corehost/cli/nethost/nethost.cpp @@ -5,35 +5,20 @@ #include "nethost.h" #include #include -#include #include -#include #include NETHOST_API int NETHOST_CALLTYPE nethost_get_hostfxr_path( nethost_get_hostfxr_path_result_fn result, const char_t * assembly_path) { - host_mode_t mode = host_mode_t::invalid; pal::string_t root_path; - if (assembly_path == nullptr) - { - mode = host_mode_t::muxer; - if (!pal::get_own_executable_path(&root_path) || !pal::realpath(&root_path)) - { - trace::error(_X("Failed to resolve full path of the current executable [%s]"), root_path.c_str()); - return StatusCode::CoreHostCurHostFindFailure; - } - } - else - { - mode = host_mode_t::libhost; + if (assembly_path != nullptr) root_path = get_directory(assembly_path); - } pal::string_t dotnet_root; pal::string_t fxr_path; - if(!fxr_resolver::try_get_path(mode, root_path, &dotnet_root, &fxr_path)) + if(!fxr_resolver::try_get_path(root_path, &dotnet_root, &fxr_path)) return StatusCode::CoreHostLibMissingFailure; result(fxr_path.c_str()); diff --git a/src/corehost/cli/nethost/nethost.h b/src/corehost/cli/nethost/nethost.h index 9db7cf681a..02ed53641e 100644 --- a/src/corehost/cli/nethost/nethost.h +++ b/src/corehost/cli/nethost/nethost.h @@ -42,8 +42,8 @@ using nethost_get_hostfxr_path_result_fn = void(*)(const char_t * hostfxr_path); // assembly_path // Optional. Path to the compenent's assembly. Whether or not this is specified // determines the behaviour for locating the hostfxr library. -// If nullptr, hostfxr will be located as if the running executable is the muxer -// If specified, hostfxr will be located as if the assembly_path is the apphost +// If nullptr, hostfxr is located using the enviroment variable or global registration +// If specified, hostfxr is located as if the assembly_path is the apphost // // Return value: // 0 on success, otherwise failure diff --git a/src/corehost/cli/test/nativehost/nativehost.cpp b/src/corehost/cli/test/nativehost/nativehost.cpp index 8e7e30c010..c51fc26e40 100644 --- a/src/corehost/cli/test/nativehost/nativehost.cpp +++ b/src/corehost/cli/test/nativehost/nativehost.cpp @@ -41,6 +41,16 @@ int main(const int argc, const pal::char_t *argv[]) if (argc >= 3) assembly_path = argv[2]; +#if defined(_WIN32) + pal::string_t testOverride; + if (pal::getenv(_X("TEST_OVERRIDE_PROGRAMFILES"), &testOverride)) + { + std::cout << tostr(testOverride).data() << std::endl; + ::SetEnvironmentVariableW(_X("ProgramFiles"), testOverride.c_str()); + ::SetEnvironmentVariableW(_X("ProgramFiles(x86)"), testOverride.c_str()); + } +#endif + int res = nethost_get_hostfxr_path(hostfxr_path_callback, assembly_path); if (res == 0) { diff --git a/src/corehost/corehost.cpp b/src/corehost/corehost.cpp index 8bbcfc5e19..f472c72832 100644 --- a/src/corehost/corehost.cpp +++ b/src/corehost/corehost.cpp @@ -154,17 +154,9 @@ int exe_start(const int argc, const pal::char_t* argv[]) app_path.append(_X(".dll")); #endif - host_mode_t mode; -#if FEATURE_APPHOST - mode = host_mode_t::apphost; -#elif FEATURE_LIBHOST - mode = host_mode_t::libhost; -#else - mode = host_mode_t::muxer; -#endif pal::string_t dotnet_root; pal::string_t fxr_path; - if (!fxr_resolver::try_get_path(mode, app_root, &dotnet_root, &fxr_path)) + if (!fxr_resolver::try_get_path(app_root, &dotnet_root, &fxr_path)) { return StatusCode::CoreHostLibMissingFailure; } diff --git a/src/test/HostActivationTests/NativeHosting/Nethost.cs b/src/test/HostActivationTests/NativeHosting/Nethost.cs index cacb5a724e..9dcfa28d99 100644 --- a/src/test/HostActivationTests/NativeHosting/Nethost.cs +++ b/src/test/HostActivationTests/NativeHosting/Nethost.cs @@ -2,10 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Microsoft.DotNet.Cli.Build; using Microsoft.DotNet.Cli.Build.Framework; using System; using System.IO; +using System.Runtime.InteropServices; using Xunit; namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.NativeHosting @@ -13,108 +13,153 @@ namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.NativeHosting public class Nethost : IClassFixture { private const string GetHostFxrPath = "nethost_get_hostfxr_path"; + private const int CoreHostLibMissingFailure = unchecked((int)0x80008083); private readonly SharedTestState sharedState; - private readonly DotNetCli dotNetCli; public Nethost(SharedTestState sharedTestState) { sharedState = sharedTestState; - dotNetCli = new DotNetCli(Path.Combine(TestArtifact.TestArtifactsPath, "sharedFrameworkPublish")); } - [Fact] - public void GetHostFxrPath_NoAssemblyPath_NoFxr() + [Theory] + [InlineData(false, true)] + [InlineData(false, false)] + [InlineData(true, true)] + [InlineData(true, false)] + public void GetHostFxrPath_DotNetRootEnvironment(bool useAssemblyPath, bool isValid) { - Command.Create(sharedState.NativeHostPath, GetHostFxrPath) + string dotNetRoot = isValid ? Path.Combine(sharedState.ValidInstallRoot, "dotnet") : sharedState.InvalidInstallRoot; + CommandResult result = Command.Create(sharedState.NativeHostPath, $"{GetHostFxrPath} {(useAssemblyPath ? sharedState.TestAssemblyPath : string.Empty)}") .CaptureStdErr() .CaptureStdOut() - .Execute() - .Should().Fail(); + .EnvironmentVariable("DOTNET_ROOT", dotNetRoot) + .Execute(); + + if (isValid) + { + result.Should().Pass() + .And.HaveStdOutContaining($"hostfxr_path: {sharedState.HostFxrPath}".ToLower()); + } + else + { + result.Should().Fail() + .And.ExitWith(CoreHostLibMissingFailure) + .And.HaveStdOutContaining($"{GetHostFxrPath} failed"); + } } - [Fact] - public void GetHostFxrPath_NoAssemblyPath_FxrSubdirectory() + [Theory] + [InlineData(false, true)] + [InlineData(false, false)] + [InlineData(true, true)] + [InlineData(true, false)] + public void GetHostFxrPath_GlobalInstallation(bool useAssemblyPath, bool isValid) { - string copiedHostPath = Path.Combine(Path.GetDirectoryName(sharedState.NativeHostPath), "host"); - SharedFramework.CopyDirectory(Path.Combine(dotNetCli.BinPath, "host"), copiedHostPath); - CommandResult result = Command.Create(sharedState.NativeHostPath, GetHostFxrPath) + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + // We don't have a good way of hooking into how the product looks for global installations yet. + return; + } + + string programFilesOverride = isValid ? sharedState.ValidInstallRoot : sharedState.InvalidInstallRoot; + CommandResult result = Command.Create(sharedState.NativeHostPath, $"{GetHostFxrPath} {(useAssemblyPath ? sharedState.TestAssemblyPath : string.Empty)}") .CaptureStdErr() .CaptureStdOut() + .EnvironmentVariable("TEST_OVERRIDE_PROGRAMFILES", programFilesOverride) .Execute(); - Directory.Delete(copiedHostPath, true); - - string expectedFxrPath = Path.Combine( - copiedHostPath, - "fxr", - Path.GetFileName(dotNetCli.GreatestVersionHostFxrPath), - RuntimeInformationExtensions.GetSharedLibraryFileNameForCurrentPlatform("hostfxr")); - result.Should().Pass() - .And.HaveStdOutContaining($"hostfxr_path: {expectedFxrPath}".ToLower()); - } - [Fact] - public void GetHostFxrPath_WithAssemblyPath_AppLocalFxr() - { - TestProjectFixture fixture = sharedState.StandaloneAppFixture; - Command.Create(sharedState.NativeHostPath, $"{GetHostFxrPath} {fixture.TestProject.AppDll}") - .CaptureStdErr() - .CaptureStdOut() - .Execute() - .Should().Pass() - .And.HaveStdOutContaining($"hostfxr_path: {fixture.TestProject.HostFxrDll}".ToLower()); + if (isValid) + { + result.Should().Pass() + .And.HaveStdOutContaining($"hostfxr_path: {sharedState.HostFxrPath}".ToLower()); + } + else + { + result.Should().Fail() + .And.ExitWith(CoreHostLibMissingFailure) + .And.HaveStdOutContaining($"{GetHostFxrPath} failed"); + } } [Fact] - public void GetHostFxrPath_WithAssemblyPath_DotNetRootEnvironment() + public void GetHostFxrPath_WithAssemblyPath_AppLocalFxr() { - string expectedFxrPath = Path.Combine( - dotNetCli.GreatestVersionHostFxrPath, - RuntimeInformationExtensions.GetSharedLibraryFileNameForCurrentPlatform("hostfxr")); - Command.Create(sharedState.NativeHostPath, $"{GetHostFxrPath} {sharedState.NativeHostPath}") + string appLocalFxrDir = Path.Combine(sharedState.BaseDirectory, "appLocalFxr"); + Directory.CreateDirectory(appLocalFxrDir); + string assemblyPath = Path.Combine(appLocalFxrDir, "AppLocalFxr.dll"); + string hostFxrPath = Path.Combine(appLocalFxrDir, RuntimeInformationExtensions.GetSharedLibraryFileNameForCurrentPlatform("hostfxr")); + File.WriteAllText(assemblyPath, string.Empty); + File.WriteAllText(hostFxrPath, string.Empty); + + Command.Create(sharedState.NativeHostPath, $"{GetHostFxrPath} {assemblyPath}") .CaptureStdErr() .CaptureStdOut() - .EnvironmentVariable("DOTNET_ROOT", dotNetCli.BinPath) .Execute() .Should().Pass() - .And.HaveStdOutContaining($"hostfxr_path: {expectedFxrPath}".ToLower()); + .And.HaveStdOutContaining($"hostfxr_path: {hostFxrPath}".ToLower()); } public class SharedTestState : IDisposable { - public RepoDirectoriesProvider RepoDirectories { get; } - public TestProjectFixture StandaloneAppFixture { get; } + public string BaseDirectory { get; } public string NativeHostPath { get; } - private readonly string baseDir; + public string HostFxrPath { get; } + public string InvalidInstallRoot { get; } + public string ValidInstallRoot { get; } + + public string TestAssemblyPath { get; } public SharedTestState() { - RepoDirectories = new RepoDirectoriesProvider(); - - baseDir = SharedFramework.CalculateUniqueTestDirectory(Path.Combine(TestArtifact.TestArtifactsPath, "nativeHosting")); - Directory.CreateDirectory(baseDir); + BaseDirectory = SharedFramework.CalculateUniqueTestDirectory(Path.Combine(TestArtifact.TestArtifactsPath, "nativeHosting")); + Directory.CreateDirectory(BaseDirectory); string nativeHostName = RuntimeInformationExtensions.GetExeFileNameForCurrentPlatform("nativehost"); - NativeHostPath = Path.Combine(baseDir, nativeHostName); + NativeHostPath = Path.Combine(BaseDirectory, nativeHostName); // Copy over native host and nethost + var repoDirectories = new RepoDirectoriesProvider(); string nethostName = RuntimeInformationExtensions.GetSharedLibraryFileNameForCurrentPlatform("nethost"); - File.Copy(Path.Combine(RepoDirectories.CorehostPackages, nethostName), Path.Combine(baseDir, nethostName)); - File.Copy(Path.Combine(RepoDirectories.Artifacts, "corehost_test", nativeHostName), NativeHostPath); + File.Copy(Path.Combine(repoDirectories.CorehostPackages, nethostName), Path.Combine(BaseDirectory, nethostName)); + File.Copy(Path.Combine(repoDirectories.Artifacts, "corehost_test", nativeHostName), NativeHostPath); + + InvalidInstallRoot = Path.Combine(BaseDirectory, "invalid"); + Directory.CreateDirectory(InvalidInstallRoot); + + ValidInstallRoot = Path.Combine(BaseDirectory, "valid"); + HostFxrPath = CreateHostFxr(Path.Combine(ValidInstallRoot, "dotnet")); + + string appDir = Path.Combine(BaseDirectory, "app"); + Directory.CreateDirectory(appDir); + string assemblyPath = Path.Combine(appDir, "App.dll"); + File.WriteAllText(assemblyPath, string.Empty); + TestAssemblyPath = assemblyPath; + } + + private string CreateHostFxr(string destinationDirectory) + { + string hostFxrName = RuntimeInformationExtensions.GetSharedLibraryFileNameForCurrentPlatform("hostfxr"); + string fxrRoot = Path.Combine(destinationDirectory, "host", "fxr"); + Directory.CreateDirectory(fxrRoot); + + string[] versions = new string[] { "1.1.0", "2.2.1", "2.3.0" }; + foreach (string version in versions) + { + string versionDirectory = Path.Combine(fxrRoot, version); + Directory.CreateDirectory(versionDirectory); + File.WriteAllText(Path.Combine(versionDirectory, hostFxrName), string.Empty); + } - var standaloneAppFixture = new TestProjectFixture("StandaloneApp", RepoDirectories); - StandaloneAppFixture = standaloneAppFixture - .EnsureRestoredForRid(standaloneAppFixture.CurrentRid, RepoDirectories.CorehostPackages) - .PublishProject(runtime: standaloneAppFixture.CurrentRid); + return Path.Combine(fxrRoot, "2.3.0", hostFxrName); } public void Dispose() { - StandaloneAppFixture.Dispose(); - if (!TestArtifact.PreserveTestRuns() && Directory.Exists(baseDir)) + if (!TestArtifact.PreserveTestRuns() && Directory.Exists(BaseDirectory)) { - Directory.Delete(baseDir, true); + Directory.Delete(BaseDirectory, true); } } } From 206eed415f17589e2ade39b4dafad8eb9498e27f Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Fri, 22 Mar 2019 17:19:37 -0700 Subject: [PATCH 08/12] Switch to caller-supplied buffer instead of callback function --- src/corehost/cli/nethost/nethost.cpp | 17 ++++++++++++-- src/corehost/cli/nethost/nethost.h | 22 +++++++++++++++---- .../cli/test/nativehost/CMakeLists.txt | 1 - .../cli/test/nativehost/nativehost.cpp | 19 +++++++++------- src/corehost/cli/test/testexe.cmake | 4 +++- 5 files changed, 47 insertions(+), 16 deletions(-) diff --git a/src/corehost/cli/nethost/nethost.cpp b/src/corehost/cli/nethost/nethost.cpp index ea57b8958b..0695834380 100644 --- a/src/corehost/cli/nethost/nethost.cpp +++ b/src/corehost/cli/nethost/nethost.cpp @@ -9,9 +9,14 @@ #include NETHOST_API int NETHOST_CALLTYPE nethost_get_hostfxr_path( - nethost_get_hostfxr_path_result_fn result, + char_t * result_buffer, + size_t buffer_size, + size_t * out_buffer_required_size, const char_t * assembly_path) { + if (out_buffer_required_size == nullptr) + return StatusCode::InvalidArgFailure; + pal::string_t root_path; if (assembly_path != nullptr) root_path = get_directory(assembly_path); @@ -21,6 +26,14 @@ NETHOST_API int NETHOST_CALLTYPE nethost_get_hostfxr_path( if(!fxr_resolver::try_get_path(root_path, &dotnet_root, &fxr_path)) return StatusCode::CoreHostLibMissingFailure; - result(fxr_path.c_str()); + size_t len = fxr_path.length(); + size_t required_size = len + 1; // null terminator + + *out_buffer_required_size = required_size; + if (result_buffer == nullptr || buffer_size < required_size) + return StatusCode::HostApiBufferTooSmall; + + fxr_path.copy(result_buffer, len); + result_buffer[len] = '\0'; return StatusCode::Success; } \ No newline at end of file diff --git a/src/corehost/cli/nethost/nethost.h b/src/corehost/cli/nethost/nethost.h index 02ed53641e..cc0c551f37 100644 --- a/src/corehost/cli/nethost/nethost.h +++ b/src/corehost/cli/nethost/nethost.h @@ -5,6 +5,8 @@ #ifndef __NETHOST_H__ #define __NETHOST_H__ +#include + #if defined(_WIN32) #ifdef NETHOST_EXPORT #define NETHOST_API __declspec(dllexport) @@ -35,9 +37,14 @@ using nethost_get_hostfxr_path_result_fn = void(*)(const char_t * hostfxr_path); // Get the path to the hostfxr library // // Parameters: -// result -// Callback invoked to return the hostfxr path. String passed in is valid for -// the duration of the call. +// result_buffer +// Buffer that will be populated with the hostfxr path, including a null terminator. +// +// buffer_size +// Size of result_buffer in char_t units +// +// out_buffer_required_size +// Minimum required size in char_t units for a buffer to hold the hostfxr path // // assembly_path // Optional. Path to the compenent's assembly. Whether or not this is specified @@ -47,9 +54,16 @@ using nethost_get_hostfxr_path_result_fn = void(*)(const char_t * hostfxr_path); // // Return value: // 0 on success, otherwise failure +// 0x80008098 - result_buffer is too small (HostApiBufferTooSmall) +// +// Remarks: +// The full search for the hostfxr library is done on every call. To minimize the need +// to call this function multiple times, pass a large result_buffer (e.g. PATH_MAX). // extern "C" NETHOST_API int NETHOST_CALLTYPE nethost_get_hostfxr_path( - nethost_get_hostfxr_path_result_fn result, + char_t * result_buffer, + size_t buffer_size, + size_t * out_buffer_required_size, const char_t * assembly_path); #endif // __NETHOST_H__ \ No newline at end of file diff --git a/src/corehost/cli/test/nativehost/CMakeLists.txt b/src/corehost/cli/test/nativehost/CMakeLists.txt index ce7a956cfb..e1eeec1d50 100644 --- a/src/corehost/cli/test/nativehost/CMakeLists.txt +++ b/src/corehost/cli/test/nativehost/CMakeLists.txt @@ -23,5 +23,4 @@ set(SOURCES include(../testexe.cmake) -set_common_libs("exe") target_link_libraries(${DOTNET_PROJECT_NAME} nethost) \ No newline at end of file diff --git a/src/corehost/cli/test/nativehost/nativehost.cpp b/src/corehost/cli/test/nativehost/nativehost.cpp index c51fc26e40..98bf0450d2 100644 --- a/src/corehost/cli/test/nativehost/nativehost.cpp +++ b/src/corehost/cli/test/nativehost/nativehost.cpp @@ -4,16 +4,11 @@ #include #include +#include #include namespace { - pal::string_t fxr_path; - void hostfxr_path_callback(const char_t *hostfxr_path) - { - fxr_path.assign(hostfxr_path); - } - std::vector tostr(const pal::string_t &value) { std::vector vect; @@ -51,8 +46,16 @@ int main(const int argc, const pal::char_t *argv[]) } #endif - int res = nethost_get_hostfxr_path(hostfxr_path_callback, assembly_path); - if (res == 0) + pal::string_t fxr_path; + size_t len = 0; + int res = nethost_get_hostfxr_path(nullptr, 0, &len, assembly_path); + if (res == StatusCode::HostApiBufferTooSmall) + { + fxr_path.resize(len); + res = nethost_get_hostfxr_path(&fxr_path[0], fxr_path.size(), &len, assembly_path); + } + + if (res == StatusCode::Success) { std::cout << "nethost_get_hostfxr_path succeeded" << std::endl; std::cout << "hostfxr_path: " << tostr(pal::to_lower(fxr_path)).data() << std::endl; diff --git a/src/corehost/cli/test/testexe.cmake b/src/corehost/cli/test/testexe.cmake index 0a49f990d9..0aa25d972f 100644 --- a/src/corehost/cli/test/testexe.cmake +++ b/src/corehost/cli/test/testexe.cmake @@ -11,4 +11,6 @@ include(${CMAKE_CURRENT_LIST_DIR}/../common.cmake) add_executable(${DOTNET_PROJECT_NAME} ${SOURCES}) install(TARGETS ${DOTNET_PROJECT_NAME} DESTINATION corehost_test) -install_symbols(${DOTNET_PROJECT_NAME} corehost_test) \ No newline at end of file +install_symbols(${DOTNET_PROJECT_NAME} corehost_test) + +set_common_libs("exe") \ No newline at end of file From 459e3720e64b0d02f9b66de774a2c27f3ac29caf Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Fri, 22 Mar 2019 19:16:42 -0700 Subject: [PATCH 09/12] Fix exit code in tests to work with unix --- src/corehost/cli/test/nativehost/nativehost.cpp | 6 ++---- src/test/HostActivationTests/NativeHosting/Nethost.cs | 8 ++++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/corehost/cli/test/nativehost/nativehost.cpp b/src/corehost/cli/test/nativehost/nativehost.cpp index 98bf0450d2..ce50fa4fd7 100644 --- a/src/corehost/cli/test/nativehost/nativehost.cpp +++ b/src/corehost/cli/test/nativehost/nativehost.cpp @@ -59,19 +59,17 @@ int main(const int argc, const pal::char_t *argv[]) { std::cout << "nethost_get_hostfxr_path succeeded" << std::endl; std::cout << "hostfxr_path: " << tostr(pal::to_lower(fxr_path)).data() << std::endl; + return 0; } else { std::cout << "nethost_get_hostfxr_path failed: " << std::hex << std::showbase << res << std::endl; + return 1; } - - return res; } else { std::cerr << "Invalid arguments" << std::endl; return -1; } - - return 0; } \ No newline at end of file diff --git a/src/test/HostActivationTests/NativeHosting/Nethost.cs b/src/test/HostActivationTests/NativeHosting/Nethost.cs index 9dcfa28d99..43b9f27084 100644 --- a/src/test/HostActivationTests/NativeHosting/Nethost.cs +++ b/src/test/HostActivationTests/NativeHosting/Nethost.cs @@ -44,8 +44,8 @@ public void GetHostFxrPath_DotNetRootEnvironment(bool useAssemblyPath, bool isVa else { result.Should().Fail() - .And.ExitWith(CoreHostLibMissingFailure) - .And.HaveStdOutContaining($"{GetHostFxrPath} failed"); + .And.ExitWith(1) + .And.HaveStdOutContaining($"{GetHostFxrPath} failed: 0x{CoreHostLibMissingFailure.ToString("x")}"); } } @@ -77,8 +77,8 @@ public void GetHostFxrPath_GlobalInstallation(bool useAssemblyPath, bool isValid else { result.Should().Fail() - .And.ExitWith(CoreHostLibMissingFailure) - .And.HaveStdOutContaining($"{GetHostFxrPath} failed"); + .And.ExitWith(1) + .And.HaveStdOutContaining($"{GetHostFxrPath} failed: 0x{CoreHostLibMissingFailure.ToString("x")}"); } } From de05524dcd7c014f576d5d853883488c97a16103 Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Fri, 22 Mar 2019 19:39:12 -0700 Subject: [PATCH 10/12] Drop nethost.h next to built lib --- src/corehost/cli/nethost/CMakeLists.txt | 1 + src/corehost/cli/nethost/nethost.h | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/corehost/cli/nethost/CMakeLists.txt b/src/corehost/cli/nethost/CMakeLists.txt index 30d749f1bd..8528cf3cb3 100644 --- a/src/corehost/cli/nethost/CMakeLists.txt +++ b/src/corehost/cli/nethost/CMakeLists.txt @@ -22,5 +22,6 @@ include(../lib.cmake) add_definitions(-DFEATURE_LIBHOST=1) add_definitions(-DNETHOST_EXPORT) +install(FILES nethost.h DESTINATION corehost) install(TARGETS nethost DESTINATION corehost) install_symbols(nethost corehost) \ No newline at end of file diff --git a/src/corehost/cli/nethost/nethost.h b/src/corehost/cli/nethost/nethost.h index cc0c551f37..c7f3edc9c2 100644 --- a/src/corehost/cli/nethost/nethost.h +++ b/src/corehost/cli/nethost/nethost.h @@ -31,8 +31,6 @@ using char_t = char; #endif -using nethost_get_hostfxr_path_result_fn = void(*)(const char_t * hostfxr_path); - // // Get the path to the hostfxr library // From 4673b6887aecc441a104ee7f97c135844768f4fa Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Mon, 25 Mar 2019 09:31:21 -0700 Subject: [PATCH 11/12] Set up tracinig. Update tests to handle registered global installations. --- src/corehost/cli/nethost/nethost.cpp | 13 +++ .../NativeHosting/Nethost.cs | 105 ++++++++++++++---- 2 files changed, 98 insertions(+), 20 deletions(-) diff --git a/src/corehost/cli/nethost/nethost.cpp b/src/corehost/cli/nethost/nethost.cpp index 0695834380..637a3eb3eb 100644 --- a/src/corehost/cli/nethost/nethost.cpp +++ b/src/corehost/cli/nethost/nethost.cpp @@ -6,8 +6,18 @@ #include #include #include +#include #include +namespace +{ + // Swallow the trace messages so we don't output to stderr of a process that we do not own unless tracing is enabled. + void swallow_trace(const pal::char_t* msg) + { + (void)msg; + } +} + NETHOST_API int NETHOST_CALLTYPE nethost_get_hostfxr_path( char_t * result_buffer, size_t buffer_size, @@ -17,6 +27,9 @@ NETHOST_API int NETHOST_CALLTYPE nethost_get_hostfxr_path( if (out_buffer_required_size == nullptr) return StatusCode::InvalidArgFailure; + trace::setup(); + error_writer_scope_t writer_scope(swallow_trace); + pal::string_t root_path; if (assembly_path != nullptr) root_path = get_directory(assembly_path); diff --git a/src/test/HostActivationTests/NativeHosting/Nethost.cs b/src/test/HostActivationTests/NativeHosting/Nethost.cs index 43b9f27084..932c9a8e22 100644 --- a/src/test/HostActivationTests/NativeHosting/Nethost.cs +++ b/src/test/HostActivationTests/NativeHosting/Nethost.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using Microsoft.DotNet.Cli.Build.Framework; +using Microsoft.Win32; using System; using System.IO; using System.Runtime.InteropServices; @@ -15,6 +16,7 @@ public class Nethost : IClassFixture private const string GetHostFxrPath = "nethost_get_hostfxr_path"; private const int CoreHostLibMissingFailure = unchecked((int)0x80008083); + private static readonly string HostFxrName = RuntimeInformationExtensions.GetSharedLibraryFileNameForCurrentPlatform("hostfxr"); private readonly SharedTestState sharedState; public Nethost(SharedTestState sharedTestState) @@ -33,9 +35,12 @@ public void GetHostFxrPath_DotNetRootEnvironment(bool useAssemblyPath, bool isVa CommandResult result = Command.Create(sharedState.NativeHostPath, $"{GetHostFxrPath} {(useAssemblyPath ? sharedState.TestAssemblyPath : string.Empty)}") .CaptureStdErr() .CaptureStdOut() + .EnvironmentVariable("COREHOST_TRACE", "1") .EnvironmentVariable("DOTNET_ROOT", dotNetRoot) .Execute(); + result.Should().HaveStdErrContaining("Using environment variable"); + if (isValid) { result.Should().Pass() @@ -45,16 +50,21 @@ public void GetHostFxrPath_DotNetRootEnvironment(bool useAssemblyPath, bool isVa { result.Should().Fail() .And.ExitWith(1) - .And.HaveStdOutContaining($"{GetHostFxrPath} failed: 0x{CoreHostLibMissingFailure.ToString("x")}"); + .And.HaveStdOutContaining($"{GetHostFxrPath} failed: 0x{CoreHostLibMissingFailure.ToString("x")}") + .And.HaveStdErrContaining($"The required library {HostFxrName} could not be found"); } } [Theory] - [InlineData(false, true)] - [InlineData(false, false)] - [InlineData(true, true)] - [InlineData(true, false)] - public void GetHostFxrPath_GlobalInstallation(bool useAssemblyPath, bool isValid) + [InlineData(false, true, false)] + [InlineData(false, true, true)] + [InlineData(false, false, false)] + [InlineData(false, false, true)] + [InlineData(true, true, false)] + [InlineData(true, true, true)] + [InlineData(true, false, false)] + [InlineData(true, false, true)] + public void GetHostFxrPath_GlobalInstallation(bool useAssemblyPath, bool useRegisteredLocation, bool isValid) { if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { @@ -62,12 +72,30 @@ public void GetHostFxrPath_GlobalInstallation(bool useAssemblyPath, bool isValid return; } - string programFilesOverride = isValid ? sharedState.ValidInstallRoot : sharedState.InvalidInstallRoot; - CommandResult result = Command.Create(sharedState.NativeHostPath, $"{GetHostFxrPath} {(useAssemblyPath ? sharedState.TestAssemblyPath : string.Empty)}") - .CaptureStdErr() - .CaptureStdOut() - .EnvironmentVariable("TEST_OVERRIDE_PROGRAMFILES", programFilesOverride) - .Execute(); + // Overide the registry key for self-registered global installs. + // If using the registered location, set the install location value to the valid/invalid root. + // If not using the registered location, do not set the value. When the value does not exist, + // the product falls back to the default install location. + CommandResult result; + string installRoot = Path.Combine(isValid ? sharedState.ValidInstallRoot : sharedState.InvalidInstallRoot); + using (var regKeyOverride = new TestRegistryKeyOverride()) + { + if (useRegisteredLocation) + { + regKeyOverride.SetInstallLocation(Path.Combine(installRoot, "dotnet"), sharedState.RepoDirectories.BuildArchitecture); + } + + string programFilesOverride = useRegisteredLocation ? sharedState.InvalidInstallRoot : installRoot; + result = Command.Create(sharedState.NativeHostPath, $"{GetHostFxrPath} {(useAssemblyPath ? sharedState.TestAssemblyPath : string.Empty)}") + .CaptureStdErr() + .CaptureStdOut() + .EnvironmentVariable("COREHOST_TRACE", "1") + .EnvironmentVariable("_DOTNET_TEST_SDK_REGISTRY_PATH", regKeyOverride.KeyPath) + .EnvironmentVariable("TEST_OVERRIDE_PROGRAMFILES", programFilesOverride) + .Execute(); + } + + result.Should().HaveStdErrContaining("Using global installation location"); if (isValid) { @@ -78,7 +106,8 @@ public void GetHostFxrPath_GlobalInstallation(bool useAssemblyPath, bool isValid { result.Should().Fail() .And.ExitWith(1) - .And.HaveStdOutContaining($"{GetHostFxrPath} failed: 0x{CoreHostLibMissingFailure.ToString("x")}"); + .And.HaveStdOutContaining($"{GetHostFxrPath} failed: 0x{CoreHostLibMissingFailure.ToString("x")}") + .And.HaveStdErrContaining($"The required library {HostFxrName} could not be found"); } } @@ -88,22 +117,59 @@ public void GetHostFxrPath_WithAssemblyPath_AppLocalFxr() string appLocalFxrDir = Path.Combine(sharedState.BaseDirectory, "appLocalFxr"); Directory.CreateDirectory(appLocalFxrDir); string assemblyPath = Path.Combine(appLocalFxrDir, "AppLocalFxr.dll"); - string hostFxrPath = Path.Combine(appLocalFxrDir, RuntimeInformationExtensions.GetSharedLibraryFileNameForCurrentPlatform("hostfxr")); + string hostFxrPath = Path.Combine(appLocalFxrDir, HostFxrName); File.WriteAllText(assemblyPath, string.Empty); File.WriteAllText(hostFxrPath, string.Empty); Command.Create(sharedState.NativeHostPath, $"{GetHostFxrPath} {assemblyPath}") .CaptureStdErr() .CaptureStdOut() + .EnvironmentVariable("COREHOST_TRACE", "1") .Execute() .Should().Pass() .And.HaveStdOutContaining($"hostfxr_path: {hostFxrPath}".ToLower()); } + private class TestRegistryKeyOverride : IDisposable + { + public string KeyPath { get; } + + private readonly RegistryKey parentKey; + private readonly RegistryKey key; + private readonly string keyName; + + public TestRegistryKeyOverride() + { + using (RegistryKey hkcu = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry32)) + { + parentKey = hkcu.CreateSubKey(@"Software\Classes\Interface"); + keyName = "_DOTNET_Test" + System.Diagnostics.Process.GetCurrentProcess().Id.ToString(); + key = parentKey.CreateSubKey(keyName); + KeyPath = key.Name; + } + } + + public void SetInstallLocation(string installLocation, string architecture) + { + using (RegistryKey dotnetLocationKey = key.CreateSubKey($@"Setup\InstalledVersions\{architecture}")) + { + dotnetLocationKey.SetValue("InstallLocation", installLocation); + } + } + + public void Dispose() + { + parentKey.DeleteSubKeyTree(keyName, throwOnMissingSubKey: false); + key.Dispose(); + parentKey.Dispose(); + } + } + public class SharedTestState : IDisposable { public string BaseDirectory { get; } public string NativeHostPath { get; } + public RepoDirectoriesProvider RepoDirectories { get; } public string HostFxrPath { get; } public string InvalidInstallRoot { get; } @@ -120,10 +186,10 @@ public SharedTestState() NativeHostPath = Path.Combine(BaseDirectory, nativeHostName); // Copy over native host and nethost - var repoDirectories = new RepoDirectoriesProvider(); + RepoDirectories = new RepoDirectoriesProvider(); string nethostName = RuntimeInformationExtensions.GetSharedLibraryFileNameForCurrentPlatform("nethost"); - File.Copy(Path.Combine(repoDirectories.CorehostPackages, nethostName), Path.Combine(BaseDirectory, nethostName)); - File.Copy(Path.Combine(repoDirectories.Artifacts, "corehost_test", nativeHostName), NativeHostPath); + File.Copy(Path.Combine(RepoDirectories.CorehostPackages, nethostName), Path.Combine(BaseDirectory, nethostName)); + File.Copy(Path.Combine(RepoDirectories.Artifacts, "corehost_test", nativeHostName), NativeHostPath); InvalidInstallRoot = Path.Combine(BaseDirectory, "invalid"); Directory.CreateDirectory(InvalidInstallRoot); @@ -140,7 +206,6 @@ public SharedTestState() private string CreateHostFxr(string destinationDirectory) { - string hostFxrName = RuntimeInformationExtensions.GetSharedLibraryFileNameForCurrentPlatform("hostfxr"); string fxrRoot = Path.Combine(destinationDirectory, "host", "fxr"); Directory.CreateDirectory(fxrRoot); @@ -149,10 +214,10 @@ private string CreateHostFxr(string destinationDirectory) { string versionDirectory = Path.Combine(fxrRoot, version); Directory.CreateDirectory(versionDirectory); - File.WriteAllText(Path.Combine(versionDirectory, hostFxrName), string.Empty); + File.WriteAllText(Path.Combine(versionDirectory, HostFxrName), string.Empty); } - return Path.Combine(fxrRoot, "2.3.0", hostFxrName); + return Path.Combine(fxrRoot, "2.3.0", HostFxrName); } public void Dispose() From 1dbdece9cd85809877bbd7508152e7fe6d16fe61 Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Mon, 25 Mar 2019 11:31:44 -0700 Subject: [PATCH 12/12] Add shared class for overriding registered install registry key in tests --- .../MultilevelSDKLookup.cs | 30 +--------- .../NativeHosting/Nethost.cs | 37 +----------- .../PortableAppActivation.cs | 17 ++---- .../RegisteredInstallKeyOverride.cs | 58 +++++++++++++++++++ 4 files changed, 66 insertions(+), 76 deletions(-) create mode 100644 src/test/HostActivationTests/RegisteredInstallKeyOverride.cs diff --git a/src/test/HostActivationTests/MultilevelSDKLookup.cs b/src/test/HostActivationTests/MultilevelSDKLookup.cs index bd166b0810..fb0331a87e 100644 --- a/src/test/HostActivationTests/MultilevelSDKLookup.cs +++ b/src/test/HostActivationTests/MultilevelSDKLookup.cs @@ -566,30 +566,10 @@ public void SdkMultilevelLookup_RegistryAccess() var dotnet = fixture.BuiltDotnet; - // To correctly test the product we need a registry key which is - // - writable without admin access (so that the tests don't require admin to run) - // - redirected in WOW64 - so that there are both 32bit and 64bit versions of the key - // this is because the product stores the info in the 32bit version only and even 64bit - // product must look into the 32bit version. - // Without the redirection we would not be able to test that the product always looks - // into 32bit only. - // Per this page https://docs.microsoft.com/en-us/windows/desktop/WinProg64/shared-registry-keys - // a user writable redirected key is for example HKCU\Software\Classes\Interface - // so we're going to use that one - it's not super clean as they key stored COM interfaces - // but we should not corrupt anything by adding a special subkey even if it's left behind. - // - // Note: If you want to inspect the values written by the test and/or modify them manually - // you have to navigate to HKCU\Software\Classes\Wow6432Node\Interface on a 64bit OS. - - RegistryKey hkcu = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry32); - RegistryKey interfaceKey = hkcu.CreateSubKey(@"Software\Classes\Interface"); - string testKeyName = "_DOTNET_Test" + System.Diagnostics.Process.GetCurrentProcess().Id.ToString(); - RegistryKey testKey = interfaceKey.CreateSubKey(testKeyName); - try + using (var regKeyOverride = new RegisteredInstallKeyOverride()) { string architecture = fixture.CurrentRid.Split('-')[1]; - RegistryKey dotnetLocationKey = testKey.CreateSubKey($@"Setup\InstalledVersions\{architecture}"); - dotnetLocationKey.SetValue("InstallLocation", _regDir); + regKeyOverride.SetInstallLocation(_regDir, architecture); // Add SDK versions AddAvailableSdkVersions(_regSdkBaseDir, "9999.0.4"); @@ -605,17 +585,13 @@ public void SdkMultilevelLookup_RegistryAccess() .WithUserProfile(_userDir) .Environment(s_DefaultEnvironment) .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "1") - .EnvironmentVariable("_DOTNET_TEST_SDK_REGISTRY_PATH", testKey.Name) + .EnvironmentVariable("_DOTNET_TEST_SDK_REGISTRY_PATH", regKeyOverride.KeyPath) .CaptureStdOut() .CaptureStdErr() .Execute() .Should().Pass() .And.HaveStdErrContaining(Path.Combine(_regSelectedMessage, "9999.0.4", _dotnetSdkDllMessageTerminator)); } - finally - { - interfaceKey.DeleteSubKeyTree(testKeyName); - } } [Fact] diff --git a/src/test/HostActivationTests/NativeHosting/Nethost.cs b/src/test/HostActivationTests/NativeHosting/Nethost.cs index 932c9a8e22..c9b01c0077 100644 --- a/src/test/HostActivationTests/NativeHosting/Nethost.cs +++ b/src/test/HostActivationTests/NativeHosting/Nethost.cs @@ -78,7 +78,7 @@ public void GetHostFxrPath_GlobalInstallation(bool useAssemblyPath, bool useRegi // the product falls back to the default install location. CommandResult result; string installRoot = Path.Combine(isValid ? sharedState.ValidInstallRoot : sharedState.InvalidInstallRoot); - using (var regKeyOverride = new TestRegistryKeyOverride()) + using (var regKeyOverride = new RegisteredInstallKeyOverride()) { if (useRegisteredLocation) { @@ -130,41 +130,6 @@ public void GetHostFxrPath_WithAssemblyPath_AppLocalFxr() .And.HaveStdOutContaining($"hostfxr_path: {hostFxrPath}".ToLower()); } - private class TestRegistryKeyOverride : IDisposable - { - public string KeyPath { get; } - - private readonly RegistryKey parentKey; - private readonly RegistryKey key; - private readonly string keyName; - - public TestRegistryKeyOverride() - { - using (RegistryKey hkcu = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry32)) - { - parentKey = hkcu.CreateSubKey(@"Software\Classes\Interface"); - keyName = "_DOTNET_Test" + System.Diagnostics.Process.GetCurrentProcess().Id.ToString(); - key = parentKey.CreateSubKey(keyName); - KeyPath = key.Name; - } - } - - public void SetInstallLocation(string installLocation, string architecture) - { - using (RegistryKey dotnetLocationKey = key.CreateSubKey($@"Setup\InstalledVersions\{architecture}")) - { - dotnetLocationKey.SetValue("InstallLocation", installLocation); - } - } - - public void Dispose() - { - parentKey.DeleteSubKeyTree(keyName, throwOnMissingSubKey: false); - key.Dispose(); - parentKey.Dispose(); - } - } - public class SharedTestState : IDisposable { public string BaseDirectory { get; } diff --git a/src/test/HostActivationTests/PortableAppActivation.cs b/src/test/HostActivationTests/PortableAppActivation.cs index e5bb97909f..be8ffcad22 100644 --- a/src/test/HostActivationTests/PortableAppActivation.cs +++ b/src/test/HostActivationTests/PortableAppActivation.cs @@ -335,21 +335,16 @@ public void Framework_Dependent_AppHost_From_Global_Registry_Location_Succeeds() // Get the framework location that was built string builtDotnet = fixture.BuiltDotnet.BinPath; - RegistryKey hkcu = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry32); - RegistryKey interfaceKey = hkcu.CreateSubKey(@"Software\Classes\Interface"); - string testKeyName = "_DOTNET_Test" + System.Diagnostics.Process.GetCurrentProcess().Id.ToString(); - RegistryKey testKey = interfaceKey.CreateSubKey(testKeyName); - try + using (var regKeyOverride = new RegisteredInstallKeyOverride()) { string architecture = fixture.CurrentRid.Split('-')[1]; - RegistryKey dotnetLocationKey = testKey.CreateSubKey($@"Setup\InstalledVersions\{architecture}"); - dotnetLocationKey.SetValue("InstallLocation", builtDotnet); + regKeyOverride.SetInstallLocation(builtDotnet, architecture); // Verify running with the default working directory Command.Create(appExe) .CaptureStdErr() .CaptureStdOut() - .EnvironmentVariable("_DOTNET_TEST_SDK_REGISTRY_PATH", testKey.Name) + .EnvironmentVariable("_DOTNET_TEST_SDK_REGISTRY_PATH", regKeyOverride.KeyPath) .Execute() .Should().Pass() .And.HaveStdOutContaining("Hello World") @@ -358,7 +353,7 @@ public void Framework_Dependent_AppHost_From_Global_Registry_Location_Succeeds() // Verify running from within the working directory Command.Create(appExe) .WorkingDirectory(fixture.TestProject.OutputDirectory) - .EnvironmentVariable("_DOTNET_TEST_SDK_REGISTRY_PATH", testKey.Name) + .EnvironmentVariable("_DOTNET_TEST_SDK_REGISTRY_PATH", regKeyOverride.KeyPath) .CaptureStdErr() .CaptureStdOut() .Execute() @@ -366,10 +361,6 @@ public void Framework_Dependent_AppHost_From_Global_Registry_Location_Succeeds() .And.HaveStdOutContaining("Hello World") .And.HaveStdOutContaining($"Framework Version:{sharedTestState.RepoDirectories.MicrosoftNETCoreAppVersion}"); } - finally - { - interfaceKey.DeleteSubKeyTree(testKeyName); - } } private string MoveDepsJsonToSubdirectory(TestProjectFixture testProjectFixture) diff --git a/src/test/HostActivationTests/RegisteredInstallKeyOverride.cs b/src/test/HostActivationTests/RegisteredInstallKeyOverride.cs new file mode 100644 index 0000000000..6226ac4d53 --- /dev/null +++ b/src/test/HostActivationTests/RegisteredInstallKeyOverride.cs @@ -0,0 +1,58 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Win32; +using System; + +namespace Microsoft.DotNet.CoreSetup.Test.HostActivation +{ + public class RegisteredInstallKeyOverride : IDisposable + { + public string KeyPath { get; } + + private readonly RegistryKey parentKey; + private readonly RegistryKey key; + private readonly string keyName; + + public RegisteredInstallKeyOverride() + { + // To test registered installs, we need a registry key which is: + // - writable without admin access - so that the tests don't require admin to run + // - redirected in WOW64 - so that there are both 32-bit and 64-bit versions of the key + // This is because the product stores the info in the 32-bit hive only and even 64-bit + // product must look into the 32-bit hive. + // Without the redirection we would not be able to test that the product always looks + // into 32-bit only. + // Per this page https://docs.microsoft.com/en-us/windows/desktop/WinProg64/shared-registry-keys + // a user writable redirected key is for example HKCU\Software\Classes\Interface + // so we're going to use that one - it's not super clean as the key stores COM interfaces, + // but we should not corrupt anything by adding a special subkey even if it's left behind. + // + // Note: If you want to inspect the values written by the test and/or modify them manually + // you have to navigate to HKCU\Software\Classes\Wow6432Node\Interface on a 64-bit OS. + using (RegistryKey hkcu = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry32)) + { + parentKey = hkcu.CreateSubKey(@"Software\Classes\Interface"); + keyName = "_DOTNET_Test" + System.Diagnostics.Process.GetCurrentProcess().Id.ToString(); + key = parentKey.CreateSubKey(keyName); + KeyPath = key.Name; + } + } + + public void SetInstallLocation(string installLocation, string architecture) + { + using (RegistryKey dotnetLocationKey = key.CreateSubKey($@"Setup\InstalledVersions\{architecture}")) + { + dotnetLocationKey.SetValue("InstallLocation", installLocation); + } + } + + public void Dispose() + { + parentKey.DeleteSubKeyTree(keyName, throwOnMissingSubKey: false); + key.Dispose(); + parentKey.Dispose(); + } + } +}