[libc-commits] [libc] [libc] Migrate from baremetal stdio.h to generic stdio.h (PR #152748)
William Huynh via libc-commits
libc-commits at lists.llvm.org
Thu Aug 14 08:13:54 PDT 2025
https://github.com/saturn691 updated https://github.com/llvm/llvm-project/pull/152748
>From 66e8d6137d780cc9f1b221c031de9969207d0568 Mon Sep 17 00:00:00 2001
From: William Huynh <William.Huynh at arm.com>
Date: Fri, 8 Aug 2025 16:40:14 +0100
Subject: [PATCH 1/3] [libc] Migrate from baremetal stdio.h to generic stdio.h
This is a follow up to the RFC here:
https://discourse.llvm.org/t/rfc-implementation-of-stdio-on-baremetal/86944
Currently, this is very rough and this PR is only for feedback. This provides
the stdout/stderr/stdin symbols (which now don't have to provided by the user).
This allows the user to have access to all functions, currently I've only
tested `fprintf` but in theory everything that works in the generic folder
should work in the baremetal configuration.
The most important part of the implementation is:
- where we want to put `std*`. Here it is a part of `libc.a`
- if we want it here, what should we set it to? I have aliased
all the streams to a _non-buffered_ stream, which does NOT
require flushing. It is based on the CookieFile that already existed
---
libc/config/baremetal/aarch64/entrypoints.txt | 2 +
libc/config/baremetal/arm/entrypoints.txt | 2 +
libc/config/baremetal/riscv/entrypoints.txt | 2 +
libc/src/__support/File/CMakeLists.txt | 29 +++++-
libc/src/__support/OSUtil/baremetal/io.cpp | 39 --------
libc/src/__support/OSUtil/baremetal/io.h | 38 ++++++++
libc/src/stdio/baremetal/CMakeLists.txt | 96 -------------------
libc/src/stdio/baremetal/printf.cpp | 54 -----------
libc/src/stdio/baremetal/putchar.cpp | 24 -----
libc/src/stdio/baremetal/puts.cpp | 26 -----
libc/src/stdio/baremetal/vprintf.cpp | 52 ----------
libc/src/stdio/fopencookie.cpp | 67 +------------
12 files changed, 72 insertions(+), 359 deletions(-)
delete mode 100644 libc/src/stdio/baremetal/printf.cpp
delete mode 100644 libc/src/stdio/baremetal/putchar.cpp
delete mode 100644 libc/src/stdio/baremetal/puts.cpp
delete mode 100644 libc/src/stdio/baremetal/vprintf.cpp
diff --git a/libc/config/baremetal/aarch64/entrypoints.txt b/libc/config/baremetal/aarch64/entrypoints.txt
index e24e2b9e2a7bb..787fa5b6eb519 100644
--- a/libc/config/baremetal/aarch64/entrypoints.txt
+++ b/libc/config/baremetal/aarch64/entrypoints.txt
@@ -124,6 +124,8 @@ set(TARGET_LIBC_ENTRYPOINTS
# stdio.h entrypoints
libc.src.stdio.asprintf
+ libc.src.stdio.fopencookie
+ libc.src.stdio.fprintf
libc.src.stdio.getchar
libc.src.stdio.printf
libc.src.stdio.putchar
diff --git a/libc/config/baremetal/arm/entrypoints.txt b/libc/config/baremetal/arm/entrypoints.txt
index 44e9c3edac353..4b19b4267e20d 100644
--- a/libc/config/baremetal/arm/entrypoints.txt
+++ b/libc/config/baremetal/arm/entrypoints.txt
@@ -124,6 +124,8 @@ set(TARGET_LIBC_ENTRYPOINTS
# stdio.h entrypoints
libc.src.stdio.asprintf
+ libc.src.stdio.fopencookie
+ libc.src.stdio.fprintf
libc.src.stdio.getchar
libc.src.stdio.printf
libc.src.stdio.putchar
diff --git a/libc/config/baremetal/riscv/entrypoints.txt b/libc/config/baremetal/riscv/entrypoints.txt
index 29cf322a2e33f..7198dab044532 100644
--- a/libc/config/baremetal/riscv/entrypoints.txt
+++ b/libc/config/baremetal/riscv/entrypoints.txt
@@ -124,6 +124,8 @@ set(TARGET_LIBC_ENTRYPOINTS
# stdio.h entrypoints
libc.src.stdio.asprintf
+ libc.src.stdio.fopencookie
+ libc.src.stdio.fprintf
libc.src.stdio.getchar
libc.src.stdio.printf
libc.src.stdio.putchar
diff --git a/libc/src/__support/File/CMakeLists.txt b/libc/src/__support/File/CMakeLists.txt
index 253243ff40ded..b351953f8409c 100644
--- a/libc/src/__support/File/CMakeLists.txt
+++ b/libc/src/__support/File/CMakeLists.txt
@@ -22,6 +22,20 @@ add_object_library(
libc.src.__support.error_or
)
+add_header_library(
+ cookie_file
+ HDRS
+ cookie_file.h
+ DEPENDS
+ .file
+ libc.hdr.errno_macros
+ libc.hdr.stdio_macros
+ libc.hdr.types.FILE
+ libc.hdr.types.cookie_io_functions_t
+ libc.src.__support.CPP.new
+ libc.src.__support.File.file
+)
+
add_object_library(
dir
SRCS
@@ -41,10 +55,17 @@ endif()
add_subdirectory(${LIBC_TARGET_OS})
-set(target_file libc.src.__support.File.${LIBC_TARGET_OS}.file)
-set(target_stdout libc.src.__support.File.${LIBC_TARGET_OS}.stdout)
-set(target_stderr libc.src.__support.File.${LIBC_TARGET_OS}.stderr)
-set(target_stdin libc.src.__support.File.${LIBC_TARGET_OS}.stdin)
+if(LIBC_TARGET_OS_IS_BAREMETAL)
+ set(target_file libc.src.__support.File.cookie_file)
+ set(target_stdout libc.src.__support.File.${LIBC_TARGET_OS}.stderr)
+ set(target_stderr libc.src.__support.File.${LIBC_TARGET_OS}.stderr)
+ set(target_stdin libc.src.__support.File.${LIBC_TARGET_OS}.stderr)
+else()
+ set(target_file libc.src.__support.File.${LIBC_TARGET_OS}.file)
+ set(target_stdout libc.src.__support.File.${LIBC_TARGET_OS}.stdout)
+ set(target_stderr libc.src.__support.File.${LIBC_TARGET_OS}.stderr)
+ set(target_stdin libc.src.__support.File.${LIBC_TARGET_OS}.stdin)
+endif()
set(file_targets "${target_file};${target_stdout};${target_stdin};${target_stderr}")
set(file_aliases "platform_file;platform_stdout;platform_stdin;platform_stderr")
diff --git a/libc/src/__support/OSUtil/baremetal/io.cpp b/libc/src/__support/OSUtil/baremetal/io.cpp
index 2a9ef6bfa6579..6b475209d421c 100644
--- a/libc/src/__support/OSUtil/baremetal/io.cpp
+++ b/libc/src/__support/OSUtil/baremetal/io.cpp
@@ -13,45 +13,6 @@
namespace LIBC_NAMESPACE_DECL {
-// These are intended to be provided by the vendor.
-//
-// The signature of these types and functions intentionally match `fopencookie`
-// which allows the following:
-//
-// ```
-// struct __llvm_libc_stdio_cookie { ... };
-// ...
-// struct __llvm_libc_stdio_cookie __llvm_libc_stdin_cookie;
-// cookie_io_functions_t stdin_func = { .read = __llvm_libc_stdio_read };
-// FILE *stdin = fopencookie(&__llvm_libc_stdin_cookie, "r", stdin_func);
-// ...
-// struct __llvm_libc_stdio_cookie __llvm_libc_stdout_cookie;
-// cookie_io_functions_t stdout_func = { .write = __llvm_libc_stdio_write };
-// FILE *stdout = fopencookie(&__llvm_libc_stdout_cookie, "w", stdout_func);
-// ...
-// struct __llvm_libc_stdio_cookie __llvm_libc_stderr_cookie;
-// cookie_io_functions_t stderr_func = { .write = __llvm_libc_stdio_write };
-// FILE *stderr = fopencookie(&__llvm_libc_stderr_cookie, "w", stderr_func);
-// ```
-//
-// At the same time, implementation of functions like `printf` and `scanf` can
-// use `__llvm_libc_stdio_read` and `__llvm_libc_stdio_write` directly to avoid
-// the extra indirection.
-//
-// All three symbols `__llvm_libc_stdin_cookie`, `__llvm_libc_stdout_cookie`,
-// and `__llvm_libc_stderr_cookie` must be provided, even if they don't point
-// at anything.
-
-struct __llvm_libc_stdio_cookie;
-
-extern "C" struct __llvm_libc_stdio_cookie __llvm_libc_stdin_cookie;
-extern "C" struct __llvm_libc_stdio_cookie __llvm_libc_stdout_cookie;
-extern "C" struct __llvm_libc_stdio_cookie __llvm_libc_stderr_cookie;
-
-extern "C" ssize_t __llvm_libc_stdio_read(void *cookie, char *buf, size_t size);
-extern "C" ssize_t __llvm_libc_stdio_write(void *cookie, const char *buf,
- size_t size);
-
ssize_t read_from_stdin(char *buf, size_t size) {
return __llvm_libc_stdio_read(static_cast<void *>(&__llvm_libc_stdin_cookie),
buf, size);
diff --git a/libc/src/__support/OSUtil/baremetal/io.h b/libc/src/__support/OSUtil/baremetal/io.h
index aed34ec7e62e3..b6c5ffb21c1a8 100644
--- a/libc/src/__support/OSUtil/baremetal/io.h
+++ b/libc/src/__support/OSUtil/baremetal/io.h
@@ -14,8 +14,46 @@
#include "src/__support/CPP/string_view.h"
#include "src/__support/macros/config.h"
+// These are intended to be provided by the vendor.
+//
+// The signature of these types and functions intentionally match `fopencookie`
+// which allows the following:
+//
+// ```
+// struct __llvm_libc_stdio_cookie { ... };
+// ...
+// struct __llvm_libc_stdio_cookie __llvm_libc_stdin_cookie;
+// cookie_io_functions_t stdin_func = { .read = __llvm_libc_stdio_read };
+// FILE *stdin = fopencookie(&__llvm_libc_stdin_cookie, "r", stdin_func);
+// ...
+// struct __llvm_libc_stdio_cookie __llvm_libc_stdout_cookie;
+// cookie_io_functions_t stdout_func = { .write = __llvm_libc_stdio_write };
+// FILE *stdout = fopencookie(&__llvm_libc_stdout_cookie, "w", stdout_func);
+// ...
+// struct __llvm_libc_stdio_cookie __llvm_libc_stderr_cookie;
+// cookie_io_functions_t stderr_func = { .write = __llvm_libc_stdio_write };
+// FILE *stderr = fopencookie(&__llvm_libc_stderr_cookie, "w", stderr_func);
+// ```
+//
+// At the same time, implementation of functions like `printf` and `scanf` can
+// use `__llvm_libc_stdio_read` and `__llvm_libc_stdio_write` directly to avoid
+// the extra indirection.
+//
+// All three symbols `__llvm_libc_stdin_cookie`, `__llvm_libc_stdout_cookie`,
+// and `__llvm_libc_stderr_cookie` must be provided, even if they don't point
+// at anything.
namespace LIBC_NAMESPACE_DECL {
+struct __llvm_libc_stdio_cookie;
+
+extern "C" struct __llvm_libc_stdio_cookie __llvm_libc_stdin_cookie;
+extern "C" struct __llvm_libc_stdio_cookie __llvm_libc_stdout_cookie;
+extern "C" struct __llvm_libc_stdio_cookie __llvm_libc_stderr_cookie;
+
+extern "C" ssize_t __llvm_libc_stdio_read(void *cookie, char *buf, size_t size);
+extern "C" ssize_t __llvm_libc_stdio_write(void *cookie, const char *buf,
+ size_t size);
+
ssize_t read_from_stdin(char *buf, size_t size);
void write_to_stderr(cpp::string_view msg);
void write_to_stdout(cpp::string_view msg);
diff --git a/libc/src/stdio/baremetal/CMakeLists.txt b/libc/src/stdio/baremetal/CMakeLists.txt
index 548938f885c94..65089274050bd 100644
--- a/libc/src/stdio/baremetal/CMakeLists.txt
+++ b/libc/src/stdio/baremetal/CMakeLists.txt
@@ -1,15 +1,3 @@
-add_entrypoint_object(
- getchar
- SRCS
- getchar.cpp
- HDRS
- ../getchar.h
- DEPENDS
- libc.hdr.stdio_macros
- libc.src.__support.OSUtil.osutil
- libc.src.__support.CPP.string_view
-)
-
add_entrypoint_object(
remove
SRCS
@@ -19,87 +7,3 @@ add_entrypoint_object(
DEPENDS
libc.include.stdio
)
-
-add_entrypoint_object(
- printf
- SRCS
- printf.cpp
- HDRS
- ../printf.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(
- putchar
- SRCS
- putchar.cpp
- HDRS
- ../putchar.h
- DEPENDS
- libc.src.__support.OSUtil.osutil
- libc.src.__support.CPP.string_view
-)
-
-add_entrypoint_object(
- puts
- SRCS
- puts.cpp
- HDRS
- ../puts.h
- DEPENDS
- libc.src.__support.OSUtil.osutil
- libc.src.__support.CPP.string_view
-)
-
-add_header_library(
- scanf_internal
- HDRS
- scanf_internal.h
- DEPENDS
- libc.src.stdio.scanf_core.reader
- libc.src.__support.OSUtil.osutil
-)
-
-add_entrypoint_object(
- scanf
- SRCS
- scanf.cpp
- HDRS
- ../scanf.h
- DEPENDS
- .scanf_internal
- libc.include.inttypes
- libc.src.stdio.scanf_core.scanf_main
- libc.src.__support.arg_list
- libc.src.__support.OSUtil.osutil
-)
-
-add_entrypoint_object(
- vprintf
- SRCS
- vprintf.cpp
- HDRS
- ../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(
- vscanf
- SRCS
- vscanf.cpp
- HDRS
- ../vscanf.h
- DEPENDS
- .scanf_internal
- libc.src.stdio.scanf_core.scanf_main
- libc.src.__support.arg_list
- libc.src.__support.OSUtil.osutil
-)
diff --git a/libc/src/stdio/baremetal/printf.cpp b/libc/src/stdio/baremetal/printf.cpp
deleted file mode 100644
index 7253c6549a4e4..0000000000000
--- a/libc/src/stdio/baremetal/printf.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-//===-- Implementation of printf 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/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/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);
- 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, &stdout_write_hook, 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/putchar.cpp b/libc/src/stdio/baremetal/putchar.cpp
deleted file mode 100644
index ac21e6e783b01..0000000000000
--- a/libc/src/stdio/baremetal/putchar.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-//===-- Baremetal Implementation of putchar -------------------------------===//
-//
-// 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/putchar.h"
-#include "src/__support/CPP/string_view.h"
-#include "src/__support/OSUtil/io.h"
-#include "src/__support/macros/config.h"
-
-namespace LIBC_NAMESPACE_DECL {
-
-LLVM_LIBC_FUNCTION(int, putchar, (int c)) {
- char uc = static_cast<char>(c);
-
- write_to_stdout(cpp::string_view(&uc, 1));
-
- return 0;
-}
-
-} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/baremetal/puts.cpp b/libc/src/stdio/baremetal/puts.cpp
deleted file mode 100644
index fcd3aa086b2bf..0000000000000
--- a/libc/src/stdio/baremetal/puts.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-//===-- Implementation of puts for baremetal-------------------------------===//
-//
-// 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/puts.h"
-#include "src/__support/CPP/string_view.h"
-#include "src/__support/OSUtil/io.h"
-#include "src/__support/macros/config.h"
-
-namespace LIBC_NAMESPACE_DECL {
-
-LLVM_LIBC_FUNCTION(int, puts, (const char *__restrict str)) {
- cpp::string_view str_view(str);
-
- // TODO: Can we combine these to avoid needing two writes?
- write_to_stdout(str_view);
- write_to_stdout("\n");
-
- return 0;
-}
-
-} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/baremetal/vprintf.cpp b/libc/src/stdio/baremetal/vprintf.cpp
deleted file mode 100644
index ab02533f14911..0000000000000
--- a/libc/src/stdio/baremetal/vprintf.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-//===-- Implementation of vprintf -------------------------------*- 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/vprintf.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/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, vprintf,
- (const char *__restrict format, va_list vlist)) {
- internal::ArgList args(vlist); // This holder class allows for easier copying
- // and pointer semantics, as well as handling
- // destruction automatically.
- static constexpr size_t BUFF_SIZE = 1024;
- char buffer[BUFF_SIZE];
-
- printf_core::WriteBuffer<printf_core::WriteMode::FLUSH_TO_STREAM> wb(
- buffer, BUFF_SIZE, &stdout_write_hook, 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/fopencookie.cpp b/libc/src/stdio/fopencookie.cpp
index da8a132a4db6e..cb82c4e0e323c 100644
--- a/libc/src/stdio/fopencookie.cpp
+++ b/libc/src/stdio/fopencookie.cpp
@@ -14,72 +14,10 @@
#include "src/__support/CPP/new.h"
#include "src/__support/File/file.h"
-#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
-namespace {
-
-class CookieFile : public LIBC_NAMESPACE::File {
- void *cookie;
- cookie_io_functions_t ops;
-
- static FileIOResult cookie_write(File *f, const void *data, size_t size);
- static FileIOResult cookie_read(File *f, void *data, size_t size);
- static ErrorOr<off_t> cookie_seek(File *f, off_t offset, int whence);
- static int cookie_close(File *f);
-
-public:
- CookieFile(void *c, cookie_io_functions_t cops, uint8_t *buffer,
- size_t bufsize, File::ModeFlags mode)
- : File(&cookie_write, &cookie_read, &CookieFile::cookie_seek,
- &cookie_close, buffer, bufsize, 0 /* default buffering mode */,
- true /* File owns buffer */, mode),
- cookie(c), ops(cops) {}
-};
-
-FileIOResult CookieFile::cookie_write(File *f, const void *data, size_t size) {
- auto cookie_file = reinterpret_cast<CookieFile *>(f);
- if (cookie_file->ops.write == nullptr)
- return 0;
- return static_cast<size_t>(cookie_file->ops.write(
- cookie_file->cookie, reinterpret_cast<const char *>(data), size));
-}
-
-FileIOResult CookieFile::cookie_read(File *f, void *data, size_t size) {
- auto cookie_file = reinterpret_cast<CookieFile *>(f);
- if (cookie_file->ops.read == nullptr)
- return 0;
- return static_cast<size_t>(cookie_file->ops.read(
- cookie_file->cookie, reinterpret_cast<char *>(data), size));
-}
-
-ErrorOr<off_t> CookieFile::cookie_seek(File *f, off_t offset, int whence) {
- auto cookie_file = reinterpret_cast<CookieFile *>(f);
- if (cookie_file->ops.seek == nullptr) {
- return Error(EINVAL);
- }
- off64_t offset64 = offset;
- int result = cookie_file->ops.seek(cookie_file->cookie, &offset64, whence);
- if (result == 0)
- return offset64;
- return -1;
-}
-
-int CookieFile::cookie_close(File *f) {
- auto cookie_file = reinterpret_cast<CookieFile *>(f);
- if (cookie_file->ops.close == nullptr)
- return 0;
- int retval = cookie_file->ops.close(cookie_file->cookie);
- if (retval != 0)
- return retval;
- delete cookie_file;
- return 0;
-}
-
-} // anonymous namespace
-
LLVM_LIBC_FUNCTION(::FILE *, fopencookie,
(void *cookie, const char *mode,
cookie_io_functions_t ops)) {
@@ -91,8 +29,9 @@ LLVM_LIBC_FUNCTION(::FILE *, fopencookie,
return nullptr;
}
AllocChecker ac;
- auto *file = new (ac) CookieFile(
- cookie, ops, buffer, File::DEFAULT_BUFFER_SIZE, File::mode_flags(mode));
+ auto *file =
+ new (ac) CookieFile(cookie, ops, buffer, File::DEFAULT_BUFFER_SIZE,
+ _IOFBF, File::mode_flags(mode));
if (!ac)
return nullptr;
return reinterpret_cast<::FILE *>(file);
>From 45aeb22b50f060b92e3dce6a041d3997dda2cf40 Mon Sep 17 00:00:00 2001
From: William Huynh <William.Huynh at arm.com>
Date: Mon, 11 Aug 2025 14:00:45 +0100
Subject: [PATCH 2/3] Some files were not tracked, commit these
---
libc/src/__support/File/CMakeLists.txt | 4 +-
.../__support/File/baremetal/CMakeLists.txt | 10 +++
libc/src/__support/File/baremetal/stderr.cpp | 38 ++++++++++
libc/src/__support/File/cookie_file.h | 75 +++++++++++++++++++
libc/src/stdio/CMakeLists.txt | 1 +
libc/src/stdio/fopencookie.cpp | 2 +-
6 files changed, 126 insertions(+), 4 deletions(-)
create mode 100644 libc/src/__support/File/baremetal/CMakeLists.txt
create mode 100644 libc/src/__support/File/baremetal/stderr.cpp
create mode 100644 libc/src/__support/File/cookie_file.h
diff --git a/libc/src/__support/File/CMakeLists.txt b/libc/src/__support/File/CMakeLists.txt
index b351953f8409c..905b8daa2faac 100644
--- a/libc/src/__support/File/CMakeLists.txt
+++ b/libc/src/__support/File/CMakeLists.txt
@@ -29,11 +29,9 @@ add_header_library(
DEPENDS
.file
libc.hdr.errno_macros
- libc.hdr.stdio_macros
- libc.hdr.types.FILE
libc.hdr.types.cookie_io_functions_t
+ libc.hdr.types.off_t
libc.src.__support.CPP.new
- libc.src.__support.File.file
)
add_object_library(
diff --git a/libc/src/__support/File/baremetal/CMakeLists.txt b/libc/src/__support/File/baremetal/CMakeLists.txt
new file mode 100644
index 0000000000000..3804b5b93e6a6
--- /dev/null
+++ b/libc/src/__support/File/baremetal/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_object_library(
+ stderr
+ SRCS
+ stderr.cpp
+ DEPENDS
+ libc.hdr.stdio_macros
+ libc.src.__support.File.cookie_file
+ libc.src.__support.File.file
+ libc.src.__support.OSUtil.osutil
+)
diff --git a/libc/src/__support/File/baremetal/stderr.cpp b/libc/src/__support/File/baremetal/stderr.cpp
new file mode 100644
index 0000000000000..d14a4de150c24
--- /dev/null
+++ b/libc/src/__support/File/baremetal/stderr.cpp
@@ -0,0 +1,38 @@
+//===--- Definition of baremetal stderr -----------------------------------===//
+//
+// 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"
+#include "src/__support/File/cookie_file.h"
+#include "src/__support/File/file.h"
+#include "src/__support/OSUtil/baremetal/io.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+// To save space, all streams are aliased to one stream. Furthermore, no
+// buffering is used.
+cookie_io_functions_t io_func = {.read = __llvm_libc_stdio_read,
+ .write = __llvm_libc_stdio_write,
+ .seek = nullptr,
+ .close = nullptr};
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wglobal-constructors"
+static CookieFile StdErr(&__llvm_libc_stderr_cookie, io_func, nullptr, 0,
+ _IONBF, File::mode_flags("r+"));
+#pragma clang diagnostic pop
+File *stderr = &StdErr;
+File *stdin = &StdErr;
+File *stdout = &StdErr;
+
+} // namespace LIBC_NAMESPACE_DECL
+
+extern "C" {
+FILE *stderr = reinterpret_cast<FILE *>(&LIBC_NAMESPACE::StdErr);
+FILE *stdin = reinterpret_cast<FILE *>(&LIBC_NAMESPACE::StdErr);
+FILE *stdout = reinterpret_cast<FILE *>(&LIBC_NAMESPACE::StdErr);
+}
diff --git a/libc/src/__support/File/cookie_file.h b/libc/src/__support/File/cookie_file.h
new file mode 100644
index 0000000000000..b7e2dde23bbb3
--- /dev/null
+++ b/libc/src/__support/File/cookie_file.h
@@ -0,0 +1,75 @@
+//===--- A platform independent cookie file class -------------------------===//
+//
+// 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/errno_macros.h"
+#include "hdr/types/cookie_io_functions_t.h"
+#include "hdr/types/off_t.h"
+#include "src/__support/CPP/new.h"
+#include "src/__support/File/file.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+class CookieFile : public LIBC_NAMESPACE::File {
+ void *cookie;
+ cookie_io_functions_t ops;
+
+ static FileIOResult cookie_write(File *f, const void *data, size_t size);
+ static FileIOResult cookie_read(File *f, void *data, size_t size);
+ static ErrorOr<off_t> cookie_seek(File *f, off_t offset, int whence);
+ static int cookie_close(File *f);
+
+public:
+ CookieFile(void *c, cookie_io_functions_t cops, uint8_t *buffer,
+ size_t bufsize, int buffer_mode, File::ModeFlags mode)
+ : File(&cookie_write, &cookie_read, &CookieFile::cookie_seek,
+ &cookie_close, buffer, bufsize, buffer_mode,
+ true /* File owns buffer */, mode),
+ cookie(c), ops(cops) {}
+};
+
+FileIOResult CookieFile::cookie_write(File *f, const void *data, size_t size) {
+ auto cookie_file = reinterpret_cast<CookieFile *>(f);
+ if (cookie_file->ops.write == nullptr)
+ return 0;
+ return static_cast<size_t>(cookie_file->ops.write(
+ cookie_file->cookie, reinterpret_cast<const char *>(data), size));
+}
+
+FileIOResult CookieFile::cookie_read(File *f, void *data, size_t size) {
+ auto cookie_file = reinterpret_cast<CookieFile *>(f);
+ if (cookie_file->ops.read == nullptr)
+ return 0;
+ return static_cast<size_t>(cookie_file->ops.read(
+ cookie_file->cookie, reinterpret_cast<char *>(data), size));
+}
+
+ErrorOr<off_t> CookieFile::cookie_seek(File *f, off_t offset, int whence) {
+ auto cookie_file = reinterpret_cast<CookieFile *>(f);
+ if (cookie_file->ops.seek == nullptr) {
+ return Error(EINVAL);
+ }
+ off64_t offset64 = offset;
+ int result = cookie_file->ops.seek(cookie_file->cookie, &offset64, whence);
+ if (result == 0)
+ return offset64;
+ return -1;
+}
+
+int CookieFile::cookie_close(File *f) {
+ auto cookie_file = reinterpret_cast<CookieFile *>(f);
+ if (cookie_file->ops.close == nullptr)
+ return 0;
+ int retval = cookie_file->ops.close(cookie_file->cookie);
+ if (retval != 0)
+ return retval;
+ delete cookie_file;
+ return 0;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/CMakeLists.txt b/libc/src/stdio/CMakeLists.txt
index b0a6ef1e291b5..273619ae2a570 100644
--- a/libc/src/stdio/CMakeLists.txt
+++ b/libc/src/stdio/CMakeLists.txt
@@ -63,6 +63,7 @@ add_entrypoint_object(
libc.hdr.types.cookie_io_functions_t
libc.hdr.types.FILE
libc.src.__support.CPP.new
+ libc.src.__support.File.cookie_file
libc.src.__support.File.file
)
diff --git a/libc/src/stdio/fopencookie.cpp b/libc/src/stdio/fopencookie.cpp
index cb82c4e0e323c..43a9acc5536c3 100644
--- a/libc/src/stdio/fopencookie.cpp
+++ b/libc/src/stdio/fopencookie.cpp
@@ -10,8 +10,8 @@
#include "hdr/stdio_macros.h"
#include "hdr/types/FILE.h"
#include "hdr/types/cookie_io_functions_t.h"
-#include "hdr/types/off_t.h"
#include "src/__support/CPP/new.h"
+#include "src/__support/File/cookie_file.h"
#include "src/__support/File/file.h"
#include "src/__support/macros/config.h"
>From 9f1846fdb83c3baef6492818a9092d3a16a965c8 Mon Sep 17 00:00:00 2001
From: William Huynh <William.Huynh at arm.com>
Date: Thu, 14 Aug 2025 16:13:41 +0100
Subject: [PATCH 3/3] Apply suggestions from @mysterymath
---
libc/src/__support/File/CMakeLists.txt | 9 ++---
.../__support/File/baremetal/CMakeLists.txt | 22 ++++++++++++
libc/src/__support/File/baremetal/stderr.cpp | 12 +++----
libc/src/__support/File/baremetal/stdin.cpp | 34 +++++++++++++++++++
libc/src/__support/File/baremetal/stdout.cpp | 34 +++++++++++++++++++
5 files changed, 97 insertions(+), 14 deletions(-)
create mode 100644 libc/src/__support/File/baremetal/stdin.cpp
create mode 100644 libc/src/__support/File/baremetal/stdout.cpp
diff --git a/libc/src/__support/File/CMakeLists.txt b/libc/src/__support/File/CMakeLists.txt
index 905b8daa2faac..bcc6cef2163a1 100644
--- a/libc/src/__support/File/CMakeLists.txt
+++ b/libc/src/__support/File/CMakeLists.txt
@@ -55,15 +55,12 @@ add_subdirectory(${LIBC_TARGET_OS})
if(LIBC_TARGET_OS_IS_BAREMETAL)
set(target_file libc.src.__support.File.cookie_file)
- set(target_stdout libc.src.__support.File.${LIBC_TARGET_OS}.stderr)
- set(target_stderr libc.src.__support.File.${LIBC_TARGET_OS}.stderr)
- set(target_stdin libc.src.__support.File.${LIBC_TARGET_OS}.stderr)
else()
set(target_file libc.src.__support.File.${LIBC_TARGET_OS}.file)
- set(target_stdout libc.src.__support.File.${LIBC_TARGET_OS}.stdout)
- set(target_stderr libc.src.__support.File.${LIBC_TARGET_OS}.stderr)
- set(target_stdin libc.src.__support.File.${LIBC_TARGET_OS}.stdin)
endif()
+set(target_stdout libc.src.__support.File.${LIBC_TARGET_OS}.stdout)
+set(target_stderr libc.src.__support.File.${LIBC_TARGET_OS}.stderr)
+set(target_stdin libc.src.__support.File.${LIBC_TARGET_OS}.stdin)
set(file_targets "${target_file};${target_stdout};${target_stdin};${target_stderr}")
set(file_aliases "platform_file;platform_stdout;platform_stdin;platform_stderr")
diff --git a/libc/src/__support/File/baremetal/CMakeLists.txt b/libc/src/__support/File/baremetal/CMakeLists.txt
index 3804b5b93e6a6..a789948368f02 100644
--- a/libc/src/__support/File/baremetal/CMakeLists.txt
+++ b/libc/src/__support/File/baremetal/CMakeLists.txt
@@ -1,3 +1,25 @@
+add_object_library(
+ stdout
+ SRCS
+ stdout.cpp
+ DEPENDS
+ libc.hdr.stdio_macros
+ libc.src.__support.File.cookie_file
+ libc.src.__support.File.file
+ libc.src.__support.OSUtil.osutil
+)
+
+add_object_library(
+ stdin
+ SRCS
+ stdin.cpp
+ DEPENDS
+ libc.hdr.stdio_macros
+ libc.src.__support.File.cookie_file
+ libc.src.__support.File.file
+ libc.src.__support.OSUtil.osutil
+)
+
add_object_library(
stderr
SRCS
diff --git a/libc/src/__support/File/baremetal/stderr.cpp b/libc/src/__support/File/baremetal/stderr.cpp
index d14a4de150c24..0a67771f034aa 100644
--- a/libc/src/__support/File/baremetal/stderr.cpp
+++ b/libc/src/__support/File/baremetal/stderr.cpp
@@ -14,25 +14,21 @@
namespace LIBC_NAMESPACE_DECL {
-// To save space, all streams are aliased to one stream. Furthermore, no
-// buffering is used.
-cookie_io_functions_t io_func = {.read = __llvm_libc_stdio_read,
+cookie_io_functions_t io_func = {.read = nullptr,
.write = __llvm_libc_stdio_write,
.seek = nullptr,
.close = nullptr};
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wglobal-constructors"
+// Buffering is implementation defined. Therefore to save RAM, we use no
+// buffering
static CookieFile StdErr(&__llvm_libc_stderr_cookie, io_func, nullptr, 0,
- _IONBF, File::mode_flags("r+"));
+ _IONBF, File::mode_flags("w"));
#pragma clang diagnostic pop
File *stderr = &StdErr;
-File *stdin = &StdErr;
-File *stdout = &StdErr;
} // namespace LIBC_NAMESPACE_DECL
extern "C" {
FILE *stderr = reinterpret_cast<FILE *>(&LIBC_NAMESPACE::StdErr);
-FILE *stdin = reinterpret_cast<FILE *>(&LIBC_NAMESPACE::StdErr);
-FILE *stdout = reinterpret_cast<FILE *>(&LIBC_NAMESPACE::StdErr);
}
diff --git a/libc/src/__support/File/baremetal/stdin.cpp b/libc/src/__support/File/baremetal/stdin.cpp
new file mode 100644
index 0000000000000..569d924749eec
--- /dev/null
+++ b/libc/src/__support/File/baremetal/stdin.cpp
@@ -0,0 +1,34 @@
+//===--- Definition of baremetal stdin ------------------------------------===//
+//
+// 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"
+#include "src/__support/File/cookie_file.h"
+#include "src/__support/File/file.h"
+#include "src/__support/OSUtil/baremetal/io.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+cookie_io_functions_t io_func = {.read = __llvm_libc_stdio_read,
+ .write = nullptr,
+ .seek = nullptr,
+ .close = nullptr};
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wglobal-constructors"
+// Buffering is implementation defined. Therefore to save RAM, we use no
+// buffering
+static CookieFile StdIn(&__llvm_libc_stdin_cookie, io_func, nullptr, 0, _IONBF,
+ File::mode_flags("r"));
+#pragma clang diagnostic pop
+File *stdin = &StdIn;
+
+} // namespace LIBC_NAMESPACE_DECL
+
+extern "C" {
+FILE *stdin = reinterpret_cast<FILE *>(&LIBC_NAMESPACE::StdIn);
+}
diff --git a/libc/src/__support/File/baremetal/stdout.cpp b/libc/src/__support/File/baremetal/stdout.cpp
new file mode 100644
index 0000000000000..ee8535c0d7643
--- /dev/null
+++ b/libc/src/__support/File/baremetal/stdout.cpp
@@ -0,0 +1,34 @@
+//===--- Definition of baremetal stdout -----------------------------------===//
+//
+// 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"
+#include "src/__support/File/cookie_file.h"
+#include "src/__support/File/file.h"
+#include "src/__support/OSUtil/baremetal/io.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+cookie_io_functions_t io_func = {.read = nullptr,
+ .write = __llvm_libc_stdio_write,
+ .seek = nullptr,
+ .close = nullptr};
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wglobal-constructors"
+// Buffering is implementation defined. Therefore to save RAM, we use no
+// buffering
+static CookieFile StdOut(&__llvm_libc_stdout_cookie, io_func, nullptr, 0,
+ _IONBF, File::mode_flags("w"));
+#pragma clang diagnostic pop
+File *stdout = &StdOut;
+
+} // namespace LIBC_NAMESPACE_DECL
+
+extern "C" {
+FILE *stdout = reinterpret_cast<FILE *>(&LIBC_NAMESPACE::StdOut);
+}
More information about the libc-commits
mailing list