GNU autotools: Debug/Release targets?
Asked Answered
L

4

85

I've been looking for this for a while: I'm currently converting a medium-size program to autotools, coming from an Eclipse-based method (with makefiles)

I'm always used to having a "debug" build, with all debug symbols and no optimizations, and a "release" build, without debug symbols and best optimizations.

Now I'm trying to replicate this in some way with autotools, so I can (perhaps) do something like:

./configure
make debug

Which would have all debug symbols and no optimizations, and where:

./configure
make

Would result in the "release" version (default)

PS: I've read about the --enable-debug flag/feature, but in my current (simple) setup, using that is unrecognized by configure

Lightsome answered 29/12, 2010 at 11:37 Comment(1)
Please change the accepted answer from ismall's to William Pursell's. The accepted answer is incorrect.Barratry
C
18

Add a clause to your configure.in or configure.ac file;

AC_ARG_ENABLE(debug,
AS_HELP_STRING([--enable-debug],
               [enable debugging, default: no]),
[case "${enableval}" in
             yes) debug=true ;;
             no)  debug=false ;;
             *)   AC_MSG_ERROR([bad value ${enableval} for --enable-debug]) ;;
esac],
[debug=false])

AM_CONDITIONAL(DEBUG, test x"$debug" = x"true")

Now in your Makefile.inor Makefile.am;

if DEBUG
AM_CFLAGS = -g3 -O0
AM_CXXFLAGS = -g3 -O0
else
AM_CFLAGS = -O2
AM_CXXFLAGS = -O2
endif

So when debugis enabled you can modify your {C/CXX}FLAGSto enable debug information.

Calesta answered 29/12, 2010 at 11:46 Comment(25)
I've applied the example you gave to the amhello test program to check, however, this fails with ./configure: line 3356: syntax error near unexpected token as_fn_append'` followed by as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'. NOTE I do use AM_CFLAGS because setting CFLAGS directly would seem to override other previous settings (I think) and using CFLAGS directly seems to fail also: CFLAGS was already defined in condition TRUE, which includes condition DEBUG ...Lightsome
Updated configure part, please recheck.Calesta
I also saw the update, however I found what was wrong and it's purely my mistake: Not copy-pasting it (because of indenting issues in your first answer and the AM_C(XX)FLAGS issue), I mistyped and ended up with "${enableval"}, so in the end the answer seems to work just as intended, thanks!Lightsome
Awesome the new version is better anyway :-)Calesta
Maybe a last comment: Shouldn't the AM_CONDITIONAL(DEBUG, test x"$debug" = "xtrue") be AM_CONDITIONAL(DEBUG, test x"$debug" = x"true")? (Currently not using quotes myself though)Lightsome
-1 This is a horrible solution, totally in opposition to the philosophy of the autotools. More description in answer given below.Trauma
Let me clarify more why this is a bad solution. What happens when the user runs 'configure CFLAGS=-O1 && make'? The compiler will be invoked with "-O1 -O2". Which level of optimization will be set? The user explicitly asked for -O1, but you'll have to check the documentation to figure out what the compiler actually did.Trauma
@William Pursell, that can be fixed by overriding CFLAGS with the user supplied one. Solution still stands.Calesta
@Ismail No, it cannot. both AM_CFLAGS and CFLAGS will be present at compile time. If you add -O2 to AM_CFLAGS and the user adds -O1 to CFLAGS, then both will be passed to the compiler.Trauma
@William Pursell, before giving a -1 you should learn that gcc -O2 -O1 will use -O1 not -O2!Calesta
@Ismail my point is that your solution will cause both flags to be passed to the compiler. Your claim that gcc will use -O1 if both -O1 and -O2 are passed is totally irrelevant if the user is using a different compiler. What is wrong with your solution is that you are making assumptions about the user's environment instead of letting the user drive the build, and that is totally in conflict with the philosophy of the autotools.Trauma
@William Pursell, this is still not true, all compilers will respect the last optimization setting because they want it to be overridden if required.Calesta
@Ismail how can you make a claim about the behavior of all compilers? Do all compilers recognize '-g3'? There are a lot of compilers out there. However, that is not the point. The point is that the package maintainer should not make such assumptions about the user's environment. Those decisions should be left to the user.Trauma
@William Pursell, you have come up with a non-issue, I compiled thousands of different packages and most will do debug like this.Calesta
@Calesta -- I just found a compiler on my machine that aborts if both -O1 and -O2 are passed on the command line. If you can modify your solution so that the user has a method to ensure that none of the flags you are specifying in AM_CFLAGS are passed to the compiler (without modifying Makefile.am or a Makefile), I will gladly remove my downvote. But this is NOT a non-issue. This is a core issue which plagues the autotools. Packages are built that ignore the philosophy of the tool chain and the results are packages that don't build as expected.Trauma
@William Pursell, ok will check. No go away, seriously :)Calesta
@Calesta I'm not trying to be aggravating, just trying to point out what I believe to be a substantial flaw. There is actually an even bigger problem with your solution. Namely, the compiler will be invoked with $(AM_CFLAGS) $(CFLAGS). If the user doesn't specify CFLAGS, then CFLAGS will default to "-g -O2" and the "debug code" will be compiled with "-g3 -O0 ... -g -O2" and -O2 optimizations will be applied.Trauma
--enable-debug should be used only to enable conditional debugging code, like assertions. The common sense there is to use its absence to define NDEBUG, and nothing more.Leech
@WilliamPursell this approach could still be useful if there are compiler options some code requires to build - like code which breaks if it does not get tail call optimization. For an example of that, see Tail Call Optimization (TCO), dependency, broken debug builds in C and C++ — and gcc 4.8.Papen
@Arne I believe that is a significantly different scenario. One significant problem with this approach is that it assumes the compiler will be able to handle flags -O2 ... -O0 rationally. This could be fixed with a configure time check. Similarly, if your code requires specific options, you need to add a configure time check that the options you add to AM_CFLAGS are recognized by the compiler and do what you want them to do.Trauma
@WilliamPursell do you have a link with descriptions for these checks? I think such a link would be very useful to readers here (if only to show the real complexity of the approach - when it is done right). Essentially what I see is that this solution makes it easy for the majority of users to enable debug in the build, while your solution likely works in almost all situation, but the majority of users will give up when reading the instructions. Nowadays most users do not know their toolchain.Papen
@Arne, sadly I agree that most users do not know their toolchain. One of the assumptions behind the autotools was the existence of informed users, and perhaps that is a fundamental flaw.Trauma
@WilliamPursell Possibly: Getting informed became harder and harder as the toolchain to use got bigger and bigger: Nowadays to solve a task you often have to chain together lots of libraries and libraries calling libraries, so most people only have superfluous knowledge of most of their tools. Essentially that means, that every tool which wants many users has to be usable as blackbox with a minimum of necessary input, and it must be possible to move gradually from blackbox-usage to more complex usecases. Otherwise the number of informed users will be very small.Papen
@Arne, I just re-read your comment above, and must take exception with the statement 'this solution makes it easy for the majority of users to enable debug'. If implemented, this solution will pass -g3 -O0 -g -O2 to the compiler when the user specifies --enable-debug. With gcc, that gives exactly the wrong behavior; with other compilers the build will fail. That is a non-trivial failing of this solution.Trauma
@WilliamPursell: You’re right… to make this work, it’s actually required to also add the AM_CFLAGS explicitly to the target CFLAGS in the Makefile: prog2_CFLAGS = $(LIBFOOCFLAGS) $(AM_CFLAGS)Papen
T
181

ismail's solution is a common approach, but it suffers from some serious problems. If the user tries to get a debug build by doing './configure --enable-debug', the configure script will set CFLAGS to '-g -O2' and the Makefile will use '-g3 -O0 ... -g -O2' when building any executables. In that case, gcc will use -O2, and some compilers will abort because of the conflicting -O options. Either scenario is not the expected behavior.

Building with debug symbols or not is NOT something the project maintainer should worry about at all. This is an issue for the user. If you are building a project and you want to make a debug build or a release build, you should use different options at configure time. For example,

$ mkdir debug
$ mkdir release
$ cd debug && /path/to/configure --prefix=/dbg \
   CPPFLAGS=-DDEBUG CFLAGS="-g -O0" && make && make install
$ cd ../release && /path/to/configure CPPFLAGS=-DNDEBUG && make && make install

This will install a build with `-DDEBUG' and '-g -O0' (a "debug build") in /dbg/bin and a 'release' install in /usr/local/bin

You can reduce the tedium of the necessary typing by using a CONFIG_SITE file. For example, you can do:

echo 'CPPFLAGS=-DDEBUG CFLAGS="-g -O0"' >> /dbg/share/config.site

and then all future invocations of 'configure --prefix=/dbg' will automatically inherit the settings to CPPFLAGS and CFLAGS without needing to be specified on the command line.

If, as the package maintainer, you want to provide the user with an easy way to build a "debug release", it is perfectly acceptable to include a script in the distribution that invokes the configure script with the appropriate arguments and invokes make && make install, but there is absolutely no need to litter your autotool metafiles with such cruft. It simply does not belong there. And be warned, many packages have made attempts to add --enable-debug which are simply wrong. If the user invokes configure CFLAGS="-g -O0" but gets a build that applies unexpected flags then you have a bug and your package is broken. This is an all too common experience, and if you maintain a package (currently thinking about tmux and curl) in which the user does not get what any reasonable person would call a "debug build" after invoking configure CFLAGS="-g -O0", then your package is broken.

An important point that must always be remembered when maintaining a package with the autotools is that the user may be using a completely different tool chain than you are. It is entirely possible that the user's tool chain will require -DMAKE_IT_A_DEBUG or -DUSE_DEBUG or -I/non/standard/path/to/headers. Perhaps it will need -O145 or -Q passed to the compiler or -debug passed to the linker, or ... anything. As the maintainer, you simply do not have the information necessary to even make the phrase "debug build" meaningful for all users. So don't try, because you might make the software unbuildable for a certain set of users.

Trauma answered 13/1, 2011 at 13:31 Comment(8)
@Honza More details are necessary to debug your issue. If $prefix/share/config.site exists and CONFIG_SITE is not set in the environment of the process running the configure script (and if the configure script is generated by autoconf), it should be read. Search for config.site in the configure script.Trauma
I tried CPPFLAGS=-DDEBUG CXXFLAGS="-g -O0" && make && make install but it seemed to ignore the flags. I had to do make CPPFLAGS=-DDEBUG CXXFLAGS="-g -O0" instead.Paddy
@Craig You didn't run configure. You need: CPPFLAGS=-DDEBUG ./configure && make ...Trauma
Oh I see -- I missed the fact that they're actually tacked on to the end of the configure command on the previous line.Paddy
If possible, use -ggdb for maximum debugging.Swithin
Note that CFLAGS must be used when compiling C binary, and CXXFLAGS must be used when compiling C++ binary.Metry
That's good and all, but this method makes it impossible to implement debug-specific targets. ismail's answer works well for that.Paragon
Ismail's solution is completely broken. In that scenario, configure --enable-debug invokes the compiler with -O0 ... -O2, which is broken even in the most common case.Trauma
C
18

Add a clause to your configure.in or configure.ac file;

AC_ARG_ENABLE(debug,
AS_HELP_STRING([--enable-debug],
               [enable debugging, default: no]),
[case "${enableval}" in
             yes) debug=true ;;
             no)  debug=false ;;
             *)   AC_MSG_ERROR([bad value ${enableval} for --enable-debug]) ;;
esac],
[debug=false])

AM_CONDITIONAL(DEBUG, test x"$debug" = x"true")

Now in your Makefile.inor Makefile.am;

if DEBUG
AM_CFLAGS = -g3 -O0
AM_CXXFLAGS = -g3 -O0
else
AM_CFLAGS = -O2
AM_CXXFLAGS = -O2
endif

So when debugis enabled you can modify your {C/CXX}FLAGSto enable debug information.

Calesta answered 29/12, 2010 at 11:46 Comment(25)
I've applied the example you gave to the amhello test program to check, however, this fails with ./configure: line 3356: syntax error near unexpected token as_fn_append'` followed by as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'. NOTE I do use AM_CFLAGS because setting CFLAGS directly would seem to override other previous settings (I think) and using CFLAGS directly seems to fail also: CFLAGS was already defined in condition TRUE, which includes condition DEBUG ...Lightsome
Updated configure part, please recheck.Calesta
I also saw the update, however I found what was wrong and it's purely my mistake: Not copy-pasting it (because of indenting issues in your first answer and the AM_C(XX)FLAGS issue), I mistyped and ended up with "${enableval"}, so in the end the answer seems to work just as intended, thanks!Lightsome
Awesome the new version is better anyway :-)Calesta
Maybe a last comment: Shouldn't the AM_CONDITIONAL(DEBUG, test x"$debug" = "xtrue") be AM_CONDITIONAL(DEBUG, test x"$debug" = x"true")? (Currently not using quotes myself though)Lightsome
-1 This is a horrible solution, totally in opposition to the philosophy of the autotools. More description in answer given below.Trauma
Let me clarify more why this is a bad solution. What happens when the user runs 'configure CFLAGS=-O1 && make'? The compiler will be invoked with "-O1 -O2". Which level of optimization will be set? The user explicitly asked for -O1, but you'll have to check the documentation to figure out what the compiler actually did.Trauma
@William Pursell, that can be fixed by overriding CFLAGS with the user supplied one. Solution still stands.Calesta
@Ismail No, it cannot. both AM_CFLAGS and CFLAGS will be present at compile time. If you add -O2 to AM_CFLAGS and the user adds -O1 to CFLAGS, then both will be passed to the compiler.Trauma
@William Pursell, before giving a -1 you should learn that gcc -O2 -O1 will use -O1 not -O2!Calesta
@Ismail my point is that your solution will cause both flags to be passed to the compiler. Your claim that gcc will use -O1 if both -O1 and -O2 are passed is totally irrelevant if the user is using a different compiler. What is wrong with your solution is that you are making assumptions about the user's environment instead of letting the user drive the build, and that is totally in conflict with the philosophy of the autotools.Trauma
@William Pursell, this is still not true, all compilers will respect the last optimization setting because they want it to be overridden if required.Calesta
@Ismail how can you make a claim about the behavior of all compilers? Do all compilers recognize '-g3'? There are a lot of compilers out there. However, that is not the point. The point is that the package maintainer should not make such assumptions about the user's environment. Those decisions should be left to the user.Trauma
@William Pursell, you have come up with a non-issue, I compiled thousands of different packages and most will do debug like this.Calesta
@Calesta -- I just found a compiler on my machine that aborts if both -O1 and -O2 are passed on the command line. If you can modify your solution so that the user has a method to ensure that none of the flags you are specifying in AM_CFLAGS are passed to the compiler (without modifying Makefile.am or a Makefile), I will gladly remove my downvote. But this is NOT a non-issue. This is a core issue which plagues the autotools. Packages are built that ignore the philosophy of the tool chain and the results are packages that don't build as expected.Trauma
@William Pursell, ok will check. No go away, seriously :)Calesta
@Calesta I'm not trying to be aggravating, just trying to point out what I believe to be a substantial flaw. There is actually an even bigger problem with your solution. Namely, the compiler will be invoked with $(AM_CFLAGS) $(CFLAGS). If the user doesn't specify CFLAGS, then CFLAGS will default to "-g -O2" and the "debug code" will be compiled with "-g3 -O0 ... -g -O2" and -O2 optimizations will be applied.Trauma
--enable-debug should be used only to enable conditional debugging code, like assertions. The common sense there is to use its absence to define NDEBUG, and nothing more.Leech
@WilliamPursell this approach could still be useful if there are compiler options some code requires to build - like code which breaks if it does not get tail call optimization. For an example of that, see Tail Call Optimization (TCO), dependency, broken debug builds in C and C++ — and gcc 4.8.Papen
@Arne I believe that is a significantly different scenario. One significant problem with this approach is that it assumes the compiler will be able to handle flags -O2 ... -O0 rationally. This could be fixed with a configure time check. Similarly, if your code requires specific options, you need to add a configure time check that the options you add to AM_CFLAGS are recognized by the compiler and do what you want them to do.Trauma
@WilliamPursell do you have a link with descriptions for these checks? I think such a link would be very useful to readers here (if only to show the real complexity of the approach - when it is done right). Essentially what I see is that this solution makes it easy for the majority of users to enable debug in the build, while your solution likely works in almost all situation, but the majority of users will give up when reading the instructions. Nowadays most users do not know their toolchain.Papen
@Arne, sadly I agree that most users do not know their toolchain. One of the assumptions behind the autotools was the existence of informed users, and perhaps that is a fundamental flaw.Trauma
@WilliamPursell Possibly: Getting informed became harder and harder as the toolchain to use got bigger and bigger: Nowadays to solve a task you often have to chain together lots of libraries and libraries calling libraries, so most people only have superfluous knowledge of most of their tools. Essentially that means, that every tool which wants many users has to be usable as blackbox with a minimum of necessary input, and it must be possible to move gradually from blackbox-usage to more complex usecases. Otherwise the number of informed users will be very small.Papen
@Arne, I just re-read your comment above, and must take exception with the statement 'this solution makes it easy for the majority of users to enable debug'. If implemented, this solution will pass -g3 -O0 -g -O2 to the compiler when the user specifies --enable-debug. With gcc, that gives exactly the wrong behavior; with other compilers the build will fail. That is a non-trivial failing of this solution.Trauma
@WilliamPursell: You’re right… to make this work, it’s actually required to also add the AM_CFLAGS explicitly to the target CFLAGS in the Makefile: prog2_CFLAGS = $(LIBFOOCFLAGS) $(AM_CFLAGS)Papen
J
8

The default Makefile created with autotools produces binaries with debug symbos. Use make install-strip to produce a release target.

Jehol answered 4/1, 2012 at 12:13 Comment(1)
Even if a binary contains debug symbols, it usually is built with the -O2 as well.Abyssinia
C
4

Another example to configure CFLAGS/CXXFLAGS without editing Makefile.in or Makefile.am. Add this code to your configure.in or configure.ac file:

test -z "$SED" && SED=sed

AC_ARG_ENABLE([debug],
  [AS_HELP_STRING([--enable-debug],
                  [whether to include debug symbols (default is no)])],
  [enable_debug=$enableval],
  [enable_debug=no]
)

if test "x$enable_debug" = xyes; then
  dnl Remove all optimization flags from CFLAGS
  changequote({,})
  CFLAGS=`echo "$CFLAGS" | $SED -e 's/-O[0-9s]*//g'`
  CXXFLAGS=`echo "$CXXFLAGS" | $SED -e 's/-O[0-9s]*//g'`

  CFLAGS=`echo "$CFLAGS" | $SED -e 's/-g[0-9]*//g'`
  CXXFLAGS=`echo "$CXXFLAGS" | $SED -e 's/-g[0-9]*//g'`
  changequote([,])

  CFLAGS="$CFLAGS -g -O0"
  CXXFLAGS="$CXXFLAGS -g -O0"
fi

echo "CFLAGS=$CFLAGS"

Test it:

$ ./configure --enable-debug | grep CFLAGS
Crissycrist answered 14/11, 2017 at 7:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.