diff --git a/setup.py b/setup.py index c6e4007e6..dd88db6ec 100644 --- a/setup.py +++ b/setup.py @@ -362,8 +362,10 @@ def build_extension(self, ext): ), shell=use_shell, ) - if DEVTOOLS == "Mono" or DEVTOOLS == "dotnet": + if DEVTOOLS == "Mono": self._build_monoclr() + if DEVTOOLS == "dotnet": + self._build_coreclr() def _get_manifest(self, build_dir): if DEVTOOLS != "MsDev" and DEVTOOLS != "MsDev15": @@ -403,6 +405,19 @@ def _build_monoclr(self): build_ext.build_ext.build_extension(self, clr_ext) + def _build_coreclr(self): + # build the clr python module + clr_ext = Extension( + "clr", + sources=[ + "src/coreclr/pynetinit.c", + "src/coreclr/clrmod.c", + "src/coreclr/coreutils.c", + ], + ) + + build_ext.build_ext.build_extension(self, clr_ext) + def _install_packages(self): """install packages using nuget""" use_shell = DEVTOOLS == "Mono" or DEVTOOLS == "dotnet" diff --git a/src/coreclr/clrmod.c b/src/coreclr/clrmod.c new file mode 100644 index 000000000..42cbb2d7c --- /dev/null +++ b/src/coreclr/clrmod.c @@ -0,0 +1,70 @@ +#include "pynetclr.h" + +/* List of functions defined in the module */ +static PyMethodDef clr_methods[] = { + {NULL, NULL, 0, NULL} /* Sentinel */ +}; + +PyDoc_STRVAR(clr_module_doc, + "clr facade module to initialize the CLR. It's later " + "replaced by the real clr module. This module has a facade " + "attribute to make it distinguishable from the real clr module." +); + +static PyNet_Args *pn_args; +char **environ = NULL; + +#if PY_MAJOR_VERSION >= 3 +static struct PyModuleDef clrdef = { + PyModuleDef_HEAD_INIT, + "clr", /* m_name */ + clr_module_doc, /* m_doc */ + -1, /* m_size */ + clr_methods, /* m_methods */ + NULL, /* m_reload */ + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL, /* m_free */ +}; +#endif + +static PyObject *_initclr(void) +{ + PyObject *m; + + /* Create the module and add the functions */ +#if PY_MAJOR_VERSION >= 3 + m = PyModule_Create(&clrdef); +#else + m = Py_InitModule3("clr", clr_methods, clr_module_doc); +#endif + if (m == NULL) + return NULL; + PyModule_AddObject(m, "facade", Py_True); + Py_INCREF(Py_True); + + pn_args = PyNet_Init(1); + if (pn_args->error) + { + return NULL; + } + + if (NULL != pn_args->module) + return pn_args->module; + + return m; +} + +#if PY_MAJOR_VERSION >= 3 +PyMODINIT_FUNC +PyInit_clr(void) +{ + return _initclr(); +} +#else +PyMODINIT_FUNC +initclr(void) +{ + _initclr(); +} +#endif diff --git a/src/coreclr/coreclrhost.h b/src/coreclr/coreclrhost.h new file mode 100644 index 000000000..0391ba38b --- /dev/null +++ b/src/coreclr/coreclrhost.h @@ -0,0 +1,55 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// +// APIs for hosting CoreCLR +// + +#ifndef __CORECLR_HOST_H__ +#define __CORECLR_HOST_H__ + +// For each hosting API, we define a function prototype and a function pointer +// The prototype is useful for implicit linking against the dynamic coreclr +// library and the pointer for explicit dynamic loading (dlopen, LoadLibrary) +#define CORECLR_HOSTING_API(function, ...) \ + int function(__VA_ARGS__); \ + typedef int (*function##_ptr)(__VA_ARGS__) + +CORECLR_HOSTING_API(coreclr_initialize, + const char* exePath, + const char* appDomainFriendlyName, + int propertyCount, + const char** propertyKeys, + const char** propertyValues, + void** hostHandle, + unsigned int* domainId); + +CORECLR_HOSTING_API(coreclr_shutdown, + void* hostHandle, + unsigned int domainId); + +CORECLR_HOSTING_API(coreclr_shutdown_2, + void* hostHandle, + unsigned int domainId, + int* latchedExitCode); + +CORECLR_HOSTING_API(coreclr_create_delegate, + void* hostHandle, + unsigned int domainId, + const char* entryPointAssemblyName, + const char* entryPointTypeName, + const char* entryPointMethodName, + void** delegate); + +CORECLR_HOSTING_API(coreclr_execute_assembly, + void* hostHandle, + unsigned int domainId, + int argc, + const char** argv, + const char* managedAssemblyPath, + unsigned int* exitCode); + +#undef CORECLR_HOSTING_API + +#endif // __CORECLR_HOST_H__ diff --git a/src/coreclr/coreutils.c b/src/coreclr/coreutils.c new file mode 100644 index 000000000..9d6ec9d8a --- /dev/null +++ b/src/coreclr/coreutils.c @@ -0,0 +1,372 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// +// Code that is used by both the Unix corerun and coreconsole. +// + +// https://github.com/dotnet/coreclr/blob/master/src/coreclr/hosts/unixcoreruncommon/coreruncommon.cpp + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(__FreeBSD__) +#include +#include +#endif +#if defined(HAVE_SYS_SYSCTL_H) || defined(__FreeBSD__) +#include +#endif +#include +#include "coreutils.h" +#ifndef SUCCEEDED +#define SUCCEEDED(Status) ((Status) >= 0) +#endif // !SUCCEEDED + +#if defined(__linux__) +#define symlinkEntrypointExecutable "/proc/self/exe" +#elif !defined(__APPLE__) +#define symlinkEntrypointExecutable "/proc/curproc/exe" +#endif + +bool GetEntrypointExecutableAbsolutePath(char** entrypointExecutable) +{ + bool result = false; + + // Get path to the executable for the current process using + // platform specific means. +#if defined(__APPLE__) + + char path[PATH_MAX]; + // On Mac, we ask the OS for the absolute path to the entrypoint executable + size_t lenActualPath = sizeof(path); + if (_NSGetExecutablePath(path, &lenActualPath) == 0) + { + char* buf = strdup(path); + if (buf == NULL) + { + perror("Could not allocate buffer for path"); + return false; + } + result = true; + } + else + { + fprintf(stderr, "Path too long\n"); + return result; + } +#elif defined (__FreeBSD__) + static const int name[] = { + CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 + }; + char path[PATH_MAX]; + size_t len; + + len = sizeof(path); + if (sysctl(name, 4, path, &len, nullptr, 0) == 0) + { + char* buf = strdup(path); + if (buf == NULL) + { + perror("Could not allocate buffer for path"); + return false; + } + result = true; + } + else + { + // ENOMEM + result = false; + } +#elif defined(__NetBSD__) && defined(KERN_PROC_PATHNAME) + static const int name[] = { + CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME, + }; + char path[MAXPATHLEN]; + size_t len; + + len = sizeof(path); + if (sysctl(name, __arraycount(name), path, &len, NULL, 0) != -1) + { + char* buf = strdup(path); + if (buf == NULL) + { + perror("Could not allocate buffer for path"); + return false; + } + result = true; + } + else + { + result = false; + } +#else + // On other OSs, return the symlink that will be resolved by GetAbsolutePath + // to fetch the entrypoint EXE absolute path, inclusive of filename. + result = GetAbsolutePath(symlinkEntrypointExecutable, entrypointExecutable); +#endif + + return result; +} + +bool GetAbsolutePath(const char* path, char** absolutePath) +{ + bool result = false; + + char realPath[PATH_MAX]; + if (realpath(path, realPath) != NULL && realPath[0] != '\0') + { + // realpath should return canonicalized path without the trailing slash + assert((realPath)[strlen(realPath)-1] != '/'); + + *absolutePath = strdup(realPath); + if (*absolutePath == NULL) + { + perror("Could not allocate buffer for path"); + return false; + } + + result = true; + } + + return result; +} + +bool GetDirectory(const char* absolutePath, char** directory) +{ + *directory = strdup(absolutePath); + if (*directory == NULL) + { + perror("Could not allocate buffer for path"); + return false; + } + + size_t len = strlen(*directory); + if((*directory)[len-1] == '/') + { + (*directory)[len-1] = '\0'; + return true; + } + + return false; +} + +bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, char** clrFilesAbsolutePath) +{ + char* clrFilesRelativePath = NULL; + const char* clrFilesPathLocal = clrFilesPath; + if (clrFilesPathLocal == NULL) + { + // There was no CLR files path specified, use the folder of the current exe + if (!GetDirectory(currentExePath, &clrFilesRelativePath)) + { + fprintf(stderr, "Failed to get directory\n"); + return false; + } + + clrFilesPathLocal = clrFilesRelativePath; + + // 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)) + { + fprintf(stderr, "Failed to convert CLR files path to absolute path\n"); + return false; + } + + return true; +} + +bool AssemblyAlreadyPresent(const char* addedAssemblies, const char* filenameWithoutExt) +{ + // Copy buffer as strtok munges input + char buf[strlen(addedAssemblies) + 1]; + strcpy(buf, addedAssemblies); + const char* token = strtok(buf, ":"); + + while (token != NULL) + { + if (strcmp(token, filenameWithoutExt) == 0) + { + return true; + } + token = strtok(NULL, ":"); + } + + return false; +} + +void AddFilesFromDirectoryToTpaList(const char* directory, char** 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 == NULL) + { + return; + } + + // Initially empty string + char* addedAssemblies = malloc(1); + if (addedAssemblies == NULL) + { + perror("Could not allocate buffer"); + closedir(dir); + return; + } + + addedAssemblies[0] = '\0'; + + // Walk the directory for each extension separately so that we first get files with .ni.dll extension, + // then files with .dll extension, etc. + size_t extIndex; + for (extIndex = 0; extIndex < sizeof(tpaExtensions) / sizeof(tpaExtensions[0]); extIndex++) + { + const char* ext = tpaExtensions[extIndex]; + size_t extLength = strlen(ext); + + struct dirent* entry; + + // For all entries in the directory + while ((entry = readdir(dir)) != NULL) + { + // 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: + { + char fullFilename[strlen(directory) + strlen(entry->d_name) + 2]; + strcpy(fullFilename, directory); + strcat(fullFilename, "/"); + strcat(fullFilename, entry->d_name); + + struct stat sb; + if (stat(fullFilename, &sb) == -1) + { + continue; + } + + if (!S_ISREG(sb.st_mode)) + { + continue; + } + } + break; + + default: + continue; + } + + const char* filename = entry->d_name; + + // Check if the extension matches the one we are looking for + int extPos = strlen(filename) - extLength; + const char* extLoc = filename + extPos; + if ((extPos <= 0) || (strncmp(extLoc, ext, extLength) != 0)) + { + continue; + } + + char filenameWithoutExt[strlen(filename) - extLength + 1]; + strncpy(filenameWithoutExt, filename, extPos); + filenameWithoutExt[extPos] = '\0'; + + // Make sure if we have an assembly with multiple extensions present, + // we insert only one version of it. + if (!AssemblyAlreadyPresent(addedAssemblies, filenameWithoutExt)) + { + char* buf = realloc( + addedAssemblies, + strlen(addedAssemblies) + strlen(filenameWithoutExt) + 2); + if (buf == NULL) + { + perror("Could not reallocate buffer"); + closedir(dir); + return; + } + addedAssemblies = buf; + + strcat(addedAssemblies, filenameWithoutExt); + strcat(addedAssemblies, ":"); + + buf = realloc( + *tpaList, + strlen(*tpaList) + strlen(directory) + strlen(filename) + 3); + if (buf == NULL) + { + perror("Could not reallocate buffer"); + free(addedAssemblies); + closedir(dir); + return; + } + *tpaList = buf; + + strcat(*tpaList, directory); + strcat(*tpaList, "/"); + strcat(*tpaList, filename); + strcat(*tpaList, ":"); + } + } + + // Rewind the directory stream to be able to iterate over it for the next extension + rewinddir(dir); + } + + free(addedAssemblies); + + closedir(dir); +} + + +const char* GetEnvValueBoolean(const char* envVariable) +{ + const char* envValue = getenv(envVariable); + if (envValue == NULL) + { + envValue = "0"; + } + + // CoreCLR expects strings "true" and "false" instead of "1" and "0". + if (strcmp(envValue, "1") == 0) + { + return "true"; + } + else + { + // Try again with lowercase + char* value = strdup(envValue); + if (value == NULL) + { + perror("Could not allocate buffer"); + return "false"; + } + + for (; *value; ++value) *value = tolower(*value); + + if (strcmp(value, "true") == 0) + { + return "true"; + } + } + + return "false"; +} diff --git a/src/coreclr/coreutils.h b/src/coreclr/coreutils.h new file mode 100644 index 000000000..cb1b9a412 --- /dev/null +++ b/src/coreclr/coreutils.h @@ -0,0 +1,47 @@ +#ifndef CORE_RUN_COMMON_H +#define CORE_RUN_COMMON_H + +#include + +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// https://github.com/dotnet/coreclr/blob/master/src/coreclr/hosts/unixcoreruncommon/coreruncommon.h + +// Get the path to entrypoint executable +bool GetEntrypointExecutableAbsolutePath(char** entrypointExecutable); + +// Get absolute path from the specified path. +// Return true in case of a success, false otherwise. +bool GetAbsolutePath(const char* path, char** absolutePath); + +// Get directory of the specified path. +// Return true in case of a success, false otherwise. +bool GetDirectory(const char* absolutePath, char** 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, char** clrFilesAbsolutePath); + +// Check if the provided assembly is already included in the list of assemblies. +// Return true if present, false otherwise. +bool AssemblyAlreadyPresent(const char* addedAssemblies, const char* filenameWithoutExt); + +// Add all *.dll, *.ni.dll, *.exe, and *.ni.exe files from the specified directory to the tpaList string. +void AddFilesFromDirectoryToTpaList(const char* directory, char** tpaList); + +const char* GetEnvValueBoolean(const char* envVariable); + +#if defined(__APPLE__) +#include +static const char * const coreClrDll = "libcoreclr.dylib"; +#else +static const char * const coreClrDll = "libcoreclr.so"; +#endif + +#endif // CORE_RUN_COMMON_H diff --git a/src/coreclr/pynetclr.h b/src/coreclr/pynetclr.h new file mode 100644 index 000000000..9b37b2515 --- /dev/null +++ b/src/coreclr/pynetclr.h @@ -0,0 +1,38 @@ +#ifndef PYNET_CLR_H +#define PYNET_CLR_H + +#include + +#define CLASS_NAME "Python.Runtime.PythonEngine" +#define ASSEMBLY_NAME "Python.Runtime" +#define PR_ASSEMBLY "Python.Runtime.dll" + +typedef void* (*py_init)(void); +typedef void (*py_finalize)(void); + +typedef struct +{ + char *pr_file; + char *error; + char *assembly_path; + char *assembly_name; + char *class_name; + char *init_method_name; + char *shutdown_method_name; + char *entry_path; + char *clr_path; + void* core_clr_lib; + void* host_handle; + unsigned int domain_id; + PyObject *module; + py_init init; + py_finalize shutdown; +} PyNet_Args; + +PyNet_Args *PyNet_Init(int); +void PyNet_Finalize(PyNet_Args *); + +void init(PyNet_Args *); +int createDelegates(PyNet_Args *); + +#endif // PYNET_CLR_H diff --git a/src/coreclr/pynetinit.c b/src/coreclr/pynetinit.c new file mode 100644 index 000000000..1a8c62665 --- /dev/null +++ b/src/coreclr/pynetinit.c @@ -0,0 +1,418 @@ +#include "pynetclr.h" + +#include "coreclrhost.h" +#include "coreutils.h" +#include "stdlib.h" + +#ifndef _WIN32 +#include "dirent.h" +#include "dlfcn.h" +#include "libgen.h" +#include "alloca.h" +#endif + +#ifndef SUCCEEDED +#define SUCCEEDED(Status) ((Status) >= 0) +#endif // !SUCCEEDED + +// Name of the environment variable controlling server GC. +// If set to 1, server GC is enabled on startup. If 0, server GC is +// disabled. Server GC is off by default. +static const char* serverGcVar = "CORECLR_SERVER_GC"; + +// initialize Core CLR and PythonNet +PyNet_Args *PyNet_Init(int ext) +{ + PyNet_Args *pn_args = (PyNet_Args *)malloc(sizeof(PyNet_Args)); + + pn_args->pr_file = PR_ASSEMBLY; + pn_args->assembly_name = ASSEMBLY_NAME; + pn_args->class_name = CLASS_NAME; + + pn_args->error = NULL; + pn_args->shutdown = NULL; + pn_args->module = NULL; + + if (ext == 0) + { + pn_args->init_method_name = "Initialize"; + } + else + { + pn_args->init_method_name = "InitExt"; + } + + pn_args->shutdown_method_name = "Shutdown"; + + init(pn_args); + + if (pn_args->error != NULL) + { + PyErr_SetString(PyExc_ImportError, pn_args->error); + } + + return pn_args; +} + +// Shuts down PythonNet and cleans up Core CLR +void PyNet_Finalize(PyNet_Args *pn_args) +{ + // Indicates failure + int exitCode = -1; + + // Call Python.Runtime.PythonEngine.Shutdown() + if (pn_args->shutdown != NULL) + { + pn_args->shutdown(); + } + + // Shutdown Core CLR + if (pn_args->core_clr_lib) + { + coreclr_shutdown_2_ptr shutdownCoreCLR = (coreclr_shutdown_2_ptr)dlsym(pn_args->core_clr_lib, "coreclr_shutdown_2"); + + if (shutdownCoreCLR == NULL) + { + fprintf(stderr, "Function coreclr_shutdown_2 not found in the libcoreclr.so\n"); + } + else if (pn_args->host_handle && pn_args->domain_id) + { + int latchedExitCode = 0; + int st = shutdownCoreCLR(pn_args->host_handle, pn_args->domain_id, &latchedExitCode); + if (!SUCCEEDED(st)) + { + fprintf(stderr, "coreclr_shutdown failed - status: 0x%08x\n", st); + exitCode = -1; + } + + if (exitCode != -1) + { + exitCode = latchedExitCode; + } + } + + if (dlclose(pn_args->core_clr_lib) != 0) + { + fprintf(stderr, "Warning - dlclose failed\n"); + } + } + + free(pn_args); +} + +void init(PyNet_Args* pn_args) +{ +#ifndef _WIN32 + //get python path system variable + PyObject *syspath = PySys_GetObject("path"); + pn_args->assembly_path = malloc(PATH_MAX); + const char *slash = "/"; + int found = 0; + + int ii; + for (ii = 0; ii < PyList_Size(syspath); ++ii) + { +#if PY_MAJOR_VERSION >= 3 + Py_ssize_t wlen; + wchar_t *wstr = PyUnicode_AsWideCharString(PyList_GetItem(syspath, ii), &wlen); + char *pydir = (char*)malloc(wlen + 1); + size_t mblen = wcstombs(pydir, wstr, wlen + 1); + if (mblen > wlen) + pydir[wlen] = '\0'; + PyMem_Free(wstr); +#else + const char *pydir = PyString_AsString(PyList_GetItem(syspath, ii)); +#endif + char *curdir = (char*) malloc(1024); + strncpy(curdir, strlen(pydir) > 0 ? pydir : ".", 1024); + strncat(curdir, slash, 1024); + +#if PY_MAJOR_VERSION >= 3 + free(pydir); +#endif + + //look in this directory for the pn_args->pr_file + DIR *dirp = opendir(curdir); + if (dirp != NULL) + { + struct dirent *dp; + while ((dp = readdir(dirp)) != NULL) + { + if (strcmp(dp->d_name, pn_args->pr_file) == 0) + { + strcpy(pn_args->assembly_path, curdir); + found = 1; + break; + } + } + closedir(dirp); + } + free(curdir); + + if (found) + { + break; + } + } + + if (!found) + { + fprintf(stderr, "Could not find assembly %s. \n", pn_args->pr_file); + return; + } +#endif + + if (!GetEntrypointExecutableAbsolutePath(&pn_args->entry_path)) + { + pn_args->error = "Unable to find entry point"; + return; + } + + if (!GetClrFilesAbsolutePath(pn_args->entry_path, "/usr/share/dotnet/shared/Microsoft.NETCore.App/2.0.0", &pn_args->clr_path)) + //if (!GetClrFilesAbsolutePath(pn_args->entry_path, NULL, &pn_args->clr_path))) + { + pn_args->error = "Unable to find clr path"; + return; + } + + int st = createDelegates(pn_args); + + if (SUCCEEDED(st)) + { + pn_args->module = pn_args->init(); + } + +#ifndef _WIN32 + free(pn_args->assembly_path); + free(pn_args->entry_path); +#endif +} + +int createDelegates(PyNet_Args * pn_args) +{ + // Indicates failure + int exitCode = -1; + +#ifdef _ARM_ + // libunwind library is used to unwind stack frame, but libunwind for ARM + // does not support ARM vfpv3/NEON registers in DWARF format correctly. + // Therefore let's disable stack unwinding using DWARF information + // See https://github.com/dotnet/coreclr/issues/6698 + // + // libunwind use following methods to unwind stack frame. + // UNW_ARM_METHOD_ALL 0xFF + // UNW_ARM_METHOD_DWARF 0x01 + // UNW_ARM_METHOD_FRAME 0x02 + // UNW_ARM_METHOD_EXIDX 0x04 + putenv((char *)("UNW_ARM_UNWIND_METHOD=6")); +#endif // _ARM_ + + char coreClrDllPath[strlen(pn_args->clr_path) + strlen(coreClrDll) + 2]; + strcpy(coreClrDllPath, pn_args->clr_path); + strcat(coreClrDllPath, "/"); + strcat(coreClrDllPath, coreClrDll); + + if (strlen(coreClrDllPath) >= PATH_MAX) + { + fprintf(stderr, "Absolute path to libcoreclr.so too long\n"); + return -1; + } + + // Get just the path component of the managed assembly path + char* appPath = NULL; + if (!GetDirectory(pn_args->assembly_path, &appPath)) + { + return -1; + } + + char* tpaList = NULL; + if (pn_args->assembly_path != NULL) + { + // Target assembly should be added to the tpa list. Otherwise corerun.exe + // may find wrong assembly to execute. + // Details can be found at https://github.com/dotnet/coreclr/issues/5631 + tpaList = malloc(strlen(appPath) + strlen(pn_args->pr_file) + 3); + + if(tpaList == NULL) + { + perror("Could not allocate buffer"); + free(appPath); + return -1; + } + + strcpy(tpaList, appPath); + strcat(tpaList, "/"); + strcat(tpaList, pn_args->pr_file); + strcat(tpaList, ":"); + } + + // Construct native search directory paths + char* nativeDllSearchDirs = malloc(strlen(appPath) + strlen(pn_args->clr_path) + 2); + + if (nativeDllSearchDirs == NULL) + { + perror("Could not allocate buffer"); + free(appPath); + if (tpaList != NULL) + { + free(tpaList); + } + return -1; + } + + strcpy(nativeDllSearchDirs, appPath); + strcat(nativeDllSearchDirs, ":"); + strcat(nativeDllSearchDirs, pn_args->clr_path); + + const char *coreLibraries = getenv("CORE_LIBRARIES"); + if (coreLibraries) + { + nativeDllSearchDirs = realloc(nativeDllSearchDirs, strlen(coreLibraries) + 2); + + if (nativeDllSearchDirs == NULL) + { + perror("Could not reallocate buffer"); + free(appPath); + if (tpaList != NULL) + { + free(tpaList); + } + return -1; + } + + strcat(nativeDllSearchDirs, ":"); + strcat(nativeDllSearchDirs, coreLibraries); + if (strcmp(coreLibraries, pn_args->clr_path) != 0) + { + AddFilesFromDirectoryToTpaList(coreLibraries, &tpaList); + } + } + + AddFilesFromDirectoryToTpaList(pn_args->clr_path, &tpaList); + + pn_args->core_clr_lib = dlopen(coreClrDllPath, RTLD_NOW | RTLD_LOCAL); + + if (pn_args->core_clr_lib != NULL) + { + coreclr_initialize_ptr initializeCoreCLR = (coreclr_initialize_ptr)dlsym(pn_args->core_clr_lib, "coreclr_initialize"); + coreclr_create_delegate_ptr createDelegate = (coreclr_create_delegate_ptr)dlsym(pn_args->core_clr_lib, "coreclr_create_delegate"); + + if (initializeCoreCLR == NULL) + { + fprintf(stderr, "Function coreclr_initialize not found in the libcoreclr.so\n"); + } + else if (createDelegate == NULL) + { + fprintf(stderr, "Function coreclr_create_delegate not found in the libcoreclr.so\n"); + } + else + { + // Check whether we are enabling server GC (off by default) + const char* useServerGc = GetEnvValueBoolean(serverGcVar); + + // 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", + "System.GC.Server", + "AppDomainCompatSwitch", + }; + const char *propertyValues[] = { + // TRUSTED_PLATFORM_ASSEMBLIES + tpaList, + // APP_PATHS + appPath, + // APP_NI_PATHS + appPath, + // NATIVE_DLL_SEARCH_DIRECTORIES + nativeDllSearchDirs, + // System.GC.Server + useServerGc, + // AppDomainCompatSwitch + "UseLatestBehaviorWhenTFMNotSpecified" + }; + + pn_args->host_handle = NULL; + pn_args->domain_id = 0; + + int st = initializeCoreCLR( + pn_args->entry_path, + "pythonnet", + sizeof(propertyKeys) / sizeof(propertyKeys[0]), + propertyKeys, + propertyValues, + &pn_args->host_handle, + &pn_args->domain_id); + + if (!SUCCEEDED(st)) + { + fprintf(stderr, "coreclr_initialize failed - status: 0x%08x\n", st); + exitCode = -1; + } + else + { + // Create init delegate + st = createDelegate( + pn_args->host_handle, + pn_args->domain_id, + pn_args->assembly_name, + pn_args->class_name, + pn_args->init_method_name, + (void**)&pn_args->init); + + if (!SUCCEEDED(st)) + { + fprintf(stderr, "coreclr_create_delegate failed - status: 0x%08x\n", st); + exitCode = -1; + } + + // Create shutdown delegate + st = createDelegate( + pn_args->host_handle, + pn_args->domain_id, + pn_args->assembly_name, + pn_args->class_name, + pn_args->shutdown_method_name, + (void**)&pn_args->shutdown); + + if (!SUCCEEDED(st)) + { + fprintf(stderr, "coreclr_create_delegate failed - status: 0x%08x\n", st); + exitCode = -1; + } + else + { + exitCode = 0; + } + } + } + } + else + { + const char* error = dlerror(); + fprintf(stderr, "dlopen failed to open the libcoreclr.so with error %s\n", error); + } + + free(appPath); + free(tpaList); + free(nativeDllSearchDirs); + + return exitCode; +} diff --git a/src/runtime/Python.Runtime.15.csproj b/src/runtime/Python.Runtime.15.csproj index 122132513..2f8502c94 100644 --- a/src/runtime/Python.Runtime.15.csproj +++ b/src/runtime/Python.Runtime.15.csproj @@ -141,7 +141,8 @@ - + + diff --git a/tools/nuget/nuget.exe b/tools/nuget/nuget.exe index 463f8e137..a34c36752 100644 Binary files a/tools/nuget/nuget.exe and b/tools/nuget/nuget.exe differ pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy