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

Reply via email to