Skip to content

include/stdio.h: Hide the kernel file system types from kernel-build programs. - #20565

Open
casaroli wants to merge 4 commits into
apache:masterfrom
casaroli:libc-stdio-kernel-types
Open

casaroli wants to merge 4 commits into
apache:masterfrom
casaroli:libc-stdio-kernel-types

Conversation

@casaroli

@casaroli casaroli commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Summary

stdio.h includes nuttx/fs/fs.h and nuttx/lib/lib.h. So every program that includes stdio.h also sees the kernel's struct file, struct inode and the other file system types. A program that defines its own struct file does not compile: error: redefinition of 'struct file'.

In the user space of a kernel build (CONFIG_BUILD_KERNEL and not __KERNEL__), programs cannot use those types. This PR makes stdio.h stop including the two headers there. Kernel code, and flat and protected builds, still get them. Removing them for every build breaks many files that rely on the indirect includes.

stdio.h itself needs only the FILE name, the fopencookie() callback types and lib_get_stream() (which stdin, stdout and stderr expand to). FILE stays an incomplete type, stdio.h declares lib_get_stream(), and the cookie types move from fs.h to a new nuttx/fs/cookie.h that both stdio.h and fs.h include.

The libc files that are built for user space and used kernel types or other headers through stdio.h now include what they use.

The first commit fixes the old nxstyle errors in three of the touched files, with no code change: the object code of the three files is identical before and after (qemu-armv8a:nsh with CONFIG_LIBC_LOCALE).

Impact

Programs of a kernel build that used kernel file system types or nuttx/lib/lib.h macros through stdio.h must include those headers themselves. Flat and protected builds, and kernel code, do not change.

The commit "include/nuttx/tls.h: Move the stream structures from nuttx/fs/fs.h." moves struct file_struct, struct streamlist and the __FS_FLAG_* stream flags from nuttx/fs/fs.h to nuttx/tls.h, where struct task_info_s holds the stream list (review). fs.h no longer includes nuttx/fs/cookie.h.

The nxstyle commit makes nxstyle accept an #include inside an initializer. lib_iconv.c includes its code page tables that way, so CI failed on 8 old warnings (#include outside of 'Included Files' section) as soon as the PR touched the file. Over all C files of the tree, the only warnings that go away are these 8 and the same ones in syscall_names.c and syscall_stublookup.c. No new warning appears.

Testing

A program that defines its own struct file and includes <stdio.h>, built outside the tree against the qemu-armv8a:knsh export package and run in QEMU 11:

Before:

ownfile.c:5:8: error: redefinition of 'struct file'

After:

nsh> ownfile
ownfile: struct file value 42

Kernel builds with -Wno-cpp -Werror, each followed by make export and the apps make import (all apps of the configuration compiled for user space): qemu-armv8a:knsh, imx93-evk:knsh, qemu-armv7a:knsh, sabre-6quad:netknsh, sama5d4-ek:knsh, rv-virt:knsh, rv-virt:knsh64, rv-virt:ksmp64, rv-virt:knsh_paging, rv-virt:knetnsh64, rv-virt:kfb64, icicle:knsh, canmv230:knsh, esp32s3-devkit:kernel_n8r2.

The apps import needs apache/nuttx-apps#3820 and apache/nuttx-apps#3823 (both merged), which add includes that some apps files took from stdio.h indirectly.

Flat builds with -Wno-cpp -Werror, size unchanged: lm3s6965-ek:qemu-flat, mps2-an500:nsh.

After the stream structures moved to nuttx/tls.h, with -Wno-cpp -Werror: qemu-armv8a:knsh, rv-virt:knetnsh64 and sabre-6quad:netknsh (each with make export and the apps make import), qemu-armv7a:knsh, rv-virt:knsh64, lm3s6965-ek:qemu-flat, lm3s6965-ek:qemu-protected, mps2-an500:nsh, esp32-devkitc:nsh, qemu-armv8a:nsh.

tools/checkpatch.sh -c -u -m -g passes.

Comment thread include/stdio.h
@github-actions github-actions Bot added Area: File System File System issues Area: OS Components OS Components issues Size: M The size of the change in this PR is medium labels Oct 9, 2026
@github-actions

github-actions Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

MemBrowse Memory Report

qemu-armv8a

  • Code: .text.init_builtin_run +60 B (+0.0%, 347,480 B)

qemu-intel64

@github-actions

github-actions Bot commented Oct 9, 2026

Copy link
Copy Markdown

🔗 Cross-repo PR dependencies

The read-only Build run reported the following dependent PR(s) and fetched head SHA(s):

CI run: https://github.com/apache/nuttx/actions/runs/37943764063

Indent four blocks of iconv() to the right column, add braces to two
one-line statements, add a blank line after declarations, and align a
break in getpass().  No code change: the object code of the three files
is identical before and after on qemu-armv8a:nsh with LIBC_LOCALE.

Assisted-by: Claude Code:claude-opus-5-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
…programs.

stdio.h included nuttx/fs/fs.h and nuttx/lib/lib.h, so every program
that includes stdio.h saw the kernel's struct file, struct inode and the
other file system types.  A program that defines its own struct file
does not compile.

In the user space of a kernel build (CONFIG_BUILD_KERNEL and not
__KERNEL__) programs cannot use those types anyway, so stdio.h no longer
includes the two headers there.  Kernel code and flat and protected
builds still get them, unchanged: doing that for every build breaks many
files that rely on the indirect includes.

stdio.h itself needs only the FILE type name, the fopencookie() callback
types and lib_get_stream(), which stdin, stdout and stderr expand to.
FILE is declared as an incomplete type, stdio.h declares
lib_get_stream(), and the cookie types move from fs.h to a new
nuttx/fs/cookie.h that both stdio.h and fs.h include.

The libc files that are built for user space and used kernel types or
other headers through stdio.h now include what they use.

Assisted-by: Claude Code:claude-opus-5-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
Comment thread include/nuttx/fs/cookie.h
* of a kernel build must not see the rest of nuttx/fs/fs.h.
*/

typedef CODE ssize_t cookie_read_function_t(FAR void *cookie, FAR char *buf,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's better to move cookie_io_functions_t and struct file_struct to stdio.h and struct streamlist to include/nuttx/tls_task.h.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done for struct file_struct and struct streamlist: both are now in nuttx/tls.h with the stream flags (I think you meant tls.h, next to ta_streamlist), and fs.h no longer has them. I also tried moving cookie_io_functions_t and its callback types to stdio.h, but that does not build: for kernel code and flat builds, stdio.h includes nuttx/lib/lib.h, which reaches nuttx/tls.h (lib.h → kmalloc.h → sched.h → tls.h) before stdio.h can define the types, and struct file_struct needs them. So they stay in the small nuttx/fs/cookie.h that both stdio.h and tls.h include. FILE stays an incomplete type in stdio.h.

Comment thread include/stdio.h

/* The standard streams, see stdin, stdout and stderr above */

FAR FILE *lib_get_stream(int fd);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why add?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stdin, stdout and stderr expand to lib_get_stream(), which is declared in nuttx/lib/lib.h. stdio.h no longer includes that header for the programs of a kernel build, so it declares the function itself.

A file that is included in an initializer provides the data of the
initializer, as in lib_iconv.c and syscall_names.c.  It cannot move to
the Included Files section, so nxstyle no longer warns about it.  A
change to such a file then passes the check.

Assisted-by: Claude Code:claude-opus-5-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
struct file_struct and struct streamlist are the stream state of a task
and have nothing to do with the file system: move them, with the
__FS_FLAG_* stream flags, from nuttx/fs/fs.h to nuttx/tls.h, where
struct task_info_s holds the stream list.  nuttx/fs/fs.h no longer
needs nuttx/fs/cookie.h.  FILE stays an incomplete type in stdio.h.

The libc files that use the stream fields include nuttx/tls.h, most of
them through libc.h.

Assisted-by: Claude Code:claude-opus-5-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: File System File System issues Area: OS Components OS Components issues Size: M The size of the change in this PR is medium

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants