1. 3

  2. 17

    So it surprised me to learn that some (many?) folks in the open source and academic world hate -Werror with passion.

    That’s because the Open Source world deploys source code to the entire world. You can not possibly come even close to covering all the systems people will try to build your code on, so making the mistake of having Werror on by default means you get a ton of feedback about things not building for unimportant reasons. That gets old very quickly. Warning flags are also quite volatile over time. In short, the in-house proprietary way of thinking here just doesn’t work, because the deployment scenario is entirely different, and you have no control over it.

    Since this is a “strong opinions, loosely held” blog, I’ll follow suit:

    The objectively correct approach here is to have a developer mode which enables ultra strict warnings (far more than mentioned in the post) as errors, and use those on CI, but have the default be a more conservative set of warnings with broad compatibility, and without Werror. That way the code quality is as strict as you like (which is, after all, the point), but you aren’t breaking things for users because of some silly warning. No good comes from that - the feedback is almost always useless, and the initial impression of your software is “it doesn’t even compile”.

    1. 3

      a ton of feedback about things not building for unimportant reasons

      And specifically this usually happens when building with a newer or just another compiler. (So many projects just test on whatever gcc they have – every time I upgrade clang I get new stupid Werror fails…)

      Werror as-is is a complete disaster. “Only use this for development” flags inevitably end up in shipped build systems. No flag should be this fragile.

      If only compiler developers got together and agreed on common warning sets. If one could say -Werror=2021 and any future version of clang and gcc interpreted this as “enable whatever warnings we agreed on in 2021” it would be usable.

      1. 3

        Yeah, I suspect people with the luxury of only “supporting” some small set of compilers/versions really underestimate how hard it is to get a warning-free build across a vast swath of versions, especially if you’re being strict about it, and double plus especially if you’re using Weverything in clang with explicit exceptions (which is obviously absolute madness in conjunction with default Werror, but I’ve seen it…).

        “Only use this for development” flags inevitably end up in shipped build systems. No flag should be this fragile.

        Meh. Here I think I disagree. Any build system used to deploy code to users needs to have some kind of configuration mechanism, and if you have to actively opt-in to warnings being errors, well… you specifically asked for warnings to be errors, so of course they are? Maybe I’ve been lucky, but I’ve never really been bothered by people doing this.

        That said, flag stability is annoying, but I think that’s a different problem - Werror just does what it says on the tin. Compiler authors could never fully agree to such a thing, it’s more or less equivalent to agreeing on a common set of implementation-specific details. The current system of GCC and clang mostly agreeing where possible is as good as that’s going to get, I’d say. Even if they agreed on a common subset, you’d end up using the extra ones anyway (because many are useful but compiler-exclusive), and we’re back to the same problem. MSVC is off in another universe entirely, but it always is.

        1. 1

          If one could say -Werror=2021

          You can! You just have to specify which warnings those are:

          -Werror=format-security -Werror=switch -Werror=maybe-uninitialized …

          This decouples the “which warnings are errors” question from the general warning level question, which is subject to those volatile warning categories (like -Wall, -Wextra, -Wpedantic). I think this is the only sane way to use -Werror, at least as a default build option in open source.

          1. 1

            Sure, but aside from having an ugly loooooong list in CFLAGS, the problem is that I don’t know of a resource that answers questions like “give me the warnings supported by both the N last gcc versions and the last N clang versions”. At least having that as a website would be something.

      2. 3

        … I’ve taken it for granted that -Wall -Weverything -Werror are always enabled.

        Separate from the -Werror question, enabling -Weverything all the time is a bad idea: https://quuxplusone.github.io/blog/2018/12/06/dont-use-weverything/.

        I used to use to do that, thinking it was a virtue to fix every warning under the sun. Then I started getting “error: include location ‘/usr/local/include’ is unsafe for cross-compilation [-Werror,-Wpoison-system-directories]”, and realized that I don’t want my projects to break whenever I upgrade clang because of bogus things like that.

        1. 3

          It’s not really articulated in the article, but I think there are two different questions being conflated:

          • Should your CI builds enable extra bonus warnings and -Werror?
          • What should the default set of warning flags be in your build system?

          CI runs on known platforms with known compiler versions. The defaults in the build system run on unknown platforms with unknown compilers. You shouldn’t get new errors in your CI platform from a surprise compiler upgrade because compiler upgrades on your CI platform should be scheduled maintenance events and you can do a PR that bumps the compiler version, see the failures, fix them, and incorporate them into the PR so that your main branch is always warning-free with whatever compiler and compiler flags you have set for CI.

          In a CI build, it’s completely acceptable to do -Werror -Wextra -Weverthing -Wno-thing-that-causes-too-many-false-positives -Wno-other-thing-that-causes-too-many-false-positives and you can make sure the -Wno-* flags are there to turn off warnings that you know are not worth fixing. You can do this because you know exactly the set of warnings that are generated by the compilers that you’re using in your CI builds.

          In a normal build, anything that builds in CI should build on any platform / compiler that meets your dependency requirements. You may still want some extra warning flags, but don’t add -Werror or you’ll cause your project to fail to build for some potential users.

          I see this as part of the growing mindset among developers that everyone runs Ubuntu, macOS, or Windows, on 64-bit x86 and so if you’ve tested your code on these three platforms then it’s fine.

        2. 3

          To give a concrete example: The Azure Storage SDK used to compile with -Werror. This broke the vcpkg build of it for me, because I was using a newer version of clang than the upstream developers tested with (I was using the stock FreeBSD base-system compiler, so this also broke it for all FreeBSD users). The warning that it was raising an error for? Clang’s -Wdocumentation had found some escape characters in comments that were not escaped in a way that Doxygen can understand. Fixing this made absolutely no difference to the generated binary code, yet with -Werror I was unable to fix it.

          To give a second concrete example: FreeBSD builds with -Werror and every time we import a new compiler into the base system it triggers more warnings and we have to either fix them or disable some warnings. Some of the code that triggers warnings is largely unmodified from 30 years ago, so while -Werror does increase code quality over time, it also increases code churn and the potential for introducing new bugs (which is more trustworthy out of code that’s been deployed for 30 years or a modified version where someone who isn’t familiar with the code fixed a new warning? The answer isn’t really clear to me in the general case).

          A warning is, by definition, something that can have false positives. If your code is definitely wrong then it’s not a warning, it’s an error. If it’s probably wrong, then it’s a warning. Actually, there’s quite a spectrum for warnings - some of the ones in gcc and clang that aren’t enabled by default have a very high false positive rate.

          The most useful purpose of -Werror is to prevent people from committing code that introduces new warnings in current compilers. It’s a great idea to enable -Werror in CI builds, where the compiler version is stable (though be aware that you’re going to need to spend some time every time you deploy a new compiler fixing the existing ones). If you enable it in the default build flags then you’re going to end up causing spurious build failures on any platform / compiler that isn’t part of your test matrix.

          1. 3

            I think this is a complete strawman, because I doubt anyone argues that -Werror is useful when developing, in CI etc. but for releases it is a disaster because if FOSS projects try to build the release tarball with CC version N+2, potentially a new warning crops up and breaks the build so they have to go in and either fix the code or (realistically) patch out -Werror.

            1. 1

              There was a talk at this year’s Linux Plumbers Conference about something related to this: turning on implicit function declarations as an error. This causes massive problems in many packages because autoconf relies on them; however, setting it as an error doesn’t cause a configuration error so you end up building the code with a feature disabled and it’s not obvious that’s what happened.

              Making this an error by default simply won’t happen without massive amounts of work to autoconf and all the code that depends on it. The proposal was to patch the compiler to produce a special log file and that is checked for problems at the end of the build.