py: Automatically provide weak links from "foo" to "ufoo" module name.

This commit implements automatic module weak links for all built-in
modules, by searching for "ufoo" in the built-in module list if "foo"
cannot be found.  This means that all modules named "ufoo" are always
available as "foo".  Also, a port can no longer add any other weak links,
which makes strict the definition of a weak link.

It saves some code size (about 100-200 bytes) on ports that previously had
lots of weak links.

Some changes from the previous behaviour:
- It doesn't intern the non-u module names (eg "foo" is not interned),
  which saves code size, but will mean that "import foo" creates a new qstr
  (namely "foo") in RAM (unless the importing module is frozen).
- help('modules') no longer lists non-u module names, only the u-variants;
  this reduces duplication in the help listing.

Weak links are effectively the same as having a set of symbolic links on
the filesystem that is searched last.  So an "import foo" will search
built-in modules first, then all paths in sys.path, then weak links last,
importing "ufoo" if it exists.  Thus a file called "foo.py" somewhere in
sys.path will still have precedence over the weak link of "foo" to "ufoo".

See issues: #1740, #4449, #5229, #5241.
This commit is contained in:
Damien George
2019-10-22 01:06:34 +11:00
parent 9c5262f25e
commit d2384efa80
12 changed files with 32 additions and 135 deletions

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014 Damien P. George
* Copyright (c) 2013-2019 Damien P. George
* Copyright (c) 2014 Paul Sokolovsky
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -381,21 +381,18 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
DEBUG_printf("Current path: %.*s\n", vstr_len(&path), vstr_str(&path));
if (stat == MP_IMPORT_STAT_NO_EXIST) {
module_obj = MP_OBJ_NULL;
#if MICROPY_MODULE_WEAK_LINKS
// check if there is a weak link to this module
if (i == mod_len) {
mp_map_elem_t *el = mp_map_lookup((mp_map_t*)&mp_builtin_module_weak_links_map, MP_OBJ_NEW_QSTR(mod_name), MP_MAP_LOOKUP);
if (el == NULL) {
goto no_exist;
module_obj = mp_module_search_umodule(mod_str);
if (module_obj != MP_OBJ_NULL) {
// found weak linked module
mp_module_call_init(mod_name, module_obj);
}
// found weak linked module
module_obj = el->value;
mp_module_call_init(mod_name, module_obj);
} else {
no_exist:
#else
{
}
#endif
if (module_obj == MP_OBJ_NULL) {
// couldn't find the file, so fail
if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
mp_raise_msg(&mp_type_ImportError, "module not found");
@@ -492,11 +489,11 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
#if MICROPY_MODULE_WEAK_LINKS
// Check if there is a weak link to this module
mp_map_elem_t *el = mp_map_lookup((mp_map_t*)&mp_builtin_module_weak_links_map, MP_OBJ_NEW_QSTR(module_name_qstr), MP_MAP_LOOKUP);
if (el != NULL) {
module_obj = mp_module_search_umodule(qstr_str(module_name_qstr));
if (module_obj != MP_OBJ_NULL) {
// Found weak-linked module
mp_module_call_init(module_name_qstr, el->value);
return el->value;
mp_module_call_init(module_name_qstr, module_obj);
return module_obj;
}
#endif