FetchContent vs. BUILD_TESTING

Is there a best practice with respect to BUILD_TESTING for projects that want to support being used as git submodules or FetchContent? The root issue I’m having is that a project currently uses BUILD_TESTING directly. This works fine when building it as a top level project, but there are issues when it is used as a subproject (by way of a git submodule or FetchContent).

This is currently being discussed at cmake: Controlling Abseil's tests with BUILD_TESTING is inconvenient · Issue #1056 · abseil/abseil-cpp · GitHub.

In researching this I found Craig Scott’s post How to use FetchContent correctly for building external dependencies - #2 by craig.scott where he says:

Dealing with tests is harder. If you use the method above to handle the install problems, then you will avoid the need for EXCLUDE_FROM_ALL and then you should be able to avoid the dependency problems you ran into. The dependency’s tests will still show up and be included in the main projects tests, but that is hard to avoid without the dependency providing some sort of switch to turn off adding tests. A well-structured project should ideally provide a project-specific CMake variable that can be passed down to turn tests on or off, and it should default to true if the dependency is being built on its own and false if it is not the top level project.

Emphasis mine. Is there a good example of an Open Source project I can look at that does this well?

Local variables “win” over cache variables, so you could do set(BUILD_TESTING OFF) before doing add_subdirectory() for abseil.

Thanks Ben.

I can live with something like that, but my question was aimed more at sub-project maintainers. Are there examples of “well-structured projects” that make this dance unnecessary, like Craig Scott suggests? Is there any consensus on what the right defaults are in this situation?

Basically I would try and namespace as much as possible. For example, offer MyProject_BUILD_TESTING then set BUILD_TESTING internally based on it. It helps to keep your relevant options grouped in the cache file and editors as well as offering useful knobs when embedded.

GLFW comes to mind. I don’t recall running into any issues with pulling it in with FetchContent.
Almost everything about it has an option that can be set when using it as a subproject.
As example:

option(BUILD_SHARED_LIBS "Build shared libraries" OFF)
option(GLFW_BUILD_EXAMPLES "Build the GLFW example programs" ${GLFW_STANDALONE})
option(GLFW_BUILD_TESTS "Build the GLFW test programs" ${GLFW_STANDALONE})
option(GLFW_BUILD_DOCS "Build the GLFW documentation" ON)
option(GLFW_INSTALL "Generate installation target" ON)