GSoC Project Updates, Week Five
We finally have a Makefile that can generate object files for MicroPython core, along with mphalport.c (the file that uses RTEMS APIs to actually “port” MicroPython). It can also generate an archive libmicropython.a using the pre-defined lib target.
In this post I want to talk about the things I learned about Make (GNU Make specifically), ABIs and why using the correct CFLAGS and LDFLAGS is very important. We also have a test_app directory now in the port (along with a Make target, creatively named “test_app” to build it) to demonstrate linking an RTEMS application with libmicropython, the application in this case being a simple demo that outputs the so-called “friendly REPL”. I also want to cover what I’m currently doing now that we have a stable Makefile, which brings us very close to the completion of the second mid-term deliverable, i.e., an RSB Recipe.
Makefile
The build process earlier was something like this:
- use MicroPython’s Makefile based build system to build core platform-independent objects (based on enabled features in
mpconfigport.h). - use RTEMS’ Waf based build system to build
mphalport.calong with a test application (init.c,main.c) and link everything together.
We don’t really want to have any Waf stuff in MicroPython and the ideal way to build the library should be using purely Makefiles. Enter, pkgconf / pkg-config. The Man page describes it as “a system for configuring build dependency information”, and RTEMS supports it. Package config allows RTEMS BSPs to create .pc file in a set location that we can then use with the pkg-config command like so:
pkg-config --with-path=/path/to/rtems-workspace/rtems/7/lib/pkgconfig --cflags i386-rtems7-pc686
This simply outputs the Cflags described in the i386-rtems7-pc686.pc file at the provided path. CFLAGS are simply additional switches that are supplied to a C compiler. Part of this information is ABI_FLAGS=-mtune=pentiumpro -march=pentium. The ABI, or Application Binary Interface is a specification that sits directly on top of the ISA. It standardizes aspects like register usage and calling conventions. We need to ensure that we consistently use the correct ABI flags because mixing different ABIs can lead to undefined behavior.
Similarly, we can pass --libs to the above command to print the required linker flags. We can append these and the Cflags to the as RTEMS_TARGET_CLFAGS and RTEMS_TARGET_LDFLAGS to the already defined CFLAGS and LDFLAGS in the MicroPython Makefile.
Here’s where the Makefile fun began. I have been using Makefiles in a limited manner for a long time now. I use one to generate this blog! It’s rather simple, with targets to fetch dependencies like the Tailwind compiler (this is a static site but I just prefer tailwind CSS). More about the blog Makefile some other time.
We ended up just needing to pass three variables to the make command to allow it to build libmicropython.a, regardless of the BSP: RTEMS_PREFIX, RTEMS_VERSION and RTEMS_BSP. We already know that pkgconfig files are present in RTEMS_PREFIX/lib/pkgconfig. The format of RTEMS_BSP is “arch/bsp”, so we use the subst and word commands provided by Make to extract RTEMS_ARCH and RTEMS_TARGET from this string. We use the shell command to assign the output of the pkg-config commands to RTEMS_TARGET_CFLAGS and RTEMS_TARGET_LDFLAGS. Here’s the relevant section from the Makefile:
RTEMS_ARCH = $(word 1, $(subst /, ,$(RTEMS_BSP)))
RTEMS_TARGET = $(word 2, $(subst /, ,$(RTEMS_BSP)))
RTEMS_PKGCONFIG = $(RTEMS_PREFIX)/lib/pkgconfig/
RTEMS_PKGCONFIG_PKG = $(RTEMS_ARCH)-rtems$(RTEMS_VERSION)-$(RTEMS_TARGET)
CROSS_COMPILE ?= $(RTEMS_ARCH)-rtems$(RTEMS_VERSION)-
# ... skipped some lines ...
RTEMS_TARGET_CFLAGS += $(shell pkg-config --with-path=$(RTEMS_PKGCONFIG) --cflags $(RTEMS_PKGCONFIG_PKG))
RTEMS_TARGET_LDFLAGS += $(shell pkg-config --with-path=$(RTEMS_PKGCONFIG) --libs $(RTEMS_PKGCONFIG_PKG))
We also use the extracted RTEMS_ARCH and RTEMS_TARGET to create the tools prefix, “i386-rtems7-” in this case.
Here’s a resource I found very helpful in learning more about Makefiles.
That is pretty much it. We can now run
RTEMS_PREFIX=~/rtems-workspace/rtems/7 RTEMS_VERSION=7 RTEMS_BSP=i386/pc686 make
and it creates build/libmicropython.a that we can link against. I also added a test_app directory with an init.c and main.c with an example application demonstrating how we can use MicroPython. We can build it using the Make target “test_app”.
One of my mentors suggested that learning the RSB would take up a significant chunk of time and it would be better if I worked on getting a Makefile that builds a library, and then he could step in to write the final RSB Recipe that will allow applications to very easily build the library and use it. I think the current Makefile can be used for that and we should be able to reach that milestone within the first half of next week whenever my mentor gets time to work on the Recipe.
Serial Input Fun
So we have serial input (first mid-term deliverable) working already, and the second one (RSB Recipe) should be done soon. My mentors suggested that we focus on the Makefile first because as I mentioned earlier, undefined behavior, and they highlighted that it is very much possible that we were having problems with serial input (before the hack) because of incorrect ABI flags. Now that we’re using them, I was able to confirm that the problem doesn’t go away with the new Makefile, so we were back to figuring out a cleaner way to set up input than calling some random function like rtems_shell_wait_for_input.
So I looked into the implementation of this function and found the termios flags responsible for properly setting up the terminal for user input here. We see these flags being set here:
new_term.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
new_term.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
new_term.c_cflag &= ~(CSIZE | PARENB);
new_term.c_cflag |= CS8;
new_term.c_cc [VMIN] = 0;
new_term.c_cc [VTIME] = 10;
rv = tcsetattr(fd, TCSANOW, &new_term);
We can have a function in our test application (remember that for now this is just an application on i386 available over a serial console. On other BSPs this would be a UART or Network).
We have been trying to get the mpremote tool to work with this port. We can expose the console over a pty by passing the relevant flags to Qemu:
qemu-system-i386 --cpu core2duo -no-reboot -append "--console=/dev/com1" -serial chardev:char0 -chardev pty,id=char0,logfile=chardev.log -kernel build/test_app.exe
and then we can use (pty number is assigned after running the above command)
mpremote connect /dev/pts/2 run ./hello_world.py
to execute scripts on the port (exciting!), but this is what I’m currently facing problems with. Getting mpremote to work is not a mid-term deliverable but my mentor mentioned during one of our meetings that it would be nice to have, so I tried to set it up today.
I looked through the termios Man page and saw what these flags did, tried various others, but currently it’s stuck here (with the above flags):
MicroPython v1.26.0-preview.133.g4739a06d5.dirty on 2025-07-05; rtems-i386/pc686 with unknown-cpu
>>>
>>>
>>> ^A
Ctrl-A is supposed to drop MicroPython into a “Raw REPL”. mpremote sends Ctrl-A and then has some logic that detects if we are indeed in a Raw REPL, sends the script as a string line-by-line, and then sends Ctrl-D to exit back into the normal REPL (the so-called “friendly” REPL). The Ctrl-A above is sent by mpremote, but with those termios flags, we have to add a newline for it to process Ctrl-A.
I can disable “Canonical Mode” on the console to disable line buffering and also set the VTIME to 0 to instantly get the entered characters, but that leaves this in a state where the REPL switches to the Raw REPL the instant I press Ctrl-A, and back to the friendly REPL when I press Ctrl-B, but I cannot input text into either of them, and this is the behavior I see with mpremote as well. It sends Ctrl-A, probably sends the “print(‘hello’)” inside hello.py, sends Ctrl-D, but errors out because it doesn’t get any output, and I also don’t see anything in the log beyond the REPL switching to Raw mode and exiting it and printing “OK”. These are the flags that give me this behavior:
term.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
term.c_oflag &= ~OPOST;
term.c_oflag |= ONLCR; /* But with cr+nl on output */
term.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
term.c_cflag |= CLOCAL | CREAD;
term.c_cc[VMIN] = 1;
term.c_cc[VTIME] = 0;
Floating Point
I also got the 4th deliverable done! This was expectedly very simple to do. MicroPython allows us to enable floats at build time by defining:
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT)
To build the test_app we also need to link it with the math library by adding -lm to our gcc command. This was giving me link-time errors regarding missing symbols powf, floorf, etc. (i.e., floating point versions of math library functions).
I found out that the the i386 architecture (the Intel 80386 microprocessor) didn’t originally have an FPU (Floating-Point Unit), and that functionality existed as separate hardware in the form of the i387 chip. So I thought that this target in RTEMS didn’t have floats and I would have to use another BSP, which would not have been ideal as it would be nice to get everything working on one BSP first. I got some help on Discord regarding this, and turns out the only thing I was missing was a simple line of configuration in the test application’s init.c:
#define CONFIGURE_RTEMS_FLOATING_POINT
The application built cleanly and I was able to use floating-point values in MicroPython.
Next Steps
So Serial Input is done (mpremote is still a work-in-progress but getting it to work is more of a configuration thing that can vary widely across BSPs), we are very close to an RSB Recipe for MicroPython, and I also got floating-point values working. The remaining mid-term deliverables are:
- Implementing
time,randomandmachineto be able to get uptime, reset the machine - Working on an initial version of Imports (.py files mounted in QEMU)
I am currently looking through the RTEMS Documentation to try and implement time so we can have functionality like sleep_ms, uptime, etc. The idea behind implementing these modules, as I discussed with my mentors, was that these should be mostly BSP agnostic and will provide us some surface area to build the BSP-specific configuration upon, and I’m hoping this will help us with that.
Imports were suggested by a mentor because this BSP has a nice feature where we can pass a directory to Qemu and there’s a driver that can be enabled that will create a virtual filesystem with the files in that directory. I have seen other ports’ mpconfigport.h files containing MICROPY_VFS and seems like that is something they define a standard interface for just like with mp_hal_stdout_tx_strn and mp_hal_stdin_rx_chr. I will share more updates on this in the next blog post :)
Thank you for your time!