Skip to content

pkg/mpaland-printf: Add alternative stdio as package #20664

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions pkg/mpaland-printf/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
PKG_NAME=mpaland-printf
PKG_URL=https://github.com/mpaland/printf
# 4.0.0
PKG_VERSION=0dd4b64bc778bf55229428cefccba4c0a81f384b
PKG_LICENSE=MIT

include $(RIOTBASE)/pkg/pkg.mk

all:
$(QQ)"$(MAKE)" -C $(PKG_SOURCE_DIR) -f $(RIOTPKG)/$(PKG_NAME)/$(PKG_NAME).mk
4 changes: 4 additions & 0 deletions pkg/mpaland-printf/Makefile.dep
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# mpaland's printf does not implement non-standard format specifiers. For
# AVR MCUs we do need the ability to print from PROGMEM, though. Hence, this
# is not compatible with AVR MCUs.
FEATURES_BLACKLIST += arch_avr8
17 changes: 17 additions & 0 deletions pkg/mpaland-printf/Makefile.include
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# wrap stdio functions to use mpaland's printf instead of the one from the
# standard C lib
LINKFLAGS += -Wl,-wrap=printf
LINKFLAGS += -Wl,-wrap=sprintf
LINKFLAGS += -Wl,-wrap=snprintf
LINKFLAGS += -Wl,-wrap=vprintf
LINKFLAGS += -Wl,-wrap=vsnprintf
LINKFLAGS += -Wl,-wrap=putchar
LINKFLAGS += -Wl,-wrap=puts

# Workaround for bug in the newlib headers shipped with e.g. Ubuntu 24.04 LTS
# not defining PRId64 / PRIu64 / PRIx64 / PRIo64 in <inttypes.h> due to an issue
# in <machine/_default_types.h>. Tested to cause no regression on fixed newlib
# headers.
ifneq (,$(filter newlib,$(FEATURES_USED)))
CFLAGS += -D__int64_t_defined=1
endif
27 changes: 27 additions & 0 deletions pkg/mpaland-printf/doc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
@defgroup pkg_mpaland-printf mpaland's printf
@ingroup pkg
@brief mpaland's printf implementation is a lean, thread-safe and
feature-complete printf implementation

# License

Licensed under the MIT license.

# Usage

Add `USEPKG += mpaland-printf` to the application's `Makefile` or compile
using `USEPKG=mpaland-printf make BOARD=<BOARD> -C <APP_DIR>`.

# Features

The package implements all standard format specifiers. However, support
for floating point is disabled by default due to the immense ROM overhead
on MCUs without FPU.

@note Support for floating point formatting can be enabled
via the `printf_float` module, i.e., by adding
`USEMODULE += printf_float` to the application's `Makefile`.
@note Support for non-standard format specifiers such as needed for
printing from flash on AVR MCUs are not implemented.

@see https://github.com/mpaland/printf
7 changes: 7 additions & 0 deletions pkg/mpaland-printf/mpaland-printf.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
MODULE := mpaland-printf

SRC := \
printf.c \
#

include $(RIOTBASE)/Makefile.base
50 changes: 50 additions & 0 deletions pkg/mpaland-printf/patches/0001-RIOT-integration.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
From 04f0f9616f74bbb93a2994d627d4ab476bd81d31 Mon Sep 17 00:00:00 2001
From: Marian Buschsieweke <marian.buschsieweke@posteo.net>
Date: Sat, 11 May 2024 17:51:01 +0200
Subject: [PATCH 1/4] RIOT integration

Use stdio_write() from stdio_base.h for output
---
printf.c | 8 ++++++++
printf.h | 2 +-
2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/printf.c b/printf.c
index 8a700ad..4a17672 100644
--- a/printf.c
+++ b/printf.c
@@ -34,6 +34,7 @@
#include <stdint.h>

#include "printf.h"
+#include "stdio_base.h"


// define this globally (e.g. gcc -DPRINTF_INCLUDE_CONFIG_H ...) to include the
@@ -912,3 +913,10 @@ int fctprintf(void (*out)(char character, void* arg), void* arg, const char* for
va_end(va);
return ret;
}
+
+
+/* RIOT integration: Use stdio_write for output */
+static void _putchar(char character)
+{
+ stdio_write(&character, sizeof(character));
+}
diff --git a/printf.h b/printf.h
index 6075bc2..154930a 100644
--- a/printf.h
+++ b/printf.h
@@ -46,7 +46,7 @@ extern "C" {
* This function is declared here only. You have to write your custom implementation somewhere
* \param character Character to output
*/
-void _putchar(char character);
+static void _putchar(char character);


/**
--
2.43.0

Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
From 2070026e3325ad7640c5cddc9cb1254aa63d61bb Mon Sep 17 00:00:00 2001
From: Marian Buschsieweke <marian.buschsieweke@posteo.net>
Date: Sat, 11 May 2024 17:51:38 +0200
Subject: [PATCH 2/4] Wrapper targets: Add endpoints for -Wl,wrap=...

This adds aliases needed to wrap printf() and friends.
---
printf.c | 38 ++++++++++++++++++++++++++++++++++++++
1 file changed, 38 insertions(+)

diff --git a/printf.c b/printf.c
index 4a17672..e06c9aa 100644
--- a/printf.c
+++ b/printf.c
@@ -32,6 +32,7 @@

#include <stdbool.h>
#include <stdint.h>
+#include <string.h>

#include "printf.h"
#include "stdio_base.h"
@@ -920,3 +921,40 @@ static void _putchar(char character)
{
stdio_write(&character, sizeof(character));
}
+
+
+/* provide entry points for linker to redirect stdio */
+__attribute__((alias("printf_")))
+int __wrap_printf(const char* format, ...);
+
+
+__attribute__((alias("sprintf_")))
+int __wrap_sprintf(char* buffer, const char* format, ...);
+
+
+__attribute__((alias("snprintf_")))
+int __wrap_snprintf(char* buffer, size_t count, const char* format, ...);
+
+
+__attribute__((alias("vprintf_")))
+int __wrap_vprintf(const char* format, va_list va);
+
+
+__attribute__((alias("vsnprintf_")))
+int __wrap_vsnprintf(char* buffer, size_t count, const char* format, va_list va);
+
+
+int __wrap_putchar(int c)
+{
+ _putchar((char)c);
+ return 1;
+}
+
+
+int __wrap_puts(const char *s)
+{
+ size_t len = strlen(s);
+ stdio_write(s, len);
+ stdio_write("\n", 1);
+ return len + 1;
+}
--
2.43.0

Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
From 33f690a4882dc567df328a900c5d12e113feb15c Mon Sep 17 00:00:00 2001
From: Marian Buschsieweke <marian.buschsieweke@posteo.net>
Date: Sat, 11 May 2024 18:38:51 +0200
Subject: [PATCH 3/4] RIOT integration: Enable floating support based on module
selection

---
printf.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/printf.c b/printf.c
index e06c9aa..5266cf7 100644
--- a/printf.c
+++ b/printf.c
@@ -62,7 +62,7 @@

// support for the floating point type (%f)
// default: activated
-#ifndef PRINTF_DISABLE_SUPPORT_FLOAT
+#ifdef MODULE_PRINTF_FLOAT
#define PRINTF_SUPPORT_FLOAT
#endif

--
2.43.0

28 changes: 28 additions & 0 deletions pkg/mpaland-printf/patches/0004-Fix-parsing-of-int8_t.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
From 81ef21a29faafbdb95800ce40b2e20b533b88ebd Mon Sep 17 00:00:00 2001
From: Marian Buschsieweke <marian.buschsieweke@posteo.net>
Date: Sat, 11 May 2024 22:42:21 +0200
Subject: [PATCH 4/4] Fix parsing of `int8_t`

The code assumes that `char` is signed, but the C standard allows
`char` to be either signed or unsigned. Instead, `singed char` and
`unsigned char` need to be used for portable code.
---
printf.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/printf.c b/printf.c
index 5266cf7..3f5f66a 100644
--- a/printf.c
+++ b/printf.c
@@ -734,7 +734,7 @@ static int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const
idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
}
else {
- const int value = (flags & FLAGS_CHAR) ? (char)va_arg(va, int) : (flags & FLAGS_SHORT) ? (short int)va_arg(va, int) : va_arg(va, int);
+ const int value = (flags & FLAGS_CHAR) ? (signed char)va_arg(va, int) : (flags & FLAGS_SHORT) ? (short int)va_arg(va, int) : va_arg(va, int);
idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned int)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
}
}
--
2.43.0

7 changes: 7 additions & 0 deletions tests/sys/snprintf/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
include ../Makefile.sys_common

# avrlibc's snprintf doesn't support uint64_t / int64_t and even fails
# to compile due to PRI*64 macros not being defined
FEATURES_BLACKLIST := arch_avr8

include $(RIOTBASE)/Makefile.include
4 changes: 4 additions & 0 deletions tests/sys/snprintf/Makefile.board.dep
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# newlib's printf is known to be incomplete, despite being bloated
ifneq (,$(filter newlib,$(USEMODULE)))
USEPKG += mpaland-printf
endif
6 changes: 6 additions & 0 deletions tests/sys/snprintf/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# snprintf

This test aims to test if the stdio implementations correctly implements
standard format specifiers. Instead of relying on the transport of stdout to
be fast and reliable, it will use snprintf to format in-memory and compare
in the app with correctness.
Loading