diff --git a/ports/unix/Makefile b/ports/unix/Makefile index 7d71fc3f955eb..0eee7b6984060 100644 --- a/ports/unix/Makefile +++ b/ports/unix/Makefile @@ -16,6 +16,10 @@ endif # If the build directory is not given, make it reflect the variant name. BUILD ?= build-$(VARIANT) +ifneq ($(MICROPY_FORCE_32BIT),) +$(warning *** The MICROPY_FORCE_32BIT flag is no longer affecting builds, please update your environment ***) +endif + include ../../py/mkenv.mk -include mpconfigport.mk include $(VARIANT_DIR)/mpconfigvariant.mk @@ -107,11 +111,7 @@ endif # while cross-compile ports require gcc, so we test here for OSX and # if necessary override the value of 'CC' set in py/mkenv.mk ifeq ($(UNAME_S),Darwin) -ifeq ($(MICROPY_FORCE_32BIT),1) -CC = clang -m32 -else CC = clang -endif # Use clang syntax for map file LDFLAGS_ARCH = -Wl,-map,$@.map -Wl,-dead_strip else @@ -174,11 +174,7 @@ ifeq ($(MICROPY_STANDALONE),1) GIT_SUBMODULES += lib/libffi DEPLIBS += libffi LIBFFI_CFLAGS := -I$(shell ls -1d $(BUILD)/lib/libffi/include) - ifeq ($(MICROPY_FORCE_32BIT),1) - LIBFFI_LDFLAGS = $(BUILD)/lib/libffi/out/lib32/libffi.a - else - LIBFFI_LDFLAGS = $(BUILD)/lib/libffi/out/lib/libffi.a - endif +LIBFFI_LDFLAGS = $(BUILD)/lib/libffi/out/lib/libffi.a else # Use system version of libffi. LIBFFI_CFLAGS := $(shell pkg-config --cflags libffi) @@ -239,10 +235,6 @@ ifneq ($(FROZEN_MANIFEST),) CFLAGS += -DMPZ_DIG_SIZE=16 # force 16 bits to work on both 32 and 64 bit archs endif -ifeq ($(MICROPY_FORCE_32BIT),1) -RUN_TESTS_MPY_CROSS_FLAGS = --mpy-cross-flags='-march=x86' -endif - ifeq ($(CROSS_COMPILE),arm-linux-gnueabi-) # Force disable error text compression when compiling for ARM as the compiler # cannot optimise out the giant strcmp list generated for MP_MATCH_COMPRESSED. diff --git a/ports/unix/README.md b/ports/unix/README.md index ee983a882cc83..5bb2479e18da0 100644 --- a/ports/unix/README.md +++ b/ports/unix/README.md @@ -5,9 +5,10 @@ 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. +as ARM, MIPS, and RISC-V. 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 -------- @@ -18,7 +19,7 @@ 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 +* an appropriate gcc (or clang for macOS) toolchain for your target * GNU Make * Python 3.x @@ -181,3 +182,64 @@ Several classes of checks are disabled via compiler flags: 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. + +### Notes about x86 (i686) support + +It used to be possible to create an x86 (32-bits) build on a x64 (64-bits) host +by passing `MICROPY_FORCE_32BIT=1` to `make`. That option was retired: x86 +usage has declined quite a bit in the past few years, and MicroPython now +supports at least one more mixed 32/64-bits target architecture for which +enabling `MICROPY_FORCE_32BIT` would make builds fail. + +x86 will be treated as a cross-compilation target from now on. This means you +will need to install a suitable compiler (on Ubuntu you can install the +`gcc-i686-linux-gnu` and `g++-i686-linux-gnu` packages, for example) and pass +the toolchain's command prefix to the `CROSS_COMPILE` command line variable. + +This change is also extended to native modules, for which you may need to pass +the toolchain's command prefix to the `CROSS` command line variable if your +x86 compiler cannot be invoked with `i686-linux-gnu-gcc`. + +Or, as an example: + +```bash +$ printf "%s %s %s %s\n" $(lsb_release -d | cut -f 2) $(uname -m) +Ubuntu 24.04.3 LTS x86_64 + +$ i686-linux-gnu-gcc --version | head -n 1 +i686-linux-gnu-gcc (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0 + +$ CROSS_COMPILE=i686-linux-gnu- make -C ports/unix +make: Entering directory '/ports/unix' +Use make V=1 or set BUILD_VERBOSE in your environment to increase build verbosity. +... +LINK build-standard/micropython + text data bss dec hex filename + 718479 36016 2092 756587 b8b6b build-standard/micropython +make: Leaving directory '/ports/unix' + +$ file -b ports/unix/build-standard/micropython | cut -d, -f-2 +ELF 32-bit LSB pie executable, Intel 80386 + +# `i686-linux-gnu-` is the default prefix for x86 native modules now, it has +# been explicitly mentioned here in case you want to see how to set it. + +$ make -C examples/natmod/features0 ARCH=x86 CROSS=i686-linux-gnu- +make: Entering directory '/examples/natmod/features0' +GEN build/features0.config.h +CC features0.c +LINK build/features0.o +arch: EM_386 +text size: 196 +bss size: 0 +GOT entries: 4 +GEN features0.mpy +make: Leaving directory '/examples/natmod/features0' + +$ cd examples/natmod/features0 && ../../../ports/unix/build-standard/micropython +MicroPython v1.28.0-preview.63.g8189e9935a.dirty on 2026-01-09; linux [GCC 13.3.0] version +Type "help()" for more information. +>>> import features0 +>>> features0.factorial(10) +3628800 +``` diff --git a/ports/unix/variants/longlong/mpconfigvariant.mk b/ports/unix/variants/longlong/mpconfigvariant.mk index 2d2c3706469fb..9fe20cd584dee 100644 --- a/ports/unix/variants/longlong/mpconfigvariant.mk +++ b/ports/unix/variants/longlong/mpconfigvariant.mk @@ -1,7 +1,7 @@ # build interpreter with "bigints" implemented as "longlong" -# otherwise, small int is essentially 64-bit -MICROPY_FORCE_32BIT := 1 +# This needs to be built for a 32-bits target, otherwise small ints will +# essentially be 64-bit wide. MICROPY_PY_FFI := 0 diff --git a/ports/unix/variants/nanbox/mpconfigvariant.mk b/ports/unix/variants/nanbox/mpconfigvariant.mk index e588e657efc5b..6d63a86e9b0a6 100644 --- a/ports/unix/variants/nanbox/mpconfigvariant.mk +++ b/ports/unix/variants/nanbox/mpconfigvariant.mk @@ -1,3 +1,4 @@ # build interpreter with nan-boxing as object model (object repr D) -MICROPY_FORCE_32BIT = 1 +# This needs to be built for a 32-bits target, as object representation D is +# only meant to work on 32-bits machines. diff --git a/ports/windows/Makefile b/ports/windows/Makefile index 6e206e7f23cb1..82fa25f21a43f 100644 --- a/ports/windows/Makefile +++ b/ports/windows/Makefile @@ -29,6 +29,13 @@ PROG ?= micropython QSTR_DEFS += ../unix/qstrdefsport.h QSTR_GLOBAL_DEPENDENCIES += $(VARIANT_DIR)/mpconfigvariant.h +# Enable building 32-bit code on 64-bit hosts. +ifeq ($(MICROPY_FORCE_32BIT),1) +CC += -m32 +CXX += -m32 +LD += -m32 +endif + # include py core make definitions include $(TOP)/py/py.mk include $(TOP)/extmod/extmod.mk diff --git a/py/dynruntime.mk b/py/dynruntime.mk index 3902acbd0b32a..a8233fdfe7a5e 100644 --- a/py/dynruntime.mk +++ b/py/dynruntime.mk @@ -47,8 +47,8 @@ CLEAN_EXTRA += $(MOD).mpy .mpy_ld_cache ifeq ($(ARCH),x86) # x86 -CROSS = -CFLAGS_ARCH += -m32 -fno-stack-protector +CROSS = i686-linux-gnu- +CFLAGS_ARCH += -fno-stack-protector MICROPY_FLOAT_IMPL ?= double else ifeq ($(ARCH),x64) diff --git a/py/py.mk b/py/py.mk index b37e3cf579800..4f17bdc29da13 100644 --- a/py/py.mk +++ b/py/py.mk @@ -21,13 +21,6 @@ QSTR_GLOBAL_REQUIREMENTS += $(HEADER_BUILD)/mpversion.h # some code is performance bottleneck and compiled with other optimization options CSUPEROPT = -O3 -# Enable building 32-bit code on 64-bit host. -ifeq ($(MICROPY_FORCE_32BIT),1) -CC += -m32 -CXX += -m32 -LD += -m32 -endif - # External modules written in C. ifneq ($(USER_C_MODULES),) # pre-define USERMOD variables as expanded so that variables are immediate diff --git a/tools/ci.sh b/tools/ci.sh index b14d96d2ca47e..63e902a791f29 100755 --- a/tools/ci.sh +++ b/tools/ci.sh @@ -623,9 +623,12 @@ CI_UNIX_OPTS_SANITIZE_UNDEFINED=( CI_UNIX_OPTS_REPR_B=( VARIANT=standard CFLAGS_EXTRA="-DMICROPY_OBJ_REPR=MICROPY_OBJ_REPR_B -DMICROPY_PY_UCTYPES=0 -Dmp_int_t=int32_t -Dmp_uint_t=uint32_t" - MICROPY_FORCE_32BIT=1 RUN_TESTS_MPY_CROSS_FLAGS="--mpy-cross-flags=\"-march=x86 -msmall-int-bits=30\"" +) +CI_UNIX_OPTS_X86=( + CROSS_COMPILE=i686-linux-gnu- + RUN_TESTS_MPY_CROSS_FLAGS=${RUN_TESTS_MPY_CROSS_FLAGS:-"--mpy-cross-flags=\"-march=x86\""} ) function ci_unix_build_helper { @@ -766,20 +769,20 @@ function ci_unix_coverage_run_native_mpy_tests { function ci_unix_32bit_setup { sudo dpkg --add-architecture i386 sudo apt-get update - sudo apt-get install gcc-multilib g++-multilib libffi-dev:i386 + sudo apt-get install gcc-i686-linux-gnu g++-i686-linux-gnu patchelf libffi-dev:i386 python -m pip install pyelftools python -m pip install ar - gcc --version + i686-linux-gnu-gcc --version python3 --version } function ci_unix_coverage_32bit_build { - ci_unix_build_helper VARIANT=coverage MICROPY_FORCE_32BIT=1 - ci_unix_build_ffi_lib_helper gcc -m32 + ci_unix_build_helper VARIANT=coverage "${CI_UNIX_OPTS_X86[@]}" + ci_unix_build_ffi_lib_helper i686-linux-gnu-gcc } function ci_unix_coverage_32bit_run_tests { - ci_unix_run_tests_full_helper coverage MICROPY_FORCE_32BIT=1 + ci_unix_run_tests_full_helper coverage "${CI_UNIX_OPTS_X86[@]}" } function ci_unix_coverage_32bit_run_native_mpy_tests { @@ -787,8 +790,8 @@ function ci_unix_coverage_32bit_run_native_mpy_tests { } function ci_unix_nanbox_build { - ci_unix_build_helper VARIANT=nanbox CFLAGS_EXTRA="-DMICROPY_PY_MATH_CONSTANTS=1" - ci_unix_build_ffi_lib_helper gcc -m32 + ci_unix_build_helper VARIANT=nanbox CFLAGS_EXTRA="-DMICROPY_PY_MATH_CONSTANTS=1" "${CI_UNIX_OPTS_X86[@]}" + ci_unix_build_ffi_lib_helper i686-linux-gnu-gcc } function ci_unix_nanbox_run_tests { @@ -796,7 +799,8 @@ function ci_unix_nanbox_run_tests { } function ci_unix_longlong_build { - ci_unix_build_helper VARIANT=longlong "${CI_UNIX_OPTS_SANITIZE_UNDEFINED[@]}" + ci_unix_build_helper VARIANT=longlong "${CI_UNIX_OPTS_SANITIZE_UNDEFINED[@]}" "${CI_UNIX_OPTS_X86[@]}" + patchelf --add-rpath "/usr/i686-linux-gnu/lib" ports/unix/build-longlong/micropython } function ci_unix_longlong_run_tests { @@ -969,14 +973,14 @@ function ci_unix_qemu_riscv64_run_tests { } function ci_unix_repr_b_build { - ci_unix_build_helper "${CI_UNIX_OPTS_REPR_B[@]}" - ci_unix_build_ffi_lib_helper gcc -m32 + ci_unix_build_helper "${CI_UNIX_OPTS_REPR_B[@]}" "${CI_UNIX_OPTS_X86[@]}" + ci_unix_build_ffi_lib_helper i686-linux-gnu-gcc } function ci_unix_repr_b_run_tests { # ci_unix_run_tests_full_no_native_helper is not used due to # https://github.com/micropython/micropython/issues/18105 - ci_unix_run_tests_helper "${CI_UNIX_OPTS_REPR_B[@]}" + ci_unix_run_tests_helper "${CI_UNIX_OPTS_REPR_B[@]}" "${CI_UNIX_OPTS_X86[@]}" } ########################################################################################