updates to CMakeFile.txt
This commit is contained in:
commit
8bf19f7144
14 changed files with 869 additions and 8 deletions
|
@ -5,14 +5,28 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
|||
|
||||
#include gtest
|
||||
include_directories(../ext-src/gtest/fused-src impl)
|
||||
link_directories(${monad_native_BINARY_DIR})
|
||||
|
||||
set(SOURCE_FILES main.cpp tests/test-getcurrentprocessid.cpp impl/getcurrentprocessorid.cpp tests/test-getcpinfo.cpp impl/getcpinfo.cpp
|
||||
../ext-src/gtest/fused-src/gtest/gtest-all.cc)
|
||||
add_executable(monad_native ${SOURCE_FILES})
|
||||
# source file definitions
|
||||
set(LIB_SOURCE_FILES impl/getcurrentprocessorid.cpp impl/getusername.cpp impl/terminal.cpp)
|
||||
set(HOST_COMMON_SOURCE_FILES host/common/coreclrutil.cpp)
|
||||
set(HOST_COMMON_TEST_SOURCE_FILES tests/host/test-hostutil.cpp)
|
||||
set(TEST_SOURCE_FILES tests/test-getcurrentprocessid.cpp ${HOST_COMMON_SOURCE_FILES} ${HOST_COMMON_TEST_SOURCE_FILES})
|
||||
set(SOURCE_FILES main.cpp ../ext-src/gtest/fused-src/gtest/gtest-all.cc)
|
||||
SET(HOST_CMDLINE_SOURCE_FILES host/cmdline/main.cpp ${HOST_COMMON_SOURCE_FILES})
|
||||
|
||||
# add pthread
|
||||
# target definitions
|
||||
add_library(ps SHARED ${LIB_SOURCE_FILES})
|
||||
add_executable(monad_native ${SOURCE_FILES} ${TEST_SOURCE_FILES})
|
||||
add_executable(host_cmdline ${HOST_CMDLINE_SOURCE_FILES})
|
||||
|
||||
# add pthread and other libs
|
||||
find_package(Threads)
|
||||
target_link_libraries(monad_native ${CMAKE_THREAD_LIBS_INIT})
|
||||
|
||||
target_link_libraries(monad_native ${CMAKE_THREAD_LIBS_INIT} ps)
|
||||
target_link_libraries(host_cmdline dl icuuc)
|
||||
|
||||
# target specific include directories
|
||||
target_include_directories(monad_native PRIVATE host)
|
||||
target_include_directories(host_cmdline PRIVATE host)
|
||||
|
||||
|
||||
|
|
446
host/cmdline/main.cpp
Normal file
446
host/cmdline/main.cpp
Normal file
|
@ -0,0 +1,446 @@
|
|||
#include <string>
|
||||
#include <iostream>
|
||||
#include "common/coreclrutil.h"
|
||||
#include "common/hostutil.h"
|
||||
#include <limits.h>
|
||||
#include <dlfcn.h>
|
||||
#include <unicode/utypes.h>
|
||||
#include <unicode/ucnv.h>
|
||||
#include <unicode/ustring.h>
|
||||
#include <unicode/uchar.h>
|
||||
|
||||
namespace Cmdline
|
||||
{
|
||||
|
||||
void printHelp()
|
||||
{
|
||||
std::cerr << "PS CoreCLR host" << std::endl;
|
||||
std::cerr << "Usage: host_cmdline [-c coreclr_path] [-alc load_context_assembly] [-s search_paths]" << std::endl;
|
||||
std::cerr << " [-b base_path] assembly_name type_name function_name [...]" << std::endl;
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "What it does:" << std::endl;
|
||||
std::cerr << "- by default the host assumes that CoreCLR is located in the same folder" << std::endl;
|
||||
std::cerr << " as host_cmdline" << std::endl;
|
||||
std::cerr << " + this behavior can be overridden with the -c command line argument" << std::endl;
|
||||
std::cerr << "- by default the host assumes that the assembly named" << std::endl;
|
||||
std::cerr << " Microsoft.PowerShell.CoreCLR.AssemblyLoadContext is part of the" << std::endl;
|
||||
std::cerr << " platform assemblies" << std::endl;
|
||||
std::cerr << " + a custom assembly containing the PowerShellAssemblyLoadContext can" << std::endl;
|
||||
std::cerr << " be provided with the -alc command line argument" << std::endl;
|
||||
std::cerr << "- all additional parameters at the end of the command line are forwarded" << std::endl;
|
||||
std::cerr << " to the specified entry function in the assembly" << std::endl;
|
||||
std::cerr << "- the host will execute the specified entry function in the specified assembly" << std::endl;
|
||||
std::cerr << " + this assembly has to be located in the search path" << std::endl;
|
||||
std::cerr << "- by default the host will add the current working directory to the assembly search path" << std::endl;
|
||||
std::cerr << " + this can be overridden with the -s command line argument" << std::endl;
|
||||
std::cerr << " + if -c is specified, it will be added to the search path instead of the current directory" << std::endl;
|
||||
std::cerr << "- by default the host assumes the PS base path for the assembly load context is the current" << std::endl;
|
||||
std::cerr << " working directory" << std::endl;
|
||||
std::cerr << " + this can be overridden with the -b command line argument" << std::endl;
|
||||
std::cerr << "- the function signature of the function that gets executed must be:" << std::endl;
|
||||
std::cerr << " public static int UnmanagedMain(int argc, [MarshalAs(UnmanagedType.LPArray,ArraySubType=UnmanagedType.LPStr,SizeParamIndex=0)] String[] argv)" << std::endl;
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "Options:" << std::endl;
|
||||
std::cerr << "-c, --clr-path path to libcoreclr.so and the managed CLR assemblies" << std::endl;
|
||||
std::cerr << "-alc path to a dll containing Microsoft.PowerShell.CoreCLR.AssemblyLoadContext" << std::endl;
|
||||
std::cerr << "-s a list of assembly search paths, separated by :" << std::endl;
|
||||
std::cerr << "-b the powershell assembly base path" << std::endl;
|
||||
std::cerr << "-v verbose output, show paths" << std::endl;
|
||||
std::cerr << "-tpa additional list of trusted platform assemblies, this references dll and exe files" << std::endl;
|
||||
std::cerr << " separated by :" << std::endl;
|
||||
std::cerr << " unless part of the same folder as CoreCLR, the main assembly referenced with the assembly_name" << std::endl;
|
||||
std::cerr << " argument, must always be added to the TPA list with this parameter" << std::endl;
|
||||
std::cerr << "assembly_name the assembly name of the assembly to execute" << std::endl;
|
||||
std::cerr << " must be available in the search path" << std::endl;
|
||||
std::cerr << "type_name the type name where the function can be found" << std::endl;
|
||||
std::cerr << "function_name the function to execute (must have the function signature described above!)" << std::endl;
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "Example:" << std::endl;
|
||||
std::cerr << "./host_cmdline -c /test/coreclr -alc /test/ps/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext.dll -s /test/ps -b /test/ps -tpa /test/ps/powershell-simple.exe 'powershell-simple, version=1.0.0.0, culture=neutral, PublicKeyToken=null' 'ps_hello_world.Program' 'UnmanagedMain' 'get-process'" << std::endl;
|
||||
}
|
||||
|
||||
struct Args
|
||||
{
|
||||
Args() :
|
||||
argc(0),
|
||||
argv(nullptr),
|
||||
verbose(false)
|
||||
{
|
||||
}
|
||||
|
||||
std::string clrPath;
|
||||
std::string assemblyLoadContextFilePath;
|
||||
std::string searchPaths;
|
||||
std::string basePath;
|
||||
std::string tpaList;
|
||||
std::string entryAssemblyName;
|
||||
std::string entryTypeName;
|
||||
std::string entryFunctionName;
|
||||
int argc;
|
||||
char** argv;
|
||||
bool verbose;
|
||||
|
||||
void debugPrint() const
|
||||
{
|
||||
std::cerr << "Args:" << std::endl;
|
||||
std::cerr << "- clrPath " << clrPath << std::endl;
|
||||
std::cerr << "- assemblyLoadContextFilePath " << assemblyLoadContextFilePath << std::endl;
|
||||
std::cerr << "- searchPaths " << searchPaths << std::endl;
|
||||
std::cerr << "- basePath " << basePath << std::endl;
|
||||
std::cerr << "- tpaList " << tpaList << std::endl;
|
||||
std::cerr << "- entryAssemblyName " << entryAssemblyName << std::endl;
|
||||
std::cerr << "- entryTypeName " << entryTypeName << std::endl;
|
||||
std::cerr << "- entryFunctionName " << entryFunctionName << std::endl;
|
||||
std::cerr << "- argc " << argc << std::endl;
|
||||
std::cerr << "- verbose " << (verbose ? "true" : "false") << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
// this is implemented without any 3rd party lib to keep the list
|
||||
// of dependencies low
|
||||
bool parseCmdline(const int argc, char** argv, Args& args)
|
||||
{
|
||||
if (argc <= 1)
|
||||
{
|
||||
std::cerr << "error: missing arguments" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 1; i < argc; ++i)
|
||||
{
|
||||
const std::string arg = argv[i];
|
||||
const bool hasNextArg = i+1 < argc;
|
||||
const std::string nextArg = hasNextArg ? std::string(argv[i+1]) : std::string("");
|
||||
|
||||
if (hasNextArg && (arg == "-c" || arg == "--clr-path"))
|
||||
{
|
||||
args.clrPath = nextArg;
|
||||
++i;
|
||||
}
|
||||
else if (hasNextArg && arg == "-alc")
|
||||
{
|
||||
args.assemblyLoadContextFilePath = nextArg;
|
||||
++i;
|
||||
}
|
||||
else if (hasNextArg && arg == "-s")
|
||||
{
|
||||
args.searchPaths = nextArg;
|
||||
++i;
|
||||
}
|
||||
else if (hasNextArg && arg == "-b")
|
||||
{
|
||||
args.basePath = nextArg;
|
||||
++i;
|
||||
}
|
||||
else if (hasNextArg && arg == "-tpa")
|
||||
{
|
||||
args.tpaList = nextArg;
|
||||
++i;
|
||||
}
|
||||
else if (arg == "-v")
|
||||
{
|
||||
args.verbose = true;
|
||||
}
|
||||
else if (args.entryAssemblyName == "")
|
||||
{
|
||||
args.entryAssemblyName = arg;
|
||||
}
|
||||
else if (args.entryTypeName == "")
|
||||
{
|
||||
args.entryTypeName = arg;
|
||||
}
|
||||
else if (args.entryFunctionName == "")
|
||||
{
|
||||
args.entryFunctionName = arg;
|
||||
}
|
||||
else
|
||||
{
|
||||
// forward command line parameters
|
||||
args.argc = argc-i;
|
||||
args.argv = &argv[i];
|
||||
|
||||
// explicitly break here because the lines above consume all remaining arguments
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// check for mandatory parameters
|
||||
if (args.entryAssemblyName == "")
|
||||
{
|
||||
std::cerr << "error: assembly_name argument missing" << std::endl;
|
||||
}
|
||||
if (args.entryTypeName == "")
|
||||
{
|
||||
std::cerr << "error: type_name argument missing" << std::endl;
|
||||
}
|
||||
if (args.entryFunctionName == "")
|
||||
{
|
||||
std::cerr << "error: function_name argument missing" << std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
// parse the command line arguments
|
||||
Cmdline::Args args;
|
||||
if (!Cmdline::parseCmdline(argc,argv,args))
|
||||
{
|
||||
Cmdline::printHelp();
|
||||
return 1;
|
||||
}
|
||||
if (args.verbose)
|
||||
args.debugPrint();
|
||||
|
||||
// get the absolute path of the current executable
|
||||
std::string currentExeAbsolutePath;
|
||||
if (!CoreCLRUtil::GetAbsolutePath(argv[0],currentExeAbsolutePath))
|
||||
{
|
||||
std::cerr << "could not get absolute path of current executable" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
if (args.verbose)
|
||||
std::cerr << "currentExeAbsolutePath=" << currentExeAbsolutePath << std::endl;
|
||||
|
||||
// CLR absolute folder path
|
||||
//
|
||||
// This path is created from the location of this executable or a path
|
||||
// specified with the -c command line argument
|
||||
std::string clrAbsolutePath;
|
||||
const char* clrPathArg = args.clrPath == "" ? nullptr : args.clrPath.c_str();
|
||||
if (!CoreCLRUtil::GetClrFilesAbsolutePath(currentExeAbsolutePath.c_str(),clrPathArg,clrAbsolutePath))
|
||||
{
|
||||
std::cerr << "could not find absolute CLR path" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
if (args.verbose)
|
||||
std::cerr << "clrAbsolutePath=" << clrAbsolutePath << std::endl;
|
||||
|
||||
// the path to the CoreCLR library
|
||||
//
|
||||
// This is typically libcoreclr.so on Linux and libcoreclr.dylib on Mac
|
||||
|
||||
std::string coreClrDllPath = clrAbsolutePath + "/" + CoreCLRUtil::coreClrDll;
|
||||
if (coreClrDllPath.size() >= PATH_MAX)
|
||||
{
|
||||
std::cerr << "Absolute path to CoreCLR library too long" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
if (args.verbose)
|
||||
std::cerr << "coreClrDllPath: " << coreClrDllPath << std::endl;
|
||||
|
||||
// TPA list
|
||||
//
|
||||
// The list of platform assemblies must include all CoreCLR assemblies
|
||||
// and the Microsoft.PowerShell.CoreCLR.AssemblyLoadContext
|
||||
//
|
||||
// if the -alc parameter was specified, add it to the TPA list here
|
||||
|
||||
std::string tpaList;
|
||||
CoreCLRUtil::AddFilesFromDirectoryToTpaList(clrAbsolutePath.c_str(),tpaList);
|
||||
|
||||
if (args.assemblyLoadContextFilePath != "")
|
||||
{
|
||||
std::string assemblyLoadContextAbsoluteFilePath;
|
||||
if (!CoreCLRUtil::GetAbsolutePath(args.assemblyLoadContextFilePath.c_str(),assemblyLoadContextAbsoluteFilePath))
|
||||
{
|
||||
std::cerr << "Failed to get absolute file path for assembly load context" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
tpaList += ":" + assemblyLoadContextAbsoluteFilePath;
|
||||
}
|
||||
|
||||
// add the -tpa command line argument
|
||||
if (args.tpaList != "")
|
||||
{
|
||||
std::string tpaAbsolutePathList = HostUtil::getAbsolutePathList(args.tpaList);
|
||||
if (tpaAbsolutePathList != "")
|
||||
tpaList += ":" + tpaAbsolutePathList;
|
||||
}
|
||||
|
||||
if (args.verbose)
|
||||
std::cerr << "tpaList: " << tpaList << std::endl;
|
||||
|
||||
// get the absolute path of the current directory
|
||||
|
||||
std::string currentDirAbsolutePath;
|
||||
if (!CoreCLRUtil::GetAbsolutePath(".",currentDirAbsolutePath))
|
||||
{
|
||||
std::cerr << "failed to get the absolute path from current working directory" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// assembly search paths
|
||||
//
|
||||
// add the current directory, and optionally the CoreCLR directory if -c was specified
|
||||
// and anything specified with the -s option
|
||||
|
||||
std::string appPath = currentDirAbsolutePath;
|
||||
if (args.clrPath != "")
|
||||
appPath += ":" + clrAbsolutePath;
|
||||
if (args.searchPaths != "")
|
||||
{
|
||||
std::string searchAbsolutePathList = HostUtil::getAbsolutePathList(args.searchPaths);
|
||||
if (searchAbsolutePathList != "")
|
||||
appPath += ":" + searchAbsolutePathList;
|
||||
}
|
||||
|
||||
if (args.verbose)
|
||||
std::cerr << "appPath: " << appPath << std::endl;
|
||||
|
||||
// search paths for native dlls
|
||||
//
|
||||
// Add both the CoreCLR directory and the regular search paths to this list
|
||||
std::string nativeDllSearchDirs = appPath + ":" + clrAbsolutePath;
|
||||
|
||||
// convert the app base to utf-16
|
||||
//
|
||||
// this is needed as a utf-16 LE string by CoreCLR/PS's assembly load context interface
|
||||
// it is either:
|
||||
// - the current dir's absolute path
|
||||
// - the path specified through the -b argument
|
||||
std::string psBasePath = currentDirAbsolutePath;
|
||||
if (args.basePath != "")
|
||||
{
|
||||
if (!CoreCLRUtil::GetAbsolutePath(args.basePath.c_str(),psBasePath))
|
||||
{
|
||||
std::cerr << "failed to get the absolute path from the base_path argument" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (args.verbose)
|
||||
std::cerr << "psBasePath=" << psBasePath << std::endl;
|
||||
|
||||
// make sure to leave 1 byte at the end for null termination
|
||||
std::basic_string<char16_t> psBasePath16(PATH_MAX+1,0);
|
||||
|
||||
UnicodeString u8str = UnicodeString(psBasePath.c_str(),"UTF-8");
|
||||
int32_t targetSize = u8str.extract(0,u8str.length(),(char*)&psBasePath16[0],(psBasePath16.size()-1)*sizeof(char16_t),"UTF-16LE");
|
||||
psBasePath16.resize(targetSize/sizeof(char16_t)+1);
|
||||
|
||||
// open the shared library
|
||||
void* coreclrLib = dlopen(coreClrDllPath.c_str(), RTLD_NOW|RTLD_LOCAL);
|
||||
if (coreclrLib == nullptr)
|
||||
{
|
||||
char* error = dlerror();
|
||||
std::cerr << "dlopen failed to open the CoreCLR library: " << error << std::endl;
|
||||
return 2;
|
||||
}
|
||||
|
||||
// query the function pointers
|
||||
CoreCLRUtil::InitializeCoreCLRFunction initializeCoreCLR = (CoreCLRUtil::InitializeCoreCLRFunction)dlsym(coreclrLib,"coreclr_initialize");
|
||||
CoreCLRUtil::ExecuteAssemblyFunction executeAssembly = (CoreCLRUtil::ExecuteAssemblyFunction)dlsym(coreclrLib,"coreclr_execute_assembly");
|
||||
CoreCLRUtil::ShutdownCoreCLRFunction shutdownCoreCLR = (CoreCLRUtil::ShutdownCoreCLRFunction)dlsym(coreclrLib,"coreclr_shutdown");
|
||||
CoreCLRUtil::CreateDelegateFunction createDelegate = (CoreCLRUtil::CreateDelegateFunction)dlsym(coreclrLib,"coreclr_create_delegate");
|
||||
|
||||
if (initializeCoreCLR == nullptr)
|
||||
{
|
||||
std::cerr << "function coreclr_initialize not found in CoreCLR library" << std::endl;
|
||||
return 3;
|
||||
}
|
||||
if (executeAssembly == nullptr)
|
||||
{
|
||||
std::cerr << "function coreclr_execute_assembly not found in CoreCLR library" << std::endl;
|
||||
return 3;
|
||||
}
|
||||
if (shutdownCoreCLR == nullptr)
|
||||
{
|
||||
std::cerr << "function coreclr_shutdown not found in CoreCLR library" << std::endl;
|
||||
return 3;
|
||||
}
|
||||
if (createDelegate == nullptr)
|
||||
{
|
||||
std::cerr << "function coreclr_create_delegate not found in CoreCLR library" << std::endl;
|
||||
return 3;
|
||||
}
|
||||
|
||||
// create list of properties to initialize CoreCLR
|
||||
const char* propertyKeys[] = {
|
||||
"TRUSTED_PLATFORM_ASSEMBLIES",
|
||||
"APP_PATHS",
|
||||
"APP_NI_PATHS",
|
||||
"NATIVE_DLL_SEARCH_DIRECTORIES",
|
||||
"AppDomainCompatSwitch"
|
||||
};
|
||||
|
||||
const char* propertyValues[] = {
|
||||
tpaList.c_str(),
|
||||
appPath.c_str(),
|
||||
appPath.c_str(),
|
||||
nativeDllSearchDirs.c_str(),
|
||||
"UseLatestBehaviorWhenTFMNotSpecified"
|
||||
};
|
||||
|
||||
|
||||
// initialize CoreCLR
|
||||
void* hostHandle;
|
||||
unsigned int domainId;
|
||||
int status = initializeCoreCLR(
|
||||
currentExeAbsolutePath.c_str(),
|
||||
"ps_cmdline_host",
|
||||
sizeof(propertyKeys)/sizeof(propertyKeys[0]),
|
||||
propertyKeys,
|
||||
propertyValues,
|
||||
&hostHandle,
|
||||
&domainId);
|
||||
|
||||
if (0 > status)
|
||||
{
|
||||
std::cerr << "coreclr_initialize failed - status: " << std::hex << status << std::endl;
|
||||
return 4;
|
||||
}
|
||||
|
||||
// initialize the PS's custom assembly load context
|
||||
typedef void (*LoaderRunHelperFp)(const char16_t* appPath);
|
||||
LoaderRunHelperFp loaderDelegate = nullptr;
|
||||
status = createDelegate(
|
||||
hostHandle,
|
||||
domainId,
|
||||
"Microsoft.PowerShell.CoreCLR.AssemblyLoadContext, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",
|
||||
"System.Management.Automation.PowerShellAssemblyLoadContextInitializer",
|
||||
"SetPowerShellAssemblyLoadContext",
|
||||
(void**)&loaderDelegate);
|
||||
if (0 > status)
|
||||
{
|
||||
std::cerr << "could not create delegate for SetPowerShellAssemblyLoadContext - status: " << std::hex << status << std::endl;
|
||||
return 4;
|
||||
}
|
||||
loaderDelegate(psBasePath16.c_str());
|
||||
|
||||
// call the unmanaged entry point for PowerShell
|
||||
typedef int (*UnmanagedMain)(int argc, char const* const* argv);
|
||||
UnmanagedMain unmanagedMain = nullptr;
|
||||
status = createDelegate(
|
||||
hostHandle,
|
||||
domainId,
|
||||
args.entryAssemblyName.c_str(),
|
||||
args.entryTypeName.c_str(),
|
||||
args.entryFunctionName.c_str(),
|
||||
(void**)&unmanagedMain);
|
||||
if (0 > status)
|
||||
{
|
||||
std::cerr << "could not create delegate for UnmanagedMain - status: " << std::hex << status << std::endl;
|
||||
return 4;
|
||||
}
|
||||
|
||||
int exitCode = unmanagedMain(args.argc,args.argv);
|
||||
|
||||
// shutdown CoreCLR
|
||||
status = shutdownCoreCLR(hostHandle,domainId);
|
||||
if (0 > status)
|
||||
{
|
||||
std::cerr << "coreclr_shutdown failed - status: " << std::hex << status << std::endl;
|
||||
}
|
||||
|
||||
// close the dynamic library
|
||||
if (0 != dlclose(coreclrLib))
|
||||
{
|
||||
std::cerr << "failed to close CoreCLR library" << std::endl;
|
||||
}
|
||||
|
||||
return exitCode;
|
||||
}
|
||||
|
167
host/common/coreclrutil.cpp
Normal file
167
host/common/coreclrutil.cpp
Normal file
|
@ -0,0 +1,167 @@
|
|||
#include "coreclrutil.h"
|
||||
#include <dirent.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <set>
|
||||
|
||||
namespace CoreCLRUtil
|
||||
{
|
||||
|
||||
bool GetAbsolutePath(const char* path, std::string& absolutePath)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
char realPath[PATH_MAX];
|
||||
if (realpath(path, realPath) != nullptr && realPath[0] != '\0')
|
||||
{
|
||||
absolutePath.assign(realPath);
|
||||
// realpath should return canonicalized path without the trailing slash
|
||||
assert(absolutePath.back() != '/');
|
||||
|
||||
result = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool GetDirectory(const char* absolutePath, std::string& directory)
|
||||
{
|
||||
directory.assign(absolutePath);
|
||||
size_t lastSlash = directory.rfind('/');
|
||||
if (lastSlash != std::string::npos)
|
||||
{
|
||||
directory.erase(lastSlash);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, std::string& clrFilesAbsolutePath)
|
||||
{
|
||||
std::string clrFilesRelativePath;
|
||||
const char* clrFilesPathLocal = clrFilesPath;
|
||||
if (clrFilesPathLocal == nullptr)
|
||||
{
|
||||
// There was no CLR files path specified, use the folder of the corerun/coreconsole
|
||||
if (!GetDirectory(currentExePath, clrFilesRelativePath))
|
||||
{
|
||||
perror("Failed to get directory from argv[0]");
|
||||
return false;
|
||||
}
|
||||
|
||||
clrFilesPathLocal = clrFilesRelativePath.c_str();
|
||||
|
||||
// TODO: consider using an env variable (if defined) as a fall-back.
|
||||
// The windows version of the corerun uses core_root env variable
|
||||
}
|
||||
|
||||
if (!GetAbsolutePath(clrFilesPathLocal, clrFilesAbsolutePath))
|
||||
{
|
||||
perror("Failed to convert CLR files path to absolute path");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList)
|
||||
{
|
||||
const char * const tpaExtensions[] = {
|
||||
".ni.dll", // Probe for .ni.dll first so that it's preferred if ni and il coexist in the same dir
|
||||
".dll",
|
||||
".ni.exe",
|
||||
".exe",
|
||||
};
|
||||
|
||||
DIR* dir = opendir(directory);
|
||||
if (dir == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::set<std::string> addedAssemblies;
|
||||
|
||||
// Walk the directory for each extension separately so that we first get files with .ni.dll extension,
|
||||
// then files with .dll extension, etc.
|
||||
for (int extIndex = 0; extIndex < sizeof(tpaExtensions) / sizeof(tpaExtensions[0]); extIndex++)
|
||||
{
|
||||
const char* ext = tpaExtensions[extIndex];
|
||||
int extLength = strlen(ext);
|
||||
|
||||
struct dirent* entry;
|
||||
|
||||
// For all entries in the directory
|
||||
while ((entry = readdir(dir)) != nullptr)
|
||||
{
|
||||
// We are interested in files only
|
||||
switch (entry->d_type)
|
||||
{
|
||||
case DT_REG:
|
||||
break;
|
||||
|
||||
// Handle symlinks and file systems that do not support d_type
|
||||
case DT_LNK:
|
||||
case DT_UNKNOWN:
|
||||
{
|
||||
std::string fullFilename;
|
||||
|
||||
fullFilename.append(directory);
|
||||
fullFilename.append("/");
|
||||
fullFilename.append(entry->d_name);
|
||||
|
||||
struct stat sb;
|
||||
if (stat(fullFilename.c_str(), &sb) == -1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!S_ISREG(sb.st_mode))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string filename(entry->d_name);
|
||||
|
||||
// Check if the extension matches the one we are looking for
|
||||
int extPos = filename.length() - extLength;
|
||||
if ((extPos <= 0) || (filename.compare(extPos, extLength, ext) != 0))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string filenameWithoutExt(filename.substr(0, extPos));
|
||||
|
||||
// Make sure if we have an assembly with multiple extensions present,
|
||||
// we insert only one version of it.
|
||||
if (addedAssemblies.find(filenameWithoutExt) == addedAssemblies.end())
|
||||
{
|
||||
addedAssemblies.insert(filenameWithoutExt);
|
||||
|
||||
tpaList.append(directory);
|
||||
tpaList.append("/");
|
||||
tpaList.append(filename);
|
||||
tpaList.append(":");
|
||||
}
|
||||
}
|
||||
|
||||
// Rewind the directory stream to be able to iterate over it for the next extension
|
||||
rewinddir(dir);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
// strip any trailing : from the tpaList
|
||||
if (tpaList.size() > 0 && tpaList[tpaList.size()-1] == ':')
|
||||
tpaList.resize(tpaList.size()-1);
|
||||
}
|
||||
|
||||
} // namespace CoreCLRUtil
|
||||
|
63
host/common/coreclrutil.h
Normal file
63
host/common/coreclrutil.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace CoreCLRUtil
|
||||
{
|
||||
|
||||
//
|
||||
// This code is mostly copied and modified from original CoreCLR project's
|
||||
// code on github: https://github.com/dotnet/coreclr
|
||||
//
|
||||
|
||||
//
|
||||
// these function signatures are the entry point API for CoreCLR
|
||||
//
|
||||
|
||||
// Prototype of the coreclr_initialize function from the libcoreclr.so
|
||||
typedef int (*InitializeCoreCLRFunction)(
|
||||
const char* exePath,
|
||||
const char* appDomainFriendlyName,
|
||||
int propertyCount,
|
||||
const char** propertyKeys,
|
||||
const char** propertyValues,
|
||||
void** hostHandle,
|
||||
unsigned int* domainId);
|
||||
|
||||
// Prototype of the coreclr_shutdown function from the libcoreclr.so
|
||||
typedef int (*ShutdownCoreCLRFunction)(
|
||||
void* hostHandle,
|
||||
unsigned int domainId);
|
||||
|
||||
// Prototype of the coreclr_execute_assembly function from the libcoreclr.so
|
||||
typedef int (*ExecuteAssemblyFunction)(
|
||||
void* hostHandle,
|
||||
unsigned int domainId,
|
||||
int argc,
|
||||
const char** argv,
|
||||
const char* managedAssemblyPath,
|
||||
unsigned int* exitCode);
|
||||
|
||||
// Prototype of coreclr_create_delegate function from the libcoreclr.so
|
||||
typedef int (*CreateDelegateFunction)(
|
||||
void* hostHandle,
|
||||
unsigned int domainId,
|
||||
const char* entryPointAssemblyName,
|
||||
const char* entryPointTypeName,
|
||||
const char* entryPointMethodName,
|
||||
void** delegate);
|
||||
|
||||
// The name of the CoreCLR native runtime DLL
|
||||
#if defined(__APPLE__)
|
||||
constexpr char coreClrDll[] = "libcoreclr.dylib";
|
||||
#else
|
||||
constexpr char coreClrDll[] = "libcoreclr.so";
|
||||
#endif
|
||||
|
||||
bool GetAbsolutePath(const char* path, std::string& absolutePath);
|
||||
bool GetDirectory(const char* absolutePath, std::string& directory);
|
||||
bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, std::string& clrFilesAbsolutePath);
|
||||
void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList);
|
||||
|
||||
} // namespace CoreCLRUtil
|
||||
|
48
host/common/hostutil.h
Normal file
48
host/common/hostutil.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "common/coreclrutil.h"
|
||||
|
||||
namespace HostUtil
|
||||
{
|
||||
|
||||
//!\brief get a list of absolute paths separated by : from a list of relative/absolute paths separated by :
|
||||
std::string getAbsolutePathList(const std::string& paths)
|
||||
{
|
||||
//std::cerr << "getAbsolutePathList: paths=" << paths << std::endl;
|
||||
std::string result;
|
||||
|
||||
// split by :
|
||||
size_t lastPos = 0;
|
||||
size_t curPos = paths.find(':',lastPos);
|
||||
do
|
||||
{
|
||||
const std::string token = paths.substr(lastPos,curPos-lastPos);
|
||||
//std::cerr << "curPos=" << curPos << " lastPos=" << lastPos << " token=" << token << std::endl;
|
||||
|
||||
// skip empty tokens
|
||||
if (token != "")
|
||||
{
|
||||
std::string absolutePath;
|
||||
if (CoreCLRUtil::GetAbsolutePath(token.c_str(),absolutePath))
|
||||
{
|
||||
// add colons correctly
|
||||
if (result.size() == 0)
|
||||
result += absolutePath;
|
||||
else
|
||||
result += ":" + absolutePath;
|
||||
}
|
||||
}
|
||||
|
||||
// increment lastPos to skip the :
|
||||
lastPos += token.size() + 1;
|
||||
curPos = paths.find(':',lastPos);
|
||||
}
|
||||
while (lastPos < paths.size());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
9
impl/getcurrentthreadid.cpp
Normal file
9
impl/getcurrentthreadid.cpp
Normal file
|
@ -0,0 +1,9 @@
|
|||
#include "getcurrentthreadid.h"
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
|
||||
HANDLE GetCurrentThreadId()
|
||||
{
|
||||
pid_t tid = pthread_self();
|
||||
return reinterpret_cast<HANDLE>(tid);
|
||||
}
|
10
impl/getcurrentthreadid.h
Normal file
10
impl/getcurrentthreadid.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include "pal.h"
|
||||
|
||||
PAL_BEGIN_EXTERNC
|
||||
|
||||
HANDLE GetCurrentThreadId();
|
||||
|
||||
PAL_END_EXTERNC
|
||||
|
8
impl/getusername.cpp
Normal file
8
impl/getusername.cpp
Normal file
|
@ -0,0 +1,8 @@
|
|||
#include "getusername.h"
|
||||
#include <unistd.h>
|
||||
|
||||
BOOL GetUserName(WCHAR_T* userName, UINT32* maxLength)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
10
impl/getusername.h
Normal file
10
impl/getusername.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include "pal.h"
|
||||
|
||||
PAL_BEGIN_EXTERNC
|
||||
|
||||
BOOL GetUserName(WCHAR_T* userName, UINT32* maxLength);
|
||||
|
||||
PAL_END_EXTERNC
|
||||
|
|
@ -52,7 +52,10 @@
|
|||
#define WIN32_FROM_HRESULT(hr) hr
|
||||
#define HRESULT_FROM_WIN32(error) error
|
||||
typedef unsigned long DWORD, *LPDWORD;
|
||||
typedef int BOOL;
|
||||
typedef char BOOL;
|
||||
typedef unsigned short WCHAR_T;
|
||||
typedef unsigned int UINT32;
|
||||
typedef int INT32;
|
||||
typedef unsigned long HRESULT;
|
||||
typedef const wchar_t *PCWSTR;
|
||||
typedef wchar_t *PWSTR;
|
||||
|
|
21
impl/terminal.cpp
Normal file
21
impl/terminal.cpp
Normal file
|
@ -0,0 +1,21 @@
|
|||
#include "terminal.h"
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
INT32 GetTerminalWidth()
|
||||
{
|
||||
struct winsize ws;
|
||||
if (-1 == ioctl(0,TIOCGWINSZ,&ws))
|
||||
return -1;
|
||||
|
||||
return ws.ws_col;
|
||||
}
|
||||
|
||||
INT32 GetTerminalHeight()
|
||||
{
|
||||
struct winsize ws;
|
||||
if (-1 == ioctl(0,TIOCGWINSZ,&ws))
|
||||
return -1;
|
||||
|
||||
return ws.ws_row;
|
||||
}
|
||||
|
11
impl/terminal.h
Normal file
11
impl/terminal.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
#include "pal.h"
|
||||
|
||||
PAL_BEGIN_EXTERNC
|
||||
|
||||
INT32 GetTerminalWidth();
|
||||
INT32 GetTerminalHeight();
|
||||
|
||||
PAL_END_EXTERNC
|
||||
|
35
tests/host/test-hostutil.cpp
Normal file
35
tests/host/test-hostutil.cpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include "common/hostutil.h"
|
||||
|
||||
TEST(HostUtilTest,simple)
|
||||
{
|
||||
// syntactical corner cases
|
||||
ASSERT_EQ("",HostUtil::getAbsolutePathList(""));
|
||||
ASSERT_EQ("",HostUtil::getAbsolutePathList(":"));
|
||||
ASSERT_EQ("",HostUtil::getAbsolutePathList("::"));
|
||||
ASSERT_EQ("",HostUtil::getAbsolutePathList(":::::"));
|
||||
|
||||
// current directory
|
||||
char* cwd = get_current_dir_name();
|
||||
ASSERT_EQ(std::string(cwd),HostUtil::getAbsolutePathList("."));
|
||||
|
||||
// relative and absolute paths that don't exist
|
||||
ASSERT_EQ("",HostUtil::getAbsolutePathList("/something/that/does/not/exist"));
|
||||
ASSERT_EQ("",HostUtil::getAbsolutePathList(":/something/that/does/not/exist:"));
|
||||
ASSERT_EQ("",HostUtil::getAbsolutePathList("something/relative/that/does/not/exist"));
|
||||
ASSERT_EQ("",HostUtil::getAbsolutePathList(":something/relative/that/does/not/exist:"));
|
||||
|
||||
// absolute existing paths
|
||||
ASSERT_EQ("/tmp",HostUtil::getAbsolutePathList("/tmp"));
|
||||
ASSERT_EQ("/tmp:/tmp",HostUtil::getAbsolutePathList("/tmp:/tmp"));
|
||||
|
||||
// relative paths
|
||||
chdir("/");
|
||||
ASSERT_EQ("/tmp",HostUtil::getAbsolutePathList("tmp"));
|
||||
ASSERT_EQ("/tmp:/tmp",HostUtil::getAbsolutePathList("/tmp:tmp:"));
|
||||
chdir(cwd);
|
||||
|
||||
// cleanup
|
||||
free(cwd);
|
||||
}
|
||||
|
16
tests/test-getcurrentthreadid.cpp
Normal file
16
tests/test-getcurrentthreadid.cpp
Normal file
|
@ -0,0 +1,16 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include "getcurrentthreadid.h"
|
||||
#include <pthread.h>
|
||||
|
||||
TEST(GetCurrentThreadId,simple)
|
||||
{
|
||||
const HANDLE currentThreadId = GetCurrentThreadId();
|
||||
const pid_t tid = pthread_self();
|
||||
|
||||
// first make sure that on this platform those types are of the same size
|
||||
ASSERT_TRUE(sizeof(HANDLE) >= sizeof(pid_t));
|
||||
|
||||
// now compare the actual values
|
||||
ASSERT_EQ(currentThreadId,reinterpret_cast<HANDLE>(tid));
|
||||
}
|
||||
|
Loading…
Reference in a new issue