More disambiguation of Python in makefiles (#18284)
[mono-project.git] / mono / mini / main-core.c
blob0b303a386e48d7a5a340e0fc49bf8fd93063a9d5
1 #include <config.h>
2 #include <mono/utils/mono-compiler.h>
4 #if ENABLE_NETCORE
6 #include "mini.h"
7 #include "mini-runtime.h"
8 #include <mono/metadata/assembly.h>
9 #include <mono/metadata/assembly-internals.h>
10 #include <mono/metadata/environment.h>
11 #include <mono/metadata/loader-internals.h>
12 #include <mono/utils/mono-logger-internals.h>
14 #ifndef STDAPICALLTYPE
15 #define STDAPICALLTYPE
16 #endif
18 #if defined(_MSC_VER) && defined(HOST_WIN32) && defined(HOST_X86)
19 // Ensure that the exported symbols are not decorated and that only one set is exported
20 #pragma comment(linker, "/export:coreclr_initialize=_coreclr_initialize@28")
21 #pragma comment(linker, "/export:coreclr_execute_assembly=_coreclr_execute_assembly@24")
22 #pragma comment(linker, "/export:coreclr_shutdown_2=_coreclr_shutdown_2@12")
23 #pragma comment(linker, "/export:coreclr_create_delegate=_coreclr_create_delegate@24")
24 #undef MONO_API
25 #define MONO_API MONO_EXTERN_C
26 #endif
28 MONO_API int STDAPICALLTYPE coreclr_initialize (const char* exePath, const char* appDomainFriendlyName,
29 int propertyCount, const char** propertyKeys, const char** propertyValues,
30 void** hostHandle, unsigned int* domainId);
32 MONO_API int STDAPICALLTYPE coreclr_execute_assembly (void* hostHandle, unsigned int domainId,
33 int argc, const char** argv,
34 const char* managedAssemblyPath, unsigned int* exitCode);
36 MONO_API int STDAPICALLTYPE coreclr_shutdown_2 (void* hostHandle, unsigned int domainId, int* latchedExitCode);
38 MONO_API int STDAPICALLTYPE coreclr_create_delegate (void* hostHandle, unsigned int domainId,
39 const char* entryPointAssemblyName, const char* entryPointTypeName, const char* entryPointMethodName,
40 void** delegate);
42 typedef struct {
43 int assembly_count;
44 char **basenames; /* Foo.dll */
45 char **assembly_filepaths; /* /blah/blah/blah/Foo.dll */
46 } MonoCoreTrustedPlatformAssemblies;
48 typedef struct {
49 int dir_count;
50 char **dirs;
51 } MonoCoreNativeLibPaths;
53 static MonoCoreTrustedPlatformAssemblies *trusted_platform_assemblies;
54 static MonoCoreNativeLibPaths *native_lib_paths;
56 static void
57 mono_core_trusted_platform_assemblies_free (MonoCoreTrustedPlatformAssemblies *a)
59 if (!a)
60 return;
61 g_strfreev (a->basenames);
62 g_strfreev (a->assembly_filepaths);
63 g_free (a);
66 static void
67 mono_core_native_lib_paths_free (MonoCoreNativeLibPaths *dl)
69 if (!dl)
70 return;
71 g_strfreev (dl->dirs);
72 g_free (dl);
75 static gboolean
76 parse_trusted_platform_assemblies (const char *assemblies_paths)
78 // From
79 // https://docs.microsoft.com/en-us/dotnet/core/tutorials/netcore-hosting#step-3---prepare-runtime-properties
80 // this is ';' separated on Windows and ':' separated elsewhere.
81 char **parts = g_strsplit (assemblies_paths, G_SEARCHPATH_SEPARATOR_S, 0);
82 int asm_count = 0;
83 for (char **p = parts; *p != NULL && **p != '\0'; p++) {
84 #if 0
85 const char *part = *p;
86 // can't use logger, it's not initialized yet.
87 printf ("\t\tassembly %d = <%s>\n", asm_count, part);
88 #endif
89 asm_count++;
91 MonoCoreTrustedPlatformAssemblies *a = g_new0 (MonoCoreTrustedPlatformAssemblies, 1);
92 a->assembly_count = asm_count;
93 a->assembly_filepaths = parts;
94 a->basenames = g_new0 (char*, asm_count + 1);
95 for (int i = 0; i < asm_count; ++i) {
96 a->basenames[i] = g_path_get_basename (a->assembly_filepaths [i]);
98 a->basenames [asm_count] = NULL;
100 trusted_platform_assemblies = a;
101 return TRUE;
104 static gboolean
105 parse_native_dll_search_directories (const char *native_dlls_dirs)
107 char **parts = g_strsplit (native_dlls_dirs, G_SEARCHPATH_SEPARATOR_S, 0);
108 int dir_count = 0;
109 for (char **p = parts; *p != NULL && **p != '\0'; p++) {
110 #if 0
111 const char *part = *p;
112 // can't use logger, it's not initialized yet.
113 printf ("\t\tnative search dir %d = <%s>\n", dir_count, part);
114 #endif
115 dir_count++;
117 MonoCoreNativeLibPaths *dl = g_new0 (MonoCoreNativeLibPaths, 1);
118 dl->dirs = parts;
119 dl->dir_count = dir_count;
121 native_lib_paths = dl;
122 return TRUE;
125 static MonoAssembly*
126 mono_core_preload_hook (MonoAssemblyLoadContext *alc, MonoAssemblyName *aname, char **assemblies_path, gboolean refonly, gpointer user_data, MonoError *error)
128 MonoAssembly *result = NULL;
129 MonoCoreTrustedPlatformAssemblies *a = (MonoCoreTrustedPlatformAssemblies *)user_data;
130 /* TODO: check that CoreCLR wants the strong name semantics here */
131 MonoAssemblyCandidatePredicate predicate = &mono_assembly_candidate_predicate_sn_same_name;
132 void* predicate_ud = aname;
134 g_assert (aname);
135 g_assert (aname->name);
136 /* alc might be a user ALC - we get here from alc.LoadFromAssemblyName(), but we should load TPA assemblies into the default alc */
137 MonoAssemblyLoadContext *default_alc = mono_domain_default_alc (mono_alc_domain (alc));
139 char *basename = g_strconcat (aname->name, ".dll", (const char*)NULL); /* TODO: make sure CoreCLR never needs to load .exe files */
141 for (int i = 0; i < a->assembly_count; ++i) {
142 if (!strcmp (basename, a->basenames[i])) {
143 MonoAssemblyOpenRequest req;
144 mono_assembly_request_prepare_open (&req, refonly ? MONO_ASMCTX_REFONLY : MONO_ASMCTX_DEFAULT, default_alc);
145 req.request.predicate = predicate;
146 req.request.predicate_ud = predicate_ud;
148 const char *fullpath = a->assembly_filepaths[i];
150 gboolean found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
152 if (found) {
153 MonoImageOpenStatus status;
154 result = mono_assembly_request_open (fullpath, &req, &status);
155 /* TODO: do something with the status at the end? */
156 if (result)
157 break;
162 g_free (basename);
164 if (!result) {
165 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "netcore preload hook: did not find '%s'.", aname->name);
166 } else {
167 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "netcore preload hook: loading '%s' from '%s'.", aname->name, result->image->name);
169 return result;
172 static void
173 install_assembly_loader_hooks (void)
175 mono_install_assembly_preload_hook_v2 (mono_core_preload_hook, (void*)trusted_platform_assemblies, FALSE);
178 static gboolean
179 parse_properties (int propertyCount, const char** propertyKeys, const char** propertyValues)
181 // The a partial list of relevant properties is
182 // https://docs.microsoft.com/en-us/dotnet/core/tutorials/netcore-hosting#step-3---prepare-runtime-properties
183 // TODO: We should also pick up at least APP_PATHS and APP_NI_PATHS
184 // and PLATFORM_RESOURCE_ROOTS for satellite assemblies in culture-specific subdirectories
186 for (int i = 0; i < propertyCount; ++i) {
187 if (!strcmp (propertyKeys[i], "TRUSTED_PLATFORM_ASSEMBLIES")) {
188 parse_trusted_platform_assemblies (propertyValues[i]);
189 } else if (!strcmp (propertyKeys[i], "NATIVE_DLL_SEARCH_DIRECTORIES")) {
190 parse_native_dll_search_directories (propertyValues[i]);
191 } else if (!strcmp (propertyKeys[i], "System.Globalization.Invariant")) {
192 // TODO: Ideally we should propagate this through AppContext options
193 g_setenv ("DOTNET_SYSTEM_GLOBALIZATION_INVARIANT", propertyValues[i], TRUE);
194 } else {
195 #if 0
196 // can't use mono logger, it's not initialized yet.
197 printf ("\t Unprocessed property %03d '%s': <%s>\n", i, propertyKeys[i], propertyValues[i]);
198 #endif
201 return TRUE;
205 // Initialize the CoreCLR. Creates and starts CoreCLR host and creates an app domain
207 // Parameters:
208 // exePath - Absolute path of the executable that invoked the ExecuteAssembly
209 // appDomainFriendlyName - Friendly name of the app domain that will be created to execute the assembly
210 // propertyCount - Number of properties (elements of the following two arguments)
211 // propertyKeys - Keys of properties of the app domain
212 // propertyValues - Values of properties of the app domain
213 // hostHandle - Output parameter, handle of the created host
214 // domainId - Output parameter, id of the created app domain
216 // Returns:
217 // HRESULT indicating status of the operation. S_OK if the assembly was successfully executed
219 int STDAPICALLTYPE coreclr_initialize (const char* exePath, const char* appDomainFriendlyName,
220 int propertyCount, const char** propertyKeys, const char** propertyValues,
221 void** hostHandle, unsigned int* domainId)
223 mono_runtime_register_appctx_properties (propertyCount, propertyKeys, propertyValues);
225 // TODO: TRUSTED_PLATFORM_ASSEMBLIES is the property key for managed assemblies mapping
226 if (!parse_properties (propertyCount, propertyKeys, propertyValues))
227 return 0x80004005; /* E_FAIL */
229 install_assembly_loader_hooks ();
230 if (native_lib_paths != NULL)
231 mono_set_pinvoke_search_directories (native_lib_paths->dir_count, native_lib_paths->dirs);
234 * Don't use Mono's legacy assembly name matching behavior - respect
235 * the requested version and culture.
237 mono_loader_set_strict_assembly_name_check (TRUE);
239 return 0;
244 // Execute a managed assembly with given arguments
246 // Parameters:
247 // hostHandle - Handle of the host
248 // domainId - Id of the domain
249 // argc - Number of arguments passed to the executed assembly
250 // argv - Array of arguments passed to the executed assembly
251 // managedAssemblyPath - Path of the managed assembly to execute (or NULL if using a custom entrypoint).
252 // exitCode - Exit code returned by the executed assembly
254 // Returns:
255 // HRESULT indicating status of the operation. S_OK if the assembly was successfully executed
257 int STDAPICALLTYPE coreclr_execute_assembly (void* hostHandle, unsigned int domainId,
258 int argc, const char** argv,
259 const char* managedAssemblyPath, unsigned int* exitCode)
261 if (exitCode == NULL)
263 return -1;
267 // Make room for program name and executable assembly
269 int mono_argc = argc + 2;
271 char **mono_argv = (char **) malloc (sizeof (char *) * (mono_argc + 1 /* null terminated */));
272 const char **ptr = (const char **) mono_argv;
274 *ptr++ = NULL;
276 // executable assembly
277 *ptr++ = (char*) managedAssemblyPath;
279 // the rest
280 for (int i = 0; i < argc; ++i)
281 *ptr++ = argv [i];
283 *ptr = NULL;
285 mono_parse_env_options (&mono_argc, &mono_argv);
287 // TODO: Should be return code of Main only (mono_jit_exec result)
288 *exitCode = mono_main (mono_argc, mono_argv);
290 return 0;
294 // Shutdown CoreCLR. It unloads the app domain and stops the CoreCLR host.
296 // Parameters:
297 // hostHandle - Handle of the host
298 // domainId - Id of the domain
299 // latchedExitCode - Latched exit code after domain unloaded
301 // Returns:
302 // HRESULT indicating status of the operation. S_OK if the assembly was successfully executed
304 int STDAPICALLTYPE coreclr_shutdown_2 (void* hostHandle, unsigned int domainId, int* latchedExitCode)
306 mono_set_pinvoke_search_directories (0, NULL);
307 MonoCoreNativeLibPaths *dl = native_lib_paths;
308 native_lib_paths = NULL;
309 mono_core_native_lib_paths_free (dl);
311 MonoCoreTrustedPlatformAssemblies *a = trusted_platform_assemblies;
312 trusted_platform_assemblies = NULL;
313 mono_core_trusted_platform_assemblies_free (a);
315 *latchedExitCode = mono_environment_exitcode_get ();
317 return 0;
321 // Create a native callable delegate for a managed method.
323 // Parameters:
324 // hostHandle - Handle of the host
325 // domainId - Id of the domain
326 // entryPointAssemblyName - Name of the assembly which holds the custom entry point
327 // entryPointTypeName - Name of the type which holds the custom entry point
328 // entryPointMethodName - Name of the method which is the custom entry point
329 // delegate - Output parameter, the function stores a pointer to the delegate at the specified address
331 // Returns:
332 // HRESULT indicating status of the operation. S_OK if the assembly was successfully executed
334 int STDAPICALLTYPE coreclr_create_delegate (void* hostHandle, unsigned int domainId,
335 const char* entryPointAssemblyName, const char* entryPointTypeName, const char* entryPointMethodName,
336 void** delegate)
338 g_error ("Not implemented");
339 return 0;
341 #else
343 MONO_EMPTY_SOURCE_FILE (main_core);
344 #endif // ENABLE_NETCORE