The approach you suggest would not work with cross-compilation, right? So it
might be better to use the output of $CPP to generate a .c file that could be
compiled and not run, that would check that the compiler options were consistent
with the preprocessor options.
Probably we need to draw a line between
- macros that often change the result of $CPP output
(e.g. -D and -I options, but also -m32/-m64)
- macros that rarely change the result of $CPP output because they are just
witness macros of optimization options (e.g. __OPTIMIZE__).
In that case, the issue boils down to: what is the safe set of options that
builders can put into CFLAGS instead of CPPFLAGS+LDFLAGS (or CC)? Clearly
options like -D and -I are unsafe, and it seems we agree that -O and
-fsanitize=address are safe. However, we disagree whether -m32 and -m64 are safe.
The list of safe options would be ad-hoc, whatever it is. For example, the
following GCC options can all affect the preprocessor; which should be
considered safe and why?
-pthread -ffast-math -fnext-runtime -fno-exceptions -fno-inline
-fno-math-errno -fstack-protector -funsigned-char -mbig-endian -melf -mwin32
-pedantic -std
My impression is that builders mentally put options like these into CFLAGS and
not CPPFLAGS because they think of them as compiler not preprocessor options. So
I would consider all these options to be safe (along with -m32 and -m64 and
-fsanitize). Presumably you would consider some to be safe and some unsafe, but
what rule would you suggest to distinguish safe from unsafe options? Whatever
the rule is, it should be simple and easy to remember.
The rule I am thinking of is, "If the option is clearly intended for the
preprocessor, it's unsafe. Otherwise it's safe." So, for example, -D, -U, and -I
are unsafe, whereas the options mentioned above are safe. This rule is simple
and easy to remember. I realize it can lead to slower 'configure' scripts, but
in practice they're not so much slower as to be worth the cost of error-prone
configuration.