py/modsys: Add sys.implementation._build entry.

For a given MicroPython firmware/executable it can be sometimes important
to know how it was built, which variant/board configuration it came from.

This commit adds a new field `sys.implementation._build` that can help
identify the configuration that MicroPython was built with.

For now it's either:
* <VARIANT> for unix, webassembly and windows ports
* <BOARD>-<VARIANT> for microcontroller ports (the variant is optional)

In the future additional elements may be added to this string, separated by
a hyphen.

Resolves issue #16498.

Signed-off-by: Damien George <damien@micropython.org>
This commit is contained in:
Damien George 2025-03-02 23:52:13 +11:00
parent b4cf82b2d6
commit f5b4545761
5 changed files with 61 additions and 4 deletions

View file

@ -75,6 +75,8 @@ Constants
* *version* - tuple (major, minor, micro, releaselevel), e.g. (1, 22, 0, '')
* *_machine* - string describing the underlying machine
* *_mpy* - supported mpy file-format version (optional attribute)
* *_build* - string that can help identify the configuration that
MicroPython was built with
This object is the recommended way to distinguish MicroPython from other
Python implementations (note that it still may not exist in the very
@ -83,6 +85,16 @@ Constants
Starting with version 1.22.0-preview, the fourth node *releaselevel* in
*implementation.version* is either an empty string or ``"preview"``.
The *_build* entry was added in version 1.25.0 and is a hyphen-separated
set of elements. New elements may be appended in the future so it's best to
access this field using ``sys.implementation._build.split("-")``. The
elements that are currently used are:
* On the unix, webassembly and windows ports the first element is the variant
name, for example ``'standard'``.
* On microcontroller targets, the first element is the board name and the second
element (if present) is the board variant, for example ``'RPI_PICO2-RISCV'``
.. admonition:: Difference to CPython
:class: attention

View file

@ -19,6 +19,19 @@ if(NOT MICROPY_PREVIEW_VERSION_2)
set(MICROPY_PREVIEW_VERSION_2 0)
endif()
# Set the board name.
if(MICROPY_BOARD)
if(MICROPY_BOARD_VARIANT)
set(MICROPY_BOARD_BUILD_NAME ${MICROPY_BOARD}-${MICROPY_BOARD_VARIANT})
else()
set(MICROPY_BOARD_BUILD_NAME ${MICROPY_BOARD})
endif()
target_compile_definitions(${MICROPY_TARGET} PRIVATE
MICROPY_BOARD_BUILD_NAME="${MICROPY_BOARD_BUILD_NAME}"
)
endif()
# Need to do this before extracting MICROPY_CPP_DEF below. Rest of frozen
# manifest handling is at the end of this file.
if(MICROPY_FROZEN_MANIFEST)

View file

@ -27,6 +27,17 @@ OBJ_EXTRA_ORDER_DEPS += $(HEADER_BUILD)/compressed.data.h
CFLAGS += -DMICROPY_ROM_TEXT_COMPRESSION=1
endif
# Set the variant or board name.
ifneq ($(VARIANT),)
CFLAGS += -DMICROPY_BOARD_BUILD_NAME=\"$(VARIANT)\"
else ifneq ($(BOARD),)
ifeq ($(BOARD_VARIANT),)
CFLAGS += -DMICROPY_BOARD_BUILD_NAME=\"$(BOARD)\"
else
CFLAGS += -DMICROPY_BOARD_BUILD_NAME=\"$(BOARD)-$(BOARD_VARIANT)\"
endif
endif
# QSTR generation uses the same CFLAGS, with these modifications.
QSTR_GEN_FLAGS = -DNO_QSTR
# Note: := to force evaluation immediately.

View file

@ -92,6 +92,17 @@ static const MP_DEFINE_STR_OBJ(mp_sys_implementation_machine_obj, MICROPY_BANNER
#endif
#if MICROPY_PY_ATTRTUPLE
#if defined(MICROPY_BOARD_BUILD_NAME)
static const MP_DEFINE_STR_OBJ(mp_sys_implementation__build_obj, MICROPY_BOARD_BUILD_NAME);
#define MICROPY_BOARD_BUILD (1)
#define SYS_IMPLEMENTATION_ELEMS__BUILD \
, MP_ROM_PTR(&mp_sys_implementation__build_obj)
#else
#define MICROPY_BOARD_BUILD (0)
#define SYS_IMPLEMENTATION_ELEMS__BUILD
#endif
#if MICROPY_PREVIEW_VERSION_2
#define SYS_IMPLEMENTATION_ELEMS__V2 \
, MP_ROM_TRUE
@ -106,6 +117,9 @@ static const qstr impl_fields[] = {
#if MICROPY_PERSISTENT_CODE_LOAD
MP_QSTR__mpy,
#endif
#if defined(MICROPY_BOARD_BUILD_NAME)
MP_QSTR__build,
#endif
#if MICROPY_PREVIEW_VERSION_2
MP_QSTR__v2,
#endif
@ -113,19 +127,20 @@ static const qstr impl_fields[] = {
static MP_DEFINE_ATTRTUPLE(
mp_sys_implementation_obj,
impl_fields,
3 + MICROPY_PERSISTENT_CODE_LOAD + MICROPY_PREVIEW_VERSION_2,
3 + MICROPY_PERSISTENT_CODE_LOAD + MICROPY_BOARD_BUILD + MICROPY_PREVIEW_VERSION_2,
SYS_IMPLEMENTATION_ELEMS_BASE
SYS_IMPLEMENTATION_ELEMS__MPY
SYS_IMPLEMENTATION_ELEMS__BUILD
SYS_IMPLEMENTATION_ELEMS__V2
);
#else
static const mp_rom_obj_tuple_t mp_sys_implementation_obj = {
{&mp_type_tuple},
3 + MICROPY_PERSISTENT_CODE_LOAD,
// Do not include SYS_IMPLEMENTATION_ELEMS__V2 because
// SYS_IMPLEMENTATION_ELEMS__MPY may be empty if
// Do not include SYS_IMPLEMENTATION_ELEMS__BUILD or SYS_IMPLEMENTATION_ELEMS__V2
// because SYS_IMPLEMENTATION_ELEMS__MPY may be empty if
// MICROPY_PERSISTENT_CODE_LOAD is disabled, which means they'll share
// the same index. Cannot query _v2 if MICROPY_PY_ATTRTUPLE is
// the same index. Cannot query _build or _v2 if MICROPY_PY_ATTRTUPLE is
// disabled.
{
SYS_IMPLEMENTATION_ELEMS_BASE

View file

@ -24,6 +24,12 @@ else:
# Effectively skip subtests
print(int)
if hasattr(sys.implementation, '_build'):
print(type(sys.implementation._build))
else:
# Effectively skip subtests
print(str)
try:
print(sys.intern('micropython') == 'micropython')
has_intern = True