From b11ac0160f815c51362fa1b41413acdfd10e09b7 Mon Sep 17 00:00:00 2001 From: Senthil Date: Mon, 28 Dec 2015 18:30:04 -0800 Subject: [PATCH] Refactoring for corehost servicing --- scripts/compile/compile-corehost.ps1 | 11 +- scripts/compile/compile-corehost.sh | 8 +- src/corehost/CMakeLists.txt | 43 +---- src/corehost/cli/CMakeLists.txt | 47 ++++++ src/corehost/{src => cli}/args.cpp | 12 -- src/corehost/{inc => cli}/args.h | 0 .../{src/main.cpp => cli/clihost.cpp} | 24 ++- src/corehost/{src => cli}/coreclr.cpp | 0 src/corehost/{inc => cli}/coreclr.h | 0 src/corehost/{src => cli}/deps_resolver.cpp | 0 src/corehost/{inc => cli}/deps_resolver.h | 0 src/corehost/cli/dll/CMakeLists.txt | 30 ++++ src/corehost/{src => cli}/servicing_index.cpp | 0 src/corehost/{inc => cli}/servicing_index.h | 0 src/corehost/{inc => common}/pal.h | 19 ++- src/corehost/{src => common}/pal.unix.cpp | 7 +- src/corehost/{src => common}/pal.windows.cpp | 11 +- src/corehost/{src => common}/trace.cpp | 0 src/corehost/{inc => common}/trace.h | 0 src/corehost/{src => common}/utils.cpp | 0 src/corehost/{inc => common}/utils.h | 0 src/corehost/corehost.cpp | 149 ++++++++++++++++++ 22 files changed, 279 insertions(+), 82 deletions(-) create mode 100644 src/corehost/cli/CMakeLists.txt rename src/corehost/{src => cli}/args.cpp (90%) rename src/corehost/{inc => cli}/args.h (100%) rename src/corehost/{src/main.cpp => cli/clihost.cpp} (93%) rename src/corehost/{src => cli}/coreclr.cpp (100%) rename src/corehost/{inc => cli}/coreclr.h (100%) rename src/corehost/{src => cli}/deps_resolver.cpp (100%) rename src/corehost/{inc => cli}/deps_resolver.h (100%) create mode 100644 src/corehost/cli/dll/CMakeLists.txt rename src/corehost/{src => cli}/servicing_index.cpp (100%) rename src/corehost/{inc => cli}/servicing_index.h (100%) rename src/corehost/{inc => common}/pal.h (90%) rename src/corehost/{src => common}/pal.unix.cpp (96%) rename src/corehost/{src => common}/pal.windows.cpp (92%) rename src/corehost/{src => common}/trace.cpp (100%) rename src/corehost/{inc => common}/trace.h (100%) rename src/corehost/{src => common}/utils.cpp (100%) rename src/corehost/{inc => common}/utils.h (100%) create mode 100644 src/corehost/corehost.cpp diff --git a/scripts/compile/compile-corehost.ps1 b/scripts/compile/compile-corehost.ps1 index d27564476..572087d63 100644 --- a/scripts/compile/compile-corehost.ps1 +++ b/scripts/compile/compile-corehost.ps1 @@ -26,11 +26,16 @@ try { if (!(Test-Path $HostDir)) { mkdir $HostDir | Out-Null } - cp "$RepoRoot\src\corehost\cmake\$Rid\$Configuration\corehost.exe" $HostDir + cp "$RepoRoot\src\corehost\cmake\$Rid\cli\$Configuration\corehost.exe" $HostDir + cp "$RepoRoot\src\corehost\cmake\$Rid\cli\dll\$Configuration\clihost.dll" $HostDir - if (Test-Path "$RepoRoot\src\corehost\cmake\$Rid\$Configuration\corehost.pdb") + if (Test-Path "$RepoRoot\src\corehost\cmake\$Rid\cli\$Configuration\corehost.pdb") { - cp "$RepoRoot\src\corehost\cmake\$Rid\$Configuration\corehost.pdb" $HostDir + cp "$RepoRoot\src\corehost\cmake\$Rid\cli\$Configuration\corehost.pdb" $HostDir + } + if (Test-Path "$RepoRoot\src\corehost\cmake\$Rid\cli\dll\$Configuration\clihost.pdb") + { + cp "$RepoRoot\src\corehost\cmake\$Rid\cli\dll\$Configuration\clihost.pdb" $HostDir } } finally { popd diff --git a/scripts/compile/compile-corehost.sh b/scripts/compile/compile-corehost.sh index e90f8c9f5..91926c579 100755 --- a/scripts/compile/compile-corehost.sh +++ b/scripts/compile/compile-corehost.sh @@ -24,5 +24,11 @@ make # Publish to artifacts [ -d "$HOST_DIR" ] || mkdir -p $HOST_DIR -cp "$REPOROOT/src/corehost/cmake/$RID/corehost" $HOST_DIR +if [[ "$OSNAME" == "osx" ]]; then + COREHOST_LIBNAME=libclihost.dylib +else + COREHOST_LIBNAME=libclihost.so +fi +cp "$REPOROOT/src/corehost/cmake/$RID/cli/corehost" $HOST_DIR +cp "$REPOROOT/src/corehost/cmake/$RID/cli/dll/${COREHOST_LIBNAME}" $HOST_DIR popd 2>&1 >/dev/null diff --git a/src/corehost/CMakeLists.txt b/src/corehost/CMakeLists.txt index 8f9657fe1..0a76ce4f4 100644 --- a/src/corehost/CMakeLists.txt +++ b/src/corehost/CMakeLists.txt @@ -1,43 +1,2 @@ -# 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 (corehost) -set (CMAKE_CXX_STANDARD 11) -include_directories(inc) - -# CMake does not recommend using globbing since it messes with the freshness checks -set(SOURCES - src/args.cpp - src/main.cpp - src/deps_resolver.cpp - src/trace.cpp - src/utils.cpp - src/coreclr.cpp - src/servicing_index.cpp - - inc/args.h - inc/pal.h - inc/servicing_index.h - inc/deps_resolver.h - inc/trace.h - inc/coreclr.h - inc/utils.h) - -if(WIN32) - list(APPEND SOURCES src/pal.windows.cpp) -else() - list(APPEND SOURCES src/pal.unix.cpp) -endif() - -add_executable(corehost ${SOURCES}) - -# Older CMake doesn't support CMAKE_CXX_STANDARD and GCC/Clang need a switch to enable C++ 11 -if(${CMAKE_CXX_COMPILER_ID} MATCHES "(Clang|GNU)") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") -endif() - -if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") - add_definitions(-D__LINUX__) - target_link_libraries (corehost "dl") -endif() +add_subdirectory(cli) diff --git a/src/corehost/cli/CMakeLists.txt b/src/corehost/cli/CMakeLists.txt new file mode 100644 index 000000000..ecc504b46 --- /dev/null +++ b/src/corehost/cli/CMakeLists.txt @@ -0,0 +1,47 @@ +# 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 (corehost) + +if(WIN32) +set(CMAKE_CXX_FLAGS_DEBUG "/MTd") +set(CMAKE_CXX_FLAGS_RELEASE "/MT") +endif() + +set (CMAKE_CXX_STANDARD 11) + +include_directories(../common) + +# CMake does not recommend using globbing since it messes with the freshness checks +set(SOURCES + ../corehost.cpp + + ../common/trace.cpp + ../common/utils.cpp + + args.cpp + clihost.cpp + coreclr.cpp + deps_resolver.cpp + servicing_index.cpp) + +if(WIN32) + list(APPEND SOURCES ../common/pal.windows.cpp) +else() + list(APPEND SOURCES ../common/pal.unix.cpp) +endif() + +add_executable(corehost ${SOURCES}) + +# Older CMake doesn't support CMAKE_CXX_STANDARD and GCC/Clang need a switch to enable C++ 11 +if(${CMAKE_CXX_COMPILER_ID} MATCHES "(Clang|GNU)") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") +endif() + +if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") + add_definitions(-D__LINUX__) + target_link_libraries (corehost "dl") +endif() + +add_subdirectory(dll) diff --git a/src/corehost/src/args.cpp b/src/corehost/cli/args.cpp similarity index 90% rename from src/corehost/src/args.cpp rename to src/corehost/cli/args.cpp index f6094de4a..49895e34c 100644 --- a/src/corehost/src/args.cpp +++ b/src/corehost/cli/args.cpp @@ -26,18 +26,6 @@ void display_help() bool parse_arguments(const int argc, const pal::char_t* argv[], arguments_t& args) { - // Read trace environment variable - pal::string_t trace_str; - if (pal::getenv(_X("COREHOST_TRACE"), &trace_str)) - { - auto trace_val = pal::xtoi(trace_str.c_str()); - if (trace_val > 0) - { - trace::enable(); - trace::info(_X("Tracing enabled")); - } - } - // Get the full name of the application if (!pal::get_own_executable_path(&args.own_path) || !pal::realpath(&args.own_path)) { diff --git a/src/corehost/inc/args.h b/src/corehost/cli/args.h similarity index 100% rename from src/corehost/inc/args.h rename to src/corehost/cli/args.h diff --git a/src/corehost/src/main.cpp b/src/corehost/cli/clihost.cpp similarity index 93% rename from src/corehost/src/main.cpp rename to src/corehost/cli/clihost.cpp index ae586eb13..c0c13e207 100644 --- a/src/corehost/src/main.cpp +++ b/src/corehost/cli/clihost.cpp @@ -8,16 +8,18 @@ #include "utils.h" #include "coreclr.h" +SHARED_API const pal::char_t* g_LIBHOST_NAME = MAKE_LIBNAME("clihost"); + enum StatusCode { - Failure = 0x87FF0000, - InvalidArgFailure = Failure | 0x1, - CoreClrResolveFailure = Failure | 0x2, - CoreClrBindFailure = Failure | 0x3, - CoreClrInitFailure = Failure | 0x4, - CoreClrExeFailure = Failure | 0x5, - ResolverInitFailure = Failure | 0x6, - ResolverResolveFailure = Failure | 0x7, + // 0x80 prefix to distinguish from corehost main's error codes. + InvalidArgFailure = 0x81, + CoreClrResolveFailure = 0x82, + CoreClrBindFailure = 0x83, + CoreClrInitFailure = 0x84, + CoreClrExeFailure = 0x85, + ResolverInitFailure = 0x86, + ResolverResolveFailure = 0x87, }; // ---------------------------------------------------------------------- @@ -223,11 +225,7 @@ int run(const arguments_t& args, const pal::string_t& clr_path) return exit_code; } -#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 +SHARED_API int corehost_main(const int argc, const pal::char_t* argv[]) { // Take care of arguments arguments_t args; diff --git a/src/corehost/src/coreclr.cpp b/src/corehost/cli/coreclr.cpp similarity index 100% rename from src/corehost/src/coreclr.cpp rename to src/corehost/cli/coreclr.cpp diff --git a/src/corehost/inc/coreclr.h b/src/corehost/cli/coreclr.h similarity index 100% rename from src/corehost/inc/coreclr.h rename to src/corehost/cli/coreclr.h diff --git a/src/corehost/src/deps_resolver.cpp b/src/corehost/cli/deps_resolver.cpp similarity index 100% rename from src/corehost/src/deps_resolver.cpp rename to src/corehost/cli/deps_resolver.cpp diff --git a/src/corehost/inc/deps_resolver.h b/src/corehost/cli/deps_resolver.h similarity index 100% rename from src/corehost/inc/deps_resolver.h rename to src/corehost/cli/deps_resolver.h diff --git a/src/corehost/cli/dll/CMakeLists.txt b/src/corehost/cli/dll/CMakeLists.txt new file mode 100644 index 000000000..649be8aa3 --- /dev/null +++ b/src/corehost/cli/dll/CMakeLists.txt @@ -0,0 +1,30 @@ +# 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(clihost) + +include_directories(../../common) + +# CMake does not recommend using globbing since it messes with the freshness checks +set(SOURCES + ../../common/trace.cpp + ../../common/utils.cpp + + ../args.cpp + ../clihost.cpp + ../coreclr.cpp + ../deps_resolver.cpp + ../servicing_index.cpp) + + +if(WIN32) + list(APPEND SOURCES ../../common/pal.windows.cpp) +else() + list(APPEND SOURCES ../../common/pal.unix.cpp) +endif() + +add_definitions(-DCOREHOST_MAKE_DLL=1) + +add_library(clihost SHARED ${SOURCES}) + diff --git a/src/corehost/src/servicing_index.cpp b/src/corehost/cli/servicing_index.cpp similarity index 100% rename from src/corehost/src/servicing_index.cpp rename to src/corehost/cli/servicing_index.cpp diff --git a/src/corehost/inc/servicing_index.h b/src/corehost/cli/servicing_index.h similarity index 100% rename from src/corehost/inc/servicing_index.h rename to src/corehost/cli/servicing_index.h diff --git a/src/corehost/inc/pal.h b/src/corehost/common/pal.h similarity index 90% rename from src/corehost/inc/pal.h rename to src/corehost/common/pal.h index 6d6521045..2e6536744 100644 --- a/src/corehost/inc/pal.h +++ b/src/corehost/common/pal.h @@ -49,13 +49,15 @@ #endif #if defined(_WIN32) -#define LIBCORECLR_NAME L"coreclr.dll" +#define MAKE_LIBNAME(NAME) (_X(NAME) _X(".dll")) #elif defined(__APPLE__) -#define LIBCORECLR_NAME "libcoreclr.dylib" +#define MAKE_LIBNAME(NAME) (_X("lib") _X(NAME) _X(".dylib")) #else -#define LIBCORECLR_NAME "libcoreclr.so" +#define MAKE_LIBNAME(NAME) (_X("lib") _X(NAME) _X(".so")) #endif +#define LIBCORECLR_NAME MAKE_LIBNAME("coreclr") + #if !defined(PATH_MAX) && !defined(_WIN32) #define PATH_MAX 4096 #endif @@ -64,6 +66,11 @@ namespace pal { #if defined(_WIN32) + #ifdef COREHOST_MAKE_DLL + #define SHARED_API extern "C" __declspec(dllexport) + #else + #define SHARED_API + #endif typedef wchar_t char_t; typedef std::wstring string_t; @@ -89,6 +96,12 @@ namespace pal void to_palstring(const char* str, pal::string_t* out); void to_stdstring(const pal::char_t* str, std::string* out); #else + #ifdef COREHOST_MAKE_DLL + #define SHARED_API extern "C" + #else + #define SHARED_API + #endif + typedef char char_t; typedef std::string string_t; typedef std::stringstream stringstream_t; diff --git a/src/corehost/src/pal.unix.cpp b/src/corehost/common/pal.unix.cpp similarity index 96% rename from src/corehost/src/pal.unix.cpp rename to src/corehost/common/pal.unix.cpp index bc7cb74a2..9e943208e 100644 --- a/src/corehost/src/pal.unix.cpp +++ b/src/corehost/common/pal.unix.cpp @@ -117,17 +117,18 @@ bool pal::get_own_executable_path(pal::string_t* recv) } #endif +// Returns true only if an env variable can be read successfully to be non-empty. bool pal::getenv(const pal::char_t* name, pal::string_t* recv) { + recv->clear(); + auto result = ::getenv(name); if (result != nullptr) { recv->assign(result); } - // We don't return false. Windows does have a concept of an error reading the variable, - // but Unix just returns null, which we treat as the variable not existing. - return true; + return (recv->length() > 0); } bool pal::realpath(pal::string_t* path) diff --git a/src/corehost/src/pal.windows.cpp b/src/corehost/common/pal.windows.cpp similarity index 92% rename from src/corehost/src/pal.windows.cpp rename to src/corehost/common/pal.windows.cpp index 7ce29cc5c..d032ab7bc 100644 --- a/src/corehost/src/pal.windows.cpp +++ b/src/corehost/common/pal.windows.cpp @@ -36,7 +36,7 @@ bool pal::load_library(const char_t* path, dll_t* dll) *dll = ::LoadLibraryW(path); if (*dll == nullptr) { - trace::error(_X("Failed to load coreclr.dll from %s, HRESULT: 0x%X"), path, HRESULT_FROM_WIN32(GetLastError())); + trace::error(_X("Failed to load the dll from %s, HRESULT: 0x%X"), path, HRESULT_FROM_WIN32(GetLastError())); return false; } @@ -85,18 +85,19 @@ bool pal::is_path_rooted(const string_t& path) return path.length() >= 2 && path[1] == L':'; } +// Returns true only if an env variable can be read successfully to be non-empty. bool pal::getenv(const char_t* name, string_t* recv) { + recv->clear(); + auto length = ::GetEnvironmentVariableW(name, nullptr, 0); if (length == 0) { auto err = GetLastError(); - if (err == ERROR_ENVVAR_NOT_FOUND) + if (err != ERROR_ENVVAR_NOT_FOUND) { - // Leave the receiver empty and return success - return true; + trace::error(_X("Failed to read enviroment variable '%s', HRESULT: 0x%X"), name, HRESULT_FROM_WIN32(GetLastError())); } - trace::error(_X("Failed to read enviroment variable '%s', HRESULT: 0x%X"), name, HRESULT_FROM_WIN32(GetLastError())); return false; } auto buf = new char_t[length]; diff --git a/src/corehost/src/trace.cpp b/src/corehost/common/trace.cpp similarity index 100% rename from src/corehost/src/trace.cpp rename to src/corehost/common/trace.cpp diff --git a/src/corehost/inc/trace.h b/src/corehost/common/trace.h similarity index 100% rename from src/corehost/inc/trace.h rename to src/corehost/common/trace.h diff --git a/src/corehost/src/utils.cpp b/src/corehost/common/utils.cpp similarity index 100% rename from src/corehost/src/utils.cpp rename to src/corehost/common/utils.cpp diff --git a/src/corehost/inc/utils.h b/src/corehost/common/utils.h similarity index 100% rename from src/corehost/inc/utils.h rename to src/corehost/common/utils.h diff --git a/src/corehost/corehost.cpp b/src/corehost/corehost.cpp new file mode 100644 index 000000000..d70a86835 --- /dev/null +++ b/src/corehost/corehost.cpp @@ -0,0 +1,149 @@ +// 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 "common/trace.h" +#include "common/pal.h" +#include "common/utils.h" + +extern const pal::char_t* g_LIBHOST_NAME; +extern int corehost_main(const int argc, const pal::char_t* argv[]); + +namespace +{ +enum StatusCode +{ + Success = 0, + CoreHostLibLoadFailure = 0x41, + CoreHostLibMissingFailure = 0x42, + CoreHostEntryPointFailure = 0x43, + CoreHostCurExeFindFailure = 0x44, +}; + +typedef int (*corehost_main_fn) (const int argc, const pal::char_t* argv[]); + +// ----------------------------------------------------------------------------- +// Load the corehost library from the path specified +// +// Parameters: +// lib_dir - dir path to the corehost library +// h_host - handle to the library which will be kept live +// main_fn - Contains the entrypoint "corehost_main" when returns success. +// +// Returns: +// Non-zero exit code on failure. "main_fn" contains "corehost_main" +// entrypoint on success. +// +StatusCode load_host_lib(const pal::string_t& lib_dir, pal::dll_t* h_host, corehost_main_fn* main_fn) +{ + pal::string_t host_path = lib_dir; + append_path(&host_path, g_LIBHOST_NAME); + + // Missing library + if (!pal::file_exists(host_path)) + { + return StatusCode::CoreHostLibMissingFailure; + } + + // Load library + if (!pal::load_library(host_path.c_str(), h_host)) + { + trace::info(_X("Load library of %s failed"), host_path.c_str()); + return StatusCode::CoreHostLibLoadFailure; + } + + // Obtain entrypoint symbol + *main_fn = (corehost_main_fn) pal::get_symbol(*h_host, "corehost_main"); + + return (*main_fn != nullptr) + ? StatusCode::Success + : StatusCode::CoreHostEntryPointFailure; +} + +// +// Turn on tracing for the corehost based on "COREHOST_TRACE" env. +// +void setup_tracing() +{ + // Read trace environment variable + pal::string_t trace_str; + if (!pal::getenv(_X("COREHOST_TRACE"), &trace_str)) + { + return; + } + + auto trace_val = pal::xtoi(trace_str.c_str()); + if (trace_val > 0) + { + trace::enable(); + trace::info(_X("Tracing enabled")); + } +} + +}; // end of anonymous namespace + +#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 +{ + setup_tracing(); + + pal::dll_t corehost; + +#ifdef COREHOST_PACKAGE_SERVICING + // No custom host asked, so load the corehost if serviced first. + pal::string_t svc_dir; + if (pal::getenv(_X("DOTNET_SERVICING"), &svc_dir)) + { + pal::string_t path = svc_dir; + append_path(&path, COREHOST_PACKAGE_NAME); + append_path(&path, COREHOST_PACKAGE_VERSION); + append_path(&path, COREHOST_PACKAGE_COREHOST_RELATIVE_DIR); + + corehost_main_fn host_main; + StatusCode code = load_host_lib(path, &corehost, &host_main); + if (code != StatusCode::Success) + { + trace::info(_X("Failed to load host library from servicing dir: %s; Status=%08X"), path.c_str(), code); + // Ignore all errors for the servicing case, and proceed to the next step. + } + else + { + trace::info(_X("Calling host entrypoint from library at servicing dir %s"), path.c_str()); + return host_main(argc, argv); + } + } +#endif + + // Get current path to look for the library app locally. + pal::string_t own_path; + if (!pal::get_own_executable_path(&own_path) || !pal::realpath(&own_path)) + { + trace::error(_X("Failed to locate current executable")); + return StatusCode::CoreHostCurExeFindFailure; + } + + // Local load of the corehost library. + auto own_dir = get_directory(own_path); + + corehost_main_fn host_main; + StatusCode code = load_host_lib(own_dir, &corehost, &host_main); + switch (code) + { + // Success, call the entrypoint. + case StatusCode::Success: + trace::info(_X("Calling host entrypoint from library at own dir %s"), own_dir.c_str()); + return host_main(argc, argv); + + // DLL missing is not fatal. + case StatusCode::CoreHostLibMissingFailure: + trace::info(_X("Calling statically linked entrypoint from own exe")); + return corehost_main(argc, argv); + + // Some other fatal error. + default: + trace::error(_X("Error loading the host library from own dir: %s; Status=%08X"), own_dir.c_str(), code); + return code; + } +}