Introduction
As I wrote in my book Why Learn C, §18.7, Warnings:
The best way to avoid debugging is not to put bugs into your programs in the first place. By default, most compilers automatically give some warnings, but not all. By enabling more warnings, the compiler can help you catch bugs before committing your code.
Hence, in your configure.ac file, you should make your project’s CFLAGS variable (e.g., CDECL_CFLAGS for cdecl) to include warning compiler options. The problem is that different compilers (or different versions of the same compiler) accept different subsets of warnings, or similar warnings with different names.  If you want your programs to be portable by being able to be compiled using different compilers (e.g., clang, gcc, xlc), you have to include the union of all the compilers’ warnings and probe the compiler you’re actually compiling with to see which warnings it understands.
  
  
  AX_CHECK_COMPILE_FLAG
The Autoconf Archive contains the AX_CHECK_COMPILE_FLAG macro that can check to see if the compiler accepts a given option:
AC_SUBST([CDECL_CFLAGS])
AX_CHECK_COMPILE_FLAG(
  [-Wcast-align],
  [CDECL_CFLAGS="$CDECL_CFLAGS -Wcast-align"]
)
AC_SUBST is needed to mark CDECL_FLAGS as a variable to be substituted in makefiles.  (Just go with it.)
AX_CHECK_COMPILE_FLAG’s first argument is just what to print following checking whether the C compiler accepts.... The next argument is what to do if it is.  In this case, it simply appends the option to CDECL_CFLAGS.
While that works, it’s a little bit verbose to have to specify both the option and the variable twice.  From a previous article, we can write another macro:
# serial 1
AC_DEFUN([MY_CHECK_COMPILE_FLAG], [
  AX_CHECK_COMPILE_FLAG([$1], [$2="$[$2] $1"])
])
Given that in m4/my_check_compile_flag.m4, you can now use it in configure.ac:
MY_CHECK_COMPILE_FLAG([-Wcast-align], [CDECL_CFLAGS])
Better.  Now just repeat that for every warning you want to enable (if the compiler supports it).  For example, here’s the complete set of warnings enabled for cdecl:
MY_CHECK_COMPILE_FLAG([-Wcast-align], [CDECL_CFLAGS])
MY_CHECK_COMPILE_FLAG([-Wcast-function-type], [CDECL_CFLAGS])
MY_CHECK_COMPILE_FLAG([-Wcomma], [CDECL_CFLAGS])
MY_CHECK_COMPILE_FLAG([-Wconditional-type-mismatch], [CDECL_CFLAGS])
MY_CHECK_COMPILE_FLAG([-Wconditional-uninitialized], [CDECL_CFLAGS])
MY_CHECK_COMPILE_FLAG([-Wconversion], [CDECL_CFLAGS])
MY_CHECK_COMPILE_FLAG([-Wduplicate-enum], [CDECL_CFLAGS])
MY_CHECK_COMPILE_FLAG([-Wembedded-directive], [CDECL_CFLAGS])
MY_CHECK_COMPILE_FLAG([-Wenum-enum-conversion], [CDECL_CFLAGS])
MY_CHECK_COMPILE_FLAG([-Wenum-float-conversion], [CDECL_CFLAGS])
MY_CHECK_COMPILE_FLAG([-Wextra], [CDECL_CFLAGS])
MY_CHECK_COMPILE_FLAG([-Wfloat-equal], [CDECL_CFLAGS])
MY_CHECK_COMPILE_FLAG([-Wfor-loop-analysis], [CDECL_CFLAGS])
MY_CHECK_COMPILE_FLAG([-Wformat-nonliteral], [CDECL_CFLAGS])
MY_CHECK_COMPILE_FLAG([-Wformat-signedness], [CDECL_CFLAGS])
MY_CHECK_COMPILE_FLAG([-Wformat-type-confusion], [CDECL_CFLAGS])
MY_CHECK_COMPILE_FLAG([-Wformat=2], [CDECL_CFLAGS])
MY_CHECK_COMPILE_FLAG([-Widiomatic-parentheses], [CDECL_CFLAGS])
MY_CHECK_COMPILE_FLAG([-Wimplicit-fallthrough], [CDECL_CFLAGS])
MY_CHECK_COMPILE_FLAG([-Wlogical-op-parentheses], [CDECL_CFLAGS])
MY_CHECK_COMPILE_FLAG([-Wmisleading-indentation], [CDECL_CFLAGS])
MY_CHECK_COMPILE_FLAG([-Wnewline-eof], [CDECL_CFLAGS])
MY_CHECK_COMPILE_FLAG([-Wno-unknown-pragmas], [CDECL_CFLAGS])
MY_CHECK_COMPILE_FLAG([-Wredundant-decls], [CDECL_CFLAGS])
MY_CHECK_COMPILE_FLAG([-Wreserved-identifier], [CDECL_CFLAGS])
MY_CHECK_COMPILE_FLAG([-Wshadow], [CDECL_CFLAGS])
MY_CHECK_COMPILE_FLAG([-Wshift-sign-overflow], [CDECL_CFLAGS])
MY_CHECK_COMPILE_FLAG([-Wshorten-64-to-32], [CDECL_CFLAGS])
MY_CHECK_COMPILE_FLAG([-Wsign-compare], [CDECL_CFLAGS])
MY_CHECK_COMPILE_FLAG([-Wsign-conversion], [CDECL_CFLAGS])
MY_CHECK_COMPILE_FLAG([-Wsometimes-uninitialized], [CDECL_CFLAGS])
MY_CHECK_COMPILE_FLAG([-Wstring-conversion], [CDECL_CFLAGS])
MY_CHECK_COMPILE_FLAG([-Wtautological-compare], [CDECL_CFLAGS])
MY_CHECK_COMPILE_FLAG([-Wtautological-type-limit-compare], [CDECL_CFLAGS])
MY_CHECK_COMPILE_FLAG([-Wuninitialized], [CDECL_CFLAGS])
MY_CHECK_COMPILE_FLAG([-Wunreachable-code], [CDECL_CFLAGS])
MY_CHECK_COMPILE_FLAG([-Wunreachable-code-return], [CDECL_CFLAGS])
MY_CHECK_COMPILE_FLAG([-Wunused], [CDECL_CFLAGS])
MY_CHECK_COMPILE_FLAG([-Wwrite-strings], [CDECL_CFLAGS])
  
  
  Side Note on CFLAGS
The reason for using a separate variable like CDECL_CFLAGS to contain compiler options for your project rather than using the conventional plain CFLAGS is because you don’t want to enable additional warnings when compiling code from Gnulib.  Why not?  While the Gnulib code is of high quality, it’s not necessarily warning-free, and you don’t want to get lots of warnings for third-party code.
Hence, use a separate variable like CDECL_CFLAGS.  In src/Makefile.am, then you set the CFLAGS to be used to your customized CFLAGS so only your code is compiled with them:
# src/Makefile.am
bin_PROGRAMS =  cdecl
AM_CFLAGS =     $(CDECL_CFLAGS)
# ...
Conclusion
You should enlist the compiler’s help to keep bugs out of your programs by enabling warnings.  Use the above example as a starting point.  Have a look through the complete set of warnings for gcc and clang for more.
There are more parts to come!
 

 
    
Top comments (0)