diff --git a/eng/SignCheckExclusionsFile.txt b/eng/SignCheckExclusionsFile.txt index 2db3b79a9339e..a78ad401525dd 100644 --- a/eng/SignCheckExclusionsFile.txt +++ b/eng/SignCheckExclusionsFile.txt @@ -7,6 +7,7 @@ ;; and SCD apps. If they are signed, the file that the SDK produces has an invalid signature and ;; can't be signed again. More info at https://github.com/dotnet/core-setup/pull/7549. *apphost.exe;;Template, https://github.com/dotnet/core-setup/pull/7549 +*singlefilehost.exe;;Template, https://github.com/dotnet/core-setup/pull/7549 *comhost.dll;;Template, https://github.com/dotnet/core-setup/pull/7549 *apphosttemplateapphostexe.exe;;Template, https://github.com/dotnet/core-setup/pull/7549 *comhosttemplatecomhostdll.dll;;Template, https://github.com/dotnet/core-setup/pull/7549 diff --git a/eng/Signing.props b/eng/Signing.props index 05f2a8bcb3957..5ceb96ac54bf9 100644 --- a/eng/Signing.props +++ b/eng/Signing.props @@ -24,7 +24,7 @@ - + diff --git a/eng/native/functions.cmake b/eng/native/functions.cmake index 060cff8987e35..49b0064499eb4 100644 --- a/eng/native/functions.cmake +++ b/eng/native/functions.cmake @@ -175,8 +175,8 @@ function(generate_exports_file) add_custom_command( OUTPUT ${outputFilename} - COMMAND ${AWK} -f ${CMAKE_SOURCE_DIR}/${AWK_SCRIPT} ${INPUT_LIST} >${outputFilename} - DEPENDS ${INPUT_LIST} ${CMAKE_SOURCE_DIR}/${AWK_SCRIPT} + COMMAND ${AWK} -f ${CLR_ENG_NATIVE_DIR}/${AWK_SCRIPT} ${INPUT_LIST} >${outputFilename} + DEPENDS ${INPUT_LIST} ${CLR_ENG_NATIVE_DIR}/${AWK_SCRIPT} COMMENT "Generating exports file ${outputFilename}" ) set_source_files_properties(${outputFilename} @@ -196,8 +196,8 @@ function(generate_exports_file_prefix inputFilename outputFilename prefix) add_custom_command( OUTPUT ${outputFilename} - COMMAND ${AWK} -f ${CMAKE_SOURCE_DIR}/${AWK_SCRIPT} ${AWK_VARS} ${inputFilename} >${outputFilename} - DEPENDS ${inputFilename} ${CMAKE_SOURCE_DIR}/${AWK_SCRIPT} + COMMAND ${AWK} -f ${CLR_ENG_NATIVE_DIR}/${AWK_SCRIPT} ${AWK_VARS} ${inputFilename} >${outputFilename} + DEPENDS ${inputFilename} ${CLR_ENG_NATIVE_DIR}/${AWK_SCRIPT} COMMENT "Generating exports file ${outputFilename}" ) set_source_files_properties(${outputFilename} diff --git a/src/coreclr/generateexportedsymbols.awk b/eng/native/generateexportedsymbols.awk similarity index 100% rename from src/coreclr/generateexportedsymbols.awk rename to eng/native/generateexportedsymbols.awk diff --git a/src/coreclr/generateversionscript.awk b/eng/native/generateversionscript.awk similarity index 100% rename from src/coreclr/generateversionscript.awk rename to eng/native/generateversionscript.awk diff --git a/src/installer/corehost/cli/CMakeLists.txt b/src/installer/corehost/cli/CMakeLists.txt index 15ce0fa117721..3c1bdb1f2f0ec 100644 --- a/src/installer/corehost/cli/CMakeLists.txt +++ b/src/installer/corehost/cli/CMakeLists.txt @@ -1,10 +1,10 @@ add_subdirectory(hostcommon) add_subdirectory(apphost) add_subdirectory(dotnet) -add_subdirectory(fxr) -add_subdirectory(hostpolicy) add_subdirectory(nethost) add_subdirectory(test_fx_ver) +add_subdirectory(fxr) +add_subdirectory(hostpolicy) add_subdirectory(test) diff --git a/src/installer/corehost/cli/apphost/CMakeLists.txt b/src/installer/corehost/cli/apphost/CMakeLists.txt index ba01e32ec47c7..ec7e8e3e2ce4b 100644 --- a/src/installer/corehost/cli/apphost/CMakeLists.txt +++ b/src/installer/corehost/cli/apphost/CMakeLists.txt @@ -2,49 +2,5 @@ # The .NET Foundation licenses this file to you under the MIT license. # See the LICENSE file in the project root for more information. -project(apphost) -set(DOTNET_PROJECT_NAME "apphost") - -# Add RPATH to the apphost binary that allows using local copies of shared libraries -# dotnet core depends on for special scenarios when system wide installation of such -# dependencies is not possible for some reason. -# This cannot be enabled for MacOS (Darwin) since its RPATH works in a different way, -# doesn't apply to libraries loaded via dlopen and most importantly, it is not transitive. -if (NOT CLR_CMAKE_TARGET_OSX) - set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) - set(CMAKE_INSTALL_RPATH "\$ORIGIN/netcoredeps") -endif() - -set(SKIP_VERSIONING 1) - -set(SOURCES - ./bundle_marker.cpp -) - -set(HEADERS - ./bundle_marker.h -) - -if(CLR_CMAKE_TARGET_WIN32) - list(APPEND SOURCES - apphost.windows.cpp) - - list(APPEND HEADERS - apphost.windows.h) -endif() - -include(../exe.cmake) - -add_definitions(-DFEATURE_APPHOST=1) - -# Disable manifest generation into the file .exe on Windows -if(CLR_CMAKE_TARGET_WIN32) - set_property(TARGET ${PROJECT_NAME} PROPERTY - LINK_FLAGS "/MANIFEST:NO" - ) -endif() - -# Specify non-default Windows libs to be used for Arm/Arm64 builds -if (CLR_CMAKE_TARGET_WIN32 AND (CLR_CMAKE_TARGET_ARCH_ARM OR CLR_CMAKE_TARGET_ARCH_ARM64)) - target_link_libraries(apphost Advapi32.lib shell32.lib) -endif() +add_subdirectory(static) +add_subdirectory(standalone) diff --git a/src/installer/corehost/cli/apphost/standalone/CMakeLists.txt b/src/installer/corehost/cli/apphost/standalone/CMakeLists.txt new file mode 100644 index 0000000000000..60d9a103b12fb --- /dev/null +++ b/src/installer/corehost/cli/apphost/standalone/CMakeLists.txt @@ -0,0 +1,54 @@ +# 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(apphost) +set(DOTNET_PROJECT_NAME "apphost") + +# Add RPATH to the apphost binary that allows using local copies of shared libraries +# dotnet core depends on for special scenarios when system wide installation of such +# dependencies is not possible for some reason. +# This cannot be enabled for MacOS (Darwin) since its RPATH works in a different way, +# doesn't apply to libraries loaded via dlopen and most importantly, it is not transitive. +if (NOT CLR_CMAKE_TARGET_OSX) + set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) + set(CMAKE_INSTALL_RPATH "\$ORIGIN/netcoredeps") +endif() + +set(SKIP_VERSIONING 1) + +include_directories(..) + +set(SOURCES + ../bundle_marker.cpp + ./hostfxr_resolver_t.cpp +) + +set(HEADERS + ../bundle_marker.h + ../../../hostfxr_resolver_t.h +) + +if(CLR_CMAKE_TARGET_WIN32) + list(APPEND SOURCES + ../apphost.windows.cpp) + + list(APPEND HEADERS + ../apphost.windows.h) +endif() + +include(../../exe.cmake) + +add_definitions(-DFEATURE_APPHOST=1) + +# Disable manifest generation into the file .exe on Windows +if(CLR_CMAKE_TARGET_WIN32) + set_property(TARGET ${PROJECT_NAME} PROPERTY + LINK_FLAGS "/MANIFEST:NO" + ) +endif() + +# Specify non-default Windows libs to be used for Arm/Arm64 builds +if (CLR_CMAKE_TARGET_WIN32 AND (CLR_CMAKE_TARGET_ARCH_ARM OR CLR_CMAKE_TARGET_ARCH_ARM64)) + target_link_libraries(apphost Advapi32.lib shell32.lib) +endif() diff --git a/src/installer/corehost/cli/apphost/standalone/hostfxr_resolver_t.cpp b/src/installer/corehost/cli/apphost/standalone/hostfxr_resolver_t.cpp new file mode 100644 index 0000000000000..4f3c3888428c5 --- /dev/null +++ b/src/installer/corehost/cli/apphost/standalone/hostfxr_resolver_t.cpp @@ -0,0 +1,61 @@ +// 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 "pal.h" +#include "fxr_resolver.h" +#include "trace.h" +#include "hostfxr_resolver_t.h" + +hostfxr_main_bundle_startupinfo_fn hostfxr_resolver_t::resolve_main_bundle_startupinfo() +{ + assert(m_hostfxr_dll != nullptr); + return reinterpret_cast(pal::get_symbol(m_hostfxr_dll, "hostfxr_main_bundle_startupinfo")); +} + +hostfxr_set_error_writer_fn hostfxr_resolver_t::resolve_set_error_writer() +{ + assert(m_hostfxr_dll != nullptr); + return reinterpret_cast(pal::get_symbol(m_hostfxr_dll, "hostfxr_set_error_writer")); +} + +hostfxr_main_startupinfo_fn hostfxr_resolver_t::resolve_main_startupinfo() +{ + assert(m_hostfxr_dll != nullptr); + return reinterpret_cast(pal::get_symbol(m_hostfxr_dll, "hostfxr_main_startupinfo")); +} + +hostfxr_main_fn hostfxr_resolver_t::resolve_main_v1() +{ + assert(m_hostfxr_dll != nullptr); + return reinterpret_cast(pal::get_symbol(m_hostfxr_dll, "hostfxr_main")); +} + +hostfxr_resolver_t::hostfxr_resolver_t(const pal::string_t& app_root) +{ + if (!fxr_resolver::try_get_path(app_root, &m_dotnet_root, &m_fxr_path)) + { + m_status_code = StatusCode::CoreHostLibMissingFailure; + } + else if (pal::load_library(&m_fxr_path, &m_hostfxr_dll)) + { + m_status_code = StatusCode::Success; + } + else + { + trace::error(_X("The library %s was found, but loading it from %s failed"), LIBFXR_NAME, m_fxr_path.c_str()); + trace::error(_X(" - Installing .NET prerequisites might help resolve this problem.")); + trace::error(_X(" %s"), DOTNET_CORE_INSTALL_PREREQUISITES_URL); + m_status_code = StatusCode::CoreHostLibLoadFailure; + } +} + +hostfxr_resolver_t::~hostfxr_resolver_t() +{ + if (m_hostfxr_dll != nullptr) + { + pal::unload_library(m_hostfxr_dll); + } +} diff --git a/src/installer/corehost/cli/apphost/static/CMakeLists.txt b/src/installer/corehost/cli/apphost/static/CMakeLists.txt new file mode 100644 index 0000000000000..967aebb24133a --- /dev/null +++ b/src/installer/corehost/cli/apphost/static/CMakeLists.txt @@ -0,0 +1,63 @@ +# 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(singlefilehost) +set(DOTNET_PROJECT_NAME "singlefilehost") + +# Add RPATH to the apphost binary that allows using local copies of shared libraries +# dotnet core depends on for special scenarios when system wide installation of such +# dependencies is not possible for some reason. +# This cannot be enabled for MacOS (Darwin) since its RPATH works in a different way, +# doesn't apply to libraries loaded via dlopen and most importantly, it is not transitive. +if (NOT CLR_CMAKE_TARGET_OSX) + set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) + set(CMAKE_INSTALL_RPATH "\$ORIGIN/netcoredeps") +endif() + +set(SKIP_VERSIONING 1) + +include_directories(..) +include_directories(../../json) + +set(SOURCES + ../bundle_marker.cpp + ./hostfxr_resolver_t.cpp + ./hostpolicy_resolver.cpp +) + +set(HEADERS + ../bundle_marker.h + ../../../hostfxr_resolver_t.h +) + +if(CLR_CMAKE_TARGET_WIN32) + list(APPEND SOURCES + ../apphost.windows.cpp) + + list(APPEND HEADERS + ../apphost.windows.h) +endif() + +include(../../exe.cmake) + +add_definitions(-DFEATURE_APPHOST=1) +add_definitions(-DFEATURE_STATIC_HOST=1) + +# Disable manifest generation into the file .exe on Windows +if(CLR_CMAKE_TARGET_WIN32) + set_property(TARGET ${PROJECT_NAME} PROPERTY + LINK_FLAGS "/MANIFEST:NO" + ) +endif() + +# Specify non-default Windows libs to be used for Arm/Arm64 builds +if (CLR_CMAKE_TARGET_WIN32 AND (CLR_CMAKE_TARGET_ARCH_ARM OR CLR_CMAKE_TARGET_ARCH_ARM64)) + target_link_libraries(singlefilehost Advapi32.lib shell32.lib) +endif() + +target_link_libraries(singlefilehost + libhostfxr_static + libhostpolicy_static + libhostcommon +) diff --git a/src/installer/corehost/cli/apphost/static/hostfxr_resolver_t.cpp b/src/installer/corehost/cli/apphost/static/hostfxr_resolver_t.cpp new file mode 100644 index 0000000000000..2c7e2b87a5f6d --- /dev/null +++ b/src/installer/corehost/cli/apphost/static/hostfxr_resolver_t.cpp @@ -0,0 +1,63 @@ +// 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 "trace.h" +#include "hostfxr.h" +#include "hostfxr_resolver_t.h" + +extern "C" +{ + int HOSTFXR_CALLTYPE hostfxr_main_bundle_startupinfo(const int argc, const pal::char_t* argv[], const pal::char_t* host_path, const pal::char_t* dotnet_root, const pal::char_t* app_path, int64_t bundle_header_offset); + int HOSTFXR_CALLTYPE hostfxr_main_startupinfo(const int argc, const pal::char_t* argv[], const pal::char_t* host_path, const pal::char_t* dotnet_root, const pal::char_t* app_path); + int HOSTFXR_CALLTYPE hostfxr_main(const int argc, const pal::char_t* argv[]); + hostfxr_error_writer_fn HOSTFXR_CALLTYPE hostfxr_set_error_writer(hostfxr_error_writer_fn error_writer); +} + +hostfxr_main_bundle_startupinfo_fn hostfxr_resolver_t::resolve_main_bundle_startupinfo() +{ + assert(m_hostfxr_dll == nullptr); + return hostfxr_main_bundle_startupinfo; +} + +hostfxr_set_error_writer_fn hostfxr_resolver_t::resolve_set_error_writer() +{ + assert(m_hostfxr_dll == nullptr); + return hostfxr_set_error_writer; +} + +hostfxr_main_startupinfo_fn hostfxr_resolver_t::resolve_main_startupinfo() +{ + assert(m_hostfxr_dll == nullptr); + return hostfxr_main_startupinfo; +} + +hostfxr_main_fn hostfxr_resolver_t::resolve_main_v1() +{ + assert(m_hostfxr_dll == nullptr); + assert(!"This function should not be called in a static host"); + return nullptr; +} + +hostfxr_resolver_t::hostfxr_resolver_t(const pal::string_t& app_root) +{ + if (app_root.length() == 0) + { + trace::info(_X("Application root path is empty. This shouldn't happen")); + m_status_code = StatusCode::CoreHostLibMissingFailure; + } + else + { + trace::info(_X("Using internal fxr")); + + m_dotnet_root.assign(app_root); + m_fxr_path.assign(app_root); + + m_status_code = StatusCode::Success; + } +} + +hostfxr_resolver_t::~hostfxr_resolver_t() +{ +} diff --git a/src/installer/corehost/cli/apphost/static/hostpolicy_resolver.cpp b/src/installer/corehost/cli/apphost/static/hostpolicy_resolver.cpp new file mode 100644 index 0000000000000..0b2a35639a2e1 --- /dev/null +++ b/src/installer/corehost/cli/apphost/static/hostpolicy_resolver.cpp @@ -0,0 +1,59 @@ +// 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 +#include +#include "hostpolicy_resolver.h" +#include +#include + +extern "C" +{ + int HOSTPOLICY_CALLTYPE corehost_load(const host_interface_t* init); + int HOSTPOLICY_CALLTYPE corehost_unload(); + corehost_error_writer_fn HOSTPOLICY_CALLTYPE corehost_set_error_writer(corehost_error_writer_fn error_writer); + int HOSTPOLICY_CALLTYPE corehost_initialize(const corehost_initialize_request_t *init_request, int32_t options, /*out*/ corehost_context_contract *context_contract); + int HOSTPOLICY_CALLTYPE corehost_main(const int argc, const pal::char_t* argv[]); + int HOSTPOLICY_CALLTYPE corehost_main_with_output_buffer(const int argc, const pal::char_t* argv[], pal::char_t buffer[], int32_t buffer_size, int32_t* required_buffer_size); +} + +int hostpolicy_resolver::load( + const pal::string_t& lib_dir, + pal::dll_t* dll, + hostpolicy_contract_t &hostpolicy_contract) +{ + static hostpolicy_contract_t contract; + + trace::info(_X("Using internal hostpolicy")); + + contract.load = corehost_load; + contract.unload = corehost_unload; + contract.set_error_writer = corehost_set_error_writer; + contract.initialize = corehost_initialize; + contract.corehost_main = corehost_main; + contract.corehost_main_with_output_buffer = corehost_main_with_output_buffer; + + hostpolicy_contract = contract; + *dll = nullptr; + + return StatusCode::Success; +} + +bool hostpolicy_resolver::try_get_dir( + host_mode_t mode, + const pal::string_t& dotnet_root, + const fx_definition_vector_t& fx_definitions, + const pal::string_t& app_candidate, + const pal::string_t& specified_deps_file, + const std::vector& probe_realpaths, + pal::string_t* impl_dir) +{ + // static apphost is not supposed to be used in a framework-dependent app + assert(!get_app(fx_definitions).get_runtime_config().get_is_framework_dependent()); + assert(mode == host_mode_t::apphost); + + impl_dir->assign(dotnet_root); + return true; +} diff --git a/src/installer/corehost/cli/dotnet/CMakeLists.txt b/src/installer/corehost/cli/dotnet/CMakeLists.txt index 4527986acfe3c..798ae4030ea0a 100644 --- a/src/installer/corehost/cli/dotnet/CMakeLists.txt +++ b/src/installer/corehost/cli/dotnet/CMakeLists.txt @@ -10,4 +10,8 @@ if(CLR_CMAKE_TARGET_WIN32) dotnet.manifest) endif() +list(APPEND SOURCES + ../apphost/standalone/hostfxr_resolver_t.cpp +) + include(../exe.cmake) diff --git a/src/installer/corehost/cli/exe.cmake b/src/installer/corehost/cli/exe.cmake index c9295d5c65f77..3acc130174aa3 100644 --- a/src/installer/corehost/cli/exe.cmake +++ b/src/installer/corehost/cli/exe.cmake @@ -18,6 +18,9 @@ list(APPEND SOURCES ${CMAKE_CURRENT_LIST_DIR}/fxr_resolver.cpp ${CMAKE_CURRENT_LIST_DIR}/../corehost.cpp ) +list(APPEND HEADERS + ${CMAKE_CURRENT_LIST_DIR}/../hostfxr_resolver_t.h +) add_executable(${DOTNET_PROJECT_NAME} ${SOURCES} ${RESOURCES}) diff --git a/src/installer/corehost/cli/fxr/CMakeLists.txt b/src/installer/corehost/cli/fxr/CMakeLists.txt index 216ecbf076bb7..ec7e8e3e2ce4b 100644 --- a/src/installer/corehost/cli/fxr/CMakeLists.txt +++ b/src/installer/corehost/cli/fxr/CMakeLists.txt @@ -2,46 +2,5 @@ # The .NET Foundation licenses this file to you under the MIT license. # See the LICENSE file in the project root for more information. -project(hostfxr) - -set(DOTNET_PROJECT_NAME "hostfxr") - -# Include directories -include_directories(../json) - -# CMake does not recommend using globbing since it messes with the freshness checks -set(SOURCES - ./command_line.cpp - ./corehost_init.cpp - ./hostfxr.cpp - ./fx_muxer.cpp - ./fx_resolver.cpp - ./fx_resolver.messages.cpp - ./framework_info.cpp - ./host_context.cpp - ./hostpolicy_resolver.cpp - ./sdk_info.cpp - ./sdk_resolver.cpp -) - -set(HEADERS - ../corehost_context_contract.h - ../hostpolicy.h - ../fx_definition.h - ../fx_reference.h - ../roll_fwd_on_no_candidate_fx_option.h - ./command_line.h - ./corehost_init.h - ./fx_muxer.h - ./fx_resolver.h - ./framework_info.h - ./host_context.h - ./hostpolicy_resolver.h - ./sdk_info.h - ./sdk_resolver.h -) - -include(../lib.cmake) - -install_with_stripped_symbols(hostfxr TARGETS corehost) -target_link_libraries(hostfxr libhostcommon) +add_subdirectory(static) +add_subdirectory(standalone) diff --git a/src/installer/corehost/cli/fxr/fx_muxer.cpp b/src/installer/corehost/cli/fxr/fx_muxer.cpp index 31c8c17797807..f41e9095ef064 100644 --- a/src/installer/corehost/cli/fxr/fx_muxer.cpp +++ b/src/installer/corehost/cli/fxr/fx_muxer.cpp @@ -66,16 +66,11 @@ namespace } } -template int load_hostpolicy( const pal::string_t& lib_dir, pal::dll_t* h_host, - hostpolicy_contract_t &hostpolicy_contract, - const char *main_entry_symbol, - T* main_fn) + hostpolicy_contract_t& hostpolicy_contract) { - assert(main_entry_symbol != nullptr && main_fn != nullptr); - int rc = hostpolicy_resolver::load(lib_dir, h_host, hostpolicy_contract); if (rc != StatusCode::Success) { @@ -83,11 +78,6 @@ int load_hostpolicy( return rc; } - // Obtain entrypoint symbol - *main_fn = reinterpret_cast(pal::get_symbol(*h_host, main_entry_symbol)); - if (*main_fn == nullptr) - return StatusCode::CoreHostEntryPointFailure; - return StatusCode::Success; } @@ -114,7 +104,18 @@ static int execute_app( hostpolicy_contract_t hostpolicy_contract{}; corehost_main_fn host_main = nullptr; - int code = load_hostpolicy(impl_dll_dir, &hostpolicy_dll, hostpolicy_contract, "corehost_main", &host_main); + int code = load_hostpolicy(impl_dll_dir, &hostpolicy_dll, hostpolicy_contract); + + // Obtain entrypoint symbol + if (code == StatusCode::Success) + { + host_main = hostpolicy_contract.corehost_main; + if (host_main == nullptr) + { + code = StatusCode::CoreHostEntryPointFailure; + } + } + if (code != StatusCode::Success) { handle_initialize_failure_or_abort(); @@ -164,7 +165,18 @@ static int execute_host_command( hostpolicy_contract_t hostpolicy_contract{}; corehost_main_with_output_buffer_fn host_main = nullptr; - int code = load_hostpolicy(impl_dll_dir, &hostpolicy_dll, hostpolicy_contract, "corehost_main_with_output_buffer", &host_main); + int code = load_hostpolicy(impl_dll_dir, &hostpolicy_dll, hostpolicy_contract); + + // Obtain entrypoint symbol + if (code == StatusCode::Success) + { + host_main = hostpolicy_contract.corehost_main_with_output_buffer; + if (host_main == nullptr) + { + code = StatusCode::CoreHostEntryPointFailure; + } + } + if (code != StatusCode::Success) return code; @@ -471,7 +483,7 @@ namespace if (!hostpolicy_resolver::try_get_dir(mode, host_info.dotnet_root, fx_definitions, app_candidate, deps_file, probe_realpaths, &hostpolicy_dir)) { - return CoreHostLibMissingFailure; + return StatusCode::CoreHostLibMissingFailure; } init.reset(new corehost_init_t(host_command, host_info, deps_file, additional_deps_serialized, probe_realpaths, mode, fx_definitions)); diff --git a/src/installer/corehost/cli/fxr/hostpolicy_resolver.h b/src/installer/corehost/cli/fxr/hostpolicy_resolver.h index 4348a53c778e0..35128327b7bca 100644 --- a/src/installer/corehost/cli/fxr/hostpolicy_resolver.h +++ b/src/installer/corehost/cli/fxr/hostpolicy_resolver.h @@ -20,6 +20,10 @@ struct hostpolicy_contract_t // 3.0+ contracts corehost_set_error_writer_fn set_error_writer; corehost_initialize_fn initialize; + + // 5.0+ contracts + corehost_main_fn corehost_main; + corehost_main_with_output_buffer_fn corehost_main_with_output_buffer; }; namespace hostpolicy_resolver @@ -38,4 +42,4 @@ namespace hostpolicy_resolver pal::string_t* impl_dir); }; -#endif // __HOSTPOLICY_RESOLVER_H__ \ No newline at end of file +#endif // __HOSTPOLICY_RESOLVER_H__ diff --git a/src/installer/corehost/cli/fxr/standalone/CMakeLists.txt b/src/installer/corehost/cli/fxr/standalone/CMakeLists.txt new file mode 100644 index 0000000000000..0a2ea92174b6f --- /dev/null +++ b/src/installer/corehost/cli/fxr/standalone/CMakeLists.txt @@ -0,0 +1,65 @@ +# 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(hostfxr) + +set(DOTNET_PROJECT_NAME "hostfxr") + +# Include directories +include_directories(../../json) +include_directories(../../fxr) + +# CMake does not recommend using globbing since it messes with the freshness checks +set(SOURCES + ./hostpolicy_resolver.cpp +) + +set(HEADERS + ../command_line.h + ../corehost_init.h + ../fx_muxer.h + ../fx_resolver.h + ../framework_info.h + ../host_context.h + ../sdk_info.h + ../sdk_resolver.h + ../hostpolicy_resolver.h +) + +if(CLR_CMAKE_TARGET_WIN32) + list(APPEND SOURCES + hostfxr.def) +else(CLR_CMAKE_TARGET_WIN32) + set(DEF_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/hostfxr_unixexports.src) + set(EXPORTS_FILE ${CMAKE_CURRENT_BINARY_DIR}/hostfxr.exports) + generate_exports_file(${DEF_SOURCES} ${EXPORTS_FILE}) + + if(CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD) + # Add linker exports file option + set(EXPORTS_LINKER_OPTION -Wl,--version-script=${EXPORTS_FILE}) + endif(CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD) + + if(CLR_CMAKE_HOST_OSX) + # Add linker exports file option + set(EXPORTS_LINKER_OPTION -Wl,-exported_symbols_list,${EXPORTS_FILE}) + endif(CLR_CMAKE_HOST_OSX) + + if(CLR_CMAKE_HOST_SUNOS) + # Add linker exports file option + set(EXPORTS_LINKER_OPTION -Wl,-M,${EXPORTS_FILE}) + endif(CLR_CMAKE_HOST_SUNOS) +endif(CLR_CMAKE_TARGET_WIN32) + +include(../../lib.cmake) + +if(CLR_CMAKE_HOST_UNIX) + add_custom_target(hostfxr_exports DEPENDS ${EXPORTS_FILE}) + add_dependencies(hostfxr hostfxr_exports) + + set_property(TARGET hostfxr APPEND_STRING PROPERTY LINK_FLAGS ${EXPORTS_LINKER_OPTION}) + set_property(TARGET hostfxr APPEND_STRING PROPERTY LINK_DEPENDS ${EXPORTS_FILE}) +endif(CLR_CMAKE_HOST_UNIX) + +install_with_stripped_symbols(hostfxr TARGETS corehost) +target_link_libraries(hostfxr libhostcommon libhostfxr_static) diff --git a/src/installer/corehost/cli/fxr/standalone/hostfxr.def b/src/installer/corehost/cli/fxr/standalone/hostfxr.def new file mode 100644 index 0000000000000..c86139a7fb58b --- /dev/null +++ b/src/installer/corehost/cli/fxr/standalone/hostfxr.def @@ -0,0 +1,21 @@ +; 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. + +EXPORTS + hostfxr_main_bundle_startupinfo + hostfxr_main_startupinfo + hostfxr_main + hostfxr_resolve_sdk + hostfxr_resolve_sdk2 + hostfxr_get_available_sdks + hostfxr_get_native_search_directories + hostfxr_set_error_writer + hostfxr_initialize_for_dotnet_command_line + hostfxr_initialize_for_runtime_config + hostfxr_run_app + hostfxr_get_runtime_delegate + hostfxr_get_runtime_property_value + hostfxr_set_runtime_property_value + hostfxr_get_runtime_properties + hostfxr_close diff --git a/src/installer/corehost/cli/fxr/standalone/hostfxr_unixexports.src b/src/installer/corehost/cli/fxr/standalone/hostfxr_unixexports.src new file mode 100644 index 0000000000000..fcf85d027fa64 --- /dev/null +++ b/src/installer/corehost/cli/fxr/standalone/hostfxr_unixexports.src @@ -0,0 +1,20 @@ +; 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. + +hostfxr_main_bundle_startupinfo +hostfxr_main_startupinfo +hostfxr_main +hostfxr_resolve_sdk +hostfxr_resolve_sdk2 +hostfxr_get_available_sdks +hostfxr_get_native_search_directories +hostfxr_set_error_writer +hostfxr_initialize_for_dotnet_command_line +hostfxr_initialize_for_runtime_config +hostfxr_run_app +hostfxr_get_runtime_delegate +hostfxr_get_runtime_property_value +hostfxr_set_runtime_property_value +hostfxr_get_runtime_properties +hostfxr_close diff --git a/src/installer/corehost/cli/fxr/hostpolicy_resolver.cpp b/src/installer/corehost/cli/fxr/standalone/hostpolicy_resolver.cpp similarity index 97% rename from src/installer/corehost/cli/fxr/hostpolicy_resolver.cpp rename to src/installer/corehost/cli/fxr/standalone/hostpolicy_resolver.cpp index de3291fecc5b5..67881d207944f 100644 --- a/src/installer/corehost/cli/fxr/hostpolicy_resolver.cpp +++ b/src/installer/corehost/cli/fxr/standalone/hostpolicy_resolver.cpp @@ -198,6 +198,9 @@ int hostpolicy_resolver::load( g_hostpolicy_contract.set_error_writer = reinterpret_cast(pal::get_symbol(g_hostpolicy, "corehost_set_error_writer")); g_hostpolicy_contract.initialize = reinterpret_cast(pal::get_symbol(g_hostpolicy, "corehost_initialize")); + g_hostpolicy_contract.corehost_main = reinterpret_cast(pal::get_symbol(g_hostpolicy, "corehost_main")); + g_hostpolicy_contract.corehost_main_with_output_buffer = reinterpret_cast(pal::get_symbol(g_hostpolicy, "corehost_main_with_output_buffer")); + // It's possible to not have corehost_set_error_writer and corehost_initialize. These were // introduced in 3.0, so 2.0 hostpolicy would not have the exports. In this case, we will // not propagate the error writer and errors will still be reported to stderr. Callers are diff --git a/src/installer/corehost/cli/fxr/static/CMakeLists.txt b/src/installer/corehost/cli/fxr/static/CMakeLists.txt new file mode 100644 index 0000000000000..16c0951c5b21b --- /dev/null +++ b/src/installer/corehost/cli/fxr/static/CMakeLists.txt @@ -0,0 +1,45 @@ +# 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(hostfxr_static) + +set(DOTNET_PROJECT_NAME "hostfxr_static") + +# Include directories +include_directories(../../json) +include_directories(../../fxr) + +# CMake does not recommend using globbing since it messes with the freshness checks +set(SOURCES + ../command_line.cpp + ../corehost_init.cpp + ../hostfxr.cpp + ../fx_muxer.cpp + ../fx_resolver.cpp + ../fx_resolver.messages.cpp + ../framework_info.cpp + ../host_context.cpp + ../sdk_info.cpp + ../sdk_resolver.cpp +) + +set(HEADERS + ../../corehost_context_contract.h + ../../hostpolicy.h + ../../fx_definition.h + ../../fx_reference.h + ../../roll_fwd_on_no_candidate_fx_option.h + ../command_line.h + ../corehost_init.h + ../fx_muxer.h + ../fx_resolver.h + ../framework_info.h + ../host_context.h + ../sdk_info.h + ../sdk_resolver.h +) + +set(SKIP_VERSIONING 1) +set(BUILD_OBJECT_LIBRARY 1) +include(../../lib_static.cmake) diff --git a/src/installer/corehost/cli/hostpolicy/CMakeLists.txt b/src/installer/corehost/cli/hostpolicy/CMakeLists.txt index ca2c78fa27951..ec7e8e3e2ce4b 100644 --- a/src/installer/corehost/cli/hostpolicy/CMakeLists.txt +++ b/src/installer/corehost/cli/hostpolicy/CMakeLists.txt @@ -2,47 +2,5 @@ # The .NET Foundation licenses this file to you under the MIT license. # See the LICENSE file in the project root for more information. -project(hostpolicy) - -set(DOTNET_PROJECT_NAME "hostpolicy") - -# Include directories -include_directories(../fxr) -include_directories(../json) - -# CMake does not recommend using globbing since it messes with the freshness checks -set(SOURCES - ./args.cpp - ./breadcrumbs.cpp - ./coreclr.cpp - ./deps_resolver.cpp - ./hostpolicy_context.cpp - ./hostpolicy.cpp - ./hostpolicy_init.cpp - ../bundle/dir_utils.cpp - ../bundle/extractor.cpp - ../bundle/file_entry.cpp - ../bundle/manifest.cpp - ../bundle/runner.cpp -) - -set(HEADERS - ./args.h - ./breadcrumbs.h - ./coreclr.h - ../corehost_context_contract.h - ./deps_resolver.h - ./hostpolicy_context.h - ../hostpolicy.h - ./hostpolicy_init.h - ../bundle/dir_utils.h - ../bundle/extractor.h - ../bundle/file_entry.h - ../bundle/manifest.h - ../bundle/runner.h -) - -include(../lib.cmake) - -install_with_stripped_symbols(hostpolicy TARGETS corehost) -target_link_libraries(hostpolicy libhostcommon) +add_subdirectory(static) +add_subdirectory(standalone) diff --git a/src/installer/corehost/cli/hostpolicy/standalone/CMakeLists.txt b/src/installer/corehost/cli/hostpolicy/standalone/CMakeLists.txt new file mode 100644 index 0000000000000..d6631543f81b5 --- /dev/null +++ b/src/installer/corehost/cli/hostpolicy/standalone/CMakeLists.txt @@ -0,0 +1,59 @@ +# 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(hostpolicy) + +set(DOTNET_PROJECT_NAME "hostpolicy") + +# CMake does not recommend using globbing since it messes with the freshness checks + +# Can't call add_library() without source files. Create an empty .c file, +# then link with the static library just recently built. +if (NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}/empty.cpp") + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/empty.cpp" "") +endif () + +set(SOURCES + ${CMAKE_CURRENT_BINARY_DIR}/empty.cpp +) + +set(HEADERS +) + +if(CLR_CMAKE_TARGET_WIN32) + list(APPEND SOURCES + hostpolicy.def) +else(CLR_CMAKE_TARGET_WIN32) + set(DEF_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/hostpolicy_unixexports.src) + set(EXPORTS_FILE ${CMAKE_CURRENT_BINARY_DIR}/hostpolicy.exports) + generate_exports_file(${DEF_SOURCES} ${EXPORTS_FILE}) + + if(CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD) + # Add linker exports file option + set(EXPORTS_LINKER_OPTION -Wl,--version-script=${EXPORTS_FILE}) + endif(CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD) + + if(CLR_CMAKE_HOST_OSX) + # Add linker exports file option + set(EXPORTS_LINKER_OPTION -Wl,-exported_symbols_list,${EXPORTS_FILE}) + endif(CLR_CMAKE_HOST_OSX) + + if(CLR_CMAKE_HOST_SUNOS) + # Add linker exports file option + set(EXPORTS_LINKER_OPTION -Wl,-M,${EXPORTS_FILE}) + endif(CLR_CMAKE_HOST_SUNOS) +endif(CLR_CMAKE_TARGET_WIN32) + +include(../../lib.cmake) + +if(CLR_CMAKE_HOST_UNIX) + add_custom_target(hostpolicy_exports DEPENDS ${EXPORTS_FILE}) + add_dependencies(hostpolicy hostpolicy_exports) + + set_property(TARGET hostpolicy APPEND_STRING PROPERTY LINK_FLAGS ${EXPORTS_LINKER_OPTION}) + set_property(TARGET hostpolicy APPEND_STRING PROPERTY LINK_DEPENDS ${EXPORTS_FILE}) +endif(CLR_CMAKE_HOST_UNIX) + +install_with_stripped_symbols(hostpolicy TARGETS corehost) +target_link_libraries(hostpolicy libhostcommon libhostpolicy_static) diff --git a/src/installer/corehost/cli/hostpolicy/standalone/hostpolicy.def b/src/installer/corehost/cli/hostpolicy/standalone/hostpolicy.def new file mode 100644 index 0000000000000..af03ab9dca68d --- /dev/null +++ b/src/installer/corehost/cli/hostpolicy/standalone/hostpolicy.def @@ -0,0 +1,12 @@ +; 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. + +EXPORTS + corehost_initialize + corehost_load + corehost_main + corehost_main_with_output_buffer + corehost_resolve_component_dependencies + corehost_set_error_writer + corehost_unload diff --git a/src/installer/corehost/cli/hostpolicy/standalone/hostpolicy_unixexports.src b/src/installer/corehost/cli/hostpolicy/standalone/hostpolicy_unixexports.src new file mode 100644 index 0000000000000..98f3e616e9499 --- /dev/null +++ b/src/installer/corehost/cli/hostpolicy/standalone/hostpolicy_unixexports.src @@ -0,0 +1,11 @@ +; 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. + +corehost_initialize +corehost_load +corehost_main +corehost_main_with_output_buffer +corehost_resolve_component_dependencies +corehost_set_error_writer +corehost_unload diff --git a/src/installer/corehost/cli/hostpolicy/static/CMakeLists.txt b/src/installer/corehost/cli/hostpolicy/static/CMakeLists.txt new file mode 100644 index 0000000000000..6845e369bdac3 --- /dev/null +++ b/src/installer/corehost/cli/hostpolicy/static/CMakeLists.txt @@ -0,0 +1,47 @@ +# 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(hostpolicy_static) + +set(DOTNET_PROJECT_NAME "hostpolicy_static") + +# Include directories +include_directories(../../fxr) +include_directories(../../json) + +# CMake does not recommend using globbing since it messes with the freshness checks +set(SOURCES + ../args.cpp + ../breadcrumbs.cpp + ../coreclr.cpp + ../deps_resolver.cpp + ../hostpolicy_context.cpp + ../hostpolicy.cpp + ../hostpolicy_init.cpp + ../../bundle/dir_utils.cpp + ../../bundle/extractor.cpp + ../../bundle/file_entry.cpp + ../../bundle/manifest.cpp + ../../bundle/runner.cpp +) + +set(HEADERS + ../args.h + ../breadcrumbs.h + ../coreclr.h + ../deps_resolver.h + ../hostpolicy_context.h + ../hostpolicy_init.h + ../../hostpolicy.h + ../../corehost_context_contract.h + ../../bundle/dir_utils.h + ../../bundle/extractor.h + ../../bundle/file_entry.h + ../../bundle/manifest.h + ../../bundle/runner.h +) + +set(SKIP_VERSIONING 1) +set(BUILD_OBJECT_LIBRARY 1) +include(../../lib_static.cmake) diff --git a/src/installer/corehost/cli/lib_static.cmake b/src/installer/corehost/cli/lib_static.cmake index 8135e9c19e0e0..00204df3ce9f4 100644 --- a/src/installer/corehost/cli/lib_static.cmake +++ b/src/installer/corehost/cli/lib_static.cmake @@ -10,7 +10,11 @@ add_definitions(-D_NO_ASYNCRTIMP) add_definitions(-D_NO_PPLXIMP) add_definitions(-DEXPORT_SHARED_API=1) -add_library(lib${DOTNET_PROJECT_NAME} STATIC ${SOURCES} ${RESOURCES}) +if (BUILD_OBJECT_LIBRARY) + add_library(lib${DOTNET_PROJECT_NAME} OBJECT ${SOURCES} ${RESOURCES}) +else () + add_library(lib${DOTNET_PROJECT_NAME} STATIC ${SOURCES} ${RESOURCES}) +endif () set_target_properties(lib${DOTNET_PROJECT_NAME} PROPERTIES MACOSX_RPATH TRUE) set_target_properties(lib${DOTNET_PROJECT_NAME} PROPERTIES PREFIX "") diff --git a/src/installer/corehost/corehost.cpp b/src/installer/corehost/corehost.cpp index 55b8ed629827c..65cfb61f3ac64 100644 --- a/src/installer/corehost/corehost.cpp +++ b/src/installer/corehost/corehost.cpp @@ -9,6 +9,7 @@ #include "fx_ver.h" #include "trace.h" #include "utils.h" +#include "hostfxr_resolver_t.h" #if defined(FEATURE_APPHOST) #include "bundle_marker.h" @@ -176,51 +177,41 @@ int exe_start(const int argc, const pal::char_t* argv[]) app_path.append(_X(".dll")); #endif - pal::string_t dotnet_root; - pal::string_t fxr_path; - if (!fxr_resolver::try_get_path(app_root, &dotnet_root, &fxr_path)) - { - return StatusCode::CoreHostLibMissingFailure; - } + hostfxr_resolver_t fxr{app_root}; - // Load library - pal::dll_t fxr; - if (!pal::load_library(&fxr_path, &fxr)) + // Obtain the entrypoints. + int rc = fxr.status_code(); + if (rc != StatusCode::Success) { - trace::error(_X("The library %s was found, but loading it from %s failed"), LIBFXR_NAME, fxr_path.c_str()); - trace::error(_X(" - Installing .NET prerequisites might help resolve this problem.")); - trace::error(_X(" %s"), DOTNET_CORE_INSTALL_PREREQUISITES_URL); - return StatusCode::CoreHostLibLoadFailure; + return rc; } - // Obtain the entrypoints. - int rc; #if defined(FEATURE_APPHOST) if (bundle_marker_t::is_bundle()) { - hostfxr_main_bundle_startupinfo_fn hostfxr_main_bundle_startupinfo = reinterpret_cast(pal::get_symbol(fxr, "hostfxr_main_bundle_startupinfo")); + auto hostfxr_main_bundle_startupinfo = fxr.resolve_main_bundle_startupinfo(); if (hostfxr_main_bundle_startupinfo != nullptr) { const pal::char_t* host_path_cstr = host_path.c_str(); - const pal::char_t* dotnet_root_cstr = dotnet_root.empty() ? nullptr : dotnet_root.c_str(); + const pal::char_t* dotnet_root_cstr = fxr.dotnet_root().empty() ? nullptr : fxr.dotnet_root().c_str(); const pal::char_t* app_path_cstr = app_path.empty() ? nullptr : app_path.c_str(); int64_t bundle_header_offset = bundle_marker_t::header_offset(); - trace::info(_X("Invoking fx resolver [%s] hostfxr_main_bundle_startupinfo"), fxr_path.c_str()); + trace::info(_X("Invoking fx resolver [%s] hostfxr_main_bundle_startupinfo"), fxr.fxr_path().c_str()); trace::info(_X("Host path: [%s]"), host_path.c_str()); - trace::info(_X("Dotnet path: [%s]"), dotnet_root.c_str()); + trace::info(_X("Dotnet path: [%s]"), fxr.dotnet_root().c_str()); trace::info(_X("App path: [%s]"), app_path.c_str()); trace::info(_X("Bundle Header Offset: [%lx]"), bundle_header_offset); - hostfxr_set_error_writer_fn set_error_writer_fn = reinterpret_cast(pal::get_symbol(fxr, "hostfxr_set_error_writer")); - propagate_error_writer_t propagate_error_writer_to_hostfxr(set_error_writer_fn); + auto set_error_writer = fxr.resolve_set_error_writer(); + propagate_error_writer_t propagate_error_writer_to_hostfxr(set_error_writer); rc = hostfxr_main_bundle_startupinfo(argc, argv, host_path_cstr, dotnet_root_cstr, app_path_cstr, bundle_header_offset); } else { // The host components will be statically linked with the app-host: https://github.com/dotnet/runtime/issues/32823 // Once this work is completed, an outdated hostfxr can only be found for framework-related apps. - trace::error(_X("The required library %s does not support single-file apps."), fxr_path.c_str()); + trace::error(_X("The required library %s does not support single-file apps."), fxr.fxr_path().c_str()); need_newer_framework_error(); rc = StatusCode::FrameworkMissingFailure; } @@ -228,60 +219,61 @@ int exe_start(const int argc, const pal::char_t* argv[]) else #endif // defined(FEATURE_APPHOST) { - hostfxr_main_startupinfo_fn hostfxr_main_startupinfo = reinterpret_cast(pal::get_symbol(fxr, "hostfxr_main_startupinfo")); + auto hostfxr_main_startupinfo = fxr.resolve_main_startupinfo(); if (hostfxr_main_startupinfo != nullptr) { const pal::char_t* host_path_cstr = host_path.c_str(); - const pal::char_t* dotnet_root_cstr = dotnet_root.empty() ? nullptr : dotnet_root.c_str(); + const pal::char_t* dotnet_root_cstr = fxr.dotnet_root().empty() ? nullptr : fxr.dotnet_root().c_str(); const pal::char_t* app_path_cstr = app_path.empty() ? nullptr : app_path.c_str(); - trace::info(_X("Invoking fx resolver [%s] hostfxr_main_startupinfo"), fxr_path.c_str()); + trace::info(_X("Invoking fx resolver [%s] hostfxr_main_startupinfo"), fxr.fxr_path().c_str()); trace::info(_X("Host path: [%s]"), host_path.c_str()); - trace::info(_X("Dotnet path: [%s]"), dotnet_root.c_str()); + trace::info(_X("Dotnet path: [%s]"), fxr.dotnet_root().c_str()); trace::info(_X("App path: [%s]"), app_path.c_str()); - hostfxr_set_error_writer_fn set_error_writer_fn = reinterpret_cast(pal::get_symbol(fxr, "hostfxr_set_error_writer")); - propagate_error_writer_t propagate_error_writer_to_hostfxr(set_error_writer_fn); + auto set_error_writer = fxr.resolve_set_error_writer(); + propagate_error_writer_t propagate_error_writer_to_hostfxr(set_error_writer); rc = hostfxr_main_startupinfo(argc, argv, host_path_cstr, dotnet_root_cstr, app_path_cstr); // This check exists to provide an error message for UI apps when running 3.0 apps on 2.0 only hostfxr, which doesn't support error writer redirection. - if (trace::get_error_writer() != nullptr && rc == static_cast(StatusCode::FrameworkMissingFailure) && !set_error_writer_fn) + if (trace::get_error_writer() != nullptr && rc == static_cast(StatusCode::FrameworkMissingFailure) && set_error_writer == nullptr) { need_newer_framework_error(); } } +#if !defined(FEATURE_STATIC_HOST) else { if (requires_hostfxr_startupinfo_interface) { - trace::error(_X("The required library %s does not support relative app dll paths."), fxr_path.c_str()); + trace::error(_X("The required library %s does not support relative app dll paths."), fxr.fxr_path().c_str()); rc = StatusCode::CoreHostEntryPointFailure; } else { - trace::info(_X("Invoking fx resolver [%s] v1"), fxr_path.c_str()); + trace::info(_X("Invoking fx resolver [%s] v1"), fxr.fxr_path().c_str()); // Previous corehost trace messages must be printed before calling trace::setup in hostfxr trace::flush(); // For compat, use the v1 interface. This requires additional file I\O to re-parse parameters and // for apphost, does not support DOTNET_ROOT or dll with different name for exe. - hostfxr_main_fn main_fn_v1 = reinterpret_cast(pal::get_symbol(fxr, "hostfxr_main")); + auto main_fn_v1 = fxr.resolve_main_v1(); if (main_fn_v1 != nullptr) { rc = main_fn_v1(argc, argv); } else { - trace::error(_X("The required library %s does not contain the expected entry point."), fxr_path.c_str()); + trace::error(_X("The required library %s does not contain the expected entry point."), fxr.fxr_path().c_str()); rc = StatusCode::CoreHostEntryPointFailure; } } } +#endif // defined(FEATURE_STATIC_HOST) } - pal::unload_library(fxr); return rc; } diff --git a/src/installer/corehost/hostfxr_resolver_t.h b/src/installer/corehost/hostfxr_resolver_t.h new file mode 100644 index 0000000000000..21047b56a3c89 --- /dev/null +++ b/src/installer/corehost/hostfxr_resolver_t.h @@ -0,0 +1,40 @@ +// 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 __HOSTFXR_RESOLVER_T_H__ +#define __HOSTFXR_RESOLVER_T_H__ + +#include "hostfxr.h" +#include "pal.h" +#include "error_codes.h" + +class hostfxr_resolver_t +{ + public: + hostfxr_resolver_t(const pal::string_t& app_root); + ~hostfxr_resolver_t(); + + StatusCode status_code() const { return m_status_code; } + + const pal::string_t& host_path() const { return m_host_path; } + const pal::string_t& dotnet_root() const { return m_dotnet_root; } + const pal::string_t& fxr_path() const { return m_fxr_path; } + + hostfxr_main_bundle_startupinfo_fn resolve_main_bundle_startupinfo(); + hostfxr_set_error_writer_fn resolve_set_error_writer(); + hostfxr_main_startupinfo_fn resolve_main_startupinfo(); + hostfxr_main_fn resolve_main_v1(); + + private: + pal::dll_t m_hostfxr_dll{nullptr}; + + pal::string_t m_host_path; + pal::string_t m_dotnet_root; + pal::string_t m_fxr_path; + + bool m_requires_startupinfo_iface{false}; + StatusCode m_status_code; +}; + +#endif // __HOSTFXR_RESOLVER_T_H__ diff --git a/src/installer/pkg/projects/Microsoft.NETCore.DotNetAppHost/runtime.Windows_NT.Microsoft.NETCore.DotNetAppHost.props b/src/installer/pkg/projects/Microsoft.NETCore.DotNetAppHost/runtime.Windows_NT.Microsoft.NETCore.DotNetAppHost.props index c74da91a0f25c..6d52e1984f8ce 100644 --- a/src/installer/pkg/projects/Microsoft.NETCore.DotNetAppHost/runtime.Windows_NT.Microsoft.NETCore.DotNetAppHost.props +++ b/src/installer/pkg/projects/Microsoft.NETCore.DotNetAppHost/runtime.Windows_NT.Microsoft.NETCore.DotNetAppHost.props @@ -2,6 +2,7 @@ + diff --git a/src/installer/pkg/projects/netcoreapp/pkg/Microsoft.NETCore.App.Host.pkgproj b/src/installer/pkg/projects/netcoreapp/pkg/Microsoft.NETCore.App.Host.pkgproj index 10915e8d504d4..8daa78d3ec711 100644 --- a/src/installer/pkg/projects/netcoreapp/pkg/Microsoft.NETCore.App.Host.pkgproj +++ b/src/installer/pkg/projects/netcoreapp/pkg/Microsoft.NETCore.App.Host.pkgproj @@ -15,6 +15,7 @@ --> + @@ -29,4 +30,4 @@ true - \ No newline at end of file + diff --git a/src/installer/test/Assets/TestProjects/StaticHostApp/Program.cs b/src/installer/test/Assets/TestProjects/StaticHostApp/Program.cs new file mode 100644 index 0000000000000..c631d81d54048 --- /dev/null +++ b/src/installer/test/Assets/TestProjects/StaticHostApp/Program.cs @@ -0,0 +1,16 @@ +// 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 System; + +namespace StaticHostApp +{ + public static class Program + { + public static void Main(string[] args) + { + Console.WriteLine("Hello World!"); + } + } +} diff --git a/src/installer/test/Assets/TestProjects/StaticHostApp/StaticHostApp.csproj b/src/installer/test/Assets/TestProjects/StaticHostApp/StaticHostApp.csproj new file mode 100644 index 0000000000000..eff31e8532b40 --- /dev/null +++ b/src/installer/test/Assets/TestProjects/StaticHostApp/StaticHostApp.csproj @@ -0,0 +1,13 @@ + + + + $(NETCoreAppFramework) + Exe + $(TestTargetRid) + $(MNAVersion) + + + + + + diff --git a/src/installer/test/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/StaticHost.cs b/src/installer/test/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/StaticHost.cs new file mode 100644 index 0000000000000..78b5c9449fe1b --- /dev/null +++ b/src/installer/test/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/StaticHost.cs @@ -0,0 +1,98 @@ +// 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 BundleTests.Helpers; +using Microsoft.DotNet.Cli.Build.Framework; +using Microsoft.DotNet.CoreSetup.Test; +using Microsoft.NET.HostModel.AppHost; +using Microsoft.NET.HostModel.Bundle; +using System; +using System.IO; +using System.Threading; +using Xunit; + +namespace AppHost.Bundle.Tests +{ + public class StaticHost : IClassFixture + { + private SharedTestState sharedTestState; + + public StaticHost(SharedTestState fixture) + { + sharedTestState = fixture; + } + + // This helper is used in lieu of SDK support for publishing apps using the singlefilehost. + // It replaces the apphost with singlefilehost, and along with appropriate app.dll updates in the host. + // For now, we leave behind the hostpolicy and hostfxr DLLs in the publish directory, because + // removing them requires deps.json update. + void ReplaceApphostWithStaticHost(TestProjectFixture fixture) + { + var staticHost = Path.Combine(fixture.RepoDirProvider.HostArtifacts, + RuntimeInformationExtensions.GetExeFileNameForCurrentPlatform("singlefilehost")); + HostWriter.CreateAppHost(staticHost, + BundleHelper.GetHostPath(fixture), + BundleHelper.GetAppPath(fixture)); + + } + + [Fact] + private void Can_Run_App_With_StatiHost() + { + var fixture = sharedTestState.TestFixture.Copy(); + var appExe = BundleHelper.GetHostPath(fixture); + + ReplaceApphostWithStaticHost(fixture); + + Command.Create(appExe) + .CaptureStdErr() + .CaptureStdOut() + .Execute() + .Should() + .Pass() + .And + .HaveStdOutContaining("Hello World"); + } + + [Fact] + private void Can_Run_SingleFile_App_With_StatiHost() + { + var fixture = sharedTestState.TestFixture.Copy(); + + ReplaceApphostWithStaticHost(fixture); + + string singleFile = BundleHelper.BundleApp(fixture); + + Command.Create(singleFile) + .CaptureStdErr() + .CaptureStdOut() + .Execute() + .Should() + .Pass() + .And + .HaveStdOutContaining("Hello World"); + } + + public class SharedTestState : IDisposable + { + public TestProjectFixture TestFixture { get; set; } + public RepoDirectoriesProvider RepoDirectories { get; set; } + + public SharedTestState() + { + RepoDirectories = new RepoDirectoriesProvider(); + TestFixture = new TestProjectFixture("StaticHostApp", RepoDirectories); + TestFixture + .EnsureRestoredForRid(TestFixture.CurrentRid, RepoDirectories.CorehostPackages) + .PublishProject(runtime: TestFixture.CurrentRid, + outputDirectory: BundleHelper.GetPublishPath(TestFixture)); + } + + public void Dispose() + { + TestFixture.Dispose(); + } + } + } +}