On Tue, Oct 27, 2026 at 6:41 AM Marco C. <[email protected]> wrote:
> Hello,
>
> I would like to propose a change to the coding standard for global data
> declarations in header files.
>
> Today Documentation/contributing/coding_style.rst asks every header to
> define EXTERN at the start of its "Public Data" section:
>
> #ifdef __cplusplus
> #define EXTERN extern "C"
> extern "C"
> {
> #else
> #define EXTERN extern
> #endif
>
> and to "#undef EXTERN" at its end. Global data is then declared with
> "EXTERN int g_foo;".
>
> Some numbers from include/ on master:
>
> - 540 headers define EXTERN.
> - Only 20 of them use it, for about 50 declarations.
> - The other 520 define and undefine it and never use it.
>
> Until 2013 the headers also declared their functions with EXTERN; the
> 2014 coding standard then said that functions do not use it. The
> definition stayed in the template, so most headers still define a macro
> that nothing in them uses.
>
> There are two problems with the macro:
>
> 1. In our headers it adds nothing. All the declarations with EXTERN are
> inside the extern "C" block of the same header (I checked the 20
> headers), so for C++ "extern int g_foo;" has C linkage too, and plain
> "extern" gives the same result in C and C++. EXTERN is defined only as
> extern or extern "C", and no file uses it for another purpose. Its one
> use is as a safety net: a declaration put outside the extern "C" block
> by mistake would still get C linkage.
>
> 2. EXTERN is not a reserved name. A program can define its own EXTERN,
> and every system header that it includes after that removes the
> program's definition with "#undef EXTERN". For example, Tcl's tcl.h
> defines EXTERN, then tclInt.h includes system headers, and Tcl's own
> "EXTERN void TclAllocateFreeObjects(void);" no longer compiles.
>
> I propose two steps.
>
> 1. Remove the unused definitions from the 520 headers that never use
> EXTERN: the "#undef EXTERN", the two "#define EXTERN" lines and the
> "#else" that holds one of them. The extern "C" block for C++ stays,
> so the code that the compiler sees does not change. I have this
> change ready (517 headers; three are left out because their SPDX
> copyright lines do not pass nxstyle) and can send it as a PR.
>
> 2. Change the rule for the 20 headers that declare data and for new code.
> These include common headers: unistd.h (optarg, ...), time.h (tzname),
> netdb.h (h_errno), netinet/in.h (in6addr_any, ...). Two options:
>
> A. Plain "extern" inside the extern "C" block, as glibc, musl and the
> BSD headers do. The coding standard drops the EXTERN definition
> from the template.
>
> B. Keep the macro, under a reserved name: __EXTERN. Names that start
> with two underscores belong to the implementation, so no program
> can use them. The template keeps its form.
>
> Both work with every compiler that NuttX supports (GCC, clang, SDCC,
> ZDS-II, IAR, Green Hills, TASKING, MSVC): they are plain C and do not
> need #pragma push_macro. A is simpler; B is a smaller change of habits.
> In both cases I can make the change of the 20 headers and of
> coding_style.rst.
>
> Is step 1 welcome as a PR, and which option do you prefer for step 2?
>
> Regards,
> Marco Casaroli
>
This plan makes sense to me.
For step 2, I would use Option A to be consistent with the glibc, musl, and
BSD headers.
My .02
Thanks,
Nathan