Add Unix version of coreconsole.
authorAditya Mandaleeka <adityam@microsoft.com>
Wed, 22 Apr 2015 06:47:33 +0000 (23:47 -0700)
committerAditya Mandaleeka <adityam@microsoft.com>
Wed, 29 Apr 2015 01:06:26 +0000 (18:06 -0700)
Created a Unix version of coreconsole which, like the Windows version,
is similar to corerun but runs the managed binary with the same name as
the executable (but with the DLL extension). Moved code that is common
between corerun and coreconsole to coreruncommon.

Remove the workaround for the XCode 6.3 SDK issue wherein some of the
system headers that we reference try to include a __debug header which
does not exist. The 6.3.1 update fixed that issue so the workaround is no
longer required.

Fix #747

CMakeLists.txt
src/ToolBox/SOS/lldbplugin/CMakeLists.txt
src/coreclr/hosts/unixcoreconsole/.gitmirrorall [new file with mode: 0644]
src/coreclr/hosts/unixcoreconsole/CMakeLists.txt [new file with mode: 0644]
src/coreclr/hosts/unixcoreconsole/coreconsole.cpp [new file with mode: 0644]
src/coreclr/hosts/unixcorerun/CMakeLists.txt
src/coreclr/hosts/unixcorerun/corerun.cpp
src/coreclr/hosts/unixcoreruncommon/.gitmirror [new file with mode: 0644]
src/coreclr/hosts/unixcoreruncommon/coreruncommon.cpp [new file with mode: 0644]
src/coreclr/hosts/unixcoreruncommon/coreruncommon.h [new file with mode: 0644]

index a769dc9..8e27629 100644 (file)
@@ -158,6 +158,7 @@ if(CLR_CMAKE_PLATFORM_UNIX)
     add_subdirectory(src/pal)
     add_subdirectory(src/coreclr/hosts/unixcorerun)
     add_subdirectory(src/corefx)
+    add_subdirectory(src/coreclr/hosts/unixcoreconsole)
 endif(CLR_CMAKE_PLATFORM_UNIX)
 
 # Add this subdir. We install the headers for the jit.
index ee781a4..3846029 100644 (file)
@@ -55,6 +55,7 @@ include_directories(inc)
 include_directories("${LLDB_H}")
 include_directories(${CLR_DIR}/src/debug/inc)
 include_directories(${CLR_DIR}/src/inc)
+include_directories(${CLR_DIR}/src/coreclr/hosts/unixcoreruncommon)
 
 set(SOURCES
     sosplugin.cpp
diff --git a/src/coreclr/hosts/unixcoreconsole/.gitmirrorall b/src/coreclr/hosts/unixcoreconsole/.gitmirrorall
new file mode 100644 (file)
index 0000000..9ee5c57
--- /dev/null
@@ -0,0 +1 @@
+This folder will be mirrored by the Git-TFS Mirror recursively.
\ No newline at end of file
diff --git a/src/coreclr/hosts/unixcoreconsole/CMakeLists.txt b/src/coreclr/hosts/unixcoreconsole/CMakeLists.txt
new file mode 100644 (file)
index 0000000..9d065df
--- /dev/null
@@ -0,0 +1,32 @@
+project(unixcoreconsole)
+
+include_directories(../unixcoreruncommon)
+
+set(CORECONSOLE_SOURCES 
+    ../unixcoreruncommon/coreruncommon.cpp
+    coreconsole.cpp 
+)
+
+add_executable(coreconsole
+    ${CORECONSOLE_SOURCES}
+)
+
+# FreeBSD implements dlopen in libc
+if(NOT CMAKE_SYSTEM_NAME STREQUAL FreeBSD)
+    target_link_libraries(coreconsole 
+        dl
+    )
+endif(NOT CMAKE_SYSTEM_NAME STREQUAL FreeBSD)
+
+# FreeBSD requires pthread to be loaded by the executable process
+if(CMAKE_SYSTEM_NAME STREQUAL FreeBSD)
+    target_link_libraries(coreconsole
+        pthread
+    )
+endif(CMAKE_SYSTEM_NAME STREQUAL FreeBSD)
+
+add_dependencies(coreconsole
+    coreclr
+)
+
+install (TARGETS coreconsole DESTINATION .)
diff --git a/src/coreclr/hosts/unixcoreconsole/coreconsole.cpp b/src/coreclr/hosts/unixcoreconsole/coreconsole.cpp
new file mode 100644 (file)
index 0000000..db7301b
--- /dev/null
@@ -0,0 +1,155 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information. 
+//
+
+//
+// A simple CoreCLR host that runs a managed binary with the same name as this executable but with the *.dll extension
+// The dll binary must contain a main entry point.
+//
+
+#include <coreruncommon.h>
+#include <string>
+#include <string.h>
+#include <sys/stat.h>
+
+// Display the help text
+void DisplayUsage()
+{
+     fprintf(
+        stderr,
+        "Runs executables on CoreCLR\n\n"
+        "Usage: <program> [OPTIONS] [ARGUMENTS]\n"
+        "Runs <program>.dll on CoreCLR.\n\n"
+        "Options:\n"
+        "-_c  path to libcoreclr.so and the managed CLR assemblies.\n"
+        "-_h  show this help message. \n");
+}
+
+// Parse the command line arguments 
+bool ParseArguments(
+        const int argc,
+        const char* argv[],
+        const char** clrFilesPath,
+        int* managedAssemblyArgc,
+        const char*** managedAssemblyArgv)
+{
+    bool success = true;
+
+    *clrFilesPath = nullptr;
+    *managedAssemblyArgv = nullptr;
+    *managedAssemblyArgc = 0;
+
+    for (int i = 1; i < argc; i++)
+    {
+        // Check for options. Options to the Unix coreconsole are prefixed with '-_' to match the convention
+        // used in the Windows version of coreconsole.
+        if (strncmp(argv[i], "-_", 2) == 0)
+        {
+            // Path to the libcoreclr.so and the managed CLR assemblies
+            if (strcmp(argv[i], "-_c") == 0)
+            {
+                i++;
+                if (i < argc)
+                {
+                    *clrFilesPath = argv[i];
+                }
+                else
+                {
+                    fprintf(stderr, "Option %s: missing path\n", argv[i - 1]);
+                    success = false;
+                    break;
+                }
+            }
+            else if (strcmp(argv[i], "-_h") == 0)
+            {
+                DisplayUsage();
+                success = false;
+                break;
+            }
+            else
+            {
+                fprintf(stderr, "Unknown option %s\n", argv[i]);
+                success = false;
+                break;
+            }
+        }
+        else
+        {
+            // We treat everything starting from the first non-option argument as arguments
+            // to the managed assembly.
+            *managedAssemblyArgc = argc - i;
+            if (*managedAssemblyArgc != 0)
+            {
+                *managedAssemblyArgv = &argv[i];
+            }
+
+            break;
+        }
+    }
+
+    return success;
+}
+
+int main(const int argc, const char* argv[])
+{
+    // Make sure we have a full path for argv[0].
+    std::string argv0AbsolutePath;
+    if (!GetAbsolutePath(argv[0], argv0AbsolutePath))
+    {
+        perror("Could not get full path to current executable");
+        return -1;
+    }
+
+    // We will try to load the managed assembly with the same name as this executable
+    // but with the .dll extension.
+    std::string programPath(argv0AbsolutePath);
+    programPath.append(".dll");
+    const char* managedAssemblyAbsolutePath = programPath.c_str();
+
+    // Check if the specified managed assembly file exists
+    struct stat sb;
+    if (stat(managedAssemblyAbsolutePath, &sb) == -1)
+    {
+        perror("Managed assembly not found");
+        return -1;
+    }
+
+    // Verify that the managed assembly path points to a file
+    if (!S_ISREG(sb.st_mode))
+    {
+        fprintf(stderr, "The specified managed assembly is not a file\n");
+        return -1;
+    }
+
+    const char* clrFilesPath;
+    const char** managedAssemblyArgv;
+    int managedAssemblyArgc;
+
+    if (!ParseArguments(
+            argc,
+            argv,
+            &clrFilesPath,
+            &managedAssemblyArgc,
+            &managedAssemblyArgv
+            ))
+    {
+        // Invalid command line
+        return -1;
+    }
+
+    std::string clrFilesAbsolutePath;
+    if(!GetClrFilesAbsolutePath(argv0AbsolutePath.c_str(), clrFilesPath, clrFilesAbsolutePath))
+    {
+        return -1;
+    }
+
+    int exitCode = ExecuteManagedAssembly(
+                            argv0AbsolutePath.c_str(),
+                            clrFilesAbsolutePath.c_str(),
+                            managedAssemblyAbsolutePath,
+                            managedAssemblyArgc,
+                            managedAssemblyArgv);
+
+    return exitCode;
+}
index fd9de1c..5ffc1db 100644 (file)
@@ -1,6 +1,9 @@
 project(unixcorerun)
 
+include_directories(../unixcoreruncommon)
+
 set(CORERUN_SOURCES 
+    ../unixcoreruncommon/coreruncommon.cpp
     corerun.cpp 
 )
 
index aacf36a..26541b7 100644 (file)
@@ -3,49 +3,10 @@
 // Licensed under the MIT license. See LICENSE file in the project root for full license information. 
 //
 
-#include <assert.h>
-#include <dlfcn.h>
-#include <dirent.h>
-#include <errno.h>
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
+#include <coreruncommon.h>
+#include <string>
 #include <string.h>
 #include <sys/stat.h>
-#include <sys/types.h>
-#include <string>
-#include <set>
-
-// The name of the CoreCLR native runtime DLL.
-#if defined(__APPLE__)
-static const char * const coreClrDll = "libcoreclr.dylib";
-#else
-static const char * const coreClrDll = "libcoreclr.so";
-#endif
-
-// Windows types used by the ExecuteAssembly function
-typedef unsigned int DWORD;
-typedef const char16_t* LPCWSTR;
-typedef const char* LPCSTR;
-typedef int32_t HRESULT;
-
-#define SUCCEEDED(Status) ((HRESULT)(Status) >= 0)
-
-// Prototype of the ExecuteAssembly function from the libcoreclr.do
-typedef HRESULT (*ExecuteAssemblyFunction)(
-                    LPCSTR exePath,
-                    LPCSTR coreClrPath,
-                    LPCSTR appDomainFriendlyName,
-                    int propertyCount,
-                    LPCSTR* propertyKeys,
-                    LPCSTR* propertyValues,
-                    int argc,
-                    LPCSTR* argv,
-                    LPCSTR managedAssemblyPath,
-                    LPCSTR entryPointAssemblyName,
-                    LPCSTR entryPointTypeName,
-                    LPCSTR entryPointMethodsName,
-                    DWORD* exitCode);
 
 // Display the command line options
 void DisplayUsage()
@@ -58,37 +19,6 @@ void DisplayUsage()
         "-c, --clr-path  path to the libcoreclr.so and the managed CLR assemblies\n");
 }
 
-// Get absolute path from the specified path.
-// Return true in case of a success, false otherwise.
-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);
-        // The 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;
-}
-
 // Parse the command line arguments 
 bool ParseArguments(
         const int argc,
@@ -162,226 +92,6 @@ bool ParseArguments(
     return success;
 }
 
-// Add all *.dll, *.ni.dll, *.exe, and *.ni.exe files from the specified directory
-// to the tpaList string;
-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);    
-}
-
-//
-// Execute the specified managed assembly. 
-//
-// Parameters:
-//  currentExePath          - Path of the current executable
-//  clrFilesAbsolutePath    - Absolute path of a folder where the libcoreclr.so and CLR managed assemblies are stored
-//  managedAssemblyPath     - Path to the managed assembly to execute
-//  managedAssemblyArgc     - Number of arguments passed to the executed assembly
-//  managedAssemblyArgv     - Array of arguments passed to the executed assembly
-//
-// Returns:
-//  ExitCode of the assembly
-//
-int ExecuteManagedAssembly(
-            const char* currentExeAbsolutePath,
-            const char* clrFilesAbsolutePath,
-            const char* managedAssemblyAbsolutePath,
-            int managedAssemblyArgc,
-            const char** managedAssemblyArgv)
-{
-    // Indicates failure
-    int exitCode = -1;
-    
-    std::string coreClrDllPath(clrFilesAbsolutePath);
-    coreClrDllPath.append("/");
-    coreClrDllPath.append(coreClrDll);
-    
-    if (coreClrDllPath.length() >= PATH_MAX)
-    {
-        fprintf(stderr, "Absolute path to libcoreclr.so too long\n");
-        return -1;
-    }
-
-    // Get just the path component of the managed assembly path
-    std::string appPath;
-    GetDirectory(managedAssemblyAbsolutePath, appPath);
-    
-    std::string nativeDllSearchDirs(appPath);
-    nativeDllSearchDirs.append(":");
-    nativeDllSearchDirs.append(clrFilesAbsolutePath);
-    
-    std::string tpaList;
-    AddFilesFromDirectoryToTpaList(clrFilesAbsolutePath, tpaList);
-
-    void* coreclrLib = dlopen(coreClrDllPath.c_str(), RTLD_NOW | RTLD_LOCAL);
-    if (coreclrLib != nullptr)
-    {
-        ExecuteAssemblyFunction executeAssembly = (ExecuteAssemblyFunction)dlsym(coreclrLib, "ExecuteAssembly");
-        if (executeAssembly != nullptr)
-        {
-            // Allowed property names:
-            // APPBASE
-            // - The base path of the application from which the exe and other assemblies will be loaded
-            //
-            // TRUSTED_PLATFORM_ASSEMBLIES
-            // - The list of complete paths to each of the fully trusted assemblies
-            //
-            // APP_PATHS
-            // - The list of paths which will be probed by the assembly loader
-            //
-            // APP_NI_PATHS
-            // - The list of additional paths that the assembly loader will probe for ngen images
-            //
-            // NATIVE_DLL_SEARCH_DIRECTORIES
-            // - The list of paths that will be probed for native DLLs called by PInvoke
-            //
-            const char *propertyKeys[] = {
-                "TRUSTED_PLATFORM_ASSEMBLIES",
-                "APP_PATHS",
-                "APP_NI_PATHS",
-                "NATIVE_DLL_SEARCH_DIRECTORIES",
-                "AppDomainCompatSwitch"
-            };
-            const char *propertyValues[] = {
-                // TRUSTED_PLATFORM_ASSEMBLIES
-                tpaList.c_str(),
-                // APP_PATHS
-                appPath.c_str(),
-                // APP_NI_PATHS
-                appPath.c_str(),
-                // NATIVE_DLL_SEARCH_DIRECTORIES
-                nativeDllSearchDirs.c_str(),
-                // AppDomainCompatSwitch
-                "UseLatestBehaviorWhenTFMNotSpecified"
-            };
-
-            HRESULT st = executeAssembly(
-                            currentExeAbsolutePath,
-                            coreClrDllPath.c_str(),
-                            "unixcorerun",
-                            sizeof(propertyKeys) / sizeof(propertyKeys[0]),
-                            propertyKeys,
-                            propertyValues,
-                            managedAssemblyArgc,
-                            managedAssemblyArgv,
-                            managedAssemblyAbsolutePath,
-                            NULL,
-                            NULL,
-                            NULL,
-                            (DWORD*)&exitCode);
-
-            if (!SUCCEEDED(st))
-            {
-                fprintf(stderr, "ExecuteAssembly failed - status: 0x%08x\n", st);
-            }
-        }
-        else
-        {
-            fprintf(stderr, "Function ExecuteAssembly not found in the libcoreclr.so\n");
-        }
-
-        if (dlclose(coreclrLib) != 0)
-        {
-            fprintf(stderr, "Warning - dlclose failed\n");
-        }
-    }
-    else
-    {
-        char* error = dlerror();
-        fprintf(stderr, "dlopen failed to open the libcoreclr.so with error %s\n", error);
-    }
-
-    return exitCode;
-}
-
 int corerun(const int argc, const char* argv[])
 {
     const char* clrFilesPath;
@@ -415,7 +125,7 @@ int corerun(const int argc, const char* argv[])
         fprintf(stderr, "The specified managed assembly is not a file\n");
         return -1;
     }
-    
+
     // Make sure we have a full path for argv[0].
     std::string argv0AbsolutePath;
     if (!GetAbsolutePath(argv[0], argv0AbsolutePath))
@@ -424,28 +134,9 @@ int corerun(const int argc, const char* argv[])
         return -1;
     }
 
-    // Convert the specified path to CLR files to an absolute path since the libcoreclr.so
-    // requires it.
     std::string clrFilesAbsolutePath;
-    std::string clrFilesRelativePath;
-
-    if (clrFilesPath == nullptr)
+    if(!GetClrFilesAbsolutePath(argv0AbsolutePath.c_str(), clrFilesPath, clrFilesAbsolutePath))
     {
-        // There was no CLR files path specified, use the folder of the corerun
-        if (!GetDirectory(argv0AbsolutePath.c_str(), clrFilesRelativePath))
-        {
-            perror("Failed to get directory from argv[0]");
-            return -1;
-        }
-        clrFilesPath = 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(clrFilesPath, clrFilesAbsolutePath))
-    {
-        perror("Failed to convert CLR files path to absolute path");
         return -1;
     }
 
@@ -455,13 +146,14 @@ int corerun(const int argc, const char* argv[])
         perror("Failed to convert managed assembly path to absolute path");
         return -1;
     }
-    
+
     int exitCode = ExecuteManagedAssembly(
                             argv0AbsolutePath.c_str(),
                             clrFilesAbsolutePath.c_str(),
                             managedAssemblyAbsolutePath.c_str(),
                             managedAssemblyArgc,
                             managedAssemblyArgv);
+
     return exitCode;
 }
 
diff --git a/src/coreclr/hosts/unixcoreruncommon/.gitmirror b/src/coreclr/hosts/unixcoreruncommon/.gitmirror
new file mode 100644 (file)
index 0000000..f507630
--- /dev/null
@@ -0,0 +1 @@
+Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror. 
\ No newline at end of file
diff --git a/src/coreclr/hosts/unixcoreruncommon/coreruncommon.cpp b/src/coreclr/hosts/unixcoreruncommon/coreruncommon.cpp
new file mode 100644 (file)
index 0000000..1294038
--- /dev/null
@@ -0,0 +1,311 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information. 
+//
+
+//
+// Code that is used by both the Unix corerun and coreconsole.
+//
+
+#include <assert.h>
+#include <dirent.h>
+#include <dlfcn.h>
+#include <limits.h>
+#include <set>
+#include <string>
+#include <string.h>
+#include <sys/stat.h>
+
+// The name of the CoreCLR native runtime DLL
+#if defined(__APPLE__)
+static const char * const coreClrDll = "libcoreclr.dylib";
+#else
+static const char * const coreClrDll = "libcoreclr.so";
+#endif
+
+// Windows types used by the ExecuteAssembly function
+typedef unsigned int DWORD;
+typedef const char16_t* LPCWSTR;
+typedef const char* LPCSTR;
+typedef int32_t HRESULT;
+
+#define SUCCEEDED(Status) ((HRESULT)(Status) >= 0)
+
+// Prototype of the ExecuteAssembly function from the libcoreclr.do
+typedef HRESULT (*ExecuteAssemblyFunction)(
+                    LPCSTR exePath,
+                    LPCSTR coreClrPath,
+                    LPCSTR appDomainFriendlyName,
+                    int propertyCount,
+                    LPCSTR* propertyKeys,
+                    LPCSTR* propertyValues,
+                    int argc,
+                    LPCSTR* argv,
+                    LPCSTR managedAssemblyPath,
+                    LPCSTR entryPointAssemblyName,
+                    LPCSTR entryPointTypeName,
+                    LPCSTR entryPointMethodsName,
+                    DWORD* exitCode);
+
+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);
+}
+
+int ExecuteManagedAssembly(
+            const char* currentExeAbsolutePath,
+            const char* clrFilesAbsolutePath,
+            const char* managedAssemblyAbsolutePath,
+            int managedAssemblyArgc,
+            const char** managedAssemblyArgv)
+{
+    // Indicates failure
+    int exitCode = -1;
+
+    std::string coreClrDllPath(clrFilesAbsolutePath);
+    coreClrDllPath.append("/");
+    coreClrDllPath.append(coreClrDll);
+
+    if (coreClrDllPath.length() >= PATH_MAX)
+    {
+        fprintf(stderr, "Absolute path to libcoreclr.so too long\n");
+        return -1;
+    }
+
+    // Get just the path component of the managed assembly path
+    std::string appPath;
+    GetDirectory(managedAssemblyAbsolutePath, appPath);
+
+    std::string nativeDllSearchDirs(appPath);
+    nativeDllSearchDirs.append(":");
+    nativeDllSearchDirs.append(clrFilesAbsolutePath);
+
+    std::string tpaList;
+    AddFilesFromDirectoryToTpaList(clrFilesAbsolutePath, tpaList);
+
+    void* coreclrLib = dlopen(coreClrDllPath.c_str(), RTLD_NOW | RTLD_LOCAL);
+    if (coreclrLib != nullptr)
+    {
+        ExecuteAssemblyFunction executeAssembly = (ExecuteAssemblyFunction)dlsym(coreclrLib, "ExecuteAssembly");
+        if (executeAssembly != nullptr)
+        {
+            // Allowed property names:
+            // APPBASE
+            // - The base path of the application from which the exe and other assemblies will be loaded
+            //
+            // TRUSTED_PLATFORM_ASSEMBLIES
+            // - The list of complete paths to each of the fully trusted assemblies
+            //
+            // APP_PATHS
+            // - The list of paths which will be probed by the assembly loader
+            //
+            // APP_NI_PATHS
+            // - The list of additional paths that the assembly loader will probe for ngen images
+            //
+            // NATIVE_DLL_SEARCH_DIRECTORIES
+            // - The list of paths that will be probed for native DLLs called by PInvoke
+            //
+            const char *propertyKeys[] = {
+                "TRUSTED_PLATFORM_ASSEMBLIES",
+                "APP_PATHS",
+                "APP_NI_PATHS",
+                "NATIVE_DLL_SEARCH_DIRECTORIES",
+                "AppDomainCompatSwitch"
+            };
+            const char *propertyValues[] = {
+                // TRUSTED_PLATFORM_ASSEMBLIES
+                tpaList.c_str(),
+                // APP_PATHS
+                appPath.c_str(),
+                // APP_NI_PATHS
+                appPath.c_str(),
+                // NATIVE_DLL_SEARCH_DIRECTORIES
+                nativeDllSearchDirs.c_str(),
+                // AppDomainCompatSwitch
+                "UseLatestBehaviorWhenTFMNotSpecified"
+            };
+
+            HRESULT st = executeAssembly(
+                            currentExeAbsolutePath,
+                            coreClrDllPath.c_str(),
+                            "unixcorerun",
+                            sizeof(propertyKeys) / sizeof(propertyKeys[0]),
+                            propertyKeys,
+                            propertyValues,
+                            managedAssemblyArgc,
+                            managedAssemblyArgv,
+                            managedAssemblyAbsolutePath,
+                            NULL,
+                            NULL,
+                            NULL,
+                            (DWORD*)&exitCode);
+
+            if (!SUCCEEDED(st))
+            {
+                fprintf(stderr, "ExecuteAssembly failed - status: 0x%08x\n", st);
+            }
+        }
+        else
+        {
+            fprintf(stderr, "Function ExecuteAssembly not found in the libcoreclr.so\n");
+        }
+
+        if (dlclose(coreclrLib) != 0)
+        {
+            fprintf(stderr, "Warning - dlclose failed\n");
+        }
+    }
+    else
+    {
+        char* error = dlerror();
+        fprintf(stderr, "dlopen failed to open the libcoreclr.so with error %s\n", error);
+    }
+
+    return exitCode;
+}
diff --git a/src/coreclr/hosts/unixcoreruncommon/coreruncommon.h b/src/coreclr/hosts/unixcoreruncommon/coreruncommon.h
new file mode 100644 (file)
index 0000000..b587e40
--- /dev/null
@@ -0,0 +1,46 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information. 
+//
+
+#include <string>
+
+// Get absolute path from the specified path.
+// Return true in case of a success, false otherwise.
+bool GetAbsolutePath(const char* path, std::string& absolutePath);
+
+// Get directory of the specified path.
+// Return true in case of a success, false otherwise.
+bool GetDirectory(const char* absolutePath, std::string& directory);
+
+//
+// Get the absolute path to use to locate libcoreclr.so and the CLR assemblies are stored. If clrFilesPath is provided,
+// this function will return the absolute path to it. Otherwise, the directory of the current executable is used.
+//
+// Return true in case of a success, false otherwise.
+//
+bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, std::string& clrFilesAbsolutePath);
+
+// Add all *.dll, *.ni.dll, *.exe, and *.ni.exe files from the specified directory to the tpaList string.
+void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList);
+
+//
+// Execute the specified managed assembly. 
+//
+// Parameters:
+//  currentExePath          - Path to the current executable
+//  clrFilesAbsolutePath    - Absolute path to the folder where the libcoreclr.so and CLR managed assemblies are stored
+//  managedAssemblyPath     - Path to the managed assembly to execute
+//  managedAssemblyArgc     - Number of arguments passed to the executed assembly
+//  managedAssemblyArgv     - Array of arguments passed to the executed assembly
+//
+// Returns:
+//  ExitCode of the assembly
+//
+int ExecuteManagedAssembly(
+            const char* currentExeAbsolutePath,
+            const char* clrFilesAbsolutePath,
+            const char* managedAssemblyAbsolutePath,
+            int managedAssemblyArgc,
+            const char** managedAssemblyArgv);
+