Giter VIP home page Giter VIP logo

pfalcon / pycopy Goto Github PK

View Code? Open in Web Editor NEW
803.0 32.0 75.0 49.12 MB

Pycopy - a minimalist and memory-efficient Python dialect. Good for desktop, cloud, constrained systems, microcontrollers, and just everything.

Home Page: http://pycopy.readthedocs.io

License: MIT License

Makefile 0.96% C 89.50% C++ 0.46% Shell 0.20% Python 8.60% Assembly 0.08% CMake 0.17% JavaScript 0.03%
micropython micropython-ports python embedded iot unbloated minimalist minimalistic suckless pycopy

pycopy's Introduction

Build Status Coverage Status

The Pycopy project

Web site | Documentation

Pycopy aims to develop and maintain a minimalist, lightweight, and extensible implementation of Python(-compatible) language. Pycopy to CPython is a similar thing as Scheme to Common Lisp. Pycopy works similarly well in the cloud, on desktop systems, on small embedded systems, and scales all the way down to microcontrollers. The project is developed and maintained by Paul Sokolovsky and is originally based on MicroPython, developed by Damien George, Paul Sokolovsky and contributors. Names "Pycopy" and "MicroPython" are used interchangeably in the project documentation and source code.

WARNING: this project is in beta stage and is subject to changes of the code-base, including project-wide name changes and API changes.

Pycopy implements the entire Python 3.4 syntax (including exceptions, with, yield from, etc., and additionally async/await keywords from Python 3.5). The following core datatypes are provided: str (including basic Unicode support), bytes, bytearray, tuple, list, dict, set, frozenset, array.array, collections.namedtuple, classes and instances. Builtin modules include sys, time, and struct, etc. Select ports have support for _thread module (multithreading). Note that only a subset of Python 3 functionality is implemented for the data types and modules.

Pycopy can execute scripts in textual source form or from precompiled bytecode, in both cases either from an on-device filesystem or "frozen" into the executable.

Pycopy is highly portable, and the main repository includes support for POSIX operating systems (Linux, MacOSX, FreeBSD, etc.), Windows, Android, and a number of bare-metal microcontroller systems (see below). Ports to other systems can be implemented easily. POSIX port (nicknamed "Unix port") is the reference port of Pycopy.

The Pycopy Zen

Just as "big Python", Pycopy has its "Zen". The main principles of Pycopy are simplicity, minimalism, and light-weightedness.

At the same time, Pycopy strives to be a full-stack language and be compatible with wider Python ecosystem. The Pycopy project resolves these seemingly conflicting goals in a well-known and elegant way: by being a multi-level project, and by providing flexible configuration options. Specifically, there's a well-defined lightweight core written in C, defining the "native Pycopy language". Above it, a number of options are provided, implementing additional functionality (oftentimes offering more CPython compatibility). For example, on top of the core, "native Pycopy builtin modules" are provided, defining the native Pycopy API, which provides a subset of CPython's modules functionality, and at the same time, some extensions to it (driven by Pycopy's goal to be efficient). These native Pycopy modules are clearly namespaced, to allow to implement modules fully compatible with CPython API without any changes to the main project.

On top of this primary project, there are separate projects to further extend Pycopy functionality and achieve full-stack ecosystem. For example, there's a pycopy-lib project (see below) to implement a fully compatible CPython standard library for Pycopy.

Finally, on top of that infrastructure, there is an ecosystem of third-party packages, which are managed by the Pycopy users themselves.

The art of working with Pycopy is to understand where a particular feature belongs. Just as with CPython, it's almost never the core project, and almost always users' third party packages.

Contributors' Guidelines further elaborate on some points touched above.

Source tree layout

Major components in this repository:

  • py/ -- the core Python implementation, including compiler, runtime, and core library.
  • mpy-cross/ -- the bytecode (cross)compiler which is used to turn scripts into precompiled bytecode.
  • ports/unix/ -- a version of Pycopy that runs on Unix (which includes Android).
  • ports/windows/ -- a version for Windows.
  • ports/stm32/ -- a version of Pycopy that runs on the PyBoard and similar STM32 boards (using ST's Cube HAL drivers).
  • ports/minimal/ -- a minimal port. Start with this if you want to port the project to another microcontroller.
  • tests/ -- test framework and test scripts.
  • docs/ -- user documentation in Sphinx reStructuredText format. Rendered HTML documentation is available at http://pycopy.readthedocs.io/ .

Additional components:

  • ports/bare-arm/ -- a bare minimum version for ARM MCUs. Used mostly to control code size.
  • ports/teensy/ -- a version that runs on the Teensy 3.1 (preliminary but functional).
  • ports/pic16bit/ -- a version for 16-bit PIC microcontrollers.
  • ports/cc3200/ -- a version that runs on the CC3200 from TI.
  • ports/esp8266/ -- a version that runs on Espressif's ESP8266 SoC.
  • ports/esp32/ -- a version that runs on Espressif's ESP32 SoC.
  • ports/nrf/ -- a version that runs on Nordic's nRF51 and nRF52 MCUs.
  • extmod/ -- additional (non-core) modules implemented in C.
  • tools/ -- various tools, including the pyboard.py module.
  • examples/ -- various example scripts.

The subdirectories above may include READMEs with additional info.

"make" is used to build the components, or "gmake" on BSD-based systems. You will also need bash, gcc, and Python 3.3+ available as the command python3 (if your system only has Python 2.7 then invoke make with the additional option PYTHON=python2).

The cross-compiler, pycopy-cross

Most ports require the Pycopy cross-compiler to be built first. This program, called pycopy-cross, is used to pre-compile Python scripts to .mpy files which can then be included (frozen) into the firmware/executable for a port. To build pycopy-cross use:

$ cd mpy-cross
$ make

The Unix version

The "unix" port requires a standard Unix environment with gcc and GNU make. x86 and x64 architectures are supported (i.e. x86 32- and 64-bit), as well as ARM and MIPS. Making full-featured port to another architecture requires writing some assembly code for the exception handling and garbage collection. Alternatively, fallback implementation based on setjmp/longjmp can be used.

To build (see section below for required dependencies):

$ make -C mpy-cross
$ cd ports/unix
$ make submodules
$ make

Then to give it a try:

$ ./pycopy
>>> list(5 * x + y for x in range(10) for y in [4, 2, 1])

Use CTRL-D (i.e. EOF) to exit the shell. Learn about command-line options (in particular, how to increase heap size which may be needed for larger applications):

$ ./pycopy --help

Run complete testsuite:

$ make test

Unix version comes with a builtin package manager called upip, e.g.:

$ ./pycopy -m upip install pycopy-pystone
$ ./pycopy -m pystone

Browse available modules on PyPI. Standard library modules come from pycopy-lib project.

pycopy executable built following the instructions above is a "production" executable for native Pycopy software. It's also possible to build pycop-dev executable which provides additional reflection, diagnostics, and extensibility capabilities, at the expense of code size and memory usage efficiency. In particular, pycopy-dev is more compatible with software written for CPython. To build the pycopy-dev variant, run make dev.

External dependencies

Building Pycopy ports may require some dependencies installed.

For Unix port, libffi library and pkg-config tool are required. On Debian/Ubuntu/Mint derivative Linux distros, install build-essential (includes toolchain and make), libffi-dev, and pkg-config packages.

Other dependencies can be built together with Pycopy. This may be required to enable extra features or capabilities, and in recent versions, these may be enabled by default. To build these additional dependencies, first fetch git submodules for them:

$ make submodules

This will fetch all the relevant git submodules (sub repositories) that the port needs. Use the same command to get the latest versions of submodules as they are updated from time to time. After that execute:

$ make deplibs

This will build all available dependencies (regardless whether they are used or not). If you intend to build Pycopy with additional options (like cross-compiling), the same set of options should be passed to make deplibs. To actually enable/disable use of dependencies, edit ports/unix/mpconfigport.mk file, which has inline descriptions of the options. For example, to build SSL module (required for upip tool described above, and so enabled by default), MICROPY_PY_USSL should be set to 1.

For some ports, building required dependences is transparent, and happens automatically. But they still need to be fetched with the make submodules command.

Contributing

Pycopy is an open-source project and welcomes contributions which are aligned with its paradigm and work process. To be productive, please be sure to follow the Contributors' Guidelines and the Code Conventions. Note that Pycopy is licenced under the MIT license, and all contributions should follow this license.

Project FAQ

Q: How Pycopy differs from other Python implementations?

A: Pycopy is intended to be a small, minimalist implementation of the "core of the Python language" (in some definition of the "core"). Beyond that, the aim is to be extensible, to be able to support features of other Python implementations. Pycopy is particularly intended to write software (and extensions just mentioned) in Python. This may sounds as oxymoron, but it's a matter of fact that other implementations have too much of their functionality implemented in other languages (e.g., in C for CPython). This is a discouraged approach for Pycopy. Instead, for interfacing with non-Python libraries, it encourages the use of FFI (Foreign Function Interface) and flexible import extensions.

Q: How Pycopy differs from other small Python implementations?

A: Please see previous question for general information on how Pycopy differs from other Python implementations. Regarding small Python implementations specifically, a common issue with them is that they structure and represent themselves as niche, special-purpose systems, and oftentimes implement very bare subset of Python. Pycopy isn't just "Python for microcontrollers" or "Python to embed in other application". First and foremost, Pycopy is a general, and general-purpose, language, suitable for developing any kind of software. Which can be even used on microcontrollers and embedded in other applications (without growing them too much), but it's not limited to that in any way. Pycopy strives to cover as many systems as possible - from clouds down to tiny IoT devices. And project's attention and focus is also shared among them according to the functionality and value particular areas may offer. For example, microcontrollers are neat cute things, but you can do only so much with them, so they represent maybe 20% of the project focus.

Q: Current focus of the project?

A:

  • Code optimizations.
  • Continue to develop inplace, buffer and stream operations allowing to write highly memory effiicient applications.
  • Garbage collection experiments.
  • Reflection features (ultimately allowing to develop optimizing compilers, etc. in Python).
  • More CPython features implemented (configurable).
  • "Development/Testing" version with improved program analysis features.
  • etc.

pycopy's People

Contributors

atx avatar aykevl avatar blmorris avatar chipaca avatar danicampora avatar deshipu avatar dhylands avatar dlech avatar dpgeorge avatar flowergrass avatar glennrub avatar iabdalkader avatar jepler avatar jimmo avatar jongy avatar lurch avatar maureenhelm avatar mcauser avatar mrsurly avatar peterhinch avatar pfalcon avatar pi-anl avatar prusnak avatar robert-hh avatar rolandvs avatar rosuav avatar stinos avatar tomlogic avatar tve avatar xbe avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pycopy's Issues

upip.install() fails on bare-metal targets

I've tried to install picoweb with upip. But it fails.
pycopy is version aa986f5
compiled with esp-idf v3.3 6ccb4cf5b7d1fdd
running on esp32 (doit-devkit)

Connection successful
('192.168.70.71', '255.255.255.0', '192.168.70.1', '192.168.200.1')
>>> import upip
>>> upip.install("picoweb")
Installing to: /lib/
Warning: pypi.org SSL certificate is not validated
Installing picoweb from https://files.pythonhosted.org/packages/a7/cb/1b48103a22f8d67985af5e30ee157c195d2a37b12864e6e8744ad8e7e1b6/picoweb-1.7.2.tar.gz
Error installing 'picoweb': TypeError('object with buffer protocol required',), packages may be partially installed
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "upip.py", line 248, in install
  File "upip.py", line 236, in install
  File "upip.py", line 209, in install_pkg
TypeError: object with buffer protocol required
>>>

Dirty flashing or upgrading from a different firmware does not work

Hello. I have flashed Tasmota on a couple of Tuya bulbs using tuya-convert and now I would like to flash pycopy and give the LEDs to a bunch of kids I teach Python to play with. The problem is that I cannot exactly wipe the bulbs before flashing them without opening them up and that is something I would like to avoid since I don't have a ~230V license. And I am afraid that without wiping them beforehand pycopy won't boot up.

Why? I have tested the Tasmota->pycopy migration path on a Sonoff esp8285 board and after figuring out SetOption78 1 on Tasmota and flashing pycopy I get only a never-ending stream of random garbage on UART. Same thing happens when I dirty-flash pycopy using esptool.py. Everything works fine when I erase the flash beforehand.

I don't know if it helps, but when I manually flash 0x0fc000 it starts to work:

esptool -b 460800 write_flash --flash_mode=dout 0x0fc000 esp_init_data_default.bin

Please advise.

CAN bus - not receiving frames of type extframe=False

There apprears to be an issue in the CAN drivers which prevents receiving messages with non extended id's.

As a test I'm using a pyboard-D to send data between the 2 CAN ports.
This works fine when the can filter is set to extframe=True.
can.init(mode=pyb.CAN.NORMAL, extframe=True, prescaler=4, sjw=1, bs1=7, bs2=1)

However, when changed to False, there are no incoming frames detected.
I can see the frames with a CAN bus analyzer, but the rx callback does not trigger.
can.init(mode=pyb.CAN.NORMAL, extframe=False, prescaler=4, sjw=1, bs1=7, bs2=1

I've tried sending frames with non-extended id's which works fine.
Any pointers into where this can be fixed? Is it STM32 specific?

ure: mixing named classes and characters in a match set raises ValueError

Tested on unix and esp8266, master branch

>>> ure.compile('\d+')
<re 3fff02f0>

>>> ure.compile('[abc0-9]+')
<re 3fff0580>

>>> ure.compile('[abc\d]+')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: Error in regex

>>> ure.compile('[\w\d]+')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: Error in regex

Generic documentation TODOs

  • Add placeholder docs for ffi module.
  • Add real docs for ffi module.
  • Fully document ure module
  • Document urandom module - placeholder added
  • Update docs for ussl module
  • Fully document uctypes module (#14)
  • Document abstract stream interface (uio module)
  • Document extended return codes (WANT_READ, WANT_WRITE) for non-blocking streams.

RFC: Introducing "import- vs run- time" semantics mode to Python

One of the biggest (performance) issues with Python is (my term) overdynamicity - the fact that many symbols in a program a looked up at runtime by symbolic name. This includes: global variables and functions, module variables and functions, object attributes and methods. (Almost the only exception is that local function variables are optimized and accessed by "address" (more specifically, by offset in function stack frame)).

Such a semantics allows to override and customize many aspects of the language, but at the same time, leads to runtime inefficiency. But following are well-known facts:

  1. Majority of applications just never override symbols in other modules.
  2. Of those which do, majority do that once at the application startup (while "setting up application environment").
  3. Remaining would be quite specialized applications, either belonging to toolset (test runners, profilers, etc.) or applications which work around something instead of implementing/fixing properly.

Formalizing to Python semantics, following optimization approach can be proposed:

  1. During import time, a particular module can modify runtime environment (including overriding symbols in other modules).
  2. However, at runtime, such modifications are not allowed.
  3. These rules apply to all modules comprising a particular application recursively. I.e. there's a clear "import-time" phase vs runtime phases of application lifetime. Note that this rules out runtime imports (indeed, imports modify runtime environment, but it should be settled by the time when runtime phase starts).

Note also that "import time" is effectively corresponds to "compile time" in other languages. Indeed, cached bytecode files are produced during import phase, and they are produced by compiling source into the bytecode. But with conventional Python semantics, compiled bytecode has an implicit "module initialization function". That's required to allow both conventional semantics and modularity. For example, module init code can (and indeed, often does, per p.2 above) override symbols in other modules, so this has to be captured as imperative code. But the proposed new semantics effectively requires executing module init code during import time, and capturing effects of it. As effects can extend beyond the current module to the whole runtime environment, implementing the new semantics would require whole-program approach.

how to identify pycopy versus micropython during runtime

Hi ,
I'm looking for a way to identify pycopy ( versus micropython ) while running a script / module.

if i look at the unix port, this information does not seem to be availalbe directly

>>> sys.implementation
(name='micropython', version=(3, 3, 2))

I could make the assumption that that a version > 2.11.0 is an indicator of the pycopy runtime/firmware,
but hope/assume that there would be another, more reliable, way to determine this.

Any suggestion for something that i could test for ?

Case study: binary stream reading/writing: new stream methods vs support stream args for ustruct functions

This is continuation of micropython/micropython#3382 . That PR proposed adding methods like stream.readbin(fmt) and stream.writebin(fmt, val). There was criticism/suggestion to instead implement everything on the level of ustruct module.

Option 0 (original):

  • stream.readbin(fmt)
  • stream.writebin(fmt, val)

Option 1: Extending existing unpack()/pack_into() functions.

Plan:

  1. Introduce ustruct.unpack1(fmt, buf) function which would unpack a single value and thus avoid extra memory allocation for a tuple as returned by standard .unpack().
  2. For ustruct.unpack(), ustruct.unpack1(), allow "buf" argument to also accept a stream object type, in which case read the data from it.

So far so good, and even nice. However, packing is worse:

  1. A natural existing func to extend in ustruct.pack_into(). But it has signature ustruct.pack_into(fmt, buffer, offset, v1, v2, ...). For the stream case, offset would be always 0, and in general would be cumbersome/confusing (this point was raised many times in micropython/micropython#3382). Some way to deal with that would be to allow None as offset. (We reject variants like "if stream is passed as buffer argument, then there's no offset argument" - these raise confusion bar too high.)
  2. Even with None as offset it's still to cumbersome. A solution might be implementing a variant of pack_into() method which wouldn't take offset param. But how to name it? I initially named it pack_s() (from "pack stream") but that's hardly beautiful. pack_into0() us hardly more clear.

Option 2: Have readbin/writebin, but as functions in the ustruct module

As another alternative suggested in micropython/micropython#3382. This would be a kind of compromise, not as convenient as methods, but avoid dealing with baggage like pack_into() offset param above. But the next question is in what order should e.g. ustruct.writebin() take args? More specifically, how natural is to have pack_into's order like ustruct.pack_into("B", stream, None, 100). This would lead to ustruct.writebin("B", stream, 100)

But (surprise) maybe it's not too natural, maybe stream arg should be first? ustruct.writebin(stream, "B", 100) , ustruct.readbin(stream, "B"). But done like that, it would mean that these new functions would round pegs in ustruct's square hole.

Overall, going thru description of options 1, 2 shows that the only reasoning behind them would be the desire to stuff the new functionality into straitjacket of CPython's struct module. But the whole idea behind readbin/writebin is different/opposite - not to make questionable (bad?) compromises with the old API, but add an API which many other languages have, to avoid the situation that Python (don't mix up with CPython) falls short to them.

Brainstorming generic async write support for advanced/wrapper streams #2

This is continuation of micropython/micropython#3396 .

Definition: miniprotocol is a simplified, "single-behavior" protocol. A real world protocol is usually a combination/composition of miniprotocols.

Classification of miniprotocols:

  1. By record delimitation type:
    1.1. Length-delimited.
    1.2. Separator-delimited.

Example: full WebSocket protocol starts with separator (line) delimited HTTP protocol, then switches to length-delimited protocol.

The idea is that length-delimited protocols are more efficient. But actually better to say that they compose better - we always know how much is left to read for the current miniprotocol, and thus can avoid over-read. The only way to have the same guarantee for separator-delimited miniproto is to read byte by byte, which is known to be not efficient. Thus, the only performance-efficient way to deal with SepProto is to buffer the underlying stream (on our side). But if this buffering happens on miniprotocol parser side, then once we need to switch to another protocol, we may have overread data, and it's a new problem how to pass that data forward to the next miniproto parser. Also, while LenProto is not susceptible to over-read problem, it doesn't mean it doesn't need buffering. For example, there can be many small records, and e.g. read "5 bytes by 5 bytes" isn't much better than SepProto's "1 byte by 1 byte". These 2 issues: a) over-read issue if buffering happens on miniproto parser side; b) need for buffering for performance in general, lead to obvious and well-known solution: buffering should happen on the input stream's side. Well, that still not ideal, if we have efficient, large-block LenProto. Consider for example that some proto start with line-based miniproto, to handle which we allocate 256 bytes buffer, and then switches to LenProto with 1K blocks. Those 256 bytes are then wasted beyond the initial line-based "handshake" phase.

  1. By exchange behavior:
    2.1. Single client request leads to protocol transaction in one direction.
    2.2. Single client request leads to exchange of records in both directions.

Example: TLS clearly consists of initial handshake phase which requires exchange, but once that is done, single user write leads to single TLS record to send to peer, and single user read is backed by single record received from peer. One way to deal with this scenario is to perform complete handshake based on user request "open connection", so we had one-directional exchanges afterwards. But it's more complex if we postpone handshake until first actual read/write operation from user. And actually, it's more complex on TLS side too: at any time, a negotiation may be requested, which leads to the same issue that a user single operation may lead to the need to postpone it and perform series of exchanges.

  1. Push vs pull handling
    3.1. We can "push" any given data into miniproto parser.
    3.2. Or we can let it "pull" data, specifying how much exactly it would like to get at the next step.

Push approach has another face of over-read problem: a parser might not accept all data we feed into it, yet produce some output already. This leads to "all hands are full" situation: we need to keep track/store input data which the parser yet not accepted, and need to deal with parser output, which me may not be able to accept in one go on our side either. Pull approach simplifies that somewhat. In reality, suitability push vs pull approach depends on the nature and direction of data passing. For application data -> convert to protocol data, push approach is obvious: the app already have that data (for classically written apps), so we can only push it, hold the remaining part which miniproto didn't consume, and iterate on sending out miniproto output until it's done and we can continue with feeding the rest of app data. On protocol data -> convert to app data, pull approach is beneficial: miniproto parser knows either how much exactly it needs, or otherwise, its internal buffer requirements, and can request data to avoid over-read.

  1. Transformational vs non-transformational
    4.1. Transformation miniprotos actually change application data when converting them to protocol records.
    4.2. Non-transformational may frame app data, but the data itself is intact.

For example, WebSocket in one direction "masks" the data, but in another direction it's verbatim. Distinction here is of optimization nature: we may use "zero copy" operation, i.e. write user data directly to the underlying stream, instead of copying it to miniproto buffer for additional processing.

Problems with bytecode encoding

  1. Description is sparse/not clear.
  2. qstr and constant encoding per code block (== function). Instead, should be per module to allow better reuse. - .mpy ver 4 provides way to achieve that for qstr's (TBC)
  3. "code info" is mis-nomer. It has both length encoded and also ends with 0? - kinda fixed in .mpy ver 5
  4. function argname qstr's are stored in const_table and waste some space there (given that qstr's a 2-byte encoded, while entry in const_table is void*).

"Beyond finishing" ideas

Things to consider beyond #15.

  • Implement "marshal" module #8
  • Add += (as a synonym for .write()) and [] operations for uio.StringIO, effectively implementing "string buffer" class with operations close to str.
  • Add +=, etc. operations to array.array as means for users to perform alloc-free arithmetics on values "larger" than native smallint (e.g. on int32, int64, float, double values).
  • Make dictionary C implementation overridable (e.g. allow to switch in more efficient, but more memory-hungry implementation).
  • Implement efficient uselect.poll() support for bare-metal ports (ready-queue instead of busy-polling).

README issues

  1. Section starting "On top of it" has two "On top of it" sentences, and otherwise suffers from long sentence syndrome.

  2. Source tree layout section says "version of MicroPython" and "MicroPython port" three times. Wait .. that is / isn't pycopy? Or maybe it's legacy language in the README, or maybe it's extra somehow and could be removed from the repo, and be in a separate (new) repo.

  3. FAQ sections needed:

3.1 Win/Lin/Mac/iOS/Android/ChromeOS/Fucsia compatibility?

3.2 Which package managers for pips/eggs? And compatibility with pips/eggs from MicroPython-land?

uctypes module TODO

  • Allow to convert PTR object to int
  • Allow to assign to PTR field - either int or another
  • Allow to pass PTR object properly to FFI functions - address held in PTR should be passed, not address of PTR field itself
  • Support of automatic field offset calculation - uctypes.calc_offsets(desc)
  • Add support for unions with .calc_offsets()
  • Add native C types: SHORT, INT, LONG, LONGLONG, unsigned variants (should alias to exact-sized types).
  • Add end-to-end usage example to docs
  • Update docs for changes above
  • Add uctypes_helper uctypeslib module to micropython-lib with convenience functions to create fields.
  • Add uctypeslib uctypeslib2 module to micropython-lib with any other functionality, starting with dumping of descriptors in readable form.
  • Implement OrderedDict literal in the core.

Unable to build this branch on my macBook

make: *** No rule to make target lib/lwip/src/core/def.c', needed by build-PYBV11/genhdr/qstr.i.last'. Stop.

I'm getting the above error , while trying to build this on my mac!!

Command that I issued:
make clean
make BOARD=PYBV11

unix port: Build fails with gcc11

Build log:

[hybroid@lip pycopy-3.6.0]$ make -C mpy-cross
make: Entering directory '/home/hybroid/dev/pycopy-3.6.0/mpy-cross'
Use make V=1 or set BUILD_VERBOSE in your environment to increase build verbosity.
mkdir -p build/genhdr
GEN build/genhdr/mpversion.h
GEN build/genhdr/moduledefs.h
GEN build/genhdr/qstr.i.last
GEN build/genhdr/qstr.split
GEN build/genhdr/qstrdefs.collected.h
QSTR updated
GEN build/genhdr/qstrdefs.generated.h
mkdir -p build/lib/utils/
mkdir -p build/py/
CC ../py/mpstate.c
CC ../py/nlr.c
CC ../py/nlrx86.c
CC ../py/nlrx64.c
CC ../py/nlrthumb.c
CC ../py/nlraarch64.c
CC ../py/nlrpowerpc.c
CC ../py/nlrxtensa.c
CC ../py/nlrsetjmp.c
CC ../py/malloc.c
CC ../py/gc.c
CC ../py/pystack.c
CC ../py/qstr.c
CC ../py/vstr.c
CC ../py/mpprint.c
CC ../py/unicode.c
CC ../py/mpz.c
CC ../py/reader.c
CC ../py/lexer.c
CC ../py/parse.c
CC ../py/scope.c
CC ../py/compile.c
CC ../py/emitcommon.c
CC ../py/emitbc.c
CC ../py/asmbase.c
CC ../py/asmx64.c
CC ../py/emitnx64.c
CC ../py/asmx86.c
CC ../py/emitnx86.c
CC ../py/asmthumb.c
CC ../py/emitnthumb.c
CC ../py/emitinlinethumb.c
CC ../py/asmarm.c
CC ../py/emitnarm.c
CC ../py/asmxtensa.c
CC ../py/emitnxtensa.c
CC ../py/emitinlinextensa.c
CC ../py/emitnxtensawin.c
CC ../py/formatfloat.c
CC ../py/parsenumbase.c
CC ../py/parsenum.c
CC ../py/emitglue.c
CC ../py/persistentcode.c
CC ../py/runtime.c
CC ../py/runtime_utils.c
CC ../py/scheduler.c
CC ../py/strict_mode.c
CC ../py/nativeglue.c
CC ../py/pairheap.c
CC ../py/ringbuf.c
CC ../py/stackctrl.c
CC ../py/argcheck.c
CC ../py/warning.c
CC ../py/profile.c
CC ../py/map.c
CC ../py/obj.c
CC ../py/objarray.c
CC ../py/objattrtuple.c
CC ../py/objbool.c
CC ../py/objboundmeth.c
CC ../py/objbufreader.c
CC ../py/objcell.c
CC ../py/objclosure.c
CC ../py/objcomplex.c
CC ../py/objdeque.c
CC ../py/objdict.c
CC ../py/objenumerate.c
CC ../py/objexcept.c
CC ../py/objfilter.c
CC ../py/objfloat.c
CC ../py/objfun.c
CC ../py/objgenerator.c
CC ../py/objgetitemiter.c
CC ../py/objint.c
CC ../py/objint_longlong.c
CC ../py/objint_mpz.c
CC ../py/objlist.c
CC ../py/objmap.c
CC ../py/objmodule.c
CC ../py/objobject.c
CC ../py/objpolyiter.c
CC ../py/objproperty.c
CC ../py/objnone.c
CC ../py/objnamedtuple.c
CC ../py/objrange.c
CC ../py/objreversed.c
CC ../py/objroproxy.c
CC ../py/objset.c
CC ../py/objsingleton.c
CC ../py/objslice.c
CC ../py/objstr.c
CC ../py/objstrunicode.c
CC ../py/objstringio.c
CC ../py/objtextio.c
CC ../py/objtuple.c
CC ../py/objtype.c
CC ../py/objzip.c
CC ../py/opmethods.c
CC ../py/sequence.c
CC ../py/stream.c
CC ../py/binary.c
CC ../py/builtinimport.c
CC ../py/builtinimport.c
../py/builtinimport.c: In function 'mp_builtin___import__':
../py/builtinimport.c:513:36: error: 'imp.module_from_hook' may be used uninitialized [-Werror=maybe-uninitialized]
  513 |                         module_obj = imp.module_from_hook;
      |                         ~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~
../py/builtinimport.c:407:22: note: 'imp' declared here
  407 |     mp_import_info_t imp;
      |                      ^~~
cc1: all warnings being treated as errors
make: *** [../py/mkrules.mk:77: build/py/builtinimport.o] Error 1
make: Leaving directory '/home/hybroid/dev/pycopy-3.6.0/mpy-cross'

Used GCC:

[hybroid@lip pycopy-3.6.0]$ LC_ALL=C gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: /build/gcc/src/gcc/configure --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://bugs.archlinux.org/ --enable-languages=c,c++,ada,fortran,go,lto,objc,obj-c++,d --with-isl --with-linker-hash-style=gnu --with-system-zlib --enable-__cxa_atexit --enable-cet=auto --enable-checking=release --enable-clocale=gnu --enable-default-pie --enable-default-ssp --enable-gnu-indirect-function --enable-gnu-unique-object --enable-install-libiberty --enable-linker-build-id --enable-lto --enable-multilib --enable-plugin --enable-shared --enable-threads=posix --disable-libssp --disable-libstdcxx-pch --disable-libunwind-exceptions --disable-werror gdc_include_dir=/usr/include/dlang/gdc
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 11.1.0 (GCC)

I tried the last commit - same thing.

modlwip.c does not properly return POLL_HUP and POLL_ERR socket errors

extmod/modlwip.c only returns POLL_HUP and POLL_ERR if the events flags specify them. AFIAK this is not AFAIK POSIX compliant which specifies these return events shall be unsolicited. e.g. see http://man7.org/linux/man-pages/man2/poll.2.html

The impact is that uasyncio (which does not set POLL_HUP and POLL_ERR flags) will not see these failed socket connections and co-routines will hang and consume memory. Eventually pycopy will run out of memory. Adding these flags to uasyncio is a work-around to getting the socket errors returned but is not the expected behavior of these ioctl polls. The modlwip.c changes below were tested and, work when appropriate exception handling is added to uasync (specifically in the start_server() loop). Socket errors will also now be returned the the yielding co-routine where appropriate exception handling including stream read.aclose() and write.aclose() must be called to clean up upon pre-mature connection termination.

extmod_modlwip_c.diff.txt

note: In diff, (flags,ret) renamed to (events,revents) to align with common parlance in ioctl polling

build failed for android port on macos

I use build-android.sh in "cross" branch to build but get some errors. Is there tutorial about how to build for android port on macos?
My steps:

make-standalone-toolchain.sh
cd ports/unix
make axtls
./build-android.sh

the last step throws error:

Use make V=1 or set BUILD_VERBOSE in your environment to increase build verbosity.
mkdir -p build-micropython-android/lib/libffi; cd build-micropython-android/lib/libffi; \
        /Users/liwenkun/Desktop/pycopy/lib/libffi/configure --host=arm-linux-androideabi --prefix=$PWD/out --disable-structs CC="clang" CXX="arm-linux-androideabi-g++" LD="arm-linux-androideabi-ld" CFLAGS="-Os -fomit-frame-pointer -fstrict-aliasing -ffast-math -fno-exceptions"; \
        /Applications/Xcode.app/Contents/Developer/usr/bin/make install-exec-recursive; /Applications/Xcode.app/Contents/Developer/usr/bin/make -C include install-data-am
checking build system type... x86_64-apple-darwin20.3.0
checking host system type... arm-unknown-linux-androideabi
checking target system type... arm-unknown-linux-androideabi
checking for gsed... sed
checking for a BSD-compatible install... /usr/local/bin/ginstall -c
checking whether build environment is sane... yes
checking for arm-linux-androideabi-strip... arm-linux-androideabi-strip
checking for a thread-safe mkdir -p... /usr/local/bin/gmkdir -p
checking for gawk... no
checking for mawk... no
checking for nawk... no
checking for awk... awk
checking whether make sets $(MAKE)... yes
checking whether make supports nested variables... yes
checking for arm-linux-androideabi-gcc... clang
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables... 
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether clang accepts -g... yes
checking for clang option to accept ISO C89... none needed
checking whether clang understands -c and -o together... yes
checking whether make supports the include directive... yes (GNU style)
checking dependency style of clang... gcc3
checking whether we are using the GNU C++ compiler... yes
checking whether arm-linux-androideabi-g++ accepts -g... yes
checking dependency style of arm-linux-androideabi-g++... gcc3
checking dependency style of clang... gcc3
checking how to print strings... printf
checking for a sed that does not truncate output... /usr/bin/sed
checking for grep that handles long lines and -e... /usr/bin/grep
checking for egrep... /usr/bin/grep -E
checking for fgrep... /usr/bin/grep -F
checking for ld used by clang... arm-linux-androideabi-ld
checking if the linker (arm-linux-androideabi-ld) is GNU ld... yes
checking for BSD- or MS-compatible name lister (nm)... /Users/liwenkun/android-sdk/ndk/16.1.4479499/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-nm -B
checking the name lister (/Users/liwenkun/android-sdk/ndk/16.1.4479499/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-nm -B) interface... BSD nm
checking whether ln -s works... yes
checking the maximum length of command line arguments... 786432
checking how to convert x86_64-apple-darwin20.3.0 file names to arm-unknown-linux-androideabi format... func_convert_file_noop
checking how to convert x86_64-apple-darwin20.3.0 file names to toolchain format... func_convert_file_noop
checking for arm-linux-androideabi-ld option to reload object files... -r
checking for arm-linux-androideabi-objdump... arm-linux-androideabi-objdump
checking how to recognize dependent libraries... pass_all
checking for arm-linux-androideabi-dlltool... no
checking for dlltool... no
checking how to associate runtime and link libraries... printf %s\n
checking for arm-linux-androideabi-ar... arm-linux-androideabi-ar
checking for archiver @FILE support... @
checking for arm-linux-androideabi-strip... (cached) arm-linux-androideabi-strip
checking for arm-linux-androideabi-ranlib... arm-linux-androideabi-ranlib
checking command to parse /Users/liwenkun/android-sdk/ndk/16.1.4479499/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-nm -B output from clang object... failed
checking for sysroot... no
checking for a working dd... /bin/dd
checking how to truncate binary pipes... /bin/dd bs=4096 count=1
checking for arm-linux-androideabi-mt... no
checking for mt... no
checking if : is a manifest tool... no
checking how to run the C preprocessor... clang -E
checking for ANSI C header files... yes
checking for sys/types.h... yes
checking for sys/stat.h... yes
checking for stdlib.h... yes
checking for string.h... yes
checking for memory.h... yes
checking for strings.h... yes
checking for inttypes.h... yes
checking for stdint.h... yes
checking for unistd.h... yes
checking for dlfcn.h... yes
checking for objdir... .libs
checking if clang supports -fno-rtti -fno-exceptions... yes
checking for clang option to produce PIC... -fPIC -DPIC
checking if clang PIC flag -fPIC -DPIC works... yes
checking if clang static flag -static works... no
checking if clang supports -c -o file.o... yes
checking if clang supports -c -o file.o... (cached) yes
checking whether the clang linker (arm-linux-androideabi-ld) supports shared libraries... yes
checking whether -lc should be explicitly linked in... yes
checking dynamic linker characteristics... Android linker
checking how to hardcode library paths into programs... immediate
checking whether stripping libraries is possible... yes
checking if libtool supports shared libraries... yes
checking whether to build shared libraries... yes
checking whether to build static libraries... yes
checking how to run the C++ preprocessor... clang -E
checking for ld used by arm-linux-androideabi-g++... arm-linux-androideabi-ld
checking if the linker (arm-linux-androideabi-ld) is GNU ld... yes
checking whether the arm-linux-androideabi-g++ linker (arm-linux-androideabi-ld) supports shared libraries... yes
checking for arm-linux-androideabi-g++ option to produce PIC... -fPIC -DPIC
checking if arm-linux-androideabi-g++ PIC flag -fPIC -DPIC works... yes
checking if arm-linux-androideabi-g++ static flag -static works... no
checking if arm-linux-androideabi-g++ supports -c -o file.o... yes
checking if arm-linux-androideabi-g++ supports -c -o file.o... (cached) yes
checking whether the arm-linux-androideabi-g++ linker (arm-linux-androideabi-ld) supports shared libraries... yes
checking dynamic linker characteristics... Android linker
checking how to hardcode library paths into programs... immediate
checking size of size_t... 8
checking for C compiler vendor... clang
checking CFLAGS for maximum warnings... -Wall
checking whether to enable maintainer-specific portions of Makefiles... no
checking sys/mman.h usability... yes
checking sys/mman.h presence... yes
checking for sys/mman.h... yes
checking for mmap... yes
checking for mkostemp... yes
checking for sys/mman.h... (cached) yes
checking for mmap... (cached) yes
checking whether read-only mmap of a plain file works... yes
checking whether mmap from /dev/zero works... yes
checking for MAP_ANON(YMOUS)... yes
checking whether mmap with MAP_ANON(YMOUS) works... yes
checking for ANSI C header files... (cached) yes
checking for memcpy... yes
checking for size_t... yes
checking for working alloca.h... yes
checking for alloca... yes
checking size of double... 8
checking size of long double... 16
checking whether byte ordering is bigendian... no
checking assembler .cfi pseudo-op support... yes
checking for _ prefix in compiled symbols... no
checking whether .eh_frame section should be read-only... no
checking for __attribute__((visibility("hidden")))... no
clang: error: no input files
checking that generated files are newer than configure... done
configure: creating ./config.status
config.status: creating include/Makefile
config.status: creating include/ffi.h
config.status: creating Makefile
config.status: creating testsuite/Makefile
config.status: creating man/Makefile
config.status: creating libffi.pc
config.status: creating fficonfig.h
config.status: linking /Users/liwenkun/Desktop/pycopy/lib/libffi/src/arm/ffitarget.h to include/ffitarget.h
config.status: executing buildir commands
config.status: skipping top_srcdir/Makefile - not created
config.status: executing depfiles commands
config.status: executing libtool commands
config.status: executing include commands
config.status: executing src commands
Making install-exec in include
make[2]: Nothing to be done for `install-exec'.
Making install-exec in testsuite
make[2]: Nothing to be done for `install-exec'.
Making install-exec in man
make[2]: Nothing to be done for `install-exec'.
depbase=`echo src/prep_cif.lo | sed 's|[^/]*$|.deps/&|;s|\.lo$||'`;\
        /bin/sh ./libtool  --tag=CC   --mode=compile clang -DHAVE_CONFIG_H -I. -I/Users/liwenkun/Desktop/pycopy/lib/libffi  -I. -I/Users/liwenkun/Desktop/pycopy/lib/libffi/include -Iinclude -I/Users/liwenkun/Desktop/pycopy/lib/libffi/src   -Os -fomit-frame-pointer -fstrict-aliasing -ffast-math -fno-exceptions  -Wall -fexceptions -MT src/prep_cif.lo -MD -MP -MF $depbase.Tpo -c -o src/prep_cif.lo /Users/liwenkun/Desktop/pycopy/lib/libffi/src/prep_cif.c &&\
        mv -f $depbase.Tpo $depbase.Plo
libtool: compile:  clang -DHAVE_CONFIG_H -I. -I/Users/liwenkun/Desktop/pycopy/lib/libffi -I. -I/Users/liwenkun/Desktop/pycopy/lib/libffi/include -Iinclude -I/Users/liwenkun/Desktop/pycopy/lib/libffi/src -Os -fomit-frame-pointer -fstrict-aliasing -ffast-math -fno-exceptions -Wall -fexceptions -MT src/prep_cif.lo -MD -MP -MF src/.deps/prep_cif.Tpo -c /Users/liwenkun/Desktop/pycopy/lib/libffi/src/prep_cif.c  -fPIC -DPIC -o src/.libs/prep_cif.o
libtool: compile:  clang -DHAVE_CONFIG_H -I. -I/Users/liwenkun/Desktop/pycopy/lib/libffi -I. -I/Users/liwenkun/Desktop/pycopy/lib/libffi/include -Iinclude -I/Users/liwenkun/Desktop/pycopy/lib/libffi/src -Os -fomit-frame-pointer -fstrict-aliasing -ffast-math -fno-exceptions -Wall -fexceptions -MT src/prep_cif.lo -MD -MP -MF src/.deps/prep_cif.Tpo -c /Users/liwenkun/Desktop/pycopy/lib/libffi/src/prep_cif.c -o src/prep_cif.o >/dev/null 2>&1
depbase=`echo src/types.lo | sed 's|[^/]*$|.deps/&|;s|\.lo$||'`;\
        /bin/sh ./libtool  --tag=CC   --mode=compile clang -DHAVE_CONFIG_H -I. -I/Users/liwenkun/Desktop/pycopy/lib/libffi  -I. -I/Users/liwenkun/Desktop/pycopy/lib/libffi/include -Iinclude -I/Users/liwenkun/Desktop/pycopy/lib/libffi/src   -Os -fomit-frame-pointer -fstrict-aliasing -ffast-math -fno-exceptions  -Wall -fexceptions -MT src/types.lo -MD -MP -MF $depbase.Tpo -c -o src/types.lo /Users/liwenkun/Desktop/pycopy/lib/libffi/src/types.c &&\
        mv -f $depbase.Tpo $depbase.Plo
libtool: compile:  clang -DHAVE_CONFIG_H -I. -I/Users/liwenkun/Desktop/pycopy/lib/libffi -I. -I/Users/liwenkun/Desktop/pycopy/lib/libffi/include -Iinclude -I/Users/liwenkun/Desktop/pycopy/lib/libffi/src -Os -fomit-frame-pointer -fstrict-aliasing -ffast-math -fno-exceptions -Wall -fexceptions -MT src/types.lo -MD -MP -MF src/.deps/types.Tpo -c /Users/liwenkun/Desktop/pycopy/lib/libffi/src/types.c  -fPIC -DPIC -o src/.libs/types.o
libtool: compile:  clang -DHAVE_CONFIG_H -I. -I/Users/liwenkun/Desktop/pycopy/lib/libffi -I. -I/Users/liwenkun/Desktop/pycopy/lib/libffi/include -Iinclude -I/Users/liwenkun/Desktop/pycopy/lib/libffi/src -Os -fomit-frame-pointer -fstrict-aliasing -ffast-math -fno-exceptions -Wall -fexceptions -MT src/types.lo -MD -MP -MF src/.deps/types.Tpo -c /Users/liwenkun/Desktop/pycopy/lib/libffi/src/types.c -o src/types.o >/dev/null 2>&1
depbase=`echo src/raw_api.lo | sed 's|[^/]*$|.deps/&|;s|\.lo$||'`;\
        /bin/sh ./libtool  --tag=CC   --mode=compile clang -DHAVE_CONFIG_H -I. -I/Users/liwenkun/Desktop/pycopy/lib/libffi  -I. -I/Users/liwenkun/Desktop/pycopy/lib/libffi/include -Iinclude -I/Users/liwenkun/Desktop/pycopy/lib/libffi/src   -Os -fomit-frame-pointer -fstrict-aliasing -ffast-math -fno-exceptions  -Wall -fexceptions -MT src/raw_api.lo -MD -MP -MF $depbase.Tpo -c -o src/raw_api.lo /Users/liwenkun/Desktop/pycopy/lib/libffi/src/raw_api.c &&\
        mv -f $depbase.Tpo $depbase.Plo
libtool: compile:  clang -DHAVE_CONFIG_H -I. -I/Users/liwenkun/Desktop/pycopy/lib/libffi -I. -I/Users/liwenkun/Desktop/pycopy/lib/libffi/include -Iinclude -I/Users/liwenkun/Desktop/pycopy/lib/libffi/src -Os -fomit-frame-pointer -fstrict-aliasing -ffast-math -fno-exceptions -Wall -fexceptions -MT src/raw_api.lo -MD -MP -MF src/.deps/raw_api.Tpo -c /Users/liwenkun/Desktop/pycopy/lib/libffi/src/raw_api.c  -fPIC -DPIC -o src/.libs/raw_api.o
libtool: compile:  clang -DHAVE_CONFIG_H -I. -I/Users/liwenkun/Desktop/pycopy/lib/libffi -I. -I/Users/liwenkun/Desktop/pycopy/lib/libffi/include -Iinclude -I/Users/liwenkun/Desktop/pycopy/lib/libffi/src -Os -fomit-frame-pointer -fstrict-aliasing -ffast-math -fno-exceptions -Wall -fexceptions -MT src/raw_api.lo -MD -MP -MF src/.deps/raw_api.Tpo -c /Users/liwenkun/Desktop/pycopy/lib/libffi/src/raw_api.c -o src/raw_api.o >/dev/null 2>&1
depbase=`echo src/java_raw_api.lo | sed 's|[^/]*$|.deps/&|;s|\.lo$||'`;\
        /bin/sh ./libtool  --tag=CC   --mode=compile clang -DHAVE_CONFIG_H -I. -I/Users/liwenkun/Desktop/pycopy/lib/libffi  -I. -I/Users/liwenkun/Desktop/pycopy/lib/libffi/include -Iinclude -I/Users/liwenkun/Desktop/pycopy/lib/libffi/src   -Os -fomit-frame-pointer -fstrict-aliasing -ffast-math -fno-exceptions  -Wall -fexceptions -MT src/java_raw_api.lo -MD -MP -MF $depbase.Tpo -c -o src/java_raw_api.lo /Users/liwenkun/Desktop/pycopy/lib/libffi/src/java_raw_api.c &&\
        mv -f $depbase.Tpo $depbase.Plo
libtool: compile:  clang -DHAVE_CONFIG_H -I. -I/Users/liwenkun/Desktop/pycopy/lib/libffi -I. -I/Users/liwenkun/Desktop/pycopy/lib/libffi/include -Iinclude -I/Users/liwenkun/Desktop/pycopy/lib/libffi/src -Os -fomit-frame-pointer -fstrict-aliasing -ffast-math -fno-exceptions -Wall -fexceptions -MT src/java_raw_api.lo -MD -MP -MF src/.deps/java_raw_api.Tpo -c /Users/liwenkun/Desktop/pycopy/lib/libffi/src/java_raw_api.c  -fPIC -DPIC -o src/.libs/java_raw_api.o
libtool: compile:  clang -DHAVE_CONFIG_H -I. -I/Users/liwenkun/Desktop/pycopy/lib/libffi -I. -I/Users/liwenkun/Desktop/pycopy/lib/libffi/include -Iinclude -I/Users/liwenkun/Desktop/pycopy/lib/libffi/src -Os -fomit-frame-pointer -fstrict-aliasing -ffast-math -fno-exceptions -Wall -fexceptions -MT src/java_raw_api.lo -MD -MP -MF src/.deps/java_raw_api.Tpo -c /Users/liwenkun/Desktop/pycopy/lib/libffi/src/java_raw_api.c -o src/java_raw_api.o >/dev/null 2>&1
depbase=`echo src/closures.lo | sed 's|[^/]*$|.deps/&|;s|\.lo$||'`;\
        /bin/sh ./libtool  --tag=CC   --mode=compile clang -DHAVE_CONFIG_H -I. -I/Users/liwenkun/Desktop/pycopy/lib/libffi  -I. -I/Users/liwenkun/Desktop/pycopy/lib/libffi/include -Iinclude -I/Users/liwenkun/Desktop/pycopy/lib/libffi/src   -Os -fomit-frame-pointer -fstrict-aliasing -ffast-math -fno-exceptions  -Wall -fexceptions -MT src/closures.lo -MD -MP -MF $depbase.Tpo -c -o src/closures.lo /Users/liwenkun/Desktop/pycopy/lib/libffi/src/closures.c &&\
        mv -f $depbase.Tpo $depbase.Plo
libtool: compile:  clang -DHAVE_CONFIG_H -I. -I/Users/liwenkun/Desktop/pycopy/lib/libffi -I. -I/Users/liwenkun/Desktop/pycopy/lib/libffi/include -Iinclude -I/Users/liwenkun/Desktop/pycopy/lib/libffi/src -Os -fomit-frame-pointer -fstrict-aliasing -ffast-math -fno-exceptions -Wall -fexceptions -MT src/closures.lo -MD -MP -MF src/.deps/closures.Tpo -c /Users/liwenkun/Desktop/pycopy/lib/libffi/src/closures.c  -fPIC -DPIC -o src/.libs/closures.o
libtool: compile:  clang -DHAVE_CONFIG_H -I. -I/Users/liwenkun/Desktop/pycopy/lib/libffi -I. -I/Users/liwenkun/Desktop/pycopy/lib/libffi/include -Iinclude -I/Users/liwenkun/Desktop/pycopy/lib/libffi/src -Os -fomit-frame-pointer -fstrict-aliasing -ffast-math -fno-exceptions -Wall -fexceptions -MT src/closures.lo -MD -MP -MF src/.deps/closures.Tpo -c /Users/liwenkun/Desktop/pycopy/lib/libffi/src/closures.c -o src/closures.o >/dev/null 2>&1
depbase=`echo src/arm/ffi.lo | sed 's|[^/]*$|.deps/&|;s|\.lo$||'`;\
        /bin/sh ./libtool  --tag=CC   --mode=compile clang -DHAVE_CONFIG_H -I. -I/Users/liwenkun/Desktop/pycopy/lib/libffi  -I. -I/Users/liwenkun/Desktop/pycopy/lib/libffi/include -Iinclude -I/Users/liwenkun/Desktop/pycopy/lib/libffi/src   -Os -fomit-frame-pointer -fstrict-aliasing -ffast-math -fno-exceptions  -Wall -fexceptions -MT src/arm/ffi.lo -MD -MP -MF $depbase.Tpo -c -o src/arm/ffi.lo /Users/liwenkun/Desktop/pycopy/lib/libffi/src/arm/ffi.c &&\
        mv -f $depbase.Tpo $depbase.Plo
libtool: compile:  clang -DHAVE_CONFIG_H -I. -I/Users/liwenkun/Desktop/pycopy/lib/libffi -I. -I/Users/liwenkun/Desktop/pycopy/lib/libffi/include -Iinclude -I/Users/liwenkun/Desktop/pycopy/lib/libffi/src -Os -fomit-frame-pointer -fstrict-aliasing -ffast-math -fno-exceptions -Wall -fexceptions -MT src/arm/ffi.lo -MD -MP -MF src/arm/.deps/ffi.Tpo -c /Users/liwenkun/Desktop/pycopy/lib/libffi/src/arm/ffi.c  -fPIC -DPIC -o src/arm/.libs/ffi.o
/Users/liwenkun/Desktop/pycopy/lib/libffi/src/arm/ffi.c:804:3: error: implicit declaration of function '__clear_cache' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
  __clear_cache(closure->tramp, closure->tramp + 8);    /* clear data map */
  ^
1 error generated.
make[2]: *** [src/arm/ffi.lo] Error 1
make[1]: *** [install-exec-recursive] Error 1
 /usr/local/bin/gmkdir -p '/Users/liwenkun/Desktop/pycopy/ports/unix/build-micropython-android/lib/libffi/out/lib/libffi-3.99999/include'
 /usr/local/bin/ginstall -c -m 644 ffi.h ffitarget.h '/Users/liwenkun/Desktop/pycopy/ports/unix/build-micropython-android/lib/libffi/out/lib/libffi-3.99999/include'
mkdir -p build-micropython-android/genhdr
python ../../py/makeversionhdr.py build-micropython-android/genhdr/mpversion.h
GEN build-micropython-android/genhdr/mpversion.h
GEN build-micropython-android/genhdr/qstr.i.last
clang -E -DNO_QSTR -Ibuild-micropython-android/tmp -I../../lib/berkeley-db-1.xx/PORT/include -I. -I../.. -Ibuild-micropython-android -I../../lib/mp-readline -Wall -Werror -Wpointer-arith -Wuninitialized -std=gnu99 -DUNIX -DFFCONF_H=\"lib/oofatfs/ffconf.h\" -DMICROPY_PY_USSL=1 -DMICROPY_SSL_AXTLS=1 -I../../lib/axtls/ssl -I../../lib/axtls/crypto -I../../extmod/axtls-include -DMICROPY_PY_BTREE=1 -DMICROPY_USE_READLINE=1 -DMICROPY_PY_TERMIOS=1 -DMICROPY_PY_SOCKET=1 -DMICROPY_PY_THREAD=1 -DMICROPY_PY_THREAD_GIL=0 -Ibuild-micropython-android/lib/libffi/out/lib/libffi-3.99999/include -DMICROPY_PY_FFI=1 -I/usr/lib/jvm/java-7-openjdk-amd64/include -DMICROPY_PY_JNI=1 -Os -fdata-sections -ffunction-sections -DNDEBUG  -U _FORTIFY_SOURCE -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool -DMICROPY_MODULE_FROZEN_MPY -DMPZ_DIG_SIZE=16  ../../lib/axtls/ssl/asn1.c ../../lib/axtls/ssl/loader.c ../../lib/axtls/ssl/tls1.c ../../lib/axtls/ssl/tls1_svr.c ../../lib/axtls/ssl/tls1_clnt.c ../../lib/axtls/ssl/x509.c ../../lib/axtls/crypto/aes.c ../../lib/axtls/crypto/bigint.c ../../lib/axtls/crypto/crypto_misc.c ../../lib/axtls/crypto/hmac.c ../../lib/axtls/crypto/md5.c ../../lib/axtls/crypto/rsa.c ../../lib/axtls/crypto/sha1.c ../../extmod/modbtree.c ../../lib/berkeley-db-1.xx/btree/bt_close.c ../../lib/berkeley-db-1.xx/btree/bt_conv.c ../../lib/berkeley-db-1.xx/btree/bt_debug.c ../../lib/berkeley-db-1.xx/btree/bt_delete.c ../../lib/berkeley-db-1.xx/btree/bt_get.c ../../lib/berkeley-db-1.xx/btree/bt_open.c ../../lib/berkeley-db-1.xx/btree/bt_overflow.c ../../lib/berkeley-db-1.xx/btree/bt_page.c ../../lib/berkeley-db-1.xx/btree/bt_put.c ../../lib/berkeley-db-1.xx/btree/bt_search.c ../../lib/berkeley-db-1.xx/btree/bt_seq.c ../../lib/berkeley-db-1.xx/btree/bt_split.c ../../lib/berkeley-db-1.xx/btree/bt_utils.c ../../lib/berkeley-db-1.xx/mpool/mpool.c modtermios.c modusocket.c modffi.c modjni.c ../../py/mpstate.c ../../py/malloc.c ../../py/gc.c ../../py/pystack.c ../../py/qstr.c ../../py/vstr.c ../../py/mpprint.c ../../py/unicode.c ../../py/mpz.c ../../py/reader.c ../../py/lexer.c ../../py/parse.c ../../py/scope.c ../../py/compile.c ../../py/emitcommon.c ../../py/emitbc.c ../../py/asmbase.c ../../py/asmx64.c ../../py/emitnx64.c ../../py/asmx86.c ../../py/emitnx86.c ../../py/asmthumb.c ../../py/emitnthumb.c ../../py/emitinlinethumb.c ../../py/asmarm.c ../../py/emitnarm.c ../../py/asmxtensa.c ../../py/emitnxtensa.c ../../py/emitinlinextensa.c ../../py/formatfloat.c ../../py/parsenumbase.c ../../py/parsenum.c ../../py/emitglue.c ../../py/persistentcode.c ../../py/runtime.c ../../py/runtime_utils.c ../../py/scheduler.c ../../py/nativeglue.c ../../py/stackctrl.c ../../py/argcheck.c ../../py/warning.c ../../py/map.c ../../py/obj.c ../../py/objarray.c ../../py/objattrtuple.c ../../py/objbool.c ../../py/objboundmeth.c ../../py/objcell.c ../../py/objclosure.c ../../py/objcomplex.c ../../py/objdeque.c ../../py/objdict.c ../../py/objenumerate.c ../../py/objexcept.c ../../py/objfilter.c ../../py/objfloat.c ../../py/objfun.c ../../py/objgenerator.c ../../py/objgetitemiter.c ../../py/objint.c ../../py/objint_longlong.c ../../py/objint_mpz.c ../../py/objlist.c ../../py/objmap.c ../../py/objmodule.c ../../py/objobject.c ../../py/objpolyiter.c ../../py/objproperty.c ../../py/objnone.c ../../py/objnamedtuple.c ../../py/objrange.c ../../py/objreversed.c ../../py/objset.c ../../py/objsingleton.c ../../py/objslice.c ../../py/objstr.c ../../py/objstrunicode.c ../../py/objstringio.c ../../py/objtuple.c ../../py/objtype.c ../../py/objzip.c ../../py/opmethods.c ../../py/sequence.c ../../py/stream.c ../../py/binary.c ../../py/builtinimport.c ../../py/builtinevex.c ../../py/builtinhelp.c ../../py/modarray.c ../../py/modbuiltins.c ../../py/modcollections.c ../../py/modgc.c ../../py/modio.c ../../py/modmath.c ../../py/modcmath.c ../../py/modmicropython.c ../../py/modstruct.c ../../py/modsys.c ../../py/moduerrno.c ../../py/modthread.c ../../py/vm.c ../../py/bc.c ../../py/showbc.c ../../py/repl.c ../../py/smallint.c ../../py/frozenmod.c ../../extmod/moductypes.c ../../extmod/modujson.c ../../extmod/modure.c ../../extmod/moduzlib.c ../../extmod/moduheapq.c ../../extmod/modutimeq.c ../../extmod/moduhashlib.c ../../extmod/moducryptolib.c ../../extmod/modubinascii.c ../../extmod/virtpin.c ../../extmod/machine_mem.c ../../extmod/machine_pinbase.c ../../extmod/machine_signal.c ../../extmod/machine_pulse.c ../../extmod/machine_i2c.c ../../extmod/machine_spi.c ../../extmod/modussl_axtls.c ../../extmod/modussl_mbedtls.c ../../extmod/modurandom.c ../../extmod/moduselect.c ../../extmod/modwebsocket.c ../../extmod/modwebrepl.c ../../extmod/modframebuf.c ../../extmod/vfs.c ../../extmod/vfs_reader.c ../../extmod/vfs_posix.c ../../extmod/vfs_posix_file.c ../../extmod/vfs_fat.c ../../extmod/vfs_fat_diskio.c ../../extmod/vfs_fat_file.c ../../extmod/utime_mphal.c ../../extmod/uos_dupterm.c ../../lib/embed/abort_.c ../../lib/utils/printf.c main.c gccollect.c unix_mphal.c mpthreadport.c input.c file.c modmachine.c modos.c moduos_vfs.c modtime.c moduselect.c alloc.c coverage.c fatfs_port.c ../../lib/mp-readline/readline.c ../../lib/timeutils/timeutils.c ../../lib/oofatfs/ff.c ../../lib/oofatfs/option/unicode.c ../../py/mpconfig.h mpconfigport.h >build-micropython-android/genhdr/qstr.i.last;
modjni.c:36:10: fatal error: 'jni.h' file not found
#include <jni.h>
         ^~~~~~~
1 error generated.
make: *** [build-micropython-android/genhdr/qstr.i.last] Error 1
make: *** Deleting file `build-micropython-android/genhdr/qstr.i.last'

Root pointer set is too bloated

Currently:

>>> import gc
>>> gc.collect()
gc_collect_root(663800, 116)

There're 116 "pointers" in the root set, most of which are garbage, pun intended. Among it are things like:

#define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE  (256)

Puts 256 bytes of stuff into root set (workaround: define to 0 for dynalloc).

const char *readline_hist[50];

D'oh.

Then more random non-pointer fields, then various concrete objects laid out in the root set structure.

uselect Poll.ipoll() returns unexpected events with 'userdata' feature

Hi,
Novice to this world, but hoping that this is a valid contribution. Apologies if I've missed something obvious or if this report isn't clear enough/in the correct place. Sorry that it's a little lengthy but I'm led to believe that more (useful) information is often better than less. Feedback accepted. :)

I was trying to use Picoweb/Uasyncio with Pycopy on an ESP8266, when I stumbled across the EAGAIN issues discussed here:
#30
micropython/micropython#4824

I applied the work-around suggested by catching the exception on s.accept() in uasyncio start_server() loop, but that then unveiled what appeared to be going on (once you enabled verbose logging). It appeared to me that uselect Poll.ipoll() method was returning unexpected events, so when uasyncio's start_server() loop was expecting a POLLIN event after yielding IORead(s) it was, in fact, receiving other events - mostly POLLOUT(4), hence why it was expecting to accept new client connections when there weren't any and raising the EAGAIN exception.

To look into this further, I came up with a minimal test-case for uselect using the same methods as uasyncio, based on others' code from previous posts:

import usocket as socket, uselect as select, ulogging as logging, gc

_blocking = False
_userdata = True
_max_events = 1000
_start_mem = 0

log = logging.getLogger("test")


def issock(s1, s2): return s1 == s2


# Two options for register method.  With userdata and without.
def register(poller, s):
    if _userdata:
        poller.register(s, select.POLLIN, "Python object")
    else:
        poller.register(s, select.POLLIN)


def start_server(port):
    ai = socket.getaddrinfo('0.0.0.0', port)[0][-1]
    print("Starting server... Port: {}".format(port))
    print("Bug in place: {}".format(_userdata))
    ss = socket.socket()
    ss.bind(ai)
    ss.listen(10)
    ss.setblocking(_blocking)
    ss.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

    poll = select.poll()
    register(poll, ss)

    i = 0

    gc.collect()
    start_mem = gc.mem_free()

    while True:
        gc.collect()
        log.debug("Memory used: {}".format(start_mem - gc.mem_free()))

        # One-shot behaviour
        res = poll.ipoll(-1, 1)
        for s, e, obj in res:
            i += 1
            log.debug("#{0} NEW SOCKET EVENT: Socket: {1}  Event: {2}  Userdata: {3}".format(i, s, e, obj))

            # New client connection on server socket
            if issock(s, ss) and e == select.POLLIN:
                s, addr = ss.accept()
                s.setblocking(_blocking)
                del addr
                # Imitate uasyncio... use register() not modify()
                register(poll, s)
                register(poll, ss)
                log.debug("New connection!")
                continue

            # Assume new client message
            if not issock(s, ss) and e == select.POLLIN:
                log.debug("Trying to read from socket...")
                msg = s.recv(1024)
                if msg:
                    print("*** NEW MESSAGE: {}".format(msg))
                    register(poll, s)

                # Empty msg > close connection
                if not msg:
                    log.debug("Closing socket...")
                    poll.unregister(s)
                    s.close()

            # If the event is not POLLIN, just log it.
            else:
                log.debug("Unhandled event: {} on socket: {}".format(e, s))
                # Re-register it for POLLIN becuase otherwise we won't get any future events (single-shot mode)
                register(poll, s)

        # Stop the server after x events
        if i >= _max_events:
            print("Closing down server...")
            poll.unregister(ss)
            ss.close()
            break


def run(userdata=True, debug=True, port=8000):
    global _userdata
    _userdata = userdata

    if debug is True:
        log.setLevel(logging.DEBUG)
    else:
        log.setLevel(logging.INFO)

    start_server(port)

After playing around with this code on the ESP8266, I discovered that the issue described only appeared to come about when adding the 'userdata' argument to the Poll.register() method. The code above can be run with/without 'userdata' and, for me, it only works as expected when the 'userdata' feature isn't used. I used a basic packet sender application as a client to send short ASCII strings. Here are the outputs:

With Poll.register() 'userdata' argument:
(No client connections during this output... just the server running on its own)

Pycopy v1.11-1462-gaf0948daa on 2020-06-14; ESP module with ESP8266
Type "help()" for more information.
>>> uatest1.run(userdata=True)
Starting server... Port: 8000
Bug in place: True
DEBUG:test:Memory used: 0
DEBUG:test:#1 NEW SOCKET EVENT: Socket: <socket state=1 timeout=0 incoming=a off=0>  Event: 4  Userdata: Python object
DEBUG:test:Unhandled event: 4 on socket: <socket state=1 timeout=0 incoming=a off=0>
DEBUG:test:Memory used: 32
DEBUG:test:#2 NEW SOCKET EVENT: Socket: <socket state=1 timeout=0 incoming=a off=0>  Event: 4  Userdata: Python object
DEBUG:test:Unhandled event: 4 on socket: <socket state=1 timeout=0 incoming=a off=0>
DEBUG:test:Memory used: 32
DEBUG:test:#3 NEW SOCKET EVENT: Socket: <socket state=1 timeout=0 incoming=a off=0>  Event: 4  Userdata: Python object
DEBUG:test:Unhandled event: 4 on socket: <socket state=1 timeout=0 incoming=a off=0>
DEBUG:test:Memory used: 32
DEBUG:test:#4 NEW SOCKET EVENT: Socket: <socket state=1 timeout=0 incoming=a off=0>  Event: 4  Userdata: Python object
DEBUG:test:Unhandled event: 4 on socket: <socket state=1 timeout=0 incoming=a off=0>
DEBUG:test:Memory used: 32

Without Poll.register() 'userdata' argument:
(+ Client connection with 3 ASCII strings sent client > server)

Pycopy v1.11-1462-gaf0948daa on 2020-06-14; ESP module with ESP8266
Type "help()" for more information.
>>> uatest1.run(userdata=False)
Starting server... Port: 8000
Bug in place: False
DEBUG:test:Memory used: 0
DEBUG:test:#1 NEW SOCKET EVENT: Socket: <socket state=1 timeout=0 incoming=1000a off=0>  Event: 1  Userdata: None
DEBUG:test:New connection!
DEBUG:test:Memory used: 96
DEBUG:test:#2 NEW SOCKET EVENT: Socket: <socket state=3 timeout=0 incoming=3fff9110 off=0>  Event: 1  Userdata: None
DEBUG:test:Trying to read from socket...
*** NEW MESSAGE: b'Testing - Message 1'
DEBUG:test:Memory used: 144
DEBUG:test:#3 NEW SOCKET EVENT: Socket: <socket state=3 timeout=0 incoming=3fff9110 off=0>  Event: 1  Userdata: None
DEBUG:test:Trying to read from socket...
*** NEW MESSAGE: b'Message 2\r'
DEBUG:test:Memory used: 128
DEBUG:test:#4 NEW SOCKET EVENT: Socket: <socket state=3 timeout=0 incoming=3fff9110 off=0>  Event: 1  Userdata: None
DEBUG:test:Trying to read from socket...
*** NEW MESSAGE: b'Message 3 - Closing after this.\r'
DEBUG:test:Memory used: 160
DEBUG:test:#5 NEW SOCKET EVENT: Socket: <socket state=4 timeout=0 incoming=0 off=0>  Event: 1  Userdata: None
DEBUG:test:Trying to read from socket...
DEBUG:test:Closing socket...
DEBUG:test:Memory used: 96

Extra info:

  • Pycopy version: v1.11-1462-gaf0948daa
  • Unix port: Works correctly on unix port with/without userdata argument. No issues.
  • Client Connections: When running with userdata arguments, ipoll returns event '5' when a client attempts to connect. Can't find out what event 5 means or if it's just a mistake?

For my Picoweb app (which was leaking memory after consecutive client connections), I've reverted uasyncio's application of userdata for callbacks by rolling back commit: pfalcon/pycopy-lib@69fecaf. This seems to have fixed my memory leak issue for now.

Sadly I'm not experienced enough to find the root cause of the issue myself. I suspect it could lie in a C module (Such as this one?) or lwIP stack, but I don't have the experience to follow what's going on at this low level.

Many thanks in advance to anyone who looks into this with me, and for all the fantastic work you guys have done on these projects.

Kind regards,

Andy

"Finishing Pycopy" TODO

Generic

  • Make sys.stdin and friends overridable
  • Implement (forward-port) __slots__ support
  • Warnings should show file/line no. - enabled in pycopy-dev
  • Add function (e.g. sys.warn()) to generate warning (with line no.) from Python code?

Ports

  • Implement uos.remove for Unix port
  • Implement uos.rename for Unix port

I/O

Modules

  • uctypes module finishing #14

Imports

  • Allow to override __import__
  • Better handling of errors during module import (remove from sys.modules)

ESP32 - Error when building firmware: implicit declaration of function 'mbedtls_ssl_endpoint'

Hi,

I'm receiving this error while trying to build ESP32 firmware:

CC ../../extmod/modussl_mbedtls.c
../../extmod/modussl_mbedtls.c: In function 'socket_new':
../../extmod/modussl_mbedtls.c:253:5: error: implicit declaration of function 'mbedtls_ssl_endpoint' [-Werror=implicit-function-declaration]
     mbedtls_ssl_endpoint(&o->ssl, args->server_side.u_bool ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT);
     ^
cc1: all warnings being treated as errors
../../py/mkrules.mk:63: recipe for target 'build-GENERIC/extmod/modussl_mbedtls.o' failed
make: *** [build-GENERIC/extmod/modussl_mbedtls.o] Error 1

I followed this advice from the README to try to build the firmware, using ESP-IDF v3.3 (checking IDF compatibility with the hash etc as directed) and the ESP32 toolchain for Linux from here. I think I've followed all the steps correctly.

Additional details:

Because I'm not very experienced at this, I'm not entirely sure what other information might be relevant to the issue. Let me know if there is anything else I can provide to help. I tried running make with --keep-going and --ignore, but it doesn't appear to be completing fully because application.bin is not being created (due to modussl_mbedtls.o missing).

Any help greatly appreciated. I know these ports aren't a priority, but if it's something I'm doing wrong or it's a simple fix/easy work-around, then finding that solution would be much appreciated. Apologies also if the issue has already been noted somewhere that I haven't seen.

Many thanks,

Andy

Ideas for adding more features/optimizing utimeq module

First of all, currently entries lack a unique identifier, so it's not even possible for an entry, because there's no way to identify it. But actually there's a unique id stored, it's counter. So, we should switch from ordering entries by "time" to ordering them by this id, and return it on insert operation. "Time" then just becomes a payload in entry. That's not going to work, LOL.

Then, we can store pointers to entries in the heap, not the entries themselves. This will allow us to have stable addresses for entries, so we can refer to them. Of course, that takes extra memory word. We could try to compensate that by removing existing entry member. A candidate is "args" field. It's not needed for coros, only for callbacks. But we can say "callbacks with params should create a closure and store that instead".

But the reason of this ticket is trying to optimize timeout handling in uasyncio, and timeouts are handled by callbacks taking a coro as an argument. So, we would need to optimize that too. As it doesn't make to store integers as objects in utimeq, we can say that an object with low bit set is an "implicit" timeout object for coro which is stored in the object field. So, event loop handles such specially and cancels the coro on processing such an entry.

We now just need to allow a coro to cancel such implicit timeout object in its turn. For this we use "stable address" feature introduced previously. So, when timeout object is allocated, we get its stable handle, and can store that in the wait_for wrapper coro, and then call special utimeq function to "cancel" it (e.g. nullize object field).

The last optimization would be to get rid of wait_for wrapper coro, and instead store timeout object handle in the coro itself. That's of course not easy, "normal" way would be to introduce timed await on the language syntax level and make compiler spawn coro objects with extra field. Or go for compromise and recognize await wait_for(...) as a special syntax form with the expected imitations. Or can just stuff extra field into any coro %).

STM32H7 Ethernet

Hi,
Is there any plan on getting eth.c to work with the STM32H7 chip? Right now it doesn't work (H7 registers are different).

ure: Escaping does not work in character set

>>> import ure as re
>>> re.compile(r'\.')
>>> re.compile(r'[a\.]')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: error in regex

Pycopy v3.1.5

Error trying to compile pycopy stable v3.2.1

Parameters:

git clone https://github.com/pfalcon/pycopy.git
cd pycopy
git checkout 4833787
git submodule update --init --recursive

$ cd ports/esp32
$ make ESPIDF
$ export ESPIDF=$HOME/Downloads/ESP32/esp-idf # Or any path you like.
$ mkdir -p $ESPIDF
$ cd $ESPIDF
$ git clone https://github.com/espressif/esp-idf.git $ESPIDF
$ git checkout 4c81978a3e2220674a432a588292a4c860eef27b
$ git submodule update --init --recursive

CC ../../extmod/virtpin.c
CC ../../extmod/machine_mem.c
CC ../../extmod/machine_pinbase.c
CC ../../extmod/machine_signal.c
CC ../../extmod/machine_pulse.c
CC ../../extmod/machine_i2c.c
CC ../../extmod/machine_spi.c
CC ../../extmod/modbluetooth.c
CC ../../extmod/modussl_axtls.c
CC ../../extmod/modussl_mbedtls.c
../../extmod/modussl_mbedtls.c: In function 'socket_new':
../../extmod/modussl_mbedtls.c:252:5: error: implicit declaration of function 'mbedtls_ssl_endpoint'; did you mean 'mbedtls_ssl_conf_endpoint'? [-Werror=implicit-function-declaration]
mbedtls_ssl_endpoint(&o->ssl, args->server_side.u_bool ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT);
^~~~~~~~~~~~~~~~~~~~
mbedtls_ssl_conf_endpoint
cc1: all warnings being treated as errors
make: *** [../../py/mkrules.mk:63: build-GENERIC/extmod/modussl_mbedtls.o] Error 1

Consider situation with removing elements from set/dict while iterating

s = {x for x in range(10)}

for e in s:
    print(e)
    if e == 5:
        s.remove(e)

in CPython leads too:

Traceback (most recent call last):
  File "set-rem.py", line 4, in <module>
    for e in s:
RuntimeError: Set changed size during iteration

In MicroPython, it doesn't. But consider if any guarantees can be given about the result.

Naming confusion in repl for baremetal ports

This isn't an issue but it may be an oversight. You have forked micropython and renamed it pycopy but whenever you enter repl it still shows micropython
MicroPython v3.0.0 on 2020-01-24; ESP32 module with ESP32
Is this intentional or did you just forget to change it? In my opinion the firmware should reflect the name of the fork it came from. I know this is cosmetic and doesn't affect functionality, but if you put this much work into changes and additions it should bear it's proper name.

BTW I love pycopy and am using it in a project I designed. Its a water sensor that beeps loudly and sends notifications through Pushover to all my devices when water in my basement isn't draining properly.

Running picoweb blocks machine.Timer

In the following screenshot you can see the signal of a timer toggling an io pin every 5ms.

like so:

tm = machine.Timer(0) 
tm.init( period=5, mode=tm.PERIODIC, callback=update)

furthermore there are dropouts of almost 50ms when picoweb is serving a http request in parallel as we can see in the middle of the Screenshot.

I know this behaviour from micropython/MicroWebSrv. I hoped of some improvement due to this asyncio stuff. But maybe this is totally normal. Or am i doing something wrong?

grafik

Allocate exception/its info lazily

Currently, uPy allocates exception and its attribute, like backtrace, eagerly. Might postpone e.g. traceback allocation until later, and store basic exception info statically. E.g., if exception is caught by except clause without as, then the actual exception object is not needed, only its type is needed.

Stack usage issues (due to inlining, etc.)

Master has issues with pretty big stack usage in some (many?) cases. This is due to fact that medern compilers prefer (only able to?) to allocate single big static stack frame for entire function at once, instead of growing/shrinking frame as they go thru various subblocks of a function. For example fo,

int i;
if (rare_condition) {
    char foo[1024];
    ...
}

1024 + 4 bytes of stack will be allocated always, even though, as suggested by the code, 1024 of those will be needed rarely. It would be smarter to allocate those 1024 only when control flow goes into the "if" body, but this seems to be the lost skill for modern gcc's and clang's. (Indeed, adjusting stack pointer in multiple places would take more code and more cycles, so they optimized it to allocate frame once at function start - ad absurdum, as the code above shows).

This is all aggravated by function inlining. As it's again the codesize saving measure, it happens not just for functions explicitly marked inline, but also may happen for static functions (for example, always would happen for a static function with a single caller).

Many times, this is a bit less serious than completely grave, because other stack-hungry functions aren't called from such functions. But they always can be, e.g. an interrupt can occur when inside such stack-hoarding function, or it may deal with user (Python) type and call Python-level method, leading to really huge stack usage.

[Question] What is main difference between MicroPython and Pycopy ?

I am curious what is main difference between MicroPython and Pycopy in terms of syntax support, underlining run-time behaviors and so on

As we know MicroPython not support complete Python syntax and have some issue with it sometimes:
http://docs.micropython.org/en/latest/genrst/syntax.html?highlight=syntax

Also there are inheritance issue (different implementation details):
micropython/micropython#6077

All it split Python ecosystem and enforce to implement two different libraries in Pure-Python and with support MicroPython ...

I am wondering how all this topics relate to Pycopy ?

Pre-built firmware?

As there is no pre-built firmware available, and there are quite a few build dependencies, I think it would be nice to include that and lower the barrier to entry. If there is any interest, I would be willing to see if I can setup a CI pipeline to arrange that.

In the meantime, I have made a dockerfile that builds all dependencies and a firmware for the ESP32 based on this repo here. Building a formware is now as simple as

docker build -t pycopy https://gist.githubusercontent.com/tdamsma/b49359448924d7aa816d50be2170a610/raw/c12ffbf690fb56a5e9f327cdd2cb81b631db3d5d/Dockerfile
docker create --name pycopy pycopy
docker cp pycopy:/esp/micropython/ports/esp32/build-GENERIC/firmware.bin firmware.bin
docker rm pycopy

The only requirement is that you have docker installed (and a bit of patience)

Update:

The method above does not work anymore, a working dockerfile (as of 2020-07-16) with instructions can be found here: https://github.com/flusflas/micropython-builder

Unknown type name 'ppp_pcb'

Compiling PyCopy 1.11 with the suggested ESP-IDF branch I get this error: unknown type name 'ppp_pcb'

Seems to be happening in Loboris fork too: loboris/ESP32-PPPOS-EXAMPLE#15

So far, I can skip this error by adding this line to Makefile:

INC += -I$(TOP)/lib/lwip/src/include

But now I've another error:

In file included from network_ppp.c:39:0:
../../lib/lwip/src/include/lwip/sockets.h:428:2: error: #error LWIP_SOCKET_OFFSET does not work with external FD_SET!
#error LWIP_SOCKET_OFFSET does not work with external FD_SET!

Fo the last error, I commented the line 408 in $(TOP)/lib/lwip/src/include/lwip/sockets.h

/* FD_SET used for lwip_select */ // LINE 407
//#ifndef FD_SET // LINE 408

...and added these in the next line (409):

#ifdef LWIP_SOCKET_OFFSET
#undef FD_SET
#undef FD_CLR
#undef FD_ISSET
#undef FD_ZERO
#undef _types_fd_set
#undef fd_set

Source: espressif/esp-idf#1141

But again, I got another error:

../../lib/lwip/src/include/lwip/arch.h:125:19: error: conflicting types for 'mem_ptr_t'
typedef uintptr_t mem_ptr_t;

All of this seems to be related to esp-idf since it changes constantly. I'm working in the suggested branch for PyCopy 1.11: 5c88c5996

Any help will be appreciated :)

๐Ÿ‘‹

Bytecode inline caching issues

Currently, (only) following opcodes cache a look up index (inline in the opcode):

  • LOAD_NAME
  • LOAD_GLOBAL
  • LOAD_ATTR
  • STORE_ATTR

This leaves out another very common opcode which looks up by qstr: LOAD_METHOD.

Relationship of this fork to Zephyr

I come across this fork just by accident, so forgive me if this question has already been answered before.

Will some target platform be dealt with a priority within this fork? (By some, I mean Zephyr of course.) Or it is intended to be platform agnostic.

There would be some obvious advantages to focus on Zephyr, I'll just point to some:

  • as Zephyr HAL is gradually promoting, we could adapt it to Python. On Zephyr HAL side there is also clear definition of synchronous or asynchronous API. I think that peripheral AIO API with async/await is missing for a long time.
  • Zephyr's subsystems (for example BLE/Mesh and Mesh model representation by Python objects)

We know that @pfalcon is long term Zephyr collaborator, so please share your PoV.

uasyncio / EAGAIN

Hi there,

I am having the same issue that should have been fixed in micropython/micropython#4322

Test code:

import uasyncio as asyncio

@asyncio.coroutine
async def serve(reader, writer):
  request = yield from reader.read()
  print((yield from reader.read()))
  yield from writer.awrite("ok\r\n")
  yield from writer.aclose()

def run():
  loop = asyncio.get_event_loop()
  loop.create_task(asyncio.start_server(serve, "127.0.0.1", 80))
  loop.run_forever()
  loop.close()
MicroPython v1.10-579-ga64fa0e8e on 2019-05-30; ESP module with ESP8266
Type "help()" for more information.
>>> import micropython
>>> micropython.mem_info()
stack: 2112 out of 8192
GC: total: 37952, used: 5280, free: 32672
 No. of 1-blocks: 24, 2-blocks: 11, max blk sz: 264, max free sz: 2025
>>> 
paste mode; Ctrl-C to cancel, Ctrl-D to finish
=== import uasyncio as asyncio
=== 
=== @asyncio.coroutine
=== async def serve(reader, writer):
===   request = yield from reader.read()
===   print((yield from reader.read()))
===   yield from writer.awrite("ok\r\n")
===   yield from writer.aclose()
=== 
=== def run():
===   loop = asyncio.get_event_loop()
===   loop.create_task(asyncio.start_server(serve, "127.0.0.1", 80))
===   loop.run_forever()
===   loop.close()
>>> run()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 13, in run
  File "uasyncio/core.py", line 163, in run_forever
  File "uasyncio/core.py", line 116, in run_forever
  File "uasyncio/__init__.py", line 252, in start_server
OSError: [Errno 11] EAGAIN
>>> run()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 13, in run
  File "uasyncio/core.py", line 163, in run_forever
  File "uasyncio/core.py", line 116, in run_forever
  File "uasyncio/__init__.py", line 245, in start_server
OSError: [Errno 12] ENOMEM
>>> run()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 13, in run
  File "uasyncio/core.py", line 163, in run_forever
  File "uasyncio/core.py", line 116, in run_forever
  File "uasyncio/__init__.py", line 245, in start_server
OSError: [Errno 12] ENOMEM
>>> micropython.mem_info()
stack: 2112 out of 8192
GC: total: 37952, used: 12112, free: 25840
 No. of 1-blocks: 152, 2-blocks: 35, max blk sz: 264, max free sz: 1605

What could be wrong here?

ESP32 missing '/lib/mbedtls_errors/mp_mbedtls_errors.c' and others..

I trying to compile Pycopy for esp32 using /tools/ci.sh
And cant so this because compiler tell me about missing /lib/mbedtls_errors/mp_mbedtls_errors.c. I do not found anything about this in google.
You can check this process here in colab:
Run CI.sh in Google Colab

When i comment line with ${MICROPY_DIR}/lib/mbedtls_errors/mp_mbedtls_errors.c in /pycopy/ports/esp32/main/CMakeLists.txt and try to run ci_esp32_build in /tools/ci.sh again, then compiller told me:

[ 93%] Building C object esp-idf/main/CMakeFiles/__idf_main.dir/pycopy/extmod/moduhashlib.c.obj
[ 93%] Building C object esp-idf/main/CMakeFiles/__idf_main.dir/pycopy/extmod/moduheapq.c.obj
/pycopy/extmod/moductypes.c: In function 'uctypes_get_buffer':
/pycopy/extmod/moductypes.c:761:18: error: 'addr' may be used uninitialized in this function [-Werror=maybe-uninitialized]
bufinfo->buf = addr;
~~~~~~~~~~~~~^~~~~~
cc1: some warnings being treated as errors
[ 93%] Building C object esp-idf/main/CMakeFiles/__idf_main.dir/pycopy/extmod/modujson.c.obj
[ 93%] Building C object esp-idf/main/CMakeFiles/__idf_main.dir/pycopy/extmod/modurandom.c.obj
esp-idf/main/CMakeFiles/__idf_main.dir/build.make:2170: recipe for target 'esp-idf/main/CMakeFiles/__idf_main.dir/pycopy/extmod/moductypes.c.obj' failed
make[3]: *** [esp-idf/main/CMakeFiles/__idf_main.dir/pycopy/extmod/moductypes.c.obj] Error 1
make[3]: *** Waiting for unfinished jobs....
make[3]: Leaving directory '/pycopy/ports/esp32/build-GENERIC'
CMakeFiles/Makefile2:4776: recipe for target 'esp-idf/main/CMakeFiles/__idf_main.dir/all' failed
make[2]: *** [esp-idf/main/CMakeFiles/__idf_main.dir/all] Error 2
make[2]: Leaving directory '/pycopy/ports/esp32/build-GENERIC'
Makefile:129: recipe for target 'all' failed
make[1]: *** [all] Error 2
make[1]: Leaving directory '/pycopy/ports/esp32/build-GENERIC'
make failed with exit code 2
Makefile:18: recipe for target 'all' failed
make: *** [all] Error 2
make: Leaving directory '/pycopy/ports/esp32'

Next, when i fix uctypes_get_buffer in /pycopy/extmod/moductypes.c like this:
-change strNo.749: addr = *(void **)self->addr; -> bufinfo->buf = *(void **)self->addr;
-change strNo.758: addr = self->addr; -> bufinfo->buf = self->addr;
-remove strNo.761 and strNo.740

Then compilation done by 100%, but linking fails:

[100%] Building C object CMakeFiles/micropython.elf.dir/project_elf_src.c.obj
[100%] Linking CXX executable micropython.elf
/root/.espressif/tools/xtensa-esp32-elf/esp-2020r3-8.4.0/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld: esp-idf/main/libmain.a(lexer.c.obj):(.literal.skip_whitespace+0x8): undefined reference to mp_strict_mode' /root/.espressif/tools/xtensa-esp32-elf/esp-2020r3-8.4.0/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld: esp-idf/main/libmain.a(objmodule.c.obj):(.literal.module_attr+0x4): undefined reference to mp_strict_runtime'
/root/.espressif/tools/xtensa-esp32-elf/esp-2020r3-8.4.0/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld: esp-idf/main/libmain.a(objmodule.c.obj):(.literal.module_attr+0x8): undefined reference to mp_strict_mode_error' /root/.espressif/tools/xtensa-esp32-elf/esp-2020r3-8.4.0/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld: esp-idf/main/libmain.a(objmodule.c.obj):(.literal.module_attr+0xc): undefined reference to mp_handle_store_ns_strict'
/root/.espressif/tools/xtensa-esp32-elf/esp-2020r3-8.4.0/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld: esp-idf/main/libmain.a(objmodule.c.obj): in function module_attr': /pycopy/py/objmodule.c:101: undefined reference to mp_strict_mode_error'
/root/.espressif/tools/xtensa-esp32-elf/esp-2020r3-8.4.0/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld: /pycopy/py/objmodule.c:107: undefined reference to mp_handle_store_ns_strict' /root/.espressif/tools/xtensa-esp32-elf/esp-2020r3-8.4.0/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld: esp-idf/main/libmain.a(objtype.c.obj): in function type_attr':
/pycopy/py/objtype.c:1141: undefined reference to mp_strict_mode_error' /root/.espressif/tools/xtensa-esp32-elf/esp-2020r3-8.4.0/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld: /pycopy/py/objtype.c:1147: undefined reference to mp_handle_store_ns_strict'
/root/.espressif/tools/xtensa-esp32-elf/esp-2020r3-8.4.0/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld: esp-idf/main/libmain.a(runtime.c.obj):(.literal.mp_parse_compile_execute+0x0): undefined reference to mp_strict_update_main_name' /root/.espressif/tools/xtensa-esp32-elf/esp-2020r3-8.4.0/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld: esp-idf/main/libmain.a(runtime.c.obj): in function mp_store_name':
/pycopy/py/runtime.c:219: undefined reference to mp_handle_store_ns_strict' /root/.espressif/tools/xtensa-esp32-elf/esp-2020r3-8.4.0/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld: esp-idf/main/libmain.a(runtime.c.obj): in function mp_delete_name':
/pycopy/py/runtime.c:227: undefined reference to mp_strict_mode_error' /root/.espressif/tools/xtensa-esp32-elf/esp-2020r3-8.4.0/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld: esp-idf/main/libmain.a(runtime.c.obj): in function mp_store_global':
/pycopy/py/runtime.c:234: undefined reference to mp_handle_store_ns_strict' /root/.espressif/tools/xtensa-esp32-elf/esp-2020r3-8.4.0/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld: esp-idf/main/libmain.a(runtime.c.obj): in function mp_delete_global':
/pycopy/py/runtime.c:242: undefined reference to mp_strict_mode_error' /root/.espressif/tools/xtensa-esp32-elf/esp-2020r3-8.4.0/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld: esp-idf/main/libmain.a(runtime.c.obj): in function mp_parse_compile_execute':
/pycopy/py/runtime.c:1562: undefined reference to mp_strict_update_main_name' /root/.espressif/tools/xtensa-esp32-elf/esp-2020r3-8.4.0/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld: esp-idf/main/libmain.a(builtinimport.c.obj): in function do_execute_raw_code':
/pycopy/py/builtinimport.c:192: undefined reference to mp_strict_update_main_name' /root/.espressif/tools/xtensa-esp32-elf/esp-2020r3-8.4.0/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld: esp-idf/main/libmain.a(modbuiltins.c.obj):(.literal.mp_builtin_globals+0x0): undefined reference to mp_strict_runtime'
/root/.espressif/tools/xtensa-esp32-elf/esp-2020r3-8.4.0/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld: esp-idf/main/libmain.a(modio.c.obj):(.rodata.mp_module_io_globals_table+0x24): undefined reference to mp_type_textiobase' /root/.espressif/tools/xtensa-esp32-elf/esp-2020r3-8.4.0/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld: esp-idf/main/libmain.a(modio.c.obj):(.rodata.mp_module_io_globals_table+0x2c): undefined reference to mp_type_textiobase'
collect2: error: ld returned 1 exit status
CMakeFiles/micropython.elf.dir/build.make:249: recipe for target 'micropython.elf' failed
make[3]: *** [micropython.elf] Error 1
make[3]: Leaving directory '/pycopy/ports/esp32/build-GENERIC'
CMakeFiles/Makefile2:470: recipe for target 'CMakeFiles/micropython.elf.dir/all' failed
make[2]: *** [CMakeFiles/micropython.elf.dir/all] Error 2
make[2]: Leaving directory '/pycopy/ports/esp32/build-GENERIC'
Makefile:129: recipe for target 'all' failed
make[1]: *** [all] Error 2
make[1]: Leaving directory '/pycopy/ports/esp32/build-GENERIC'
make failed with exit code 2
Makefile:18: recipe for target 'all' failed
make: *** [all] Error 2
make: Leaving directory '/pycopy/ports/esp32'

Can you tell me how to compile Pycopy for esp32 ?

May be you can make a Colab Notebook, for compiling Pycopy ? i think it will be a great, when anyone can load Notebook and customize, compile and download a firmware..

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.