Search code examples
c++cmake

How to selectively enable or disable -Werror argument for entire (external project) directories in my project?


I have a project in which I would like to use -Werror. Let's call its directory proj. There is a directory within proj/external and that is an exception so I don't want to use the -Werror for that.

Is there a way to create an exception for an entire directory in CMake for using or not using a compiler argument?


Solution

  • CMake 3.24+ Solution

    If your minimum required CMake version for the project is equal to or greater than v3.24, you can use the CMAKE_COMPILE_WARNING_AS_ERROR variable:

    This variable is used to initialize the COMPILE_WARNING_AS_ERROR property on all the targets.

    So just set the variable to a desired value at the top of each variable scope where you want a specific value to be used inside that scope. CMake non-cache variables are scoped to directories and functions. Ex.

    set(COMPILE_WARNING_AS_ERROR YES)
    add_library(foo foo.cpp)
    set(COMPILE_WARNING_AS_ERROR NO)
    add_subdirectory(bar)
    set(COMPILE_WARNING_AS_ERROR YES)
    add_executable(baz baz.cpp)
    

    For the specific case of variable scoping for external projects, if you are adding it with add_subdirectory, I'm assuming you don't want to touch the external project's CMakeLists.txt file, so you can instead wrap your call to add_subdirectory with a fuction, and set the variable inside the function, and then call the function.

    There are several benefits to this approach:

    • Cross-Platform with Less boilerplate: No more explicitly written generator expressions to use the right flag for each compiler.
    • Allows user-override: Not all users will want to build with warnings as errors. This new feature comes with a --compile-no-warning-as-error command-line flag that users can use to disable any effects of this variable/target-property when set by a dev in a CMakeLists.txt file.

    CMake 4.0 adds the LINK_WARNING_AS_ERROR target property, CMAKE_LINK_WARNING_AS_ERROR variable, and --cmake-link-no-warning-as-error commandline argument.

    Pre-3.24 Solution: If you are adding the external directory via add_subdirectory or FetchContent

    In the CMakeLists.txt file at the subdirectory for proj, do

    # add `-Werror` to the current directory's `COMPILE_OPTIONS`
    add_compile_options(-Werror)
    
    # retrieve a copy of the current directory's `COMPILE_OPTIONS`
    get_directory_property(old_dir_compile_options COMPILE_OPTIONS)
    
    # modify the actual value of the current directory's `COMPILE_OPTIONS` (copy from above line remains unchanged). subdirectories inherit a copy of their parent's `COMPILE_OPTIONS` at the time the subdirectory is processed.
    add_compile_options(-Wno-error)
    
    # add you subdirectory (whichever way you do it)
    # add_subdirectory(external ...)
    # FetchContent_MakeAvailable(...)
    
    # restore the current directory's old `COMPILE_OPTIONS`
    set_directory_properties(PROPERTIES COMPILE_OPTIONS "${old_dir_compile_options}")
    

    Docs:

    If you are adding it via ExternalProject_Add

    You probably don't need to do anything unless the external project itself is adding -Werror, in which case I don't know if you can do anything about it.

    Obligatory caveats / comments:

    • -Werror is a flag for gcc and friends (clang, etc.). If you want to support MSVC, you need to put guards in either via if(...), or via generator expressions.
    • whether or not to use -Werror is not without controversy. If you want to support other users using your project and you want to satisfy both sides of the debate, use some mechanism to either guard these lines of configuration behind a CMake options, or isolate them to your local build only.