[libc-commits] [libc] [libc] Add putc, fputc, and fprintf to stdio/baremetal (PR #144567)

William Huynh via libc-commits libc-commits at lists.llvm.org
Wed Jul 2 07:37:25 PDT 2025


https://github.com/saturn691 updated https://github.com/llvm/llvm-project/pull/144567

>From 519f3e0920f683e964191c233aa845c14c27d232 Mon Sep 17 00:00:00 2001
From: William Huynh <William.Huynh at arm.com>
Date: Tue, 17 Jun 2025 17:57:12 +0100
Subject: [PATCH 1/8] [libc] Add putc, fputc, and fprintf to stdio/baremetal

Also groups the *_write_hook into a new header file which can be
extended to easily support other [v][f]printf functions
---
 libc/config/baremetal/aarch64/entrypoints.txt |  3 ++
 libc/config/baremetal/arm/entrypoints.txt     |  3 ++
 libc/config/baremetal/riscv/entrypoints.txt   |  3 ++
 libc/src/stdio/baremetal/CMakeLists.txt       | 49 +++++++++++++++++++
 libc/src/stdio/baremetal/fprintf.cpp          | 46 +++++++++++++++++
 libc/src/stdio/baremetal/fputc.cpp            | 25 ++++++++++
 libc/src/stdio/baremetal/printf.cpp           | 14 +-----
 libc/src/stdio/baremetal/putc.cpp             | 25 ++++++++++
 libc/src/stdio/baremetal/putchar.cpp          |  3 +-
 libc/src/stdio/baremetal/vprintf.cpp          | 11 +----
 libc/src/stdio/baremetal/write_utils.h        | 48 ++++++++++++++++++
 11 files changed, 208 insertions(+), 22 deletions(-)
 create mode 100644 libc/src/stdio/baremetal/fprintf.cpp
 create mode 100644 libc/src/stdio/baremetal/fputc.cpp
 create mode 100644 libc/src/stdio/baremetal/putc.cpp
 create mode 100644 libc/src/stdio/baremetal/write_utils.h

diff --git a/libc/config/baremetal/aarch64/entrypoints.txt b/libc/config/baremetal/aarch64/entrypoints.txt
index a8e653fdd5159..08b143d045463 100644
--- a/libc/config/baremetal/aarch64/entrypoints.txt
+++ b/libc/config/baremetal/aarch64/entrypoints.txt
@@ -124,8 +124,11 @@ set(TARGET_LIBC_ENTRYPOINTS
 
     # stdio.h entrypoints
     libc.src.stdio.asprintf
+    libc.src.stdio.fprintf
+    libc.src.stdio.fputc
     libc.src.stdio.getchar
     libc.src.stdio.printf
+    libc.src.stdio.putc
     libc.src.stdio.putchar
     libc.src.stdio.puts
     libc.src.stdio.remove
diff --git a/libc/config/baremetal/arm/entrypoints.txt b/libc/config/baremetal/arm/entrypoints.txt
index acafef17fa5d1..276f00a04b16a 100644
--- a/libc/config/baremetal/arm/entrypoints.txt
+++ b/libc/config/baremetal/arm/entrypoints.txt
@@ -124,8 +124,11 @@ set(TARGET_LIBC_ENTRYPOINTS
 
     # stdio.h entrypoints
     libc.src.stdio.asprintf
+    libc.src.stdio.fprintf
+    libc.src.stdio.fputc
     libc.src.stdio.getchar
     libc.src.stdio.printf
+    libc.src.stdio.putc
     libc.src.stdio.putchar
     libc.src.stdio.puts
     libc.src.stdio.remove
diff --git a/libc/config/baremetal/riscv/entrypoints.txt b/libc/config/baremetal/riscv/entrypoints.txt
index 023826f12d723..dc173f69ce554 100644
--- a/libc/config/baremetal/riscv/entrypoints.txt
+++ b/libc/config/baremetal/riscv/entrypoints.txt
@@ -124,8 +124,11 @@ set(TARGET_LIBC_ENTRYPOINTS
 
     # stdio.h entrypoints
     libc.src.stdio.asprintf
+    libc.src.stdio.fprintf
+    libc.src.stdio.fputc
     libc.src.stdio.getchar
     libc.src.stdio.printf
+    libc.src.stdio.putc
     libc.src.stdio.putchar
     libc.src.stdio.puts
     libc.src.stdio.remove
diff --git a/libc/src/stdio/baremetal/CMakeLists.txt b/libc/src/stdio/baremetal/CMakeLists.txt
index e879230a9d02c..ba1b0a690844a 100644
--- a/libc/src/stdio/baremetal/CMakeLists.txt
+++ b/libc/src/stdio/baremetal/CMakeLists.txt
@@ -1,3 +1,27 @@
+add_entrypoint_object(
+  fprintf
+  SRCS
+    fprintf.cpp
+  HDRS
+    ../fprintf.h
+    write_utils.h
+  DEPENDS
+    libc.src.__support.OSUtil.osutil
+    libc.src.__support.CPP.string_view
+    libc.src.stdio.printf_core.printf_main
+)
+
+add_entrypoint_object(
+  fputc
+  SRCS
+    fputc.cpp
+  HDRS
+    ../fputc.h
+    write_utils.h
+  DEPENDS
+    libc.src.__support.CPP.string_view
+)
+
 add_entrypoint_object(
   getchar
   SRCS
@@ -20,12 +44,24 @@ add_entrypoint_object(
     libc.include.stdio
 )
 
+add_entrypoint_object(
+  putc
+  SRCS
+    putc.cpp
+  HDRS
+    ../putc.h
+    write_utils.h
+  DEPENDS
+    libc.src.__support.CPP.string_view
+)
+
 add_entrypoint_object(
   printf
   SRCS
     printf.cpp
   HDRS
     ../printf.h
+    write_utils.h
   DEPENDS
     libc.src.stdio.printf_core.printf_main
     libc.src.stdio.printf_core.writer
@@ -102,3 +138,16 @@ add_entrypoint_object(
     libc.src.__support.arg_list
     libc.src.__support.OSUtil.osutil
 )
+
+add_header_library(
+  baremetal_write_utils
+  HDRS
+    write_utils.h
+  DEPENDS
+    libc.hdr.types.FILE
+    libc.hdr.stdio_macros
+    libc.src.__support.OSUtil.osutil
+    libc.src.__support.CPP.string_view
+    .stdout
+    .stderr
+)
\ No newline at end of file
diff --git a/libc/src/stdio/baremetal/fprintf.cpp b/libc/src/stdio/baremetal/fprintf.cpp
new file mode 100644
index 0000000000000..530c811af5652
--- /dev/null
+++ b/libc/src/stdio/baremetal/fprintf.cpp
@@ -0,0 +1,46 @@
+//===-- Implementation of fprintf for baremetal -----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdio/fprintf.h"
+
+#include "hdr/types/FILE.h"
+#include "src/__support/arg_list.h"
+#include "src/__support/macros/config.h"
+#include "src/stdio/baremetal/write_utils.h"
+#include "src/stdio/printf_core/printf_main.h"
+
+#include <stdarg.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, fprintf,
+                   (::FILE *__restrict stream, const char *__restrict format,
+                    ...)) {
+  va_list vlist;
+  va_start(vlist, format);
+  internal::ArgList args(vlist); // This holder class allows for easier copying
+                                 // and pointer semantics, as well as handling
+                                 // destruction automatically.
+  va_end(vlist);
+  static constexpr size_t BUFF_SIZE = 1024;
+  char buffer[BUFF_SIZE];
+
+  printf_core::WriteBuffer<printf_core::WriteMode::FLUSH_TO_STREAM> wb(
+      buffer, BUFF_SIZE, get_write_hook(stream), nullptr);
+  printf_core::Writer<printf_core::WriteMode::FLUSH_TO_STREAM> writer(wb);
+
+  int retval = printf_core::printf_main(&writer, format, args);
+
+  int flushval = wb.overflow_write("");
+  if (flushval != printf_core::WRITE_OK)
+    retval = flushval;
+
+  return retval;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/baremetal/fputc.cpp b/libc/src/stdio/baremetal/fputc.cpp
new file mode 100644
index 0000000000000..e33bbc663b970
--- /dev/null
+++ b/libc/src/stdio/baremetal/fputc.cpp
@@ -0,0 +1,25 @@
+//===-- Baremetal Implementation of fputc ---------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdio/fputc.h"
+
+#include "src/__support/CPP/string_view.h"
+#include "src/__support/macros/config.h"
+#include "src/stdio/baremetal/write_utils.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, fputc, (int c, ::FILE *stream)) {
+  char uc = static_cast<char>(c);
+
+  write(stream, cpp::string_view(&uc, 1));
+
+  return 0;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/baremetal/printf.cpp b/libc/src/stdio/baremetal/printf.cpp
index 7253c6549a4e4..5a320cc232456 100644
--- a/libc/src/stdio/baremetal/printf.cpp
+++ b/libc/src/stdio/baremetal/printf.cpp
@@ -7,27 +7,17 @@
 //===----------------------------------------------------------------------===//
 
 #include "src/stdio/printf.h"
-#include "src/__support/OSUtil/io.h"
+
 #include "src/__support/arg_list.h"
 #include "src/__support/macros/config.h"
-#include "src/stdio/printf_core/core_structs.h"
+#include "src/stdio/baremetal/write_utils.h"
 #include "src/stdio/printf_core/printf_main.h"
-#include "src/stdio/printf_core/writer.h"
 
 #include <stdarg.h>
 #include <stddef.h>
 
 namespace LIBC_NAMESPACE_DECL {
 
-namespace {
-
-LIBC_INLINE int stdout_write_hook(cpp::string_view new_str, void *) {
-  write_to_stdout(new_str);
-  return printf_core::WRITE_OK;
-}
-
-} // namespace
-
 LLVM_LIBC_FUNCTION(int, printf, (const char *__restrict format, ...)) {
   va_list vlist;
   va_start(vlist, format);
diff --git a/libc/src/stdio/baremetal/putc.cpp b/libc/src/stdio/baremetal/putc.cpp
new file mode 100644
index 0000000000000..8150ae21eda23
--- /dev/null
+++ b/libc/src/stdio/baremetal/putc.cpp
@@ -0,0 +1,25 @@
+//===-- Baremetal Implementation of putc ----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdio/putc.h"
+
+#include "src/__support/CPP/string_view.h"
+#include "src/__support/macros/config.h"
+#include "src/stdio/baremetal/write_utils.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, putc, (int c, ::FILE *stream)) {
+  char uc = static_cast<char>(c);
+
+  write(stream, cpp::string_view(&uc, 1));
+
+  return 0;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/baremetal/putchar.cpp b/libc/src/stdio/baremetal/putchar.cpp
index ac21e6e783b01..fcaae40d09397 100644
--- a/libc/src/stdio/baremetal/putchar.cpp
+++ b/libc/src/stdio/baremetal/putchar.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "src/stdio/putchar.h"
+
 #include "src/__support/CPP/string_view.h"
 #include "src/__support/OSUtil/io.h"
 #include "src/__support/macros/config.h"
@@ -14,7 +15,7 @@
 namespace LIBC_NAMESPACE_DECL {
 
 LLVM_LIBC_FUNCTION(int, putchar, (int c)) {
-  char uc = static_cast<char>(c);
+  char uc = static_cast<unsigned char>(c);
 
   write_to_stdout(cpp::string_view(&uc, 1));
 
diff --git a/libc/src/stdio/baremetal/vprintf.cpp b/libc/src/stdio/baremetal/vprintf.cpp
index ab02533f14911..38985a9b85209 100644
--- a/libc/src/stdio/baremetal/vprintf.cpp
+++ b/libc/src/stdio/baremetal/vprintf.cpp
@@ -7,9 +7,11 @@
 //===----------------------------------------------------------------------===//
 
 #include "src/stdio/vprintf.h"
+
 #include "src/__support/OSUtil/io.h"
 #include "src/__support/arg_list.h"
 #include "src/__support/macros/config.h"
+#include "src/stdio/baremetal/write_utils.h"
 #include "src/stdio/printf_core/core_structs.h"
 #include "src/stdio/printf_core/printf_main.h"
 #include "src/stdio/printf_core/writer.h"
@@ -19,15 +21,6 @@
 
 namespace LIBC_NAMESPACE_DECL {
 
-namespace {
-
-LIBC_INLINE int stdout_write_hook(cpp::string_view new_str, void *) {
-  write_to_stdout(new_str);
-  return printf_core::WRITE_OK;
-}
-
-} // namespace
-
 LLVM_LIBC_FUNCTION(int, vprintf,
                    (const char *__restrict format, va_list vlist)) {
   internal::ArgList args(vlist); // This holder class allows for easier copying
diff --git a/libc/src/stdio/baremetal/write_utils.h b/libc/src/stdio/baremetal/write_utils.h
new file mode 100644
index 0000000000000..ce493189c472a
--- /dev/null
+++ b/libc/src/stdio/baremetal/write_utils.h
@@ -0,0 +1,48 @@
+//===-- Baremetal helper functions for writing to stdout/stderr -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "hdr/stdio_macros.h" // For stdout/err
+#include "hdr/types/FILE.h"
+#include "src/__support/CPP/string_view.h"
+#include "src/__support/OSUtil/io.h"
+#include "src/__support/macros/config.h"
+#include "src/stdio/printf_core/core_structs.h" // For printf_core::WRITE_OK
+
+#include <stddef.h>
+
+namespace LIBC_NAMESPACE_DECL {
+namespace {
+
+LIBC_INLINE int stdout_write_hook(cpp::string_view new_str, void *) {
+  write_to_stdout(new_str);
+  return printf_core::WRITE_OK;
+}
+
+LIBC_INLINE int stderr_write_hook(cpp::string_view new_str, void *) {
+  write_to_stderr(new_str);
+  return printf_core::WRITE_OK;
+}
+
+LIBC_INLINE void write(::FILE *f, cpp::string_view new_str) {
+  if (f == stdout) {
+    write_to_stdout(new_str);
+  } else {
+    write_to_stderr(new_str);
+  }
+}
+
+LIBC_INLINE decltype(&stdout_write_hook) get_write_hook(::FILE *f) {
+  if (f == stdout) {
+    return &stdout_write_hook;
+  }
+
+  return &stderr_write_hook;
+}
+
+} // namespace
+} // namespace LIBC_NAMESPACE_DECL

>From b30faff331872519d86bd0d742da76776178ac73 Mon Sep 17 00:00:00 2001
From: William Huynh <William.Huynh at arm.com>
Date: Tue, 17 Jun 2025 18:08:21 +0100
Subject: [PATCH 2/8] fixup! [libc] Add putc, fputc, and fprintf to
 stdio/baremetal

---
 libc/src/stdio/baremetal/CMakeLists.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libc/src/stdio/baremetal/CMakeLists.txt b/libc/src/stdio/baremetal/CMakeLists.txt
index ba1b0a690844a..a7c3180ecfc71 100644
--- a/libc/src/stdio/baremetal/CMakeLists.txt
+++ b/libc/src/stdio/baremetal/CMakeLists.txt
@@ -150,4 +150,4 @@ add_header_library(
     libc.src.__support.CPP.string_view
     .stdout
     .stderr
-)
\ No newline at end of file
+)

>From 20b1e653660252278d683d90c1f0346d9b321771 Mon Sep 17 00:00:00 2001
From: William Huynh <William.Huynh at arm.com>
Date: Tue, 17 Jun 2025 18:25:26 +0100
Subject: [PATCH 3/8] fixup! fixup! [libc] Add putc, fputc, and fprintf to
 stdio/baremetal

---
 libc/src/stdio/baremetal/CMakeLists.txt |  5 -----
 libc/src/stdio/baremetal/fprintf.cpp    |  2 +-
 libc/src/stdio/baremetal/fputc.cpp      |  4 ++--
 libc/src/stdio/baremetal/getchar.cpp    |  2 +-
 libc/src/stdio/baremetal/printf.cpp     |  2 +-
 libc/src/stdio/baremetal/putc.cpp       |  4 ++--
 libc/src/stdio/baremetal/putchar.cpp    |  4 ++--
 libc/src/stdio/baremetal/puts.cpp       |  2 +-
 libc/src/stdio/baremetal/remove.cpp     |  2 +-
 libc/src/stdio/baremetal/vprintf.cpp    |  5 +----
 libc/src/stdio/baremetal/write_utils.h  | 12 +++++-------
 11 files changed, 17 insertions(+), 27 deletions(-)

diff --git a/libc/src/stdio/baremetal/CMakeLists.txt b/libc/src/stdio/baremetal/CMakeLists.txt
index a7c3180ecfc71..8c366c7e7cf2b 100644
--- a/libc/src/stdio/baremetal/CMakeLists.txt
+++ b/libc/src/stdio/baremetal/CMakeLists.txt
@@ -6,7 +6,6 @@ add_entrypoint_object(
     ../fprintf.h
     write_utils.h
   DEPENDS
-    libc.src.__support.OSUtil.osutil
     libc.src.__support.CPP.string_view
     libc.src.stdio.printf_core.printf_main
 )
@@ -64,9 +63,7 @@ add_entrypoint_object(
     write_utils.h
   DEPENDS
     libc.src.stdio.printf_core.printf_main
-    libc.src.stdio.printf_core.writer
     libc.src.__support.arg_list
-    libc.src.__support.OSUtil.osutil
 )
 
 add_entrypoint_object(
@@ -121,9 +118,7 @@ add_entrypoint_object(
     ../vprintf.h
   DEPENDS
     libc.src.stdio.printf_core.printf_main
-    libc.src.stdio.printf_core.writer
     libc.src.__support.arg_list
-    libc.src.__support.OSUtil.osutil
 )
 
 add_entrypoint_object(
diff --git a/libc/src/stdio/baremetal/fprintf.cpp b/libc/src/stdio/baremetal/fprintf.cpp
index 530c811af5652..ac1c4747e4bf7 100644
--- a/libc/src/stdio/baremetal/fprintf.cpp
+++ b/libc/src/stdio/baremetal/fprintf.cpp
@@ -31,7 +31,7 @@ LLVM_LIBC_FUNCTION(int, fprintf,
   char buffer[BUFF_SIZE];
 
   printf_core::WriteBuffer<printf_core::WriteMode::FLUSH_TO_STREAM> wb(
-      buffer, BUFF_SIZE, get_write_hook(stream), nullptr);
+      buffer, BUFF_SIZE, write_utils::get_write_hook(stream), nullptr);
   printf_core::Writer<printf_core::WriteMode::FLUSH_TO_STREAM> writer(wb);
 
   int retval = printf_core::printf_main(&writer, format, args);
diff --git a/libc/src/stdio/baremetal/fputc.cpp b/libc/src/stdio/baremetal/fputc.cpp
index e33bbc663b970..7d49df1254307 100644
--- a/libc/src/stdio/baremetal/fputc.cpp
+++ b/libc/src/stdio/baremetal/fputc.cpp
@@ -1,4 +1,4 @@
-//===-- Baremetal Implementation of fputc ---------------------------------===//
+//===-- Implementation of fputc for baremetal -------------------*- C++ -*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -17,7 +17,7 @@ namespace LIBC_NAMESPACE_DECL {
 LLVM_LIBC_FUNCTION(int, fputc, (int c, ::FILE *stream)) {
   char uc = static_cast<char>(c);
 
-  write(stream, cpp::string_view(&uc, 1));
+  write_utils::write(stream, cpp::string_view(&uc, 1));
 
   return 0;
 }
diff --git a/libc/src/stdio/baremetal/getchar.cpp b/libc/src/stdio/baremetal/getchar.cpp
index 8fb7bc32537e7..0c718fab86ffa 100644
--- a/libc/src/stdio/baremetal/getchar.cpp
+++ b/libc/src/stdio/baremetal/getchar.cpp
@@ -1,4 +1,4 @@
-//===-- Baremetal implementation of getchar -------------------------------===//
+//===-- Implementation of getchar for baremetal -----------------*- C++ -*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
diff --git a/libc/src/stdio/baremetal/printf.cpp b/libc/src/stdio/baremetal/printf.cpp
index 5a320cc232456..f519b84c0900c 100644
--- a/libc/src/stdio/baremetal/printf.cpp
+++ b/libc/src/stdio/baremetal/printf.cpp
@@ -29,7 +29,7 @@ LLVM_LIBC_FUNCTION(int, printf, (const char *__restrict format, ...)) {
   char buffer[BUFF_SIZE];
 
   printf_core::WriteBuffer<printf_core::WriteMode::FLUSH_TO_STREAM> wb(
-      buffer, BUFF_SIZE, &stdout_write_hook, nullptr);
+      buffer, BUFF_SIZE, &write_utils::stdout_write_hook, nullptr);
   printf_core::Writer<printf_core::WriteMode::FLUSH_TO_STREAM> writer(wb);
 
   int retval = printf_core::printf_main(&writer, format, args);
diff --git a/libc/src/stdio/baremetal/putc.cpp b/libc/src/stdio/baremetal/putc.cpp
index 8150ae21eda23..6482956830614 100644
--- a/libc/src/stdio/baremetal/putc.cpp
+++ b/libc/src/stdio/baremetal/putc.cpp
@@ -1,4 +1,4 @@
-//===-- Baremetal Implementation of putc ----------------------------------===//
+//===-- Implementation of putc for baremetal --------------------*- C++ -*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -17,7 +17,7 @@ namespace LIBC_NAMESPACE_DECL {
 LLVM_LIBC_FUNCTION(int, putc, (int c, ::FILE *stream)) {
   char uc = static_cast<char>(c);
 
-  write(stream, cpp::string_view(&uc, 1));
+  write_utils::write(stream, cpp::string_view(&uc, 1));
 
   return 0;
 }
diff --git a/libc/src/stdio/baremetal/putchar.cpp b/libc/src/stdio/baremetal/putchar.cpp
index fcaae40d09397..f0175964eb125 100644
--- a/libc/src/stdio/baremetal/putchar.cpp
+++ b/libc/src/stdio/baremetal/putchar.cpp
@@ -1,4 +1,4 @@
-//===-- Baremetal Implementation of putchar -------------------------------===//
+//===-- Implementation of putchar for baremetal -----------------*- C++ -*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -15,7 +15,7 @@
 namespace LIBC_NAMESPACE_DECL {
 
 LLVM_LIBC_FUNCTION(int, putchar, (int c)) {
-  char uc = static_cast<unsigned char>(c);
+  char uc = static_cast<char>(c);
 
   write_to_stdout(cpp::string_view(&uc, 1));
 
diff --git a/libc/src/stdio/baremetal/puts.cpp b/libc/src/stdio/baremetal/puts.cpp
index fcd3aa086b2bf..72619cb548900 100644
--- a/libc/src/stdio/baremetal/puts.cpp
+++ b/libc/src/stdio/baremetal/puts.cpp
@@ -1,4 +1,4 @@
-//===-- Implementation of puts for baremetal-------------------------------===//
+//===-- Implementation of puts for baremetal --------------------*- C++ -*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
diff --git a/libc/src/stdio/baremetal/remove.cpp b/libc/src/stdio/baremetal/remove.cpp
index d383d0cf78887..0301c0db58fa0 100644
--- a/libc/src/stdio/baremetal/remove.cpp
+++ b/libc/src/stdio/baremetal/remove.cpp
@@ -1,4 +1,4 @@
-//===-- Linux implementation of remove ------------------------------------===//
+//===-- Implementation of remove for baremetal ------------------*- C++ -*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
diff --git a/libc/src/stdio/baremetal/vprintf.cpp b/libc/src/stdio/baremetal/vprintf.cpp
index 38985a9b85209..21a45111f2d42 100644
--- a/libc/src/stdio/baremetal/vprintf.cpp
+++ b/libc/src/stdio/baremetal/vprintf.cpp
@@ -8,13 +8,10 @@
 
 #include "src/stdio/vprintf.h"
 
-#include "src/__support/OSUtil/io.h"
 #include "src/__support/arg_list.h"
 #include "src/__support/macros/config.h"
 #include "src/stdio/baremetal/write_utils.h"
-#include "src/stdio/printf_core/core_structs.h"
 #include "src/stdio/printf_core/printf_main.h"
-#include "src/stdio/printf_core/writer.h"
 
 #include <stdarg.h>
 #include <stddef.h>
@@ -30,7 +27,7 @@ LLVM_LIBC_FUNCTION(int, vprintf,
   char buffer[BUFF_SIZE];
 
   printf_core::WriteBuffer<printf_core::WriteMode::FLUSH_TO_STREAM> wb(
-      buffer, BUFF_SIZE, &stdout_write_hook, nullptr);
+      buffer, BUFF_SIZE, &write_utils::stdout_write_hook, nullptr);
   printf_core::Writer<printf_core::WriteMode::FLUSH_TO_STREAM> writer(wb);
 
   int retval = printf_core::printf_main(&writer, format, args);
diff --git a/libc/src/stdio/baremetal/write_utils.h b/libc/src/stdio/baremetal/write_utils.h
index ce493189c472a..8862de1e32355 100644
--- a/libc/src/stdio/baremetal/write_utils.h
+++ b/libc/src/stdio/baremetal/write_utils.h
@@ -13,10 +13,8 @@
 #include "src/__support/macros/config.h"
 #include "src/stdio/printf_core/core_structs.h" // For printf_core::WRITE_OK
 
-#include <stddef.h>
-
 namespace LIBC_NAMESPACE_DECL {
-namespace {
+namespace write_utils {
 
 LIBC_INLINE int stdout_write_hook(cpp::string_view new_str, void *) {
   write_to_stdout(new_str);
@@ -36,13 +34,13 @@ LIBC_INLINE void write(::FILE *f, cpp::string_view new_str) {
   }
 }
 
-LIBC_INLINE decltype(&stdout_write_hook) get_write_hook(::FILE *f) {
-  if (f == stdout) {
+using StreamWriter = int (*)(cpp::string_view, void *);
+LIBC_INLINE StreamWriter get_write_hook(::FILE *f) {
+  if (f == stdout)
     return &stdout_write_hook;
-  }
 
   return &stderr_write_hook;
 }
 
-} // namespace
+} // namespace write_utils
 } // namespace LIBC_NAMESPACE_DECL

>From 581740f04724172dec5f5fdd072f5ded2205538d Mon Sep 17 00:00:00 2001
From: William Huynh <William.Huynh at arm.com>
Date: Fri, 20 Jun 2025 08:49:16 +0100
Subject: [PATCH 4/8] fixup! fixup! fixup! [libc] Add putc, fputc, and fprintf
 to stdio/baremetal

---
 libc/src/stdio/baremetal/CMakeLists.txt | 26 ++++++++++++++++-------
 libc/src/stdio/baremetal/printf.cpp     |  2 +-
 libc/src/stdio/baremetal/vprintf.cpp    |  2 +-
 libc/src/stdio/baremetal/write_hooks.h  | 28 +++++++++++++++++++++++++
 libc/src/stdio/baremetal/write_utils.h  | 25 ++++++++++------------
 5 files changed, 60 insertions(+), 23 deletions(-)
 create mode 100644 libc/src/stdio/baremetal/write_hooks.h

diff --git a/libc/src/stdio/baremetal/CMakeLists.txt b/libc/src/stdio/baremetal/CMakeLists.txt
index 8c366c7e7cf2b..9dbbc1e9b671d 100644
--- a/libc/src/stdio/baremetal/CMakeLists.txt
+++ b/libc/src/stdio/baremetal/CMakeLists.txt
@@ -4,10 +4,10 @@ add_entrypoint_object(
     fprintf.cpp
   HDRS
     ../fprintf.h
-    write_utils.h
-  DEPENDS
+    DEPENDS
     libc.src.__support.CPP.string_view
     libc.src.stdio.printf_core.printf_main
+    .baremetal_write_utils
 )
 
 add_entrypoint_object(
@@ -16,9 +16,9 @@ add_entrypoint_object(
     fputc.cpp
   HDRS
     ../fputc.h
-    write_utils.h
   DEPENDS
     libc.src.__support.CPP.string_view
+    .baremetal_write_utils
 )
 
 add_entrypoint_object(
@@ -49,9 +49,9 @@ add_entrypoint_object(
     putc.cpp
   HDRS
     ../putc.h
-    write_utils.h
-  DEPENDS
+    DEPENDS
     libc.src.__support.CPP.string_view
+    .baremetal_write_utils
 )
 
 add_entrypoint_object(
@@ -60,10 +60,10 @@ add_entrypoint_object(
     printf.cpp
   HDRS
     ../printf.h
-    write_utils.h
-  DEPENDS
+    DEPENDS
     libc.src.stdio.printf_core.printf_main
     libc.src.__support.arg_list
+    .baremetal_write_hooks
 )
 
 add_entrypoint_object(
@@ -119,6 +119,7 @@ add_entrypoint_object(
   DEPENDS
     libc.src.stdio.printf_core.printf_main
     libc.src.__support.arg_list
+    .baremetal_write_hooks
 )
 
 add_entrypoint_object(
@@ -134,6 +135,16 @@ add_entrypoint_object(
     libc.src.__support.OSUtil.osutil
 )
 
+add_header_library(
+  baremetal_write_hooks
+  HDRS
+    write_hooks.h
+  DEPENDS
+    libc.src.__support.OSUtil.osutil
+    libc.src.__support.CPP.string_view
+    libc.src.stdio.printf_core.core_structs
+)
+
 add_header_library(
   baremetal_write_utils
   HDRS
@@ -143,6 +154,7 @@ add_header_library(
     libc.hdr.stdio_macros
     libc.src.__support.OSUtil.osutil
     libc.src.__support.CPP.string_view
+    .baremetal_write_hooks
     .stdout
     .stderr
 )
diff --git a/libc/src/stdio/baremetal/printf.cpp b/libc/src/stdio/baremetal/printf.cpp
index f519b84c0900c..96f288fde14fa 100644
--- a/libc/src/stdio/baremetal/printf.cpp
+++ b/libc/src/stdio/baremetal/printf.cpp
@@ -10,7 +10,7 @@
 
 #include "src/__support/arg_list.h"
 #include "src/__support/macros/config.h"
-#include "src/stdio/baremetal/write_utils.h"
+#include "src/stdio/baremetal/write_hooks.h"
 #include "src/stdio/printf_core/printf_main.h"
 
 #include <stdarg.h>
diff --git a/libc/src/stdio/baremetal/vprintf.cpp b/libc/src/stdio/baremetal/vprintf.cpp
index 21a45111f2d42..2114a79f57299 100644
--- a/libc/src/stdio/baremetal/vprintf.cpp
+++ b/libc/src/stdio/baremetal/vprintf.cpp
@@ -10,7 +10,7 @@
 
 #include "src/__support/arg_list.h"
 #include "src/__support/macros/config.h"
-#include "src/stdio/baremetal/write_utils.h"
+#include "src/stdio/baremetal/write_hooks.h"
 #include "src/stdio/printf_core/printf_main.h"
 
 #include <stdarg.h>
diff --git a/libc/src/stdio/baremetal/write_hooks.h b/libc/src/stdio/baremetal/write_hooks.h
new file mode 100644
index 0000000000000..d03fe0e98f605
--- /dev/null
+++ b/libc/src/stdio/baremetal/write_hooks.h
@@ -0,0 +1,28 @@
+//===-- Baremetal helper functions for writing to stdout/stderr -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/CPP/string_view.h"
+#include "src/__support/OSUtil/io.h"
+#include "src/__support/macros/config.h"
+#include "src/stdio/printf_core/core_structs.h" // For printf_core::WRITE_OK
+
+namespace LIBC_NAMESPACE_DECL {
+namespace write_utils {
+
+LIBC_INLINE int stdout_write_hook(cpp::string_view new_str, void *) {
+  write_to_stdout(new_str);
+  return printf_core::WRITE_OK;
+}
+
+LIBC_INLINE int stderr_write_hook(cpp::string_view new_str, void *) {
+  write_to_stderr(new_str);
+  return printf_core::WRITE_OK;
+}
+
+} // namespace write_utils
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/baremetal/write_utils.h b/libc/src/stdio/baremetal/write_utils.h
index 8862de1e32355..b16f408c17fad 100644
--- a/libc/src/stdio/baremetal/write_utils.h
+++ b/libc/src/stdio/baremetal/write_utils.h
@@ -10,36 +10,33 @@
 #include "hdr/types/FILE.h"
 #include "src/__support/CPP/string_view.h"
 #include "src/__support/OSUtil/io.h"
+#include "src/__support/libc_errno.h"
 #include "src/__support/macros/config.h"
-#include "src/stdio/printf_core/core_structs.h" // For printf_core::WRITE_OK
+#include "src/stdio/baremetal/write_hooks.h"
 
 namespace LIBC_NAMESPACE_DECL {
 namespace write_utils {
 
-LIBC_INLINE int stdout_write_hook(cpp::string_view new_str, void *) {
-  write_to_stdout(new_str);
-  return printf_core::WRITE_OK;
-}
-
-LIBC_INLINE int stderr_write_hook(cpp::string_view new_str, void *) {
-  write_to_stderr(new_str);
-  return printf_core::WRITE_OK;
-}
-
 LIBC_INLINE void write(::FILE *f, cpp::string_view new_str) {
   if (f == stdout) {
     write_to_stdout(new_str);
-  } else {
+  } else if (f == stderr) {
     write_to_stderr(new_str);
+  } else {
+    libc_errno = 1;
   }
 }
 
 using StreamWriter = int (*)(cpp::string_view, void *);
 LIBC_INLINE StreamWriter get_write_hook(::FILE *f) {
-  if (f == stdout)
+  if (f == stdout) {
     return &stdout_write_hook;
+  } else if (f == stderr) {
+    return &stderr_write_hook;
+  }
 
-  return &stderr_write_hook;
+  libc_errno = 1;
+  return NULL;
 }
 
 } // namespace write_utils

>From 4474161123a25eeeb8ea233dba98dc245ee3dbaa Mon Sep 17 00:00:00 2001
From: William Huynh <William.Huynh at arm.com>
Date: Fri, 20 Jun 2025 08:51:15 +0100
Subject: [PATCH 5/8] fixup! fixup! fixup! fixup! [libc] Add putc, fputc, and
 fprintf to stdio/baremetal

---
 libc/src/stdio/baremetal/CMakeLists.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libc/src/stdio/baremetal/CMakeLists.txt b/libc/src/stdio/baremetal/CMakeLists.txt
index 9dbbc1e9b671d..f798084f0dd3b 100644
--- a/libc/src/stdio/baremetal/CMakeLists.txt
+++ b/libc/src/stdio/baremetal/CMakeLists.txt
@@ -4,7 +4,7 @@ add_entrypoint_object(
     fprintf.cpp
   HDRS
     ../fprintf.h
-    DEPENDS
+  DEPENDS
     libc.src.__support.CPP.string_view
     libc.src.stdio.printf_core.printf_main
     .baremetal_write_utils

>From 94ea13ffd10c78f4e380b6170dfb3992ec8bc2b8 Mon Sep 17 00:00:00 2001
From: William Huynh <William.Huynh at arm.com>
Date: Fri, 20 Jun 2025 08:52:22 +0100
Subject: [PATCH 6/8] fixup! fixup! fixup! fixup! fixup! [libc] Add putc,
 fputc, and fprintf to stdio/baremetal

---
 libc/src/stdio/baremetal/CMakeLists.txt | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libc/src/stdio/baremetal/CMakeLists.txt b/libc/src/stdio/baremetal/CMakeLists.txt
index f798084f0dd3b..b720b99869bd7 100644
--- a/libc/src/stdio/baremetal/CMakeLists.txt
+++ b/libc/src/stdio/baremetal/CMakeLists.txt
@@ -49,7 +49,7 @@ add_entrypoint_object(
     putc.cpp
   HDRS
     ../putc.h
-    DEPENDS
+  DEPENDS
     libc.src.__support.CPP.string_view
     .baremetal_write_utils
 )
@@ -60,7 +60,7 @@ add_entrypoint_object(
     printf.cpp
   HDRS
     ../printf.h
-    DEPENDS
+  DEPENDS
     libc.src.stdio.printf_core.printf_main
     libc.src.__support.arg_list
     .baremetal_write_hooks

>From 9b4168f4389327a40662187d0a2fa519cc1a207d Mon Sep 17 00:00:00 2001
From: William Huynh <William.Huynh at arm.com>
Date: Fri, 20 Jun 2025 15:37:20 +0100
Subject: [PATCH 7/8] fixup! fixup! fixup! fixup! fixup! fixup! [libc] Add
 putc, fputc, and fprintf to stdio/baremetal

---
 libc/src/stdio/baremetal/fprintf.cpp   | 5 +++++
 libc/src/stdio/baremetal/write_utils.h | 6 ++----
 2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/libc/src/stdio/baremetal/fprintf.cpp b/libc/src/stdio/baremetal/fprintf.cpp
index ac1c4747e4bf7..4081bf166bb16 100644
--- a/libc/src/stdio/baremetal/fprintf.cpp
+++ b/libc/src/stdio/baremetal/fprintf.cpp
@@ -30,6 +30,11 @@ LLVM_LIBC_FUNCTION(int, fprintf,
   static constexpr size_t BUFF_SIZE = 1024;
   char buffer[BUFF_SIZE];
 
+  write_utils::StreamWriter write_hook = write_utils::get_write_hook(stream);
+  if (write_hook == nullptr) {
+    return 0;
+  }
+
   printf_core::WriteBuffer<printf_core::WriteMode::FLUSH_TO_STREAM> wb(
       buffer, BUFF_SIZE, write_utils::get_write_hook(stream), nullptr);
   printf_core::Writer<printf_core::WriteMode::FLUSH_TO_STREAM> writer(wb);
diff --git a/libc/src/stdio/baremetal/write_utils.h b/libc/src/stdio/baremetal/write_utils.h
index b16f408c17fad..a59542b0bd9cc 100644
--- a/libc/src/stdio/baremetal/write_utils.h
+++ b/libc/src/stdio/baremetal/write_utils.h
@@ -10,7 +10,6 @@
 #include "hdr/types/FILE.h"
 #include "src/__support/CPP/string_view.h"
 #include "src/__support/OSUtil/io.h"
-#include "src/__support/libc_errno.h"
 #include "src/__support/macros/config.h"
 #include "src/stdio/baremetal/write_hooks.h"
 
@@ -23,7 +22,7 @@ LIBC_INLINE void write(::FILE *f, cpp::string_view new_str) {
   } else if (f == stderr) {
     write_to_stderr(new_str);
   } else {
-    libc_errno = 1;
+    // Do nothing
   }
 }
 
@@ -35,8 +34,7 @@ LIBC_INLINE StreamWriter get_write_hook(::FILE *f) {
     return &stderr_write_hook;
   }
 
-  libc_errno = 1;
-  return NULL;
+  return nullptr;
 }
 
 } // namespace write_utils

>From 6ab2fd1525685c17863622525705b7b56f6c0d76 Mon Sep 17 00:00:00 2001
From: William Huynh <William.Huynh at arm.com>
Date: Wed, 2 Jul 2025 15:37:11 +0100
Subject: [PATCH 8/8] Minor styling improvments

---
 libc/src/stdio/baremetal/fputc.cpp     | 1 -
 libc/src/stdio/baremetal/putc.cpp      | 1 -
 libc/src/stdio/baremetal/write_utils.h | 5 ++---
 3 files changed, 2 insertions(+), 5 deletions(-)

diff --git a/libc/src/stdio/baremetal/fputc.cpp b/libc/src/stdio/baremetal/fputc.cpp
index 7d49df1254307..30ab32fbdc1ee 100644
--- a/libc/src/stdio/baremetal/fputc.cpp
+++ b/libc/src/stdio/baremetal/fputc.cpp
@@ -16,7 +16,6 @@ namespace LIBC_NAMESPACE_DECL {
 
 LLVM_LIBC_FUNCTION(int, fputc, (int c, ::FILE *stream)) {
   char uc = static_cast<char>(c);
-
   write_utils::write(stream, cpp::string_view(&uc, 1));
 
   return 0;
diff --git a/libc/src/stdio/baremetal/putc.cpp b/libc/src/stdio/baremetal/putc.cpp
index 6482956830614..231e339b9bc40 100644
--- a/libc/src/stdio/baremetal/putc.cpp
+++ b/libc/src/stdio/baremetal/putc.cpp
@@ -16,7 +16,6 @@ namespace LIBC_NAMESPACE_DECL {
 
 LLVM_LIBC_FUNCTION(int, putc, (int c, ::FILE *stream)) {
   char uc = static_cast<char>(c);
-
   write_utils::write(stream, cpp::string_view(&uc, 1));
 
   return 0;
diff --git a/libc/src/stdio/baremetal/write_utils.h b/libc/src/stdio/baremetal/write_utils.h
index a59542b0bd9cc..61502abd824aa 100644
--- a/libc/src/stdio/baremetal/write_utils.h
+++ b/libc/src/stdio/baremetal/write_utils.h
@@ -28,11 +28,10 @@ LIBC_INLINE void write(::FILE *f, cpp::string_view new_str) {
 
 using StreamWriter = int (*)(cpp::string_view, void *);
 LIBC_INLINE StreamWriter get_write_hook(::FILE *f) {
-  if (f == stdout) {
+  if (f == stdout)
     return &stdout_write_hook;
-  } else if (f == stderr) {
+  else if (f == stderr)
     return &stderr_write_hook;
-  }
 
   return nullptr;
 }



More information about the libc-commits mailing list