Nuitka
The Python compiler
Loading...
Searching...
No Matches
MetaPathBasedLoader.c
1// Copyright 2026, Kay Hayen, mailto:kay.hayen@gmail.com find license text at end of file
2
3// This implements the loading of C compiled modules and shared library
4// extension modules bundled for standalone mode.
5
6// This is achieved mainly by registered a "sys.meta_path" loader, that then
7// gets asked for module names, and responds if knows about one. It's fed by
8// a table created at compile time.
9
10// The nature and use of these 2 loaded module kinds is very different, but
11// having them as distinct loaders would only require to duplicate the search
12// and registering of stuff.
13
14// This file is included from another C file, help IDEs to still parse it on
15// its own.
16#ifdef __IDE_ONLY__
17#include "nuitka/prelude.h"
18#endif
19
20#include "nuitka/unfreezing.h"
21
22#ifdef _WIN32
23#include <windows.h>
24#endif
25
26// Toggle to control the extension module preservation hack.
27//
28// This handles cases where Nuitka is unable to set the loading package context properly
29// (via `_Py_PackageContext`), causing an extension module (e.g. `duckdb`) to load into
30// the parent package namespace instead of its intended nested location (e.g. `duckdb.duckdb`).
31//
32// This results in conflicts where the extension overwrites existing Nuitka-compiled submodules
33// (e.g. `duckdb.functional`) or creates new modules in the wrong place (e.g. `duckdb.typing`).
34//
35// The algorithm resolves these conflicts:
36// 1. Identification: We scan for existing submodules that would be obscured.
37// 2. Preservation: These submodules are saved before the extension module loads.
38// 3. Relocation: After extension load, we identify modules (both preserved and newly created
39// by the extension) that are wrongly located at the top level. We move (alias) them to
40// the nested name the extension expects (e.g. `duckdb.functional` -> `duckdb.duckdb.functional`).
41// 4. Restoration: We restore the preserved module object to its original location so
42// that standard imports continue to work.
43// spell-checker: ignore duckdb
44#if PYTHON_VERSION >= 0x3c0 && !defined(_NUITKA_USE_UNEXPOSED_API)
45#define _NUITKA_EXTENSION_MODULE_PRESERVATION_HACK 1
46#endif
47
48extern PyTypeObject Nuitka_Loader_Type;
49
51 /* Python object folklore: */
52 PyObject_HEAD
53
54 /* The loader entry, to know what was loaded exactly. */
55 struct Nuitka_MetaPathBasedLoaderEntry const *m_loader_entry;
56};
57
58#if _NUITKA_EXE_MODE
59static inline bool isVerbose(void) { return Py_VerboseFlag != 0; }
60#elif _NUITKA_SYSFLAG_VERBOSE
61static inline bool isVerbose(void) { return true; }
62#else
63static inline bool isVerbose(void) { return false; }
64#endif
65
66static struct Nuitka_MetaPathBasedLoaderEntry *loader_entries = NULL;
67
68static bool hasFrozenModule(char const *name) {
69 for (struct _frozen const *p = PyImport_FrozenModules; p != NULL; p++) {
70 if (p->name == NULL) {
71 return false;
72 }
73
74 if (strcmp(p->name, name) == 0) {
75 break;
76 }
77 }
78
79 return true;
80}
81
82static char *appendModuleNameAsPath(char *buffer, char const *module_name, size_t buffer_size) {
83 // Skip to the end
84 while (*buffer != 0) {
85 buffer++;
86 buffer_size -= 1;
87 }
88
89 while (*module_name) {
90 if (buffer_size < 1) {
91 abort();
92 }
93
94 if (*module_name == '.') {
95 *buffer++ = SEP;
96 module_name++;
97 } else {
98 *buffer++ = *module_name++;
99 }
100
101 buffer_size -= 1;
102 }
103
104 *buffer = 0;
105
106 return buffer;
107}
108
109#if defined(_WIN32) && _NUITKA_STANDALONE_MODE
110
111static void appendModuleNameAsPathW(wchar_t *buffer, PyObject *module_name, size_t buffer_size) {
112 Py_ssize_t size;
113 wchar_t const *module_name_wstr = Nuitka_UnicodeAsWideString(module_name, &size);
114
115 while (size > 0) {
116 wchar_t c = *module_name_wstr++;
117 size -= 1;
118
119 if (c == L'.') {
120 c = FILENAME_SEP_CHAR;
121 }
122
123 appendWCharSafeW(buffer, c, buffer_size);
124 }
125}
126#endif
127
128// TODO: This updates the wrong absolute path. We ought to change it to
129// the "module_path_name" at the time of writing it, then we save a few
130// bytes in the blob, and don't have to create that string here.
131#if _NUITKA_STANDALONE_MODE
132static void patchCodeObjectPaths(PyCodeObject *code_object, PyObject *module_path) {
133 code_object->co_filename = module_path;
134 Py_INCREF(module_path);
135
136 Py_ssize_t consts_count = PyTuple_GET_SIZE(code_object->co_consts);
137
138 for (Py_ssize_t i = 0; i < consts_count; i++) {
139 PyObject *constant = PyTuple_GET_ITEM(code_object->co_consts, i);
140
141 if (PyCode_Check(constant)) {
142 patchCodeObjectPaths((PyCodeObject *)constant, module_path);
143 }
144 }
145}
146#endif
147
148NUITKA_MAY_BE_UNUSED static PyObject *MAKE_RELATIVE_PATH_FROM_NAME(char const *name, bool is_package, bool dir_only) {
149 char buffer[MAXPATHLEN + 1] = {0};
150
151 appendModuleNameAsPath(buffer, name, sizeof(buffer));
152
153 if (dir_only == false) {
154 if (is_package) {
155 appendCharSafe(buffer, SEP, sizeof(buffer));
156 appendStringSafe(buffer, "__init__.py", sizeof(buffer));
157 } else {
158 appendStringSafe(buffer, ".py", sizeof(buffer));
159 }
160 } else {
161 if (is_package == false) {
162 char *sep = strrchr(buffer, SEP);
163 if (sep) {
164 *sep = 0;
165 } else {
166 buffer[0] = '.';
167 buffer[1] = 0;
168 }
169 }
170 }
171
172 PyObject *module_path_entry_base = Nuitka_String_FromString(buffer);
173
174 PyObject *result = MAKE_RELATIVE_PATH(module_path_entry_base);
175
176 Py_DECREF(module_path_entry_base);
177
178 return result;
179}
180
181static PyObject *_makeDunderPathObject(PyThreadState *tstate, PyObject *module_path_entry) {
182 CHECK_OBJECT(module_path_entry);
183
184 PyObject *path_list = MAKE_LIST_EMPTY(tstate, 1);
185 if (unlikely(path_list == NULL)) {
186 return NULL;
187 }
188
189 PyList_SET_ITEM0(path_list, 0, module_path_entry);
190
191 CHECK_OBJECT(path_list);
192 return path_list;
193}
194
195static PyObject *getModuleDirectory(PyThreadState *tstate, struct Nuitka_MetaPathBasedLoaderEntry const *entry);
196static PyObject *getModuleFileValue(PyThreadState *tstate, struct Nuitka_MetaPathBasedLoaderEntry const *entry);
197
198static PyObject *loadModuleFromCodeObject(PyThreadState *tstate, PyObject *module, PyCodeObject *code_object,
199 struct Nuitka_MetaPathBasedLoaderEntry const *entry) {
200 assert(code_object != NULL);
201
202 char const *name = entry->name;
203 bool is_package = (entry->flags & NUITKA_PACKAGE_FLAG) != 0;
204
205 {
206 NUITKA_MAY_BE_UNUSED bool b_res = Nuitka_SetModuleString(name, module);
207 assert(b_res != false);
208 }
209
210 PyObject *module_path_entry = NULL;
211 PyObject *module_path;
212
213#if defined(_NUITKA_FREEZER_HAS_FILE_PATH)
214 if (entry->file_path != NULL) {
215 module_path = getModuleFileValue(tstate, entry);
216
217 if (unlikely(module_path == NULL)) {
218 return NULL;
219 }
220
221 if (is_package) {
222 module_path_entry = getModuleDirectory(tstate, entry);
223
224 if (unlikely(module_path_entry == NULL)) {
225 Py_DECREF(module_path);
226
227 return NULL;
228 }
229 }
230 } else
231#endif
232 {
233 char buffer[MAXPATHLEN + 1] = {0};
234
235 if (is_package) {
236 appendModuleNameAsPath(buffer, name, sizeof(buffer));
237 PyObject *module_path_entry_base = Nuitka_String_FromString(buffer);
238
239 module_path_entry = MAKE_RELATIVE_PATH(module_path_entry_base);
240 Py_DECREF(module_path_entry_base);
241
242 appendCharSafe(buffer, SEP, sizeof(buffer));
243 appendStringSafe(buffer, "__init__.py", sizeof(buffer));
244 } else {
245 appendModuleNameAsPath(buffer, name, sizeof(buffer));
246 appendStringSafe(buffer, ".py", sizeof(buffer));
247 }
248
249 PyObject *module_path_name = Nuitka_String_FromString(buffer);
250
251 module_path = MAKE_RELATIVE_PATH(module_path_name);
252 Py_DECREF(module_path_name);
253 }
254
255 if (is_package) {
256 /* Set __path__ properly, unlike frozen module importer does. */
257 PyObject *path_list = _makeDunderPathObject(tstate, module_path_entry);
258
259 int res = PyObject_SetAttr(module, const_str_plain___path__, path_list);
260 if (unlikely(res != 0)) {
261 return NULL;
262 }
263
264 Py_DECREF(path_list);
265
266 PyObject *module_name = LOOKUP_ATTRIBUTE(tstate, module, const_str_plain___name__);
267 CHECK_OBJECT(module_name);
268
269 res = PyObject_SetAttr(module, const_str_plain___package__, module_name);
270
271 if (unlikely(res != 0)) {
272 return NULL;
273 }
274 }
275
276#if _NUITKA_STANDALONE_MODE
277 patchCodeObjectPaths(code_object, module_path);
278#endif
279
280 PGO_onModuleEntered(name);
281 module = PyImport_ExecCodeModuleEx((char *)name, (PyObject *)code_object, Nuitka_String_AsString(module_path));
282 PGO_onModuleExit(name, module == NULL);
283
284 Py_DECREF(module_path);
285
286 return module;
287}
288
289static struct Nuitka_MetaPathBasedLoaderEntry *findEntry(char const *name) {
290 struct Nuitka_MetaPathBasedLoaderEntry *current = loader_entries;
291 assert(current);
292
293 while (current->name != NULL) {
294 if ((current->flags & NUITKA_TRANSLATED_FLAG) != 0) {
295 current->name = UN_TRANSLATE_NAME(current->name);
296 current->flags -= NUITKA_TRANSLATED_FLAG;
297 }
298
299 if (strcmp(name, current->name) == 0) {
300 return current;
301 }
302
303 current++;
304 }
305
306 return NULL;
307}
308
309#if !_NUITKA_STANDALONE_MODE
310static struct Nuitka_MetaPathBasedLoaderEntry *findContainingPackageEntry(char const *name) {
311 struct Nuitka_MetaPathBasedLoaderEntry *current = loader_entries;
312
313 // Consider the package name of the searched entry.
314 char const *package_name_end = strrchr(name, '.');
315 if (package_name_end == NULL) {
316 return NULL;
317 }
318
319 size_t length = package_name_end - name;
320
321 while (current->name != NULL) {
322 if ((current->flags & NUITKA_TRANSLATED_FLAG) != 0) {
323 current->name = UN_TRANSLATE_NAME(current->name);
324 current->flags -= NUITKA_TRANSLATED_FLAG;
325 }
326
327 if ((current->flags & NUITKA_PACKAGE_FLAG) != 0) {
328 if (strlen(current->name) == length && strncmp(name, current->name, length) == 0) {
329 return current;
330 }
331 }
332
333 current++;
334 }
335
336 return NULL;
337}
338
339static PyObject *_getFileList(PyThreadState *tstate, PyObject *dirname) {
340 static PyObject *listdir_func = NULL;
341
342 // TODO: Use OS_LISTDIR instead.
343
344 if (listdir_func == NULL) {
345 listdir_func = PyObject_GetAttrString(IMPORT_HARD_OS(), "listdir");
346 }
347
348 if (unlikely(listdir_func == NULL)) {
349 return NULL;
350 }
351
352 PyObject *result = CALL_FUNCTION_WITH_SINGLE_ARG(tstate, listdir_func, dirname);
353
354 return result;
355}
356
357#if PYTHON_VERSION < 0x300
358static PyObject *_getImportingSuffixesByPriority(PyThreadState *tstate, int kind) {
359 static PyObject *result = NULL;
360
361 if (result == NULL) {
362 result = MAKE_LIST_EMPTY(tstate, 0);
363
364 PyObject *imp_module = PyImport_ImportModule("imp");
365 PyObject *get_suffixes_func = PyObject_GetAttrString(imp_module, "get_suffixes");
366
367 PyObject *suffix_list = CALL_FUNCTION_NO_ARGS(tstate, get_suffixes_func);
368
369 for (int i = 0; i < PyList_GET_SIZE(suffix_list); i++) {
370 PyObject *module_kind = PyTuple_GET_ITEM(PyList_GET_ITEM(suffix_list, i), 2);
371
372 if (PyInt_AsLong(module_kind) == kind) {
373 LIST_APPEND0(result, PyTuple_GET_ITEM(PyList_GET_ITEM(suffix_list, i), 0));
374 }
375 }
376
377 Py_DECREF(suffix_list);
378 }
379
380 return result;
381}
382#endif
383
384static PyObject *getExtensionModuleSuffixesByPriority(PyThreadState *tstate) {
385 static PyObject *result = NULL;
386
387 if (result == NULL) {
388#if PYTHON_VERSION < 0x300
389 result = _getImportingSuffixesByPriority(tstate, 3);
390#else
391 static PyObject *machinery_module = NULL;
392
393 if (machinery_module == NULL) {
394 machinery_module = PyImport_ImportModule("importlib.machinery");
395 }
396
397 result = PyObject_GetAttrString(machinery_module, "EXTENSION_SUFFIXES");
398#endif
399 }
400
401 CHECK_OBJECT(result);
402 return result;
403}
404
405static PyObject *installed_extension_modules = NULL;
406
407static bool scanModuleInPackagePath(PyThreadState *tstate, PyObject *module_name, char const *parent_module_name) {
408 PyObject *sys_modules = Nuitka_GetSysModules();
409
410 PyObject *parent_module = PyDict_GetItemString(sys_modules, parent_module_name);
411 CHECK_OBJECT(parent_module);
412
413 PyObject *parent_path = PyObject_GetAttr(parent_module, const_str_plain___path__);
414
415 // Accept that it might be deleted.
416 if (parent_path == NULL || !PyList_Check(parent_path)) {
417 return false;
418 }
419
420 PyObject *candidates = MAKE_LIST_EMPTY(tstate, 0);
421
422 // Search only relative to the parent name of course.
423 char const *module_relative_name_str = Nuitka_String_AsString(module_name) + strlen(parent_module_name) + 1;
424
425 Py_ssize_t parent_path_size = PyList_GET_SIZE(parent_path);
426
427 for (Py_ssize_t i = 0; i < parent_path_size; i += 1) {
428 PyObject *path_element = PyList_GET_ITEM(parent_path, i);
429
430 PyObject *filenames_list = _getFileList(tstate, path_element);
431
432 if (filenames_list == NULL) {
433 CLEAR_ERROR_OCCURRED(tstate);
434 continue;
435 }
436
437 Py_ssize_t filenames_list_size = PyList_GET_SIZE(filenames_list);
438
439 for (Py_ssize_t j = 0; j < filenames_list_size; j += 1) {
440 PyObject *filename = PyList_GET_ITEM(filenames_list, j);
441
442 if (Nuitka_String_CheckExact(filename)) {
443 char const *filename_str = Nuitka_String_AsString(filename);
444
445 if (strncmp(filename_str, module_relative_name_str, strlen(module_relative_name_str)) == 0 &&
446 filename_str[strlen(module_relative_name_str)] == '.') {
447 LIST_APPEND1(candidates, MAKE_TUPLE2(tstate, path_element, filename));
448 }
449 }
450 }
451 }
452
453#if 0
454 PRINT_STRING("CANDIDATES:");
455 PRINT_STRING(Nuitka_String_AsString(module_name));
456 PRINT_STRING(module_relative_name_str);
457 PRINT_ITEM(candidates);
458 PRINT_NEW_LINE();
459#endif
460
461 // Look up C-extension suffixes, these are used with highest priority.
462 PyObject *suffix_list = getExtensionModuleSuffixesByPriority(tstate);
463
464 bool result = false;
465
466 for (Py_ssize_t i = 0; i < PyList_GET_SIZE(suffix_list); i += 1) {
467 PyObject *suffix = PyList_GET_ITEM(suffix_list, i);
468
469 char const *suffix_str = Nuitka_String_AsString(suffix);
470
471 for (Py_ssize_t j = 0; j < PyList_GET_SIZE(candidates); j += 1) {
472 PyObject *entry = PyList_GET_ITEM(candidates, j);
473
474 PyObject *directory = PyTuple_GET_ITEM(entry, 0);
475 PyObject *candidate = PyTuple_GET_ITEM(entry, 1);
476
477 char const *candidate_str = Nuitka_String_AsString(candidate);
478
479 if (strcmp(suffix_str, candidate_str + strlen(module_relative_name_str)) == 0) {
480 PyObject *fullpath = JOIN_PATH2(directory, candidate);
481
482 if (installed_extension_modules == NULL) {
483 installed_extension_modules = MAKE_DICT_EMPTY(tstate);
484 }
485
486// Force path to unicode, to have easier consumption, as we need a wchar_t or char *
487// from it later, and we don't want to test there.
488#if PYTHON_VERSION < 0x300 && defined(_WIN32)
489 PyObject *tmp = PyUnicode_FromObject(fullpath);
490 Py_DECREF(fullpath);
491 fullpath = tmp;
492#endif
493
494 DICT_SET_ITEM(installed_extension_modules, module_name, fullpath);
495
496 result = true;
497 break;
498 }
499 }
500 }
501
502 Py_DECREF(candidates);
503
504 return result;
505}
506
507static PyObject *callIntoExtensionModule(PyThreadState *tstate, char const *full_name, const filename_char_t *filename,
508 bool is_package);
509
510static PyObject *callIntoInstalledExtensionModule(PyThreadState *tstate, PyObject *module_name,
511 PyObject *extension_module_filename) {
512#if _WIN32
513 // We can rely on unicode object to be there in case of Windows, to have an easier time to
514 // create the string needed.
515 assert(PyUnicode_CheckExact(extension_module_filename));
516
517 wchar_t const *extension_module_filename_str = Nuitka_UnicodeAsWideString(extension_module_filename, NULL);
518#else
519 char const *extension_module_filename_str = Nuitka_String_AsString(extension_module_filename);
520#endif
521
522 // TODO: The value of "is_package" is guessed, maybe infer from filename being
523 // a "__init__.so" and the like.
524 return callIntoExtensionModule(tstate, Nuitka_String_AsString(module_name), extension_module_filename_str, false);
525}
526
527#endif
528
529static char const *getEntryModeString(struct Nuitka_MetaPathBasedLoaderEntry const *entry) {
530 char const *mode = "compiled";
531
532 if ((entry->flags & NUITKA_EXTENSION_MODULE_FLAG) != 0) {
533 mode = "extension";
534 } else if ((entry->flags & NUITKA_BYTECODE_FLAG) != 0) {
535 mode = "bytecode";
536 }
537
538 return mode;
539}
540
541static char *_kw_list_find_module[] = {(char *)"fullname", (char *)"unused", NULL};
542
543static PyObject *_nuitka_loader_find_module(PyObject *self, PyObject *args, PyObject *kwds) {
544 PyObject *module_name;
545 PyObject *unused;
546
547 int res = PyArg_ParseTupleAndKeywords(args, kwds, "O|O:find_module", (char **)_kw_list_find_module, &module_name,
548 &unused);
549
550 if (unlikely(res == 0)) {
551 return NULL;
552 }
553
554 char const *name = Nuitka_String_AsString(module_name);
555
556 if (isVerbose()) {
557 PySys_WriteStderr("import %s # considering responsibility (find_module)\n", name);
558 }
559
560 struct Nuitka_MetaPathBasedLoaderEntry *entry = findEntry(name);
561
562 if (entry) {
563 if (isVerbose()) {
564 PySys_WriteStderr("import %s # claimed responsibility (%s)\n", name, getEntryModeString(entry));
565 }
566
567 PyObject *metapath_based_loader = (PyObject *)&Nuitka_Loader_Type;
568
569 Py_INCREF(metapath_based_loader);
570 return metapath_based_loader;
571 }
572
573 if (hasFrozenModule(name)) {
574 if (isVerbose()) {
575 PySys_WriteStderr("import %s # claimed responsibility (frozen)\n", name);
576 }
577
578 PyObject *metapath_based_loader = (PyObject *)&Nuitka_Loader_Type;
579
580 Py_INCREF(metapath_based_loader);
581 return metapath_based_loader;
582 }
583
584#if !_NUITKA_STANDALONE_MODE
585 entry = findContainingPackageEntry(name);
586
587 if (entry != NULL) {
588 PyThreadState *tstate = PyThreadState_GET();
589
590 bool result = scanModuleInPackagePath(tstate, module_name, entry->name);
591
592 if (result) {
593 PyObject *metapath_based_loader = (PyObject *)&Nuitka_Loader_Type;
594
595 Py_INCREF(metapath_based_loader);
596 return metapath_based_loader;
597 }
598 }
599#endif
600
601 if (isVerbose()) {
602 PySys_WriteStderr("import %s # denied responsibility\n", name);
603 }
604
605 Py_INCREF_IMMORTAL(Py_None);
606 return Py_None;
607}
608
609static char const *_kw_list_get_data[] = {"filename", NULL};
610
611static PyObject *_nuitka_loader_get_data(PyObject *self, PyObject *args, PyObject *kwds) {
612 PyObject *filename;
613
614 int res = PyArg_ParseTupleAndKeywords(args, kwds, "O:get_data", (char **)_kw_list_get_data, &filename);
615
616 if (unlikely(res == 0)) {
617 return NULL;
618 }
619
620 PyThreadState *tstate = PyThreadState_GET();
621
622 return GET_FILE_BYTES(tstate, filename);
623}
624
625static void setModuleFileValue(PyThreadState *tstate, PyObject *module, filename_char_t const *filename) {
626 CHECK_OBJECT(module);
627 assert(filename != NULL);
628
629 assert(PyModule_Check(module));
630
631 PyObject *dict = PyModule_GetDict(module);
632
633 // TODO: We should have DICT_SET_ITEM0/1 for these things.
634 PyObject *new_file_value = Nuitka_String_FromFilename(filename);
635 DICT_SET_ITEM(dict, const_str_plain___file__, new_file_value);
636 Py_DECREF(new_file_value);
637}
638
639#if PYTHON_VERSION < 0x300
640typedef void (*entrypoint_t)(void);
641#else
642typedef PyObject *(*entrypoint_t)(void);
643#endif
644
645#ifndef _WIN32
646// Shared libraries loading.
647#include <dlfcn.h>
648#endif
649
650#if PYTHON_VERSION >= 0x350
651static PyObject *createModuleSpec(PyThreadState *tstate, PyObject *module_name, PyObject *origin, bool is_package);
652#endif
653
654static void _fillExtensionModuleDllEntryFunctionName(PyThreadState *tstate, char *buffer, size_t buffer_size,
655 char const *name) {
656
657#if PYTHON_VERSION >= 0x350
658 PyObject *name_bytes_obj = PyBytes_FromString(name);
659 PyObject *name_obj = BYTES_DECODE2(tstate, name_bytes_obj, Nuitka_String_FromString("utf8"));
660 Py_DECREF(name_bytes_obj);
661
662 PyObject *name_ascii = UNICODE_ENCODE2(tstate, name_obj, const_str_plain_ascii);
663
664 if (name_ascii == NULL) {
665 DROP_ERROR_OCCURRED(tstate);
666
667 PyObject *name_punycode = UNICODE_ENCODE2(tstate, name_obj, const_str_plain_punycode);
668
669 CHECK_OBJECT(name_punycode);
670
671 snprintf(buffer, buffer_size, "PyInitU_%s", Nuitka_Bytes_AsString(name_punycode));
672
673 Py_DECREF(name_punycode);
674 } else {
675 Py_DECREF(name_ascii);
676
677 snprintf(buffer, buffer_size, "PyInit_%s", name);
678 }
679 Py_DECREF(name_obj);
680#else
681
682 snprintf(buffer, buffer_size,
683#if PYTHON_VERSION < 0x300
684 "init%s",
685#else
686 "PyInit_%s",
687#endif
688 name);
689#endif
690}
691
692#if _NUITKA_STANDALONE_MODE
693// Create the filename from full path module name with dots, and translate these
694// into directory separators.
695static void _makeModuleCFilenameValue(filename_char_t *filename, size_t filename_size, char const *module_name_cstr,
696 PyObject *module_name, bool is_package) {
697#ifdef _WIN32
698#if _NUITKA_ONEFILE_DLL_MODE
699 filename_char_t const *base_directory = getDllDirectory();
700#else
701 filename_char_t const *base_directory = getBinaryDirectoryWideChars(true);
702#endif
703 copyStringSafeW(filename, base_directory, filename_size);
704 appendWCharSafeW(filename, FILENAME_SEP_CHAR, filename_size);
705 appendModuleNameAsPathW(filename, module_name, filename_size);
706 if (is_package) {
707 appendWCharSafeW(filename, FILENAME_SEP_CHAR, filename_size);
708 appendStringSafeW(filename, "__init__", filename_size);
709 }
710 appendStringSafeW(filename, ".pyd", filename_size);
711#else
712#if _NUITKA_ONEFILE_DLL_MODE
713 filename_char_t const *base_directory = getDllDirectory();
714#else
715 filename_char_t const *base_directory = getBinaryDirectoryHostEncoded(true);
716#endif
717 copyStringSafe(filename, base_directory, filename_size);
718 appendCharSafe(filename, FILENAME_SEP_CHAR, filename_size);
719 appendModuleNameAsPath(filename, module_name_cstr, filename_size);
720 if (is_package) {
721 appendCharSafe(filename, FILENAME_SEP_CHAR, filename_size);
722 appendStringSafe(filename, "__init__", filename_size);
723 }
724 appendStringSafe(filename, ".so", filename_size);
725#endif
726}
727#endif
728
729#if PYTHON_VERSION >= 0x3c0 && defined(_NUITKA_USE_UNEXPOSED_API)
730extern _Thread_local const char *pkgcontext;
731#endif
732
733static const char *NuitkaImport_SwapPackageContext(const char *new_context) {
734// TODO: The locking APIs for 3.13 give errors here that are not explained
735// yet.
736#if PYTHON_VERSION >= 0x3c0
737 // spell-checker: ignore pkgcontext
738 struct _import_runtime_state *imports = Nuitka_PyRuntime__imports;
739 const char *old_context = imports->pkgcontext;
740 imports->pkgcontext = new_context;
741#if PYTHON_VERSION >= 0x3c0 && defined(_NUITKA_USE_UNEXPOSED_API)
742 pkgcontext = new_context;
743#endif
744 return old_context;
745#elif PYTHON_VERSION >= 0x370
746 char const *old_context = _Py_PackageContext;
747 _Py_PackageContext = (char *)new_context;
748 return old_context;
749#else
750 char *old_context = _Py_PackageContext;
751 _Py_PackageContext = (char *)new_context;
752 return (char const *)old_context;
753#endif
754}
755
756static entrypoint_t _loadExtensionModuleInitAddress(PyThreadState *tstate, char const *full_name,
757 const filename_char_t *filename) {
758 // Determine the basename of the module to load.
759 char const *dot = strrchr(full_name, '.');
760 char const *name;
761
762 if (dot == NULL) {
763 name = full_name;
764 } else {
765 name = dot + 1;
766 }
767
768 char entry_function_name[1024];
769 _fillExtensionModuleDllEntryFunctionName(tstate, entry_function_name, sizeof(entry_function_name), name);
770
771#ifdef _WIN32
772 if (isVerbose()) {
773 PySys_WriteStderr("import %s # LoadLibraryExW(\"%S\");\n", full_name, filename);
774 }
775
776#ifndef _NUITKA_EXPERIMENTAL_DEBUG_STANDALONE
777 // Disable all but critical errors, prevents dialogs from showing.
778 // spell-checker: ignore SEM_FAILCRITICALERRORS
779 unsigned int old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
780#endif
781
782 HINSTANCE hDLL;
783#if PYTHON_VERSION >= 0x380
784 Py_BEGIN_ALLOW_THREADS;
785 hDLL = LoadLibraryExW(filename, NULL,
786// Where the onefile bootstrap is ran, we don't have anything to load from.
787#if !_NUITKA_ONEFILE_DLL_MODE
788 LOAD_LIBRARY_SEARCH_APPLICATION_DIR |
789#endif
790 LOAD_LIBRARY_SEARCH_SYSTEM32 | LOAD_LIBRARY_SEARCH_USER_DIRS |
791 LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR);
792 Py_END_ALLOW_THREADS;
793#else
794 hDLL = LoadLibraryExW(filename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
795#endif
796
797#ifndef _NUITKA_EXPERIMENTAL_DEBUG_STANDALONE
798 SetErrorMode(old_mode);
799#endif
800
801 if (unlikely(hDLL == NULL)) {
802 char buffer[1024];
803
804 char error_message[1024];
805 int size;
806
807 unsigned int error_code = GetLastError();
808
809 size = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error_code, 0,
810 (LPTSTR)error_message, sizeof(error_message), NULL);
811
812 // Report either way even if failed to get error message.
813 if (size == 0) {
814 int ret = PyOS_snprintf(buffer, sizeof(buffer), "LoadLibraryExW '%S' failed with error code %d", filename,
815 error_code);
816
817 assert(ret >= 0);
818 } else {
819 // Strip trailing newline.
820 if (size >= 2 && error_message[size - 2] == '\r' && error_message[size - 1] == '\n') {
821 size -= 2;
822 error_message[size] = '\0';
823 }
824 int ret = PyOS_snprintf(buffer, sizeof(buffer), "LoadLibraryExW '%S' failed: %s", filename, error_message);
825 assert(ret >= 0);
826 }
827
828 SET_CURRENT_EXCEPTION_TYPE0_STR(tstate, PyExc_ImportError, buffer);
829 return NULL;
830 }
831
832 entrypoint_t entrypoint = (entrypoint_t)GetProcAddress(hDLL, entry_function_name);
833#else
834 // This code would work for all versions, we are avoiding access to interpreter
835 // structure internals of 3.8 or higher.
836 // spell-checker: ignore getdlopenflags,dlopenflags
837
838#ifdef __wasi__
839 const char *error = "dynamic libraries are not implemented in wasi";
840 SET_CURRENT_EXCEPTION_TYPE0_STR(tstate, PyExc_ImportError, error);
841 return NULL;
842
843 entrypoint_t entrypoint = NULL;
844#else
845 static PyObject *dlopenflags_object = NULL;
846 if (dlopenflags_object == NULL) {
847 dlopenflags_object = CALL_FUNCTION_NO_ARGS(tstate, Nuitka_SysGetObject("getdlopenflags"));
848 }
849 int dlopenflags = PyInt_AsLong(dlopenflags_object);
850
851 if (isVerbose()) {
852 PySys_WriteStderr("import %s # dlopen(\"%s\", %x);\n", full_name, filename, dlopenflags);
853 }
854
855 void *handle = dlopen(filename, dlopenflags);
856
857 if (unlikely(handle == NULL)) {
858 const char *error = dlerror();
859
860 if (unlikely(error == NULL)) {
861 error = "unknown dlopen() error";
862 }
863
864 SET_CURRENT_EXCEPTION_TYPE0_STR(tstate, PyExc_ImportError, error);
865 return NULL;
866 }
867
868 entrypoint_t entrypoint = (entrypoint_t)dlsym(handle, entry_function_name);
869#endif // __wasi__
870#endif
871
872 return entrypoint;
873}
874
875static PyObject *callIntoExtensionModule(PyThreadState *tstate, char const *full_name, const filename_char_t *filename,
876 bool is_package) {
877 // Determine the package name and basename of the module to load.
878 char const *dot = strrchr(full_name, '.');
879 char const *package;
880
881 if (dot == NULL) {
882 package = NULL;
883 } else {
884 // The extension modules do expect it to be full name in context.
885 package = (char *)full_name;
886 }
887
888 entrypoint_t entrypoint = _loadExtensionModuleInitAddress(tstate, full_name, filename);
889
890 if (entrypoint == NULL) {
891 return NULL;
892 }
893
894 assert(entrypoint);
895
896 char const *old_context = NuitkaImport_SwapPackageContext(package);
897
898#if _NUITKA_EXTENSION_MODULE_PRESERVATION_HACK
899 char const *base_name = strrchr(full_name, '.');
900 PyObject *base_name_obj = NULL;
901 PyObject *prefix_name_obj = NULL;
902 PyObject *preserved_basename_module = NULL;
903 PyObject *preserved_sub_modules = NULL;
904
905 if (base_name != NULL) {
906 base_name_obj = Nuitka_String_FromString(base_name + 1);
907 preserved_basename_module = Nuitka_GetModule(tstate, base_name_obj);
908 Py_XINCREF(preserved_basename_module);
909
910 prefix_name_obj = Nuitka_String_FromStringAndSize(full_name, base_name - full_name + 1);
911
912 if (preserved_basename_module != NULL) {
913 preserved_sub_modules = MAKE_DICT_EMPTY(tstate);
914
915 PyObject *modules_dict = Nuitka_GetSysModules();
916
917 Py_ssize_t pos = 0;
918 PyObject *key, *value;
919
920 PyObject *base_name_prefix = BINARY_OPERATION_ADD_OBJECT_UNICODE_UNICODE(base_name_obj, const_str_dot);
921#if _NUITKA_EXPERIMENTAL_DEBUG_EXTENSION_MODULE_PRESERVATION_HACK
922 PRINT_STRING("Scanning for sub-modules needing protection:");
923 PRINT_ITEM_LINE(base_name_prefix);
924#endif
925 while (Nuitka_DictNext(modules_dict, &pos, &key, &value)) {
926 // TODO: Should have nuitka_bool return values for these as well maybe.
927 PyObject *starts_with_result = UNICODE_STARTSWITH2(tstate, key, base_name_prefix);
928
929 if (CHECK_IF_TRUE(starts_with_result) == 1) {
930 DICT_SET_ITEM(preserved_sub_modules, key, value);
931 }
932
933 Py_DECREF(starts_with_result);
934 }
935
936#if _NUITKA_EXPERIMENTAL_DEBUG_EXTENSION_MODULE_PRESERVATION_HACK
937 PRINT_ITEM_LINE(preserved_sub_modules);
938#endif
939 }
940 }
941#endif
942
943 // Finally call into the DLL.
944 PGO_onModuleEntered(full_name);
945
946 if (isVerbose()) {
947 PySys_WriteStderr("import %s # calling entrypoint\n", full_name);
948 }
949
950 Nuitka_DelModuleString(tstate, full_name);
951
952#if PYTHON_VERSION < 0x300
953 (*entrypoint)();
954#else
955 PyObject *module = (*entrypoint)();
956#endif
957
958 if (isVerbose()) {
959 PySys_WriteStderr("import %s # return from entrypoint\n", full_name);
960 }
961
962#if 0
963 PRINT_FORMAT("import %s # create module as ", full_name);
964 PRINT_ITEM(module);
965 PRINT_NEW_LINE();
966#endif
967
968 NuitkaImport_SwapPackageContext(old_context);
969
970#if PYTHON_VERSION < 0x300
971 PyObject *module = Nuitka_GetModuleString(tstate, full_name);
972#endif
973
974 PGO_onModuleExit(full_name, module == NULL);
975
976 if (unlikely(module == NULL)) {
977 if (unlikely(!HAS_ERROR_OCCURRED(tstate))) {
978 PyErr_Format(PyExc_SystemError, "dynamic module '%s' not initialized properly", full_name);
979 }
980
981 return NULL;
982 }
983
984#if PYTHON_VERSION >= 0x300
985#if PYTHON_VERSION >= 0x350
986 PyModuleDef *def;
987
988 if (Py_TYPE(module) == &PyModuleDef_Type) {
989 if (isVerbose()) {
990 PySys_WriteStderr("import %s # entrypoint returned module def\n", full_name);
991 }
992
993 def = (PyModuleDef *)module;
994
995 PyObject *full_name_obj = Nuitka_String_FromString(full_name);
996
997 PyObject *origin = Nuitka_String_FromFilename(filename);
998
999 PyObject *spec_value = createModuleSpec(tstate, full_name_obj, origin, is_package);
1000 CHECK_OBJECT(spec_value);
1001
1002 module = PyModule_FromDefAndSpec(def, spec_value);
1003
1004 if (unlikely(module == NULL)) {
1005 Py_DECREF(spec_value);
1006
1007 PyErr_Format(PyExc_SystemError, "dynamic module '%s' not initialized properly from def", full_name);
1008
1009 return NULL;
1010 }
1011
1012 SET_ATTRIBUTE(tstate, module, const_str_plain___spec__, spec_value);
1013
1014 setModuleFileValue(tstate, module, filename);
1015
1016 /* Set __path__ properly, unlike frozen module importer does. */
1017 PyObject *path_list = _makeDunderPathObject(tstate, origin);
1018
1019 int res = PyObject_SetAttr(module, const_str_plain___path__, path_list);
1020 if (unlikely(res != 0)) {
1021 return NULL;
1022 }
1023
1024 Py_DECREF(path_list);
1025
1026 Nuitka_SetModule(full_name_obj, module);
1027 Py_DECREF(full_name_obj);
1028
1029#if _NUITKA_EXPERIMENTAL_OLD_EXTENSION_MODULE_LOADING
1030 SET_ATTRIBUTE(tstate, spec_value, const_str_plain__initializing, Py_True);
1031 res = PyModule_ExecDef(module, def);
1032 SET_ATTRIBUTE(tstate, spec_value, const_str_plain__initializing, Py_False);
1033
1034 Py_DECREF(spec_value);
1035 CHECK_OBJECT(spec_value);
1036
1037 if (unlikely(res == -1)) {
1038 return NULL;
1039 }
1040
1041 if (isVerbose()) {
1042 PySys_WriteStderr("import %s # executed module def\n", full_name);
1043 }
1044#endif
1045
1046 CHECK_OBJECT(module);
1047
1048 return module;
1049 } else {
1050 if (isVerbose()) {
1051 PySys_WriteStderr("import %s # entrypoint returned module\n", full_name);
1052 }
1053
1054 def = PyModule_GetDef(module);
1055 assert(def != NULL);
1056
1057 def->m_base.m_init = entrypoint;
1058
1059#if PYTHON_VERSION >= 0x3d0
1060 if (PyState_FindModule(def) == NULL) {
1061 if (PyState_AddModule(module, def) == -1) {
1062 return NULL;
1063 }
1064 }
1065#endif
1066
1067 // Set "__spec__" and "__file__" after load.
1068 setModuleFileValue(tstate, module, filename);
1069 PyObject *full_name_obj = Nuitka_String_FromString(full_name);
1070 SET_ATTRIBUTE(tstate, module, const_str_plain___name__, full_name_obj);
1071 PyObject *spec_value =
1072 createModuleSpec(tstate, full_name_obj, LOOKUP_ATTRIBUTE(tstate, module, const_str_plain___file__), false);
1073
1074 SET_ATTRIBUTE(tstate, module, const_str_plain___spec__, spec_value);
1075
1076 // Fixup "__package__" after load. It seems some modules ignore _Py_PackageContext value.
1077 // so we patch it up here if it's None, but a package was specified.
1078 if (package != NULL) {
1079 PyObject *package_name = LOOKUP_ATTRIBUTE(tstate, module, const_str_plain___package__);
1080
1081 if (package_name == Py_None) {
1082 char package2[2048];
1083 copyStringSafeN(package2, full_name, dot - full_name, sizeof(package2));
1084
1085 PyObject *package_name_obj = Nuitka_String_FromString(package2);
1086 SET_ATTRIBUTE(tstate, module, const_str_plain___package__, package_name_obj);
1087 Py_DECREF(package_name_obj);
1088 }
1089
1090 Py_DECREF(package_name);
1091 }
1092 }
1093
1094 if (likely(def != NULL)) {
1095 def->m_base.m_init = entrypoint;
1096 }
1097
1098#else
1099 PyModuleDef *def = PyModule_GetDef(module);
1100
1101 if (unlikely(def == NULL)) {
1102 PyErr_Format(PyExc_SystemError, "initialization of %s did not return an extension module", filename);
1103
1104 return NULL;
1105 }
1106
1107 def->m_base.m_init = entrypoint;
1108#endif
1109#endif
1110
1111 // Set filename attribute if not already set, in some branches we don't
1112 // do it, esp. not for older Python.
1113 setModuleFileValue(tstate, module, filename);
1114
1115 // Call the standard import fix-ups for extension modules. Their interface
1116 // changed over releases.
1117#if PYTHON_VERSION < 0x300
1118 PyObject *res2 = _PyImport_FixupExtension((char *)full_name, (char *)filename);
1119
1120 if (unlikely(res2 == NULL)) {
1121 return NULL;
1122 }
1123#else
1124 PyObject *full_name_obj = PyUnicode_FromString(full_name);
1125 CHECK_OBJECT(full_name_obj);
1126 PyObject *filename_obj = Nuitka_String_FromFilename(filename);
1127
1128 CHECK_OBJECT(filename_obj);
1129
1130// See above, we need to correct modules imported if we don't successfully swap
1131// the package context.
1132#if _NUITKA_EXTENSION_MODULE_PRESERVATION_HACK
1133 if (preserved_basename_module != NULL) {
1134#if _NUITKA_EXPERIMENTAL_DEBUG_EXTENSION_MODULE_PRESERVATION_HACK
1135 PRINT_STRING("Module Preservation: Handling preservation for extension module ");
1136 PRINT_ITEM_LINE(full_name_obj);
1137 PRINT_STRING("Module Preservation: Restoring preserved module ");
1138 PRINT_ITEM(base_name_obj);
1139
1140 PyObject *current = Nuitka_GetModule(tstate, base_name_obj);
1141 if (current == preserved_basename_module) {
1142 PRINT_STRING(" (unchanged, identical object)");
1143 } else if (current != NULL) {
1144 PRINT_STRING(" (overwriting current value ");
1145 PRINT_ITEM(current);
1146 PRINT_STRING(")");
1147 }
1148 PRINT_STRING(" with preserved value ");
1149 PRINT_ITEM_LINE(preserved_basename_module);
1150#endif
1151 Nuitka_SetModule(base_name_obj, preserved_basename_module);
1152 Py_DECREF(preserved_basename_module);
1153 }
1154
1155 if (base_name_obj != NULL) {
1156 PyObject *need_correction = MAKE_LIST_EMPTY(tstate, 0);
1157
1158 {
1159 PyObject *modules_dict = Nuitka_GetSysModules();
1160
1161 Py_ssize_t pos = 0;
1162 PyObject *key, *value;
1163
1164 PyObject *base_name_prefix = BINARY_OPERATION_ADD_OBJECT_UNICODE_UNICODE(base_name_obj, const_str_dot);
1165#if _NUITKA_EXPERIMENTAL_DEBUG_EXTENSION_MODULE_PRESERVATION_HACK
1166 PRINT_STRING("Module Preservation: Scanning for modules needing correction (renaming) under '");
1167 PRINT_ITEM(base_name_prefix);
1168 PRINT_STRING("'\n");
1169#endif
1170 while (Nuitka_DictNext(modules_dict, &pos, &key, &value)) {
1171 // TODO: Should have nuitka_bool return values for these as well maybe.
1172 PyObject *starts_with_result = UNICODE_STARTSWITH2(tstate, key, base_name_prefix);
1173
1174 if (CHECK_IF_TRUE(starts_with_result) == 1) {
1175 LIST_APPEND0(need_correction, key);
1176 }
1177
1178 Py_DECREF(starts_with_result);
1179 }
1180 }
1181
1182#if _NUITKA_EXPERIMENTAL_DEBUG_EXTENSION_MODULE_PRESERVATION_HACK
1183 PRINT_STRING("Module Preservation: The following modules need correction: ");
1184 PRINT_ITEM_LINE(need_correction);
1185#endif
1186
1187 Py_ssize_t n = PyList_GET_SIZE(need_correction);
1188
1189 for (Py_ssize_t i = 0; i < n; i++) {
1190 PyObject *module_to_correct_name = PyList_GET_ITEM(need_correction, i);
1191
1192 PyObject *correct_module_name =
1193 BINARY_OPERATION_ADD_OBJECT_UNICODE_UNICODE(prefix_name_obj, module_to_correct_name);
1194
1195 PyObject *module_to_correct = Nuitka_GetModule(tstate, module_to_correct_name);
1196
1197#if _NUITKA_EXPERIMENTAL_DEBUG_EXTENSION_MODULE_PRESERVATION_HACK
1198 PRINT_STRING("Module Preservation: Relocating (moving) ");
1199 PRINT_ITEM(module_to_correct_name);
1200 PRINT_STRING(" to ");
1201 PRINT_ITEM(correct_module_name);
1202 PRINT_STRING(" (Module object: ");
1203 PRINT_ITEM(module_to_correct);
1204 PRINT_STRING(")\n");
1205#endif
1206 Nuitka_SetModule(correct_module_name, module_to_correct);
1207
1208 Nuitka_DelModule(tstate, module_to_correct_name);
1209 }
1210
1211 if (preserved_sub_modules != NULL) {
1212 Py_ssize_t pos = 0;
1213 PyObject *key, *value;
1214
1215 while (Nuitka_DictNext(preserved_sub_modules, &pos, &key, &value)) {
1216#if _NUITKA_EXPERIMENTAL_DEBUG_EXTENSION_MODULE_PRESERVATION_HACK
1217 PRINT_STRING("Module Preservation: Restoring preserved submodule: ");
1218 PRINT_ITEM(key);
1219
1220 PyObject *current = Nuitka_GetModule(tstate, key);
1221 if (current == value) {
1222 PRINT_STRING(" (unchanged, identical object)\n");
1223 } else if (current != NULL) {
1224 PRINT_STRING(" (changed from ");
1225 PRINT_ITEM(current);
1226 PRINT_STRING(")\n");
1227 } else {
1228 PRINT_STRING(" (new)\n");
1229 }
1230#endif
1231 Nuitka_SetModule(key, value);
1232 }
1233 }
1234
1235 Py_XDECREF(preserved_sub_modules);
1236
1237 Py_DECREF(base_name_obj);
1238 Py_DECREF(prefix_name_obj);
1239 }
1240#endif
1241
1242#if PYTHON_VERSION < 0x3d0
1243 int res = _PyImport_FixupExtensionObject(module, full_name_obj, filename_obj
1244#if PYTHON_VERSION >= 0x370
1245 ,
1246 Nuitka_GetSysModules()
1247#endif
1248 );
1249#endif
1250
1251#if PYTHON_VERSION >= 0x3d0
1252 Nuitka_SetModuleString(full_name, module);
1253#endif
1254
1255 Py_DECREF(full_name_obj);
1256 Py_DECREF(filename_obj);
1257
1258#if PYTHON_VERSION < 0x3d0
1259 if (unlikely(res == -1)) {
1260 return NULL;
1261 }
1262#endif
1263#endif
1264
1265 return module;
1266}
1267
1268static void loadTriggeredModule(PyThreadState *tstate, char const *name, char const *trigger_name) {
1269 char trigger_module_name[2048];
1270
1271 copyStringSafe(trigger_module_name, name, sizeof(trigger_module_name));
1272 appendStringSafe(trigger_module_name, trigger_name, sizeof(trigger_module_name));
1273
1274 struct Nuitka_MetaPathBasedLoaderEntry *entry = findEntry(trigger_module_name);
1275
1276 if (entry != NULL) {
1277 if (isVerbose()) {
1278 PySys_WriteStderr("Loading %s\n", trigger_module_name);
1279 }
1280
1281 IMPORT_EMBEDDED_MODULE(tstate, trigger_module_name);
1282
1283 if (unlikely(HAS_ERROR_OCCURRED(tstate))) {
1284 if ((entry->flags & NUITKA_ABORT_MODULE_FLAG) != 0) {
1285 printf("Critical error loading %s.\n", trigger_module_name);
1286 abort();
1287 } else {
1288 PyObject *trigger_module_name_str = Nuitka_String_FromString(trigger_module_name);
1289 PyErr_WriteUnraisable(trigger_module_name_str);
1290 Py_DECREF(trigger_module_name_str);
1291 }
1292 }
1293 }
1294}
1295
1296static void loadPostLoadCode(PyThreadState *tstate, PyObject *module_name, char const *name, PyObject *module) {
1297 PyObject *parent_module = NULL;
1298 PyObject *base_name_obj = NULL;
1299 PyObject *parent_name_obj = NULL;
1300
1301 // Python's import machinery normally handles sys.modules placement and parent package binding
1302 // strictly after the loader finishes executing. However, post-load hooks execute before the
1303 // loader returns. We must temporarily emulate these bindings so that post-load code using
1304 // standard `import x` or `sys.modules["x"]` operates on the fully constructed target module.
1305 if (Nuitka_GetModule(tstate, module_name) == NULL) {
1306 if (isVerbose()) {
1307 PySys_WriteStderr("Adding module '%s' to sys.modules temporarily for -postLoad.\n", name);
1308 }
1309
1310 Nuitka_SetModule(module_name, module);
1311 }
1312
1313 char const *dot = strrchr(name, '.');
1314 if (dot != NULL) {
1315 parent_name_obj = Nuitka_String_FromStringAndSize(name, dot - name);
1316 parent_module = Nuitka_GetModule(tstate, parent_name_obj);
1317
1318 if (parent_module != NULL) {
1319 base_name_obj = Nuitka_String_FromString(dot + 1);
1320
1321 if (isVerbose()) {
1322 PySys_WriteStderr("Binding submodule '%s' to parent module temporarily for -postLoad.\n", name);
1323 }
1324
1325 SET_ATTRIBUTE(tstate, parent_module, base_name_obj, module);
1326 }
1327 }
1328
1329 loadTriggeredModule(tstate, name, "-postLoad");
1330
1331 Py_XDECREF(parent_name_obj);
1332 Py_XDECREF(base_name_obj);
1333}
1334
1335#if PYTHON_VERSION >= 0x350
1336static bool executeExtensionModuleDef(PyThreadState *tstate, PyObject *module) {
1337 if (unlikely(!PyModule_Check(module))) {
1338 return true;
1339 }
1340
1341 PyModuleDef *def = PyModule_GetDef(module);
1342 if (def == NULL) {
1343 return true;
1344 }
1345
1346 void *state = PyModule_GetState(module);
1347 if (state != NULL) {
1348 return true;
1349 }
1350
1351 int res = PyModule_ExecDef(module, def);
1352
1353 if (unlikely(res == -1)) {
1354 return false;
1355 }
1356
1357 return true;
1358}
1359#endif
1360
1361#if PYTHON_VERSION >= 0x300
1362static void _fixupSpecAttribute(PyThreadState *tstate, PyObject *module) {
1363 PyObject *spec_value = LOOKUP_ATTRIBUTE(tstate, module, const_str_plain___spec__);
1364
1365 if (spec_value && spec_value != Py_None) {
1366 if (HAS_ATTR_BOOL(tstate, spec_value, const_str_plain__initializing)) {
1367 SET_ATTRIBUTE(tstate, spec_value, const_str_plain__initializing, Py_False);
1368 }
1369 }
1370}
1371#endif
1372
1373// Pointers to bytecode data.
1374static char **_bytecode_data = NULL;
1375
1376#if _NUITKA_STANDALONE_MODE && !defined(_NUITKA_DEPLOYMENT_MODE) && \
1377 !defined(_NUITKA_NO_DEPLOYMENT_EXCLUDED_MODULE_USAGE)
1378static void raiseExcludedModuleImportError(struct Nuitka_MetaPathBasedLoaderEntry const *entry) {
1379 PyErr_Format(PyExc_ImportError,
1380 "Module '%s' was actively excluded from Nuitka compilation. Disable with "
1381 "'--no-deployment-flag=excluded-module-usage': %s",
1382 entry->name, (char const *)entry->python_init_func);
1383}
1384#endif
1385
1386static PyObject *loadModule(PyThreadState *tstate, PyObject *module, PyObject *module_name,
1387 struct Nuitka_MetaPathBasedLoaderEntry const *entry) {
1388#if _NUITKA_STANDALONE_MODE && !defined(_NUITKA_DEPLOYMENT_MODE) && \
1389 !defined(_NUITKA_NO_DEPLOYMENT_EXCLUDED_MODULE_USAGE)
1390 if ((entry->flags & NUITKA_EXCLUDED_MODULE_FLAG) != 0) {
1391 raiseExcludedModuleImportError(entry);
1392 return NULL;
1393 }
1394#endif
1395
1396#if _NUITKA_STANDALONE_MODE
1397 if ((entry->flags & NUITKA_EXTENSION_MODULE_FLAG) != 0) {
1398 bool is_package = (entry->flags & NUITKA_PACKAGE_FLAG) != 0;
1399
1400 filename_char_t filename[MAXPATHLEN + 1];
1401 _makeModuleCFilenameValue(filename, sizeof(filename) / sizeof(filename_char_t), entry->name, module_name,
1402 is_package);
1403
1404 callIntoExtensionModule(tstate, entry->name, filename, is_package);
1405 } else
1406#endif
1407 if ((entry->flags & NUITKA_BYTECODE_FLAG) != 0) {
1408 // TODO: Do node use marshal, but our own stuff, once we
1409 // can do code objects too.
1410
1411 PyCodeObject *code_object =
1412 (PyCodeObject *)PyMarshal_ReadObjectFromString(_bytecode_data[entry->bytecode_index], entry->bytecode_size);
1413
1414 // TODO: Probably a bit harsh reaction.
1415 if (unlikely(code_object == NULL)) {
1416 PyErr_Print();
1417 abort();
1418 }
1419
1420 return loadModuleFromCodeObject(tstate, module, code_object, entry);
1421 } else {
1422 assert((entry->flags & NUITKA_EXTENSION_MODULE_FLAG) == 0);
1423 assert(entry->python_init_func);
1424
1425 {
1426 NUITKA_MAY_BE_UNUSED bool res = Nuitka_SetModule(module_name, module);
1427 assert(res != false);
1428 }
1429
1430 // Run the compiled module code, we get the module returned.
1431#if PYTHON_VERSION < 0x300
1432 NUITKA_MAY_BE_UNUSED
1433#endif
1434 PyObject *result = entry->python_init_func(tstate, module, entry);
1435 CHECK_OBJECT_X(result);
1436
1437#if PYTHON_VERSION >= 0x300
1438 if (likely(result != NULL)) {
1439 _fixupSpecAttribute(tstate, result);
1440 }
1441#endif
1442 }
1443
1444 if (unlikely(HAS_ERROR_OCCURRED(tstate))) {
1445 return NULL;
1446 }
1447
1448 if (isVerbose()) {
1449 PySys_WriteStderr("Loaded %s\n", entry->name);
1450 }
1451
1452 return Nuitka_GetModule(tstate, module_name);
1453}
1454
1455static PyObject *_EXECUTE_EMBEDDED_MODULE(PyThreadState *tstate, PyObject *module, PyObject *module_name,
1456 char const *name) {
1457 // In case of extension modules, that is fine to be NULL.
1458 CHECK_OBJECT_X(module);
1459 CHECK_OBJECT(module_name);
1460
1461 struct Nuitka_MetaPathBasedLoaderEntry *entry = findEntry(name);
1462 bool frozen_import = entry == NULL && hasFrozenModule(name);
1463
1464 if (entry != NULL || frozen_import) {
1465 // Execute the "preLoad" code produced for the module potentially. This
1466 // is from plugins typically, that want to modify things for the the
1467 // module before loading, to e.g. set a plug-in path, or do some monkey
1468 // patching in order to make things compatible.
1469 loadTriggeredModule(tstate, name, "-preLoad");
1470 }
1471
1472 PyObject *result = NULL;
1473
1474 if (entry != NULL) {
1475#ifdef _NUITKA_EXPERIMENTAL_FORCE_GC_COLLECT_ON_IMPORT
1476 PyGC_Collect();
1477#endif
1478
1479 result = loadModule(tstate, module, module_name, entry);
1480
1481#if !defined(_NUITKA_DEPLOYMENT_MODE) && !defined(_NUITKA_NO_DEPLOYMENT_PERFECT_SUPPORT)
1482 if (unlikely(HAS_ERROR_OCCURRED(tstate))) {
1483 if ((entry->flags & NUITKA_PERFECT_SUPPORTED_FLAG) != 0) {
1484 struct Nuitka_ExceptionPreservationItem saved_exception;
1485 FETCH_ERROR_OCCURRED_STATE(tstate, &saved_exception);
1486
1487 PyObject *exception_arg = PyUnicode_FromFormat("Nuitka: import of module '%s' failed unexpectedly "
1488 "despite intended perfect support, please raise a "
1489 "Nuitka issue and compile with an older version of "
1490 "the module in the meantime",
1491 name);
1492
1493 raiseReplacementRuntimeError(tstate, &saved_exception, exception_arg);
1494 }
1495 }
1496#endif
1497
1498#ifdef _NUITKA_EXPERIMENTAL_FORCE_GC_COLLECT_ON_IMPORT
1499 PyGC_Collect();
1500#endif
1501
1502 if (unlikely(result == NULL)) {
1503 return NULL;
1504 }
1505 }
1506
1507 if (frozen_import) {
1508 PGO_onModuleEntered(name);
1509 int res = PyImport_ImportFrozenModule((char *)name);
1510 PGO_onModuleExit(name, res == -1);
1511
1512 if (unlikely(res == -1)) {
1513 return NULL;
1514 }
1515
1516 if (res == 1) {
1517 result = Nuitka_GetModule(tstate, module_name);
1518 }
1519 }
1520
1521 if (result != NULL) {
1522#if PYTHON_VERSION >= 0x350
1523 bool delay_post_load = entry != NULL && (entry->flags & NUITKA_EXTENSION_MODULE_FLAG) != 0 && module == NULL;
1524
1525 if (delay_post_load == false && entry != NULL && (entry->flags & NUITKA_EXTENSION_MODULE_FLAG) != 0 &&
1526 module != NULL) {
1527 if (unlikely(executeExtensionModuleDef(tstate, result) == false)) {
1528 return NULL;
1529 }
1530 }
1531#else
1532 bool delay_post_load = false;
1533#endif
1534
1535 if (delay_post_load == false) {
1536 // Execute the "postLoad" code produced for the module potentially. This
1537 // is from plugins typically, that want to modify the module immediately
1538 // after loading, to e.g. set a plug-in path, or do some monkey patching
1539 // in order to make things compatible.
1540 loadPostLoadCode(tstate, module_name, name, result);
1541 }
1542
1543 return result;
1544 }
1545
1546 Py_INCREF_IMMORTAL(Py_None);
1547 return Py_None;
1548}
1549
1550// Note: This may become an entry point for hard coded imports of compiled
1551// stuff.
1552PyObject *IMPORT_EMBEDDED_MODULE(PyThreadState *tstate, char const *name) {
1553 PyObject *module_name = Nuitka_String_FromString(name);
1554
1555 // Check if it's already loaded, and don't do it again otherwise.
1556 PyObject *module = Nuitka_GetModule(tstate, module_name);
1557
1558 if (module != NULL) {
1559 Py_DECREF(module_name);
1560 return module;
1561 }
1562
1563#if PYTHON_VERSION < 0x300
1564 module = PyModule_New(name);
1565#else
1566 module = PyModule_NewObject(module_name);
1567#endif
1568
1569 PyObject *result = _EXECUTE_EMBEDDED_MODULE(tstate, module, module_name, name);
1570
1571#if PYTHON_VERSION < 0x350
1572 if (unlikely(result == NULL)) {
1573 Nuitka_DelModule(tstate, module_name);
1574 }
1575#endif
1576
1577 Py_DECREF(module_name);
1578
1579 return result;
1580}
1581
1582PyObject *EXECUTE_EMBEDDED_MODULE(PyThreadState *tstate, PyObject *module) {
1583 PyObject *module_name = LOOKUP_ATTRIBUTE(tstate, module, const_str_plain___name__);
1584 assert(module_name);
1585
1586 char const *name = Nuitka_String_AsString(module_name);
1587
1588 return _EXECUTE_EMBEDDED_MODULE(tstate, module, module_name, name);
1589}
1590
1591static PyObject *_nuitka_loader_load_module(PyObject *self, PyObject *args, PyObject *kwds) {
1592 PyObject *module_name;
1593 PyObject *unused;
1594
1595 int res = PyArg_ParseTupleAndKeywords(args, kwds, "O|O:load_module", (char **)_kw_list_find_module, &module_name,
1596 &unused);
1597
1598 if (unlikely(res == 0)) {
1599 return NULL;
1600 }
1601
1602 assert(module_name);
1603 assert(Nuitka_String_Check(module_name));
1604
1605 char const *name = Nuitka_String_AsString(module_name);
1606
1607 if (isVerbose()) {
1608 PySys_WriteStderr("Loading %s\n", name);
1609 }
1610
1611 PyThreadState *tstate = PyThreadState_GET();
1612
1613#if !_NUITKA_STANDALONE_MODE
1614 if (installed_extension_modules != NULL) {
1615 PyObject *extension_module_filename = DICT_GET_ITEM0(tstate, installed_extension_modules, module_name);
1616
1617 if (extension_module_filename != NULL) {
1618 // TODO: Should we not set __file__ for the module here, but there is no object.
1619 return callIntoInstalledExtensionModule(tstate, module_name, extension_module_filename);
1620 }
1621 }
1622#endif
1623
1624 return IMPORT_EMBEDDED_MODULE(tstate, name);
1625}
1626
1627static char const *_kw_list_is_package[] = {"fullname", NULL};
1628
1629static PyObject *_nuitka_loader_is_package(PyObject *self, PyObject *args, PyObject *kwds) {
1630 PyObject *module_name;
1631
1632 int res = PyArg_ParseTupleAndKeywords(args, kwds, "O:is_package", (char **)_kw_list_is_package, &module_name);
1633
1634 if (unlikely(res == 0)) {
1635 return NULL;
1636 }
1637
1638 assert(module_name);
1639 assert(Nuitka_String_Check(module_name));
1640
1641 char const *name = Nuitka_String_AsString(module_name);
1642
1643 struct Nuitka_MetaPathBasedLoaderEntry *entry = findEntry(name);
1644
1645 PyObject *result;
1646
1647 if (entry) {
1648 result = BOOL_FROM((entry->flags & NUITKA_PACKAGE_FLAG) != 0);
1649 } else {
1650 // TODO: Maybe needs to be an exception.
1651 result = Py_None;
1652 }
1653
1654 Py_INCREF_IMMORTAL(result);
1655 return result;
1656}
1657
1658static char const *_kw_list_iter_modules[] = {"package", NULL};
1659
1660static PyObject *_nuitka_loader_iter_modules(PyObject *self_obj, PyObject *args, PyObject *kwds) {
1661 struct Nuitka_LoaderObject *self = (struct Nuitka_LoaderObject *)self_obj;
1662 PyObject *prefix;
1663
1664 int res = PyArg_ParseTupleAndKeywords(args, kwds, "O:iter_modules", (char **)_kw_list_iter_modules, &prefix);
1665
1666 if (unlikely(res == 0)) {
1667 return NULL;
1668 }
1669
1670 NUITKA_MAY_BE_UNUSED PyThreadState *tstate = PyThreadState_GET();
1671
1672 PyObject *result = MAKE_LIST_EMPTY(tstate, 0);
1673
1674 struct Nuitka_MetaPathBasedLoaderEntry *current = loader_entries;
1675 assert(current);
1676
1677 char const *s;
1678
1679 if (self->m_loader_entry) {
1680 s = self->m_loader_entry->name;
1681 } else {
1682 s = "";
1683 }
1684
1685 while (current->name != NULL) {
1686 if ((current->flags & NUITKA_TRANSLATED_FLAG) != 0) {
1687 current->name = UN_TRANSLATE_NAME(current->name);
1688 current->flags -= NUITKA_TRANSLATED_FLAG;
1689 }
1690
1691 int c = strncmp(s, current->name, strlen(s));
1692
1693 if (c != 0) {
1694 current++;
1695 continue;
1696 }
1697
1698 if (strcmp(current->name, "__main__") == 0) {
1699 current++;
1700 continue;
1701 }
1702
1703 if (current->name[strlen(s)] != '.') {
1704 current++;
1705 continue;
1706 }
1707
1708 char const *sub = strchr(current->name + strlen(s) + 1, '.');
1709
1710 if (sub != NULL) {
1711 current++;
1712 continue;
1713 }
1714
1715 PyObject *name;
1716 if (self->m_loader_entry) {
1717 name = Nuitka_String_FromString(current->name + strlen(s) + 1);
1718 } else {
1719 name = Nuitka_String_FromString(current->name);
1720 }
1721
1722 if (CHECK_IF_TRUE(prefix)) {
1723 PyObject *old = name;
1724 name = PyUnicode_Concat(prefix, name);
1725 Py_DECREF(old);
1726 }
1727
1728 PyObject *r = MAKE_TUPLE_EMPTY(tstate, 2);
1729 PyTuple_SET_ITEM(r, 0, name);
1730 PyTuple_SET_ITEM_IMMORTAL(r, 1, BOOL_FROM((current->flags & NUITKA_PACKAGE_FLAG) != 0));
1731
1732 LIST_APPEND1(result, r);
1733
1734 current++;
1735 }
1736
1737 return result;
1738}
1739
1740static PyObject *getModuleDirectory(PyThreadState *tstate, struct Nuitka_MetaPathBasedLoaderEntry const *entry) {
1741#if defined(_NUITKA_FREEZER_HAS_FILE_PATH)
1742#if defined(_WIN32)
1743 wchar_t buffer[1024];
1744 buffer[0] = 0;
1745
1746 appendWStringSafeW(buffer, entry->file_path, sizeof(buffer));
1747 stripFilenameW(buffer);
1748 PyObject *dir_name = NuitkaUnicode_FromWideChar(buffer, -1);
1749#else
1750 char buffer[1024];
1751 copyStringSafe(buffer, entry->file_path, sizeof(buffer));
1752
1753 PyObject *dir_name = Nuitka_String_FromString(dirname(buffer));
1754#endif
1755#else
1756#if _NUITKA_MODULE_MODE
1757 char const *name = entry->compilation_name;
1758 if (name == NULL) {
1759 name = entry->name;
1760 }
1761#else
1762 char const *name = entry->name;
1763#endif
1764
1765 PyObject *module_name;
1766
1767 if ((entry->flags & NUITKA_PACKAGE_FLAG) != 0) {
1768 module_name = Nuitka_String_FromString(name);
1769 } else {
1770 char buffer[1024];
1771 copyStringSafe(buffer, name, sizeof(buffer));
1772
1773 char *dot = strrchr(buffer, '.');
1774 if (dot != NULL) {
1775 *dot = 0;
1776 }
1777
1778 module_name = Nuitka_String_FromString(buffer);
1779 }
1780
1781#if PYTHON_VERSION < 0x300
1782 PyObject *module_path = STR_REPLACE3(tstate, module_name, const_str_dot, getPathSeparatorStringObject());
1783#else
1784 PyObject *module_path = UNICODE_REPLACE3(tstate, module_name, const_str_dot, getPathSeparatorStringObject());
1785#endif
1786 Py_DECREF(module_name);
1787
1788 if (unlikely(module_path == NULL)) {
1789 return NULL;
1790 }
1791
1792 PyObject *dir_name = MAKE_RELATIVE_PATH(module_path);
1793 Py_DECREF(module_path);
1794#endif
1795
1796 return dir_name;
1797}
1798
1799#if PYTHON_VERSION >= 0x300
1800// Used in module template too, therefore exported.
1801PyObject *getImportLibBootstrapModule(void) {
1802 static PyObject *importlib = NULL;
1803 if (importlib == NULL) {
1804 importlib = PyImport_ImportModule("importlib._bootstrap");
1805 }
1806
1807 return importlib;
1808}
1809#endif
1810
1811static PyObject *getModuleFileValue(PyThreadState *tstate, struct Nuitka_MetaPathBasedLoaderEntry const *entry) {
1812 PyObject *dir_name = getModuleDirectory(tstate, entry);
1813
1814 char filename_buffer[1024];
1815
1816 if ((entry->flags & NUITKA_PACKAGE_FLAG) != 0) {
1817 copyStringSafe(filename_buffer, "__init__", sizeof(filename_buffer));
1818 } else {
1819 char const *basename = strrchr(entry->name, '.');
1820
1821 if (basename == NULL) {
1822 basename = entry->name;
1823 } else {
1824 basename += 1;
1825 }
1826
1827 copyStringSafe(filename_buffer, basename, sizeof(filename_buffer));
1828 }
1829
1830 if ((entry->flags & NUITKA_EXTENSION_MODULE_FLAG) != 0) {
1831#if defined(_WIN32)
1832 appendStringSafe(filename_buffer, ".pyd", sizeof(filename_buffer));
1833#else
1834 appendStringSafe(filename_buffer, ".so", sizeof(filename_buffer));
1835#endif
1836 } else {
1837 appendStringSafe(filename_buffer, ".py", sizeof(filename_buffer));
1838 }
1839
1840 PyObject *module_filename = Nuitka_String_FromString(filename_buffer);
1841
1842 PyObject *result = JOIN_PATH2(dir_name, module_filename);
1843
1844 Py_DECREF(module_filename);
1845
1846 return result;
1847}
1848
1849#if PYTHON_VERSION >= 0x300
1850
1851static PyObject *_nuitka_loader_repr_module(PyObject *self, PyObject *args, PyObject *kwds) {
1852 PyObject *module;
1853 PyObject *unused;
1854
1855 int res =
1856 PyArg_ParseTupleAndKeywords(args, kwds, "O|O:module_repr", (char **)_kw_list_find_module, &module, &unused);
1857
1858 if (unlikely(res == 0)) {
1859 return NULL;
1860 }
1861
1862 PyThreadState *tstate = PyThreadState_GET();
1863
1864 return PyUnicode_FromFormat("<module '%s' from %R>", PyModule_GetName(module),
1865 Nuitka_GetFilenameObject(tstate, module));
1866}
1867
1868static PyObject *getModuleSpecClass(PyObject *importlib_module) {
1869 static PyObject *module_spec_class = NULL;
1870
1871 if (module_spec_class == NULL) {
1872 module_spec_class = PyObject_GetAttrString(importlib_module, "ModuleSpec");
1873 }
1874
1875 return module_spec_class;
1876}
1877
1878static PyObject *createModuleSpec(PyThreadState *tstate, PyObject *module_name, PyObject *origin, bool is_package) {
1879 CHECK_OBJECT(module_name);
1880 assert(Nuitka_String_Check(module_name));
1881 CHECK_OBJECT_X(origin);
1882
1883 PyObject *importlib_module = getImportLibBootstrapModule();
1884
1885 if (unlikely(importlib_module == NULL)) {
1886 return NULL;
1887 }
1888
1889 PyObject *module_spec_class = getModuleSpecClass(importlib_module);
1890
1891 if (unlikely(module_spec_class == NULL)) {
1892 return NULL;
1893 }
1894
1895 PyObject *args = MAKE_TUPLE2(tstate, module_name, (PyObject *)&Nuitka_Loader_Type);
1896
1897 PyObject *kw_values[] = {is_package ? Py_True : Py_False, origin};
1898
1899 char const *kw_keys[] = {"is_package", "origin"};
1900
1901 PyObject *kw_args = MAKE_DICT_X_CSTR(kw_keys, kw_values, sizeof(kw_values) / sizeof(PyObject *));
1902
1903 PyObject *result = CALL_FUNCTION(tstate, module_spec_class, args, kw_args);
1904
1905 Py_DECREF(args);
1906 Py_DECREF(kw_args);
1907
1908 return result;
1909}
1910
1911#if !_NUITKA_STANDALONE_MODE
1912// We might have to load stuff from installed modules in our package namespaces.
1913static PyObject *createModuleSpecViaPathFinder(PyThreadState *tstate, PyObject *module_name,
1914 char const *parent_module_name) {
1915 if (scanModuleInPackagePath(tstate, module_name, parent_module_name)) {
1916 return createModuleSpec(tstate, module_name, NULL, false);
1917 } else {
1918 // Without error this means we didn't make it.
1919 return NULL;
1920 }
1921}
1922#endif
1923
1924#if _NUITKA_STANDALONE_MODE
1925static PyObject *getImportLibPathFinderClass(void) {
1926 static PyObject *path_finder_class = NULL;
1927
1928 if (path_finder_class == NULL) {
1929 static PyObject *machinery_module = NULL;
1930
1931 if (machinery_module == NULL) {
1932 machinery_module = PyImport_ImportModule("importlib.machinery");
1933 }
1934
1935 path_finder_class = PyObject_GetAttrString(machinery_module, "PathFinder");
1936 }
1937
1938 return path_finder_class;
1939}
1940
1941static PyObject *findExternalModuleSpecViaPathFinder(PyThreadState *tstate, PyObject *module_name,
1942 PyObject *search_path,
1943 struct Nuitka_MetaPathBasedLoaderEntry const *entry) {
1944 if ((entry->flags & NUITKA_EXTENSION_MODULE_FLAG) == 0 || (entry->flags & NUITKA_PACKAGE_FLAG) == 0) {
1945 return NULL;
1946 }
1947
1948 PyObject *path_finder_class = getImportLibPathFinderClass();
1949
1950 if (unlikely(path_finder_class == NULL)) {
1951 return NULL;
1952 }
1953
1954 PyObject *find_spec = PyObject_GetAttrString(path_finder_class, "find_spec");
1955
1956 if (unlikely(find_spec == NULL)) {
1957 return NULL;
1958 }
1959
1960 PyObject *args[2] = {module_name, search_path == NULL ? Py_None : search_path};
1961 PyObject *path_finder_spec = CALL_FUNCTION_WITH_ARGS2(tstate, find_spec, args);
1962
1963 Py_DECREF(find_spec);
1964
1965 if (path_finder_spec == NULL) {
1966 return NULL;
1967 }
1968
1969 if (path_finder_spec == Py_None) {
1970 Py_DECREF(path_finder_spec);
1971 return NULL;
1972 }
1973
1974 PyObject *origin = PyObject_GetAttrString(path_finder_spec, "origin");
1975
1976 if (unlikely(origin == NULL)) {
1977 Py_DECREF(path_finder_spec);
1978 return NULL;
1979 }
1980
1981 PyObject *module_origin = getModuleFileValue(tstate, entry);
1982
1983 if (unlikely(module_origin == NULL)) {
1984 Py_DECREF(path_finder_spec);
1985 return NULL;
1986 }
1987
1988 int same_origin = PyObject_RichCompareBool(origin, module_origin, Py_EQ);
1989
1990 Py_DECREF(origin);
1991 Py_DECREF(module_origin);
1992
1993 if (unlikely(same_origin == -1)) {
1994 Py_DECREF(path_finder_spec);
1995 return NULL;
1996 }
1997
1998 if (same_origin == 1) {
1999 Py_DECREF(path_finder_spec);
2000 return NULL;
2001 }
2002
2003 return path_finder_spec;
2004}
2005#endif
2006
2007static char const *_kw_list_find_spec[] = {"fullname", "is_package", "path", NULL};
2008
2009static PyObject *_nuitka_loader_find_spec(PyObject *self, PyObject *args, PyObject *kwds) {
2010 PyObject *module_name;
2011 PyObject *is_package_arg = Py_None; // We currently ignore "is_package"
2012 PyObject *path_arg = Py_None;
2013
2014 int res = PyArg_ParseTupleAndKeywords(args, kwds, "O|OO:find_spec", (char **)_kw_list_find_spec, &module_name,
2015 &is_package_arg, &path_arg);
2016
2017 if (unlikely(res == 0)) {
2018 return NULL;
2019 }
2020
2021 char const *full_name = Nuitka_String_AsString(module_name);
2022
2023 if (isVerbose()) {
2024 PySys_WriteStderr("import %s # considering responsibility (find_spec)\n", full_name);
2025 }
2026
2027 struct Nuitka_MetaPathBasedLoaderEntry const *entry = findEntry(full_name);
2028
2029 PyThreadState *tstate = PyThreadState_GET();
2030
2031#if !_NUITKA_STANDALONE_MODE
2032 // We need to deal with things located in compiled packages, that were not included,
2033 // e.g. extension modules, but also other files, that were asked to not be included
2034 // or added later.
2035 if (entry == NULL) {
2036 entry = findContainingPackageEntry(full_name);
2037
2038 if (entry != NULL) {
2039 PyObject *result = createModuleSpecViaPathFinder(tstate, module_name, entry->name);
2040
2041 if (result != NULL) {
2042 if (isVerbose()) {
2043 PySys_WriteStderr("import %s # claimed responsibility (%s, contained in compiled package %s)\n",
2044 full_name, getEntryModeString(entry), entry->name);
2045 }
2046
2047 return result;
2048 }
2049
2050 if (HAS_ERROR_OCCURRED(tstate)) {
2051 return NULL;
2052 }
2053
2054 entry = NULL;
2055 }
2056 }
2057#endif
2058
2059#if _NUITKA_STANDALONE_MODE
2060 if (entry != NULL) {
2061 PyObject *path_finder_spec = findExternalModuleSpecViaPathFinder(tstate, module_name, path_arg, entry);
2062
2063 if (path_finder_spec != NULL) {
2064 if (isVerbose()) {
2065 PySys_WriteStderr("import %s # denied responsibility to PathFinder alternative\n", full_name);
2066 }
2067
2068 return path_finder_spec;
2069 }
2070
2071 if (HAS_ERROR_OCCURRED(tstate)) {
2072 return NULL;
2073 }
2074 }
2075#endif
2076
2077 if (entry == NULL) {
2078 if (isVerbose()) {
2079 PySys_WriteStderr("import %s # denied responsibility\n", full_name);
2080 }
2081
2082 Py_INCREF_IMMORTAL(Py_None);
2083 return Py_None;
2084 }
2085
2086 if (isVerbose()) {
2087 PySys_WriteStderr("import %s # claimed responsibility (%s)\n", Nuitka_String_AsString(module_name),
2088 getEntryModeString(entry));
2089 }
2090
2091#if _NUITKA_STANDALONE_MODE && !defined(_NUITKA_DEPLOYMENT_MODE) && \
2092 !defined(_NUITKA_NO_DEPLOYMENT_EXCLUDED_MODULE_USAGE)
2093 if ((entry->flags & NUITKA_EXCLUDED_MODULE_FLAG) != 0) {
2094 raiseExcludedModuleImportError(entry);
2095 return NULL;
2096 }
2097#endif
2098
2099 return createModuleSpec(tstate, module_name, getModuleFileValue(tstate, entry),
2100 (entry->flags & NUITKA_PACKAGE_FLAG) != 0);
2101}
2102
2103#if PYTHON_VERSION >= 0x350
2104static char const *_kw_list_create_module[] = {"spec", NULL};
2105
2106static PyObject *_nuitka_loader_create_module(PyObject *self, PyObject *args, PyObject *kwds) {
2107 PyObject *spec;
2108
2109 int res = PyArg_ParseTupleAndKeywords(args, kwds, "O:create_module", (char **)_kw_list_create_module, &spec);
2110
2111 if (unlikely(res == 0)) {
2112 return NULL;
2113 }
2114
2115 PyThreadState *tstate = PyThreadState_GET();
2116
2117 PyObject *module_name = LOOKUP_ATTRIBUTE(tstate, spec, const_str_plain_name);
2118
2119 if (unlikely(module_name == NULL)) {
2120 return NULL;
2121 }
2122
2123 // Check if module name is a proper string.
2124 char const *name = Nuitka_String_AsString(module_name);
2125 if (unlikely(name == NULL)) {
2126 Py_DECREF(module_name);
2127 return NULL;
2128 }
2129
2130 if (isVerbose()) {
2131 PySys_WriteStderr("import %s # create module\n", name);
2132 }
2133
2134 // During spec creation, we have populated the dictionary with a filename to load from
2135 // for extension modules that were found installed in the system and below our package.
2136#if !_NUITKA_STANDALONE_MODE && !_NUITKA_EXPERIMENTAL_OLD_EXTENSION_MODULE_LOADING
2137 if (installed_extension_modules != NULL) {
2138 PyObject *extension_module_filename = DICT_GET_ITEM0(tstate, installed_extension_modules, module_name);
2139
2140 if (extension_module_filename != NULL) {
2141 Py_DECREF(module_name);
2142 return callIntoInstalledExtensionModule(tstate, module_name, extension_module_filename);
2143 }
2144 }
2145#endif
2146
2147#if _NUITKA_EXPERIMENTAL_OLD_EXTENSION_MODULE_LOADING
2148 struct Nuitka_MetaPathBasedLoaderEntry *entry = NULL;
2149#else
2150 struct Nuitka_MetaPathBasedLoaderEntry *entry = findEntry(name);
2151#endif
2152
2153 PyObject *result;
2154
2155 if ((entry != NULL) && ((entry->flags & NUITKA_EXTENSION_MODULE_FLAG) != 0)) {
2156 result = _EXECUTE_EMBEDDED_MODULE(tstate, NULL, module_name, name);
2157 } else {
2158 result = PyModule_NewObject(module_name);
2159 }
2160
2161 Py_DECREF(module_name);
2162
2163 return result;
2164}
2165
2166static char const *_kw_list_exec_module[] = {"module", NULL};
2167
2168static PyObject *_nuitka_loader_exec_module(PyObject *self, PyObject *args, PyObject *kwds) {
2169 PyObject *module;
2170
2171 int res = PyArg_ParseTupleAndKeywords(args, kwds, "O:exec_module", (char **)_kw_list_exec_module, &module);
2172
2173 if (unlikely(res == 0)) {
2174 return NULL;
2175 }
2176
2177 PyThreadState *tstate = PyThreadState_GET();
2178
2179 PyObject *module_name = LOOKUP_ATTRIBUTE(tstate, module, const_str_plain___name__);
2180
2181 if (unlikely(module_name == NULL)) {
2182 return NULL;
2183 }
2184
2185 // Check if module name is a proper string.
2186 char const *name = Nuitka_String_AsString(module_name);
2187 if (unlikely(name == NULL)) {
2188 Py_DECREF(module_name);
2189 return NULL;
2190 }
2191
2192 if (isVerbose()) {
2193 PySys_WriteStderr("import %s # execute module\n", name);
2194 }
2195
2196 // During spec creation, we have populated the dictionary with a filename to load from
2197 // for extension modules that were found installed in the system and below our package.
2198#if !_NUITKA_STANDALONE_MODE && _NUITKA_EXPERIMENTAL_OLD_EXTENSION_MODULE_LOADING
2199 if (installed_extension_modules != NULL) {
2200 PyObject *extension_module_filename = DICT_GET_ITEM0(tstate, installed_extension_modules, module_name);
2201
2202 if (extension_module_filename != NULL) {
2203 // Set filename attribute
2204 bool b_res = SET_ATTRIBUTE(tstate, module, const_str_plain___file__, extension_module_filename);
2205
2206 if (unlikely(b_res == false)) {
2207 // Might be refuted, which wouldn't be harmful.
2208 CLEAR_ERROR_OCCURRED(tstate);
2209 }
2210
2211 return callIntoInstalledExtensionModule(tstate, module_name, extension_module_filename);
2212 }
2213 }
2214#endif
2215
2216#if _NUITKA_EXPERIMENTAL_OLD_EXTENSION_MODULE_LOADING
2217 struct Nuitka_MetaPathBasedLoaderEntry *entry = NULL;
2218#else
2219 struct Nuitka_MetaPathBasedLoaderEntry *entry = findEntry(name);
2220#endif
2221
2222 if ((entry != NULL) && ((entry->flags & NUITKA_EXTENSION_MODULE_FLAG) != 0)) {
2223 Py_INCREF(module);
2224
2225 if (unlikely(executeExtensionModuleDef(tstate, module) == false)) {
2226 Py_DECREF(module_name);
2227 Py_DECREF(module);
2228
2229 return NULL;
2230 }
2231
2232 loadPostLoadCode(tstate, module_name, name, module);
2233
2234 Py_DECREF(module_name);
2235
2236 CHECK_OBJECT(module);
2237
2238 return module;
2239 }
2240
2241 Py_DECREF(module_name);
2242
2243 return EXECUTE_EMBEDDED_MODULE(tstate, module);
2244}
2245
2246#if PYTHON_VERSION >= 0x370
2247
2248// The resource reader class is implemented in a separate file.
2249#include "MetaPathBasedLoaderResourceReader.c"
2250
2251static PyObject *_nuitka_loader_get_resource_reader(PyObject *self, PyObject *args, PyObject *kwds) {
2252 PyObject *module_name;
2253
2254 int res =
2255 PyArg_ParseTupleAndKeywords(args, kwds, "O:get_resource_reader", (char **)_kw_list_exec_module, &module_name);
2256
2257 if (unlikely(res == 0)) {
2258 return NULL;
2259 }
2260
2261 char const *name = Nuitka_String_AsString(module_name);
2262
2263 struct Nuitka_MetaPathBasedLoaderEntry *entry = findEntry(name);
2264
2265 if (entry) {
2266 if (isVerbose()) {
2267 PySys_WriteStderr("import %s # get_resource_reader (%s)\n", name, getEntryModeString(entry));
2268 }
2269
2270 return Nuitka_ResourceReader_New(entry);
2271 }
2272
2273 PyErr_Format(PyExc_RuntimeError, "Requested resource reader for unhandled module %s", module_name);
2274 return NULL;
2275}
2276
2277#endif
2278
2279#endif
2280
2281#endif
2282
2283static char const *_kw_list_find_distributions[] = {"context", NULL};
2284
2285static PyObject *_nuitka_loader_find_distributions(PyObject *self, PyObject *args, PyObject *kwds) {
2286 PyObject *context;
2287
2288 int res =
2289 PyArg_ParseTupleAndKeywords(args, kwds, "O:find_distributions", (char **)_kw_list_find_distributions, &context);
2290
2291 if (unlikely(res == 0)) {
2292 return NULL;
2293 }
2294
2295 PyThreadState *tstate = PyThreadState_GET();
2296
2297 PyObject *name = LOOKUP_ATTRIBUTE(tstate, context, const_str_plain_name);
2298
2299 if (unlikely(name == NULL)) {
2300 return NULL;
2301 }
2302
2303 PyObject *temp = MAKE_LIST_EMPTY(tstate, 0);
2304
2305 Py_ssize_t pos = 0;
2306 PyObject *distribution_name;
2307
2308 while (Nuitka_DistributionNext(&pos, &distribution_name)) {
2309 bool include = false;
2310 if (name == Py_None) {
2311 include = true;
2312 } else {
2313 PyObject *name_lower = CALL_METHOD_NO_ARGS(tstate, name, const_str_plain_lower);
2314 if (unlikely(name_lower == NULL)) {
2315 return NULL;
2316 }
2317 PyObject *distribution_name_lower = CALL_METHOD_NO_ARGS(tstate, distribution_name, const_str_plain_lower);
2318 if (unlikely(distribution_name_lower == NULL)) {
2319 Py_DECREF(name_lower);
2320 return NULL;
2321 }
2322
2323 nuitka_bool cmp_res = RICH_COMPARE_EQ_NBOOL_OBJECT_OBJECT(name_lower, distribution_name_lower);
2324
2325 Py_DECREF(name_lower);
2326 Py_DECREF(distribution_name_lower);
2327
2328 if (unlikely(cmp_res == NUITKA_BOOL_EXCEPTION)) {
2329 Py_DECREF(name);
2330 return NULL;
2331 }
2332
2333 include = cmp_res == NUITKA_BOOL_TRUE;
2334 }
2335
2336 if (include) {
2337 // Create a distribution object from our data.
2338 PyObject *distribution = Nuitka_Distribution_New(tstate, distribution_name);
2339
2340 if (distribution == NULL) {
2341 Py_DECREF(temp);
2342 return NULL;
2343 }
2344
2345 LIST_APPEND1(temp, distribution);
2346 }
2347 }
2348
2349 // We are expected to return an iterator.
2350 PyObject *result = MAKE_ITERATOR_INFALLIBLE(temp);
2351
2352 Py_DECREF(temp);
2353 return result;
2354}
2355
2356static char const *_kw_list_sys_path_hook[] = {"path", NULL};
2357
2358static PyObject *_nuitka_loader_sys_path_hook(PyObject *self, PyObject *args, PyObject *kwds) {
2359 PyObject *path;
2360
2361 int res = PyArg_ParseTupleAndKeywords(args, kwds, "O:sys_path_hook", (char **)_kw_list_sys_path_hook, &path);
2362
2363 if (unlikely(res == 0)) {
2364 return NULL;
2365 }
2366
2367#if 0
2368 PRINT_STRING("CONSIDER PATH:");
2369 PRINT_ITEM(path);
2370 PRINT_NEW_LINE();
2371#endif
2372
2373 struct Nuitka_MetaPathBasedLoaderEntry *entry = loader_entries;
2374 assert(entry);
2375
2376 PyThreadState *tstate = PyThreadState_GET();
2377
2378 while (entry->name != NULL) {
2379 if ((entry->flags & NUITKA_TRANSLATED_FLAG) != 0) {
2380 entry->name = UN_TRANSLATE_NAME(entry->name);
2381 entry->flags -= NUITKA_TRANSLATED_FLAG;
2382 }
2383
2384 if ((entry->flags & NUITKA_PACKAGE_FLAG) != 0) {
2385 PyObject *module_directory = getModuleDirectory(tstate, entry);
2386
2387#if 0
2388 PRINT_STRING(entry->name);
2389 PRINT_STRING(" ");
2390 PRINT_ITEM(module_directory);
2391 PRINT_NEW_LINE();
2392#endif
2393
2394 nuitka_bool cmp_res = compareFilePaths(tstate, module_directory, path);
2395
2396 if (unlikely(cmp_res == NUITKA_BOOL_EXCEPTION)) {
2397 return NULL;
2398 }
2399
2400 // Create the loader for the module.
2401 if (cmp_res == NUITKA_BOOL_TRUE) {
2402#if 0
2403 PRINT_STRING("Success:");
2404 PRINT_STRING(entry->name);
2405 PRINT_NEW_LINE();
2406#endif
2407 return Nuitka_Loader_New(entry);
2408 }
2409 } else {
2410#if 0
2411 PRINT_STRING(entry->name);
2412 PRINT_STRING(" not a package ");
2413 PRINT_NEW_LINE();
2414#endif
2415 }
2416
2417 entry++;
2418 }
2419
2420#if 0
2421 PRINT_STRING("Not responsible:");
2422 PRINT_ITEM(path);
2423 PRINT_NEW_LINE();
2424#endif
2425
2426 SET_CURRENT_EXCEPTION_TYPE0(tstate, PyExc_ImportError);
2427 return NULL;
2428}
2429
2430static PyMethodDef Nuitka_Loader_methods[] = {
2431 {"iter_modules", CAST_METHOD_KW(_nuitka_loader_iter_modules), METH_VARARGS | METH_KEYWORDS, NULL},
2432 {"get_data", CAST_METHOD_KW(_nuitka_loader_get_data), METH_STATIC | METH_VARARGS | METH_KEYWORDS, NULL},
2433 {"find_module", CAST_METHOD_KW(_nuitka_loader_find_module), METH_STATIC | METH_VARARGS | METH_KEYWORDS, NULL},
2434 {"load_module", CAST_METHOD_KW(_nuitka_loader_load_module), METH_STATIC | METH_VARARGS | METH_KEYWORDS, NULL},
2435 {"is_package", CAST_METHOD_KW(_nuitka_loader_is_package), METH_STATIC | METH_VARARGS | METH_KEYWORDS, NULL},
2436#if PYTHON_VERSION >= 0x300
2437 {"module_repr", CAST_METHOD_KW(_nuitka_loader_repr_module), METH_STATIC | METH_VARARGS | METH_KEYWORDS, NULL},
2438 {"find_spec", CAST_METHOD_KW(_nuitka_loader_find_spec), METH_STATIC | METH_VARARGS | METH_KEYWORDS, NULL},
2439#endif
2440#if PYTHON_VERSION >= 0x350
2441 {"create_module", CAST_METHOD_KW(_nuitka_loader_create_module), METH_STATIC | METH_VARARGS | METH_KEYWORDS, NULL},
2442 {"exec_module", CAST_METHOD_KW(_nuitka_loader_exec_module), METH_STATIC | METH_VARARGS | METH_KEYWORDS, NULL},
2443#endif
2444#if PYTHON_VERSION >= 0x370
2445 {"get_resource_reader", CAST_METHOD_KW(_nuitka_loader_get_resource_reader),
2446 METH_STATIC | METH_VARARGS | METH_KEYWORDS, NULL},
2447#endif
2448
2449 {"find_distributions", CAST_METHOD_KW(_nuitka_loader_find_distributions),
2450 METH_STATIC | METH_VARARGS | METH_KEYWORDS, NULL},
2451
2452 {"sys_path_hook", CAST_METHOD_KW(_nuitka_loader_sys_path_hook), METH_STATIC | METH_VARARGS | METH_KEYWORDS, NULL},
2453
2454 {NULL, NULL} // terminator
2455};
2456
2457static PyObject *Nuitka_Loader_tp_repr(struct Nuitka_LoaderObject *loader) {
2458 if (loader->m_loader_entry == NULL) {
2459 // TODO: Indicate in module mode, which one it is for.
2460 return Nuitka_String_FromString("<nuitka_module_loader>");
2461 } else {
2462 return Nuitka_String_FromFormat("<nuitka_module_loader for '%s'>", loader->m_loader_entry->name);
2463 }
2464}
2465
2466#include "nuitka/freelists.h"
2467
2468// TODO: A free list is not the right thing for those, they are probably living forever, but it's
2469// no big harm too, but make it small, maybe be allowing a toggle that makes a specific macro not
2470// use the free list mechanism at all.
2471
2472// Freelist setup
2473#define MAX_LOADER_FREE_LIST_COUNT 10
2474static struct Nuitka_LoaderObject *free_list_loaders = NULL;
2475static int free_list_loaders_count = 0;
2476
2477static void Nuitka_Loader_tp_dealloc(struct Nuitka_LoaderObject *loader) {
2478 Nuitka_GC_UnTrack(loader);
2479
2480 releaseToFreeList(free_list_loaders, loader, MAX_LOADER_FREE_LIST_COUNT);
2481}
2482
2483static int Nuitka_Loader_tp_traverse(struct Nuitka_LoaderObject *loader, visitproc visit, void *arg) { return 0; }
2484
2485static PyObject *Nuitka_Loader_get_name(struct Nuitka_LoaderObject *loader, void *closure) {
2486 PyObject *result = Nuitka_String_FromString(loader->m_loader_entry->name);
2487
2488 return result;
2489}
2490static PyObject *Nuitka_Loader_get_path(struct Nuitka_LoaderObject *loader, void *closure) {
2491 PyThreadState *tstate = PyThreadState_GET();
2492 PyObject *result = getModuleFileValue(tstate, loader->m_loader_entry);
2493
2494 return result;
2495}
2496
2497static PyObject *Nuitka_Loader_get__module__(struct Nuitka_LoaderObject *loader, void *closure) {
2498 PyObject *result = const_str_plain___nuitka__;
2499
2500 Py_INCREF_IMMORTAL(result);
2501 return result;
2502}
2503
2504static PyGetSetDef Nuitka_Loader_tp_getset[] = {{(char *)"__module__", (getter)Nuitka_Loader_get__module__, NULL, NULL},
2505 {(char *)"name", (getter)Nuitka_Loader_get_name, NULL, NULL},
2506 {(char *)"path", (getter)Nuitka_Loader_get_path, NULL, NULL},
2507 {NULL}};
2508
2509PyTypeObject Nuitka_Loader_Type = {
2510 PyVarObject_HEAD_INIT(NULL, 0) "nuitka_module_loader",
2511 sizeof(struct Nuitka_LoaderObject), // tp_basicsize
2512 0, // tp_itemsize
2513 (destructor)Nuitka_Loader_tp_dealloc, // tp_dealloc
2514 0, // tp_print
2515 0, // tp_getattr
2516 0, // tp_setattr
2517 0, // tp_reserved
2518 (reprfunc)Nuitka_Loader_tp_repr, // tp_repr
2519 0, // tp_as_number
2520 0, // tp_as_sequence
2521 0, // tp_as_mapping
2522 0, // tp_hash
2523 0, // tp_call
2524 0, // tp_str
2525 0, // tp_getattro (PyObject_GenericGetAttr)
2526 0, // tp_setattro
2527 0, // tp_as_buffer
2528 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, // tp_flags
2529 0, // tp_doc
2530 (traverseproc)Nuitka_Loader_tp_traverse, // tp_traverse
2531 0, // tp_clear
2532 0, // tp_richcompare
2533 0, // tp_weaklistoffset
2534 0, // tp_iter
2535 0, // tp_iternext
2536 Nuitka_Loader_methods, // tp_methods
2537 0, // tp_members
2538 Nuitka_Loader_tp_getset, // tp_getset
2539};
2540
2541/* Used by modules to register child loaders for packages. */
2542PyObject *Nuitka_Loader_New(struct Nuitka_MetaPathBasedLoaderEntry const *entry) {
2543 struct Nuitka_LoaderObject *result;
2544
2545 allocateFromFreeListFixed(free_list_loaders, struct Nuitka_LoaderObject, Nuitka_Loader_Type);
2546 Nuitka_GC_Track(result);
2547
2548 result->m_loader_entry = entry;
2549
2550 return (PyObject *)result;
2551}
2552
2553#if _NUITKA_MODULE_MODE
2554void updateMetaPathBasedLoaderModuleRoot(char const *module_root_name) {
2555 assert(module_root_name != NULL);
2556 char const *last_dot = strrchr(module_root_name, '.');
2557
2558 if (last_dot != NULL) {
2559 struct Nuitka_MetaPathBasedLoaderEntry *current = loader_entries;
2560 assert(current);
2561
2562 while (current->name != NULL) {
2563 if ((current->flags & NUITKA_TRANSLATED_FLAG) != 0) {
2564 current->name = UN_TRANSLATE_NAME(current->name);
2565 current->flags -= NUITKA_TRANSLATED_FLAG;
2566 }
2567
2568 char name[2048];
2569
2570 if (strcmp(last_dot + 1, current->name) == 0) {
2571 copyStringSafeN(name, module_root_name, last_dot - module_root_name + 1, sizeof(name));
2572 appendStringSafe(name, current->name, sizeof(name));
2573
2574 current->compilation_name = current->name;
2575 current->name = strdup(name);
2576 } else if (strncmp(last_dot + 1, current->name, strlen(last_dot + 1)) == 0 &&
2577 current->name[strlen(last_dot + 1)] == '.') {
2578 copyStringSafeN(name, module_root_name, last_dot - module_root_name + 1, sizeof(name));
2579 appendStringSafe(name, current->name, sizeof(name));
2580
2581 current->compilation_name = current->name;
2582 current->name = strdup(name);
2583 }
2584
2585 current++;
2586 }
2587 }
2588}
2589#endif
2590
2591void registerMetaPathBasedLoader(struct Nuitka_MetaPathBasedLoaderEntry *_loader_entries,
2592 unsigned char **bytecode_data) {
2593 // Do it only once.
2594 if (loader_entries) {
2595 assert(_loader_entries == loader_entries);
2596
2597 return;
2598 }
2599
2600 _bytecode_data = (char **)bytecode_data;
2601
2602 if (isVerbose()) {
2603 PySys_WriteStderr("Setup nuitka compiled module/bytecode/extension importer.\n");
2604 }
2605
2606 loader_entries = _loader_entries;
2607
2608#if _NUITKA_MODULE_MODE && PYTHON_VERSION < 0x3c0
2609 if (_Py_PackageContext != NULL) {
2610 updateMetaPathBasedLoaderModuleRoot(_Py_PackageContext);
2611 }
2612#endif
2613
2614 Nuitka_PyType_Ready(&Nuitka_Loader_Type, NULL, true, false, false, false, false);
2615
2616#if PYTHON_VERSION >= 0x370
2617 Nuitka_PyType_Ready(&Nuitka_ResourceReader_Type, NULL, true, false, false, false, false);
2618#endif
2619
2620 // Register it as a meta path loader.
2621 PyObject *global_loader = Nuitka_Loader_New(NULL);
2622
2623 LIST_INSERT_CONST(Nuitka_SysGetObject("meta_path"),
2624#if PYTHON_VERSION < 0x300
2625 0,
2626#else
2627 2,
2628#endif
2629
2630 global_loader);
2631
2632 // Our "sys.path_hooks" entry uses "os.path" to compare filenames, so we need
2633 // to load it without.
2634 PyThreadState *tstate = PyThreadState_GET();
2635 IMPORT_HARD_OS_PATH(tstate);
2636
2637 // Register our loader as a "sys.path_hook" so it can provide for the paths.
2638#if _NUITKA_STANDALONE_MODE
2639 LIST_INSERT_CONST(Nuitka_SysGetObject("path_hooks"), 0, PyObject_GetAttrString(global_loader, "sys_path_hook"));
2640#else
2641 // TODO: For accelerated mode the loader doesn't have the ability
2642 // to handle "site-packages" on its own yet, and therefore we
2643 // cannot have it take precedence.
2644 LIST_APPEND1(Nuitka_SysGetObject("path_hooks"), PyObject_GetAttrString(global_loader, "sys_path_hook"));
2645#endif
2646}
2647
2648#if _NUITKA_STANDALONE_MODE
2649// This is called for the technical module imported early on during interpreter
2650// into, to still get compatible "__file__" attributes.
2651void setEarlyFrozenModulesFileAttribute(PyThreadState *tstate) {
2652 PyObject *sys_modules = Nuitka_GetSysModules();
2653 Py_ssize_t pos = 0;
2654 PyObject *key, *value;
2655
2656 PyObject *builtin_module_names = Nuitka_SysGetObject("builtin_module_names");
2657
2658 while (Nuitka_DictNext(sys_modules, &pos, &key, &value)) {
2659 if (key != NULL && value != NULL && PyModule_Check(value)) {
2660 bool is_package = HAS_ATTR_BOOL(tstate, value, const_str_plain___path__);
2661
2662 if (is_package || HAS_ATTR_BOOL(tstate, value, const_str_plain___file__) ||
2663 PySequence_Contains(builtin_module_names, key) == 0) {
2664 PyObject *file_value = MAKE_RELATIVE_PATH_FROM_NAME(Nuitka_String_AsString(key), is_package, false);
2665 PyObject_SetAttr(value, const_str_plain___file__, file_value);
2666 Py_DECREF(file_value);
2667 CHECK_OBJECT(file_value);
2668 }
2669 }
2670 }
2671
2672 assert(!HAS_ERROR_OCCURRED(tstate));
2673}
2674
2675#endif
2676
2677// The importlib distribution class is implemented in a separate file.
2678#include "MetaPathBasedLoaderImportlibMetadataDistribution.c"
2679
2680// Part of "Nuitka", an optimizing Python compiler that is compatible and
2681// integrates with CPython, but also works on its own.
2682//
2683// Licensed under the GNU Affero General Public License, Version 3 (the "License");
2684// you may not use this file except in compliance with the License.
2685// You may obtain a copy of the License at
2686//
2687// http://www.gnu.org/licenses/agpl.txt
2688//
2689// Unless required by applicable law or agreed to in writing, software
2690// distributed under the License is distributed on an "AS IS" BASIS,
2691// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2692// See the License for the specific language governing permissions and
2693// limitations under the License.
Definition exceptions.h:712
Definition MetaPathBasedLoader.c:50
Definition unfreezing.h:36