Best practices for CFLAGS handling in configure scripts?
Asked Answered
Z

2

18

I'm not a fan of autoconf, but in the interest of principle of least surprise, I'm trying to make my (non-autoconf) configure scripts behave as closely as possible to what users expect from an autoconf-based build system. The GNU coding standards are actually rather reasonable on this topic, and explicitly mention the possibility of not using autoconf/automake but providing a compatible interface in another way:

https://www.gnu.org/prep/standards/standards.html#Configuration

One issue I cannot find any good description of, however, is how to best handle CFLAGS. It's clear to me that any essential flags (like -I$(srcdir)/inc) that are none of the user's business don't belong in CFLAGS in either the configure script or the makefile, as overriding them would completely break the build. So these I've either hard-coded in the makefile, or (if they require some detection) put the detection logic in configure, but passed them through a separate make variable instead of CFLAGS so they won't get overridden.

What I'm still unclear on how to handle best, though, is optional things like optimization levels/options, warning flags, debugging, etc. Should flags enabled by things like --enable-debug or --enable-warnings get added to CFLAGS or passed in some other make variable? What if they conflict with flags already in user-provided CFLAGS?

I can see where for a lot of projects the answer might should just be "don't mess with that at all and let the user choose their CFLAGS", but some of my usage cases are projects where the user base is generally interested in having out-of-the-box optimized and debugging configurations.

Edit: Another issue I forgot: when it comes to detecting and automatically using certain CFLAGS that aren't essential but preferred, should this be done only if the user left CFLAGS blank in the environment, or always?

Zerk answered 1/5, 2012 at 21:38 Comment(1)
-I options never belong in CFLAGS of any kind. Options to the preprocessor belong in CPPFLAGS.Clinkscales
C
8

If you want to handle argument like --enable-warnings, you have a lot of work to do. If you want to keep it simple, you can have that argument add something like

CFLAGS="$CFLAGS -Wall -Wextra"; CPPFLAGS="$CPPFLAGS -DWARNINGS"

in your configure script, but this actually opens a big can of worms. Are those options recognized by all compilers, or are you assuming that your user is using a compiler which recognizes those options and for which they do what you want? Probably you need to wrap that assignment in another check for a set of compilers you know about. Or you need to put in a check that the compiler being used by the user at least doesn't error out when passed those flags (perhaps the user has already set -Wsome in CFLAGS, and the compiler will error out with the conflicting argument -Wall.) The same problems apply to --enable-debug. It seems perfectly reasonable to respond to --enable-debug by appending -DEBUG to CPPFLAGS, so the user does not need to examine your source to determine if debugging is enabled via -DEBUG rather than -DDEBUG, but you cannot predict all situations and it is generally best to err on the side of caution and not do such things.

If you want your users to have "out-of-the-box optimized and debugging configurations", the configure script for the project is the wrong place to do it. Keep the configury simple, and have you users use a package management system like pkgsrc for such things. If you want your distribution tarball to have some of that functionality, provide a set of scripts (perhaps invoked automagically by the configure script after detecting a platform, but provide the ability to override that feature) for common platforms that make assignments for the user and thus provide the desired functionality. But keep the configure script itself bare-bones.

Clinkscales answered 2/5, 2012 at 13:14 Comment(3)
I agree with your remarks about compiler compatibility; I test any such options to see that the compiler accepts them. -g is POSIX standard for debugging, and -On (although not the exact meaning of different values for n aside from zero vs nonzero) is too, so there's definitely some degree of this sort of thing you can do in a portable manner (aside from -D possibilities you already mentioned).Zerk
I'd disagree about forcing your users to go through extra hoops just to have sane options. Why not allow flexibility at the build level rather than adding an extra hoop? - it's not like the competence level of users running build scripts are particularly lowJerkwater
@mnunberg What is the definition of "sane"? The user can very easily have "sane" options (as defined by the user) inserted by default through the environment, or in wrapper scripts that they've written themselves. The problem is that what is "sane" for one person is not for someone else, and trying to guess can lead to build failures. Deciding for the user what is "sane" presumes the user's incompetence.Clinkscales
J
1

It would be sane enough to have the user expect to have to wrestle with things when providing custom flags. CFLAGS can be appended, CPPFLAGS can be prepended (header search paths options look at the first path, while compiler optimizations and directives look at the last options (or rather, they override prior options))

--enable-debug and perhaps other command-line directives provided to the configure script do not only have to change compiler options, but have the possibility of changing things within the source as well (maybe, for example, redefining inline macros to be actual functions), so their uses are somewhat different.

In conclusion, have user-specified CPPFLAGS prepended, user specified CFLAGS appended; any configure script option may be either appended or prepended depending on context.

Jerkwater answered 2/5, 2012 at 17:7 Comment(2)
Whether to prepend or append is a very good point (+1), and I think makes the case for not even trying. If the user specifies --enable-debug and puts "-O2" in CFLAGS, what should you do? If you append a -O0, you get '-O2 ... -O0' at the compile line. Some compilers will treat that as an error. Some compilers will treat it as -O0. Some presumably treat it as -O2 (I've encountered compilers that do each of the first 2 cases, but have never met one that does the latter. I'm sure such a thing exists.) Is it proper to append or prepend? I would argue that both are wrong.Clinkscales
+1 on that. I guess my revised logic would be that the *FLAGS environment variables constitute a "danger" zone of sorts. Common (sane.. and this means variable configurations which a user may wish to apply to the project.. which is project dependent) should be specified via command-line options. If there is some special requirement, a user can use the environment FLAGS variables at their own risk.Jerkwater

© 2022 - 2024 — McMap. All rights reserved.