The cppmem module *must* be switched into MicroPython heap mode or C++ code will inevitably run out of RAM.
Thus boot.py needs to be included in every build.
This module redirects all pre-init object memory allocations into a static, fixed-sized, linear, non-freeing memory pool.
It then auto-switches into "MICROPYTHON" mode, whereupon all C++ `new` and `delete` calls are remapped to `m_malloc` and `m_free` respectively.
MicroPython's GET_STR_DATA_LEN macro returns a const byte array and len, which std::string would copy into heap.
Using string_view lets us wrap the existing const values.
* Feature parity between Badger 2040 and Tufty 2040.
* Add ulab to Tufty 2040.
* Don't include modules_py modules for boards that don't use/need them.
* Tweak modules_py.cmake so modules can be copied by parent CMake files.
* Simplify copy_module function to avoid repetition.