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