Merge pull request #681 from schellap/refac

Refactor and build library for corehost
This commit is contained in:
Senthil 2016-01-07 02:58:23 -08:00
commit 697debb5d4
22 changed files with 279 additions and 82 deletions

View file

@ -26,11 +26,16 @@ try {
if (!(Test-Path $HostDir)) { if (!(Test-Path $HostDir)) {
mkdir $HostDir | Out-Null 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 { } finally {
popd popd

View file

@ -24,5 +24,11 @@ make
# Publish to artifacts # Publish to artifacts
[ -d "$HOST_DIR" ] || mkdir -p $HOST_DIR [ -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 popd 2>&1 >/dev/null

View file

@ -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) cmake_minimum_required (VERSION 2.6)
project (corehost) add_subdirectory(cli)
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()

View file

@ -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)

View file

@ -26,18 +26,6 @@ void display_help()
bool parse_arguments(const int argc, const pal::char_t* argv[], arguments_t& args) 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 // Get the full name of the application
if (!pal::get_own_executable_path(&args.own_path) || !pal::realpath(&args.own_path)) if (!pal::get_own_executable_path(&args.own_path) || !pal::realpath(&args.own_path))
{ {

View file

@ -8,16 +8,18 @@
#include "utils.h" #include "utils.h"
#include "coreclr.h" #include "coreclr.h"
SHARED_API const pal::char_t* g_LIBHOST_NAME = MAKE_LIBNAME("clihost");
enum StatusCode enum StatusCode
{ {
Failure = 0x87FF0000, // 0x80 prefix to distinguish from corehost main's error codes.
InvalidArgFailure = Failure | 0x1, InvalidArgFailure = 0x81,
CoreClrResolveFailure = Failure | 0x2, CoreClrResolveFailure = 0x82,
CoreClrBindFailure = Failure | 0x3, CoreClrBindFailure = 0x83,
CoreClrInitFailure = Failure | 0x4, CoreClrInitFailure = 0x84,
CoreClrExeFailure = Failure | 0x5, CoreClrExeFailure = 0x85,
ResolverInitFailure = Failure | 0x6, ResolverInitFailure = 0x86,
ResolverResolveFailure = Failure | 0x7, ResolverResolveFailure = 0x87,
}; };
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
@ -223,11 +225,7 @@ int run(const arguments_t& args, const pal::string_t& clr_path)
return exit_code; return exit_code;
} }
#if defined(_WIN32) SHARED_API int corehost_main(const int argc, const pal::char_t* argv[])
int __cdecl wmain(const int argc, const pal::char_t* argv[])
#else
int main(const int argc, const pal::char_t* argv[])
#endif
{ {
// Take care of arguments // Take care of arguments
arguments_t args; arguments_t args;

View file

@ -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})

View file

@ -49,13 +49,15 @@
#endif #endif
#if defined(_WIN32) #if defined(_WIN32)
#define LIBCORECLR_NAME L"coreclr.dll" #define MAKE_LIBNAME(NAME) (_X(NAME) _X(".dll"))
#elif defined(__APPLE__) #elif defined(__APPLE__)
#define LIBCORECLR_NAME "libcoreclr.dylib" #define MAKE_LIBNAME(NAME) (_X("lib") _X(NAME) _X(".dylib"))
#else #else
#define LIBCORECLR_NAME "libcoreclr.so" #define MAKE_LIBNAME(NAME) (_X("lib") _X(NAME) _X(".so"))
#endif #endif
#define LIBCORECLR_NAME MAKE_LIBNAME("coreclr")
#if !defined(PATH_MAX) && !defined(_WIN32) #if !defined(PATH_MAX) && !defined(_WIN32)
#define PATH_MAX 4096 #define PATH_MAX 4096
#endif #endif
@ -64,6 +66,11 @@
namespace pal namespace pal
{ {
#if defined(_WIN32) #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 wchar_t char_t;
typedef std::wstring string_t; typedef std::wstring string_t;
@ -89,6 +96,12 @@ namespace pal
void to_palstring(const char* str, pal::string_t* out); void to_palstring(const char* str, pal::string_t* out);
void to_stdstring(const pal::char_t* str, std::string* out); void to_stdstring(const pal::char_t* str, std::string* out);
#else #else
#ifdef COREHOST_MAKE_DLL
#define SHARED_API extern "C"
#else
#define SHARED_API
#endif
typedef char char_t; typedef char char_t;
typedef std::string string_t; typedef std::string string_t;
typedef std::stringstream stringstream_t; typedef std::stringstream stringstream_t;

View file

@ -117,17 +117,18 @@ bool pal::get_own_executable_path(pal::string_t* recv)
} }
#endif #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) bool pal::getenv(const pal::char_t* name, pal::string_t* recv)
{ {
recv->clear();
auto result = ::getenv(name); auto result = ::getenv(name);
if (result != nullptr) if (result != nullptr)
{ {
recv->assign(result); recv->assign(result);
} }
// We don't return false. Windows does have a concept of an error reading the variable, return (recv->length() > 0);
// but Unix just returns null, which we treat as the variable not existing.
return true;
} }
bool pal::realpath(pal::string_t* path) bool pal::realpath(pal::string_t* path)

View file

@ -36,7 +36,7 @@ bool pal::load_library(const char_t* path, dll_t* dll)
*dll = ::LoadLibraryW(path); *dll = ::LoadLibraryW(path);
if (*dll == nullptr) 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; return false;
} }
@ -85,18 +85,19 @@ bool pal::is_path_rooted(const string_t& path)
return path.length() >= 2 && path[1] == L':'; 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) bool pal::getenv(const char_t* name, string_t* recv)
{ {
recv->clear();
auto length = ::GetEnvironmentVariableW(name, nullptr, 0); auto length = ::GetEnvironmentVariableW(name, nullptr, 0);
if (length == 0) if (length == 0)
{ {
auto err = GetLastError(); auto err = GetLastError();
if (err == ERROR_ENVVAR_NOT_FOUND) if (err != ERROR_ENVVAR_NOT_FOUND)
{ {
// Leave the receiver empty and return success trace::error(_X("Failed to read enviroment variable '%s', HRESULT: 0x%X"), name, HRESULT_FROM_WIN32(GetLastError()));
return true;
} }
trace::error(_X("Failed to read enviroment variable '%s', HRESULT: 0x%X"), name, HRESULT_FROM_WIN32(GetLastError()));
return false; return false;
} }
auto buf = new char_t[length]; auto buf = new char_t[length];

149
src/corehost/corehost.cpp Normal file
View file

@ -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;
}
}