Hello, A correction to my numbers: I counted only include/. The headers in arch/*/include and in the boards' include/ directories follow the same template, and the public headers include some of them (arch/irq.h, arch/arch.h, arch/syscall.h, arch/setjmp.h), so they also undefine a program's EXTERN.
With them, on master: - 1344 headers define EXTERN (540 in include/, 280 in arch/, 524 in boards/). - 38 use it, for about 70 declarations (20 in include/, 16 in arch/, mostly irq.h, and 2 in boards/). - The other 1306 never use it. The proposal is the same: step 1 removes the unused definitions from all 1306 headers, step 2 changes the 38 that use the macro. As before, all their declarations are inside the extern "C" block of their header. Regards, Marco Casaroli On Tue, Oct 27, 2026 at 11: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
