circuitpython/ports/unix
Yoctopuce dev dbbaa959c8 py/formatfloat: Improve accuracy of float formatting code.
Following discussions in PR #16666, this commit updates the float
formatting code to improve the `repr` reversibility, i.e. the percentage of
valid floating point numbers that do parse back to the same number when
formatted by `repr` (in CPython it's 100%).

This new code offers a choice of 3 float conversion methods, depending on
the desired tradeoff between code size and conversion precision:

- BASIC method is the smallest code footprint

- APPROX method uses an iterative method to approximate the exact
  representation, which is a bit slower but but does not have a big impact
  on code size.  It provides `repr` reversibility on >99.8% of the cases in
  double precision, and on >98.5% in single precision (except with REPR_C,
  where reversibility is 100% as the last two bits are not taken into
  account).

- EXACT method uses higher-precision floats during conversion, which
  provides perfect results but has a higher impact on code size.  It is
  faster than APPROX method, and faster than the CPython equivalent
  implementation.  It is however not available on all compilers when using
  FLOAT_IMPL_DOUBLE.

Here is the table comparing the impact of the three conversion methods on
code footprint on PYBV10 (using single-precision floats) and reversibility
rate for both single-precision and double-precision floats.  The table
includes current situation as a baseline for the comparison:

              PYBV10  REPR_C   FLOAT  DOUBLE
    current = 364688   12.9%   27.6%   37.9%
    basic   = 364812   85.6%   60.5%   85.7%
    approx  = 365080  100.0%   98.5%   99.8%
    exact   = 366408  100.0%  100.0%  100.0%

Signed-off-by: Yoctopuce dev <dev@yoctopuce.com>
2025-08-01 00:47:33 +10:00
..
mbedtls unix: Use the bare metal mbedTLS config in the coverage buiid. 2025-02-03 15:02:02 +11:00
variants py/mpconfig,ports: Define new HEX_FMT formatting macro. 2025-07-25 10:55:28 +10:00
alloc.c unix/alloc: Remove unused MICROPY_FORCE_PLAT_ALLOC_EXEC option. 2024-10-03 11:09:42 +10:00
coverage.c py/formatfloat: Improve accuracy of float formatting code. 2025-08-01 00:47:33 +10:00
coveragecpp.cpp unix/coveragecpp: Verify struct-initializing macros' C++-compatibility. 2025-04-24 15:55:06 +02:00
fatfs_port.c unix/fatfs_port: Fix month offset in timestamp calculation. 2020-09-02 00:19:06 +10:00
gccollect.c unix/alloc: Don't trace executable memory for GC pointers. 2024-09-26 22:36:55 +10:00
input.c unix/input: Flush the prompt after writing it to stdout. 2024-02-15 16:45:00 +11:00
input.h ports: Make new ports/ sub-directory and move all ports there. 2017-09-06 13:40:51 +10:00
main.c extmod/modbluetooth: Add timeout to deinit. 2025-06-04 02:21:32 +10:00
Makefile unix: Allow the GIL to be enabled. 2025-07-23 11:35:38 +10:00
modffi.c unix/modffi: Restrict uint32_t values to 32 bits. 2024-09-23 11:47:18 +10:00
modjni.c all: Use new mp_obj_new_str_from_cstr() function. 2024-07-04 15:55:03 +10:00
modmachine.c shared/runtime/pyexec: Make a raised SystemExit always do a forced exit. 2024-07-20 12:13:14 +10:00
modos.c all: Use new mp_obj_new_str_from_cstr() function. 2024-07-04 15:55:03 +10:00
modsocket.c unix/modsocket: Expose MSG_PEEK flag for recv & recvfrom. 2025-06-03 12:52:06 +10:00
modtermios.c unix/modtermios: Add more baudrate options. 2024-07-15 11:27:23 +10:00
modtime.c shared/timeutils: Standardize supported date range on all platforms. 2025-07-09 11:54:21 +10:00
mpbthciport.c unix/mpbthciport: Remove thread detached attribute. 2024-07-17 15:01:04 +10:00
mpbtstackport.h unix: Implement BLE H4 HCI UART for btstack/nimble. 2020-09-08 12:53:24 +10:00
mpbtstackport_common.c extmod/btstack: Switch to use hci_dump_init instead of hci_dump_open. 2023-04-22 00:39:31 +10:00
mpbtstackport_h4.c all: Remove the "STATIC" macro and just use "static" instead. 2024-03-07 14:20:42 +11:00
mpbtstackport_usb.c unix/mpbtstackport_usb: Remove thread detached attribute. 2024-07-17 15:02:57 +10:00
mpconfigport.h unix/mpconfigport: Include time.h to get definition of time_t. 2025-07-24 11:42:53 +10:00
mpconfigport.mk unix: Allow the GIL to be enabled. 2025-07-23 11:35:38 +10:00
mphalport.h unix: Allow the GIL to be enabled. 2025-07-23 11:35:38 +10:00
mpnimbleport.c extmod/nimble: Make stm32 and unix NimBLE ports use synchronous events. 2020-11-13 17:19:05 +11:00
mpnimbleport.h unix: Implement BLE H4 HCI UART for btstack/nimble. 2020-09-08 12:53:24 +10:00
mpthreadport.c unix/mpthreadport: Ensure consistent type of PTHREAD_STACK_MIN. 2025-07-24 13:29:36 +10:00
mpthreadport.h unix: Add recursive mutex support. 2025-02-03 15:02:02 +11:00
qstrdefsport.h all: Add *FORMAT-OFF* in various places. 2020-02-28 10:31:07 +11:00
README.md unix/README: Add some small documentation about sanitizers. 2025-07-01 15:19:07 +10:00
unix_mphal.c all: Remove the "STATIC" macro and just use "static" instead. 2024-03-07 14:20:42 +11:00

MicroPython Unix port

The "unix" port runs in standard Unix-like environments including Linux, BSD, macOS, and Windows Subsystem for Linux.

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

Building

Dependencies

To build the unix port locally then you will need:

  • git command line executable, unless you downloaded a source .tar.xz file from https://micropython.org/download/
  • gcc (or clang for macOS) toolchain
  • GNU Make
  • Python 3.x

To build the default "standard" variant and configuration, then you will also need:

  • pkg-config tool
  • libffi library and headers

On Debian/Ubuntu/Mint and related Linux distros, you can install all these dependencies with a command like:

# apt install build-essential git python3 pkg-config libffi-dev

(See below for steps to build either a standalone or minimal MicroPython executable that doesn't require system libffi or pkg-config.)

Default build steps

To set up the environment for building (not needed every time), starting from the top-level MicroPython directory:

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

The mpy-cross step builds the MicroPython cross-compiler. The make submodules step can be skipped if you didn't clone the MicroPython source from git.

Next, to build the actual executable (still in the ports/unix directory):

$ make

Then to give it a try:

$ ./build-standard/micropython
>>> 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):

$ ./build-standard/micropython -h

To run the complete testsuite, use:

$ make test

The Unix port comes with a built-in package manager called mip, e.g.:

$ ./build-standard/micropython -m mip install hmac

or

$ ./build-standard/micropython
>>> import mip
>>> mip.install("hmac")

Browse available modules at micropython-lib. See Package management for more information about mip.

Minimal Variant

The "standard" variant of MicroPython is the default. It enables most features, including external modules interfaced using libffi. To instead build the "minimal" variant, which disables almost all optional features and modules:

$ cd ports/unix
$ make submodules
$ make VARIANT=minimal

The executable will be built at build-minimal/micropython.

Additional variants can be found in the variants sub-directory of the port, although these are mostly of interest to MicroPython maintainers.

Standalone build

By default, the "standard" variant uses pkg-config to link to the system's shared libffi library.

It is possible to instead build a standalone MicroPython where libffi is built from source and linked statically into the micropython executable. This is mostly useful for embedded or cross-compiled applications.

Building standalone requires autoconf and libtool to also be installed.

To build standalone:

$ export MICROPY_STANDALONE=1
$ make submodules                # fetches libffi submodule
$ make deplibs                   # build just the external libraries
$ make                           # build MicroPython itself

make deplibs causes all supported external libraries (currently only libffi) to be built inside the build directory, so it needs to run again only after make clean.

If you intend to build MicroPython with additional options (like cross-compiling), the same set of options should be passed to both make deplibs and make.

Other dependencies

To actually enable/disable use of dependencies, edit the ports/unix/mpconfigport.mk file, which has inline descriptions of the options. For example, to build the SSL module, MICROPY_PY_SSL should be set to 1.

Debug Symbols

By default, builds are stripped of symbols and debug information to save size.

To build a debuggable version of the Unix port, there are two options:

  1. Run make [other arguments] DEBUG=1. Note setting DEBUG also reduces the optimisation level and enables assertions, so it's not a good option for builds that also want the best performance.
  2. Run make [other arguments] STRIP=. Note that the value of STRIP is empty. This will skip the build step that strips symbols and debug information, but changes nothing else in the build configuration.

Optimisation Level

The default compiler optimisation level is -Os, or -Og if DEBUG=1 is set.

Setting the variable COPT will explicitly set the optimisation level. For example make [other arguments] COPT=-O0 DEBUG=1 will build a binary with no optimisations, assertions enabled, and debug symbols.

Sanitizers

Sanitizers are extra runtime checks supported by gcc and clang. The CI process supports building with the "undefined behavior" (UBSan) or "address" (ASan) sanitizers. The script tools/ci.sh is the source of truth about how to build and run in these modes.

Several classes of checks are disabled via compiler flags:

  • In the undefined behavior sanitizer, checks based on the presence of the non_null attribute are disabled because the code makes technically incorrect calls like memset(NULL, 0, 0). A future C standard is likely to permit such calls.
  • In the address sanitizer, detect_stack_use_after_return is disabled. This check is intended to make sure locals in a "returned from" stack frame are not used. However, this mode interferes with various assumptions that MicroPython's stack checking, NLR, and GC rely on.