Better GCC debugging flags with autoconf

A little write-up as a memorandum for future projects.

I read Chris Wellons' article on development flags some time ago and I discovered some fun stuff that I did not know about.

I've since incorporated some of the ideas explained therein, and as I use Autoconf for larger projects naturally I add those flags through it.

Unfortunately Autoconf requires non-trivial definitions to enable some of them, so this page was written with the goal of being easier to access common copy-pastable snippets instead of searching other projects all the time.

First, AC_PROG_CC automatically adds -g -O2 but all we need is just -g3. The following m4 macro will remove all text matching a regexp from the value of a variable; it's meant to be used with CFLAGS so that -g3 can be added like a normal assignment.

AC_DEFUN([AX_VAR_PATDEL],
  [AS_VAR_COPY([workvar], [$1])
   workvar=`printf "%s\n" "$workvar" | sed "s/$2//g"`
   AS_VAR_COPY([$1], [workvar])
   AS_UNSET([workvar])])
	  

To remove the default flags mentioned above just write it as AX_VAR_PATDEL([CFLAGS], [\(-g\|-O2\)]).

To add the sanitizers we must first check if the compiler supports the given type. While as time passes this check will thankfully become obsolete, the time until then might be longer than we'd like to; thus, people might still find themselves with versions missing one or more sanitizer.

The following macro will try compiling a test program with the flag to test and execute the second or third parameter as appropriate.

AC_DEFUN([AX_CHECK_COMPILER_FLAG],
 [AS_VAR_SET([supported_flag], [no])
  AS_VAR_COPY([old_cflags], [CFLAGS])
dnl
  CFLAGS="$CFLAGS -Werror $1"
dnl
  AC_MSG_CHECKING([if compiler supports $1])
  AC_LINK_IFELSE([AC_LANG_SOURCE([int main() { return 0; }])],
    [AS_VAR_SET([supported_flag], [yes])],
    [AS_VAR_SET([supported_flag], [no])])
  AC_MSG_RESULT([$supported_flag])
dnl
  AS_VAR_SET([CFLAGS], [$old_cflags])
  AS_UNSET([old_cflags])
dnl
  AS_IF([test "x$supported_flag" = "xyes"],
    [m4_if([$2], ,:,[$2])],
    [m4_if([$3], ,:,[$3])])
dnl
  AS_UNSET([$supported_flag])])
	  

Then just test the compiler like so: AX_CHECK_COMPILER_FLAG([-fsanitize=address], [CFLAGS="$CFLAGS -fsanitize=address"]).

Lastly, since I also use Flymake it's a good idea to add flags enabling static checks to the check-syntax command in Automake:

.PHONY: check-syntax
check-syntax:
     $(AM_V_CC)$(COMPILE) -Wall -Wextra -Wno-unused-parameter -Wno-unused-function -Wdouble-promotion -Wconversion -Wno-sign-conversion -fsyntax-only $(CHK_SOURCES)
	  

There are still some details to iron out, for example it might be more convenient to allow testing multiple compiler flags at once, and everything is very GCC/clang specific so it's useless when using cl as in Wellons' article or some more obscure compiler, but overall it reaches the goal of giving better debugging.