Skip to content

Commit

Permalink
pkg/mpaland-printf: Add alternative stdio as package
Browse files Browse the repository at this point in the history
This packs the stdio implementation from [1] as alternative to
what the used standard C lib provides with the intent to provide a
thread-safe, smaller, and more feature-complete alternative on
newlib targets.

Compared to `newlib_nano` this reduces `.text` by a bit more than 200 B
while adding support for standard format specifiers such as `RPIu8`,
`PRIu16`, `PRIu64`, `%z`, and `%t`.

Note that `newlib_nano`'s stdio can be thread-safe in reentrant mode
at the cost of RAM (per thread) and latency. Especially the increase
in latency can be prohibitive when real time requirements need to be
met.

[1]: https://github.com/mpaland/printf
  • Loading branch information
maribu committed May 11, 2024
1 parent 1f5e2c7 commit 326e9c3
Show file tree
Hide file tree
Showing 9 changed files with 334 additions and 0 deletions.
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
9 changes: 9 additions & 0 deletions pkg/mpaland-printf/Makefile.include
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# 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
29 changes: 29 additions & 0 deletions pkg/mpaland-printf/doc.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* @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
* `printf_float` module, e.g. 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 875a37ec418c41ffd060e39b2153357a32175ac5 Mon Sep 17 00:00:00 2001
From: Marian Buschsieweke <[email protected]>
Date: Sat, 11 May 2024 17:51:01 +0200
Subject: [PATCH 1/2] 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..fd83570 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..e185911 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.45.0

Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
From 6fcc450e49791de23446b26cb4b2dc388590c763 Mon Sep 17 00:00:00 2001
From: Marian Buschsieweke <[email protected]>
Date: Sat, 11 May 2024 17:51:38 +0200
Subject: [PATCH 2/2] 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 fd83570..4694bab 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.45.0

Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
From 8436eab79cda1de6e81d5d1d00c379036efa3900 Mon Sep 17 00:00:00 2001
From: Marian Buschsieweke <[email protected]>
Date: Sat, 11 May 2024 18:38:51 +0200
Subject: [PATCH 3/3] RIOT integration: Enable floating support based on module
selection

---
printf.c | 94 ++++++++++++++++++++++++++++----------------------------
1 file changed, 47 insertions(+), 47 deletions(-)

diff --git a/printf.c b/printf.c
index e06c9aa..c4980e3 100644
--- a/printf.c
+++ b/printf.c
@@ -32,10 +32,10 @@

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

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


// define this globally (e.g. gcc -DPRINTF_INCLUDE_CONFIG_H ...) to include the
@@ -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

@@ -914,47 +914,47 @@ 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));
-}
-
-
-/* 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;
-}
+
+
+/* RIOT integration: Use stdio_write for output */
+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.45.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 24d4f4ef60aaaef3c471eb248799ebefde33cc03 Mon Sep 17 00:00:00 2001
From: Marian Buschsieweke <[email protected]>
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..440cfa6 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.45.0

0 comments on commit 326e9c3

Please sign in to comment.