Hi all, after all the time where we've all been complaining about the difficulty to adjust CFLAGS during the build, I could tackle the problem for a first step in the right direction.
First, let's start with a bit of history to explain the situation and why it was bad. Originally, a trivial makefile with very simple rules and a single object to build (haproxy.o) had just CFLAGS set to "-O2 -g" or something like that, and that was perfect. It was possible to just pass a different CFLAGS value on the "make" command line and be done with it. Options started to pile up, but in a way that remained manageable for a long time (e.g. add PCRE support, later dlmalloc), so CFLAGS was still the only thing to override if needed. With 32/64 bit variants and so on, we started to feel the need to split those CFLAGS into multiple pieces for more flexibility. But these pieces were still aggregated into CFLAGS so that those used to overriding it were still happy. This situation forced us not to break these precious CFLAGS that some users were relying on. And that went like this for a long time, though the definition of this CFLAGS variable became more and more complicated by inheriting from some automatic options. For example, in 3.0-dev7, CFLAGS is initialized to "$(ARCH_FLAGS) $(CPU_CFLAGS) $(DEBUG_CFLAGS) $(SPEC_CFLAGS)", i.e. it concatenates 4 variables (in apparence). The 4th one (SPEC_CFLAGS) is already a concatenation of a fixed one (WARN_CFLAGS) and a series of automatically detected ones (the rest of it). ARCH_FLAGS is set from a a fixed list of presets depending on the ARCH variable, and CPU_CFLAGS is set from a list of presets depending on the CPU variable. And the most beautiful is that CFLAGS alone is no longer sufficient since some of the USE_* options append their own values behind it, and we complete with $(TARGET_CFLAGS) $(SMALL_OPTS) $(DEFINE). Yeah I know that's ugly. We all know it. Whenever someone asks me "how can I enable -fsanitize=address because I'd like to run ASAN", I respond "hmmm it depends what options you already use and which ones area easiest to hack". Some distros simply found that stuffing their regular CFLAGS into DEBUG_CFLAGS or CPU_CFLAGS does the trick most of the time. Others use other combinations depending on the tricks they figured. After this analysis, I figured that we needed to simplify all this, get back to what is more natural to use or more commonly found, without breaking everything for everyone. What is certain however in the current situation, is that nobody is overriding CFLAGS since it's too rich, too complex and too unpredictable. So it was really time to reset it. Thus here's what was done: - CFLAGS is now empty by default and can be passed some build options that are appended at the end of the automatic flags. This means that -Os, -ggdb3, -Wfoobar, -Wno-foobar, -I../secret-place/include etc will properly be honored without having to trick anything anymore. Thus for package maintainers, building with CFLAGS="$DISTRO_CFLAGS" should just get the work done. - LDFLAGS is now empty by default and can be passed some build options that are prepended to the list of linker options. - ARCH_FLAGS now defaults to -g and is passed to both the compiler and the linker. It may be overridden to change the word size (-m32/-m64), enable alternate debugging formats (-ggdb3), enable LTO (-flto), ASAN (-fsanitize=address) etc. It's in fact for flags that must be consistent between the compiler and the linker. It was not renamed since it was already there and used quite a bit already. - CPU_CFLAGS was preserved for ease of porting but is empty by default. Some may find it convenient to pass their -march, -mtune etc there. - CPU and ARCH are gone. Let's face it, only 2 of them were usable and no single maintainer will be crazy enough to use these options here and resort to another approach for other archs. However the previous values are mentioned in the doc as a hint about what's known to work well. - OPT_CFLAGS was created with "-O2" and nothing else. As developers, we spend our time juggling between -O2 and -O0 depending on whether we're testing or debugging. Some embedded distros also have options to pass -O2 or -Os to choose between fast and small, and that may fit very well there. - STD_CFLAGS contains a few flags related to standards compliance. It is currently set to -fwrapv, -fno-strict-overflow and/or empty depending on what the compiler prefers. It's important not to touch it unless you know exactly what you're doing, and previously these options used to be lost by accident when overriding other ones. - WARN_CFLAGS is now set to the list of warnings to be enabled. It's discovered automatically but may be overridden without breaking the rest. - NOWARN_CFLAGS is now set to the list of warnings to be disabled. It's discovered automatically byt may also be overridden. - DEBUG_CFLAGS is gone. It used to only contain -g by default and was often abused as a way to pass CFLAGS. - ERROR_CFLAGS contains a synthetic list of -Werror and -Wfatal-errors depending on ERR and FAILFAST. It may easily be overridden if desired though I don't see much value in doing this. - the rest is unchanged for now. This means that now one can simply produce a smaller build this way: $ make -j$(nproc) TARGET=linux-glibc CFLAGS=-Os In practice it will emit "-O2 ... -Os" but that's fine and very common. A cleaner method if your build system already has this option alone is: $ make -j$(nproc) TARGET=linux-glibc OPT_CFLAGS=-Os Those who have a collection of flags to pass to gcc both at the compilation and linking stages can use ARCH_FLAGS: $ distro_flags="-Og -ggdb3 -flto" $ make -j$(nproc) TARGET=linux-glibc ARCH_FLAGS="$distro_flags" Those who build with an antique compiler and need to shut up some warnings will now have a better experience: $ make TARGET=linux-glibc CC=gcc-4.4 CFLAGS=-fno-strict-aliasing $ make TARGET=linux-glibc CC=gcc-4.2 WARN_CFLAGS= NOWARN_CFLAGS= The rest continues to work as previously (e.g. ADDINC and ADDLIB). When the removed variables are set, the makefile automatically detects it and emits a warning indicating where it's now recommended to set these values, so the porting effort should remain very very low. My local scripts even continue to work! There are still a few entries I'm not much decided upon at this point: - DEBUG continues to support passing -DDEBUG_foo and so on, but it's technically a list of CFLAGS. Many of the developers and probably prod users who build themselves use it. I'd be tempted to kill it "just because I can" but I think it would be more annoying to all of us than helpful, so I tend to think it could stay. - DEFINE is exactly the same, but it's used for general defines (e.g. change some internal defaults). Technically both are interchangable. It could be thought that DEBUG would be moved into DEFINE but again, I sense it would cause more grief than it could help, and frankly, overall these are not the parts that raised any complaints, so as we use to say "if it ain't broke don't fix it". - CPU_CFLAGS could possibly go if everyone wants to concatenate all their arch-specific flags into CFLAGS, but I tend to find this more readable in build scripts, especially when cross-compiling. I took care of updating the CI matrix BTW and the changes were really tiny. On a related topic, after a discussion with William I also performed three minor changes: - support USE_FOO=0 : previously, USE_FOO had to be either empty (off) or filled with whatever to be turned on. I agree that it's sometimes confusing and not always convenient when it gets the output from a command (e.g. USE_FOO=$? after a test). Now the value 0 will work as the empty string and will disable the feature. If you think that you might have left some USE_FOO=0 to enable FOO in your scripts, please double-check them. - emit a warning when writing USE_FOOBRA=1 while it was supposed to be USE_FOOBAR=1. It happened to all of us quite a few times already, particularly with USE_QUIC_OPENSSL_COMPAT which has enough words to permit a reversal. Now if a USE_something variable is passed and is not known, a warning will just mention that it is ignored. This is really helpful IMHO as it saves debugging time. - the warning options are no longer reported in "haproxy -vv". That was totally pointless (since automatically detected, and not affecting the resulting code) and it was polluting the output making it more difficult to spot the important options. However, they're reported on their own lines in the output of the less known "make opts". William suggested that the warning on the misspelled USE_foo could be backported since it's not much intrusive and helps spot manipulation problems. I'm definitely open to this. I'm interested in hearing about comments, questions or even complaints from package maintainers, developers, and generally speaking all those who build a lot from sources. We can still adjust certain things if there are good ideas or if I suppressed something that was important for someone. Please let me know. Thanks, Willy