Problem with FetchContent dependencies when using XYZ_DIR (XYZ_ROOT works)

For SFML we’re attempting to move away from checked-in binaries to using FetchContent and building the dependencies on-the-fly.

This seems to work pretty well, expect in the case when consuming SFML via find_package while using SFML_DIR. For some reason, CMake fails to find the dependency targets and fails to configure.
However, when you use SFML_ROOT everything works as expected.

Looking at the output for --debug-find it for some reason does check the correct place with SFML_ROOT (i.e. C:/Temp/SFML/lib/cmake/Vorbis/), but doesn’t do so for SFML_DIR. Even though when looking at the log (posted below), it’s not obvious why CMake suddenly decides to do a search in lib/cmake/* and/or why it doesn’t do so for SFML_DIR.

While we can certainly try to get everyone to use SFML_ROOT, I’d still like to understand the underlying problem and see if there’s a way to fix this on our end.

I’m willing to try and reproduce it at a smaller scope, but since it’s a bit of work, I wanted to first check, if this is already a well understood problem and see if anyone is willing to look at the full implementation (any additional comments are welcome as well!).

SFML PR: Build dependency libraries instead of bundling pre-built binaries. by binary1248 · Pull Request #3141 · SFML/SFML · GitHub

Steps to Reproduce

  1. Build & install SFML to some directory:
    • cmake -S . -B build -DCMAKE_INSTALL_PREFIX=C:/Temp/SFML
    • cmake --build build --target install
  2. Create the two files from below
  3. Run CMake for the project:
    • cmake -S . -B build -DSFML_DIR=C:/Temp/SFML/lib/cmake/SFML
cmake_minimum_required(VERSION 3.28)
project(CMakeSFMLProject LANGUAGES CXX)

set(SFML_STATIC_LIBRARIES ON)
find_package(SFML REQUIRED COMPONENTS Graphics Audio)

add_executable(main main.cpp)
target_link_libraries(main PRIVATE SFML::Graphics SFML::Audio)
#include <SFML/Graphics.hpp>

int main()
{
    auto window = sf::RenderWindow({1920u, 1080u}, "CMake SFML Project");
    window.setFramerateLimit(144);

    while (window.isOpen())
    {
        for (auto event = sf::Event(); window.pollEvent(event);)
        {
            if (event.type == sf::Event::Closed)
            {
                window.close();
            }
        }

        window.clear();
        window.display();
    }
}

Actual Behavior

The build fails to configure:

Call Stack (most recent call first):
  CMakeLists.txt:28 (find_package)


CMake Error at CMakeLists.txt:28 (find_package):
  Found package configuration file:

    C:/Temp/SFML/lib/cmake/SFML/SFMLConfig.cmake

  but it set SFML_FOUND to FALSE so package "SFML" is considered to be NOT
  FOUND.  Reason given by package:

  The following imported targets are referenced, but are missing:
  Vorbis::vorbis Vorbis::vorbisfile Vorbis::vorbisenc FLAC::FLAC

Output of using --debug-find for the vorbis dependency:

Details
-- Could NOT find Vorbis (missing: Vorbis_DIR)
CMake Debug Log at C:/Temp/SFML/lib/cmake/SFML/SFMLConfigDependencies.cmake:45 (find_package):
  The internally managed CMAKE_FIND_PACKAGE_REDIRECTS_DIR.

    C:/Temp/CMakeSFML/build/CMakeFiles/pkgRedirects

  <PackageName>_ROOT CMake variable [CMAKE_FIND_USE_PACKAGE_ROOT_PATH].

    none

  CMAKE_PREFIX_PATH variable [CMAKE_FIND_USE_CMAKE_PATH].

    none

  CMAKE_FRAMEWORK_PATH and CMAKE_APPBUNDLE_PATH variables
  [CMAKE_FIND_USE_CMAKE_PATH].

    none

  Env variable Vorbis_DIR [CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH].

    none

  CMAKE_PREFIX_PATH env variable [CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH].

    none

  CMAKE_FRAMEWORK_PATH and CMAKE_APPBUNDLE_PATH env variables
  [CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH].

    none

  Paths specified by the find_package HINTS option.

    none

  Standard system environment variables
  [CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH].

    C:/Program Files/PowerShell/7
    C:/VulkanSDK/1.3.250.1/Bin
    C:/Windows/System32
    C:/Windows
    C:/Windows/System32/wbem
    C:/Windows/System32/WindowsPowerShell/v1.0
    C:/Windows/System32/OpenSSH
    C:/tools
    C:/Program Files/dotnet
    C:/Temp/CMakeSFML/C
    C:/Program Files/doxygen
    C:/Program Files/Git/cmd
    C:/Program Files/CMake
    C:/Program Files/OpenCppCoverage

  CMake User Package Registry [CMAKE_FIND_USE_PACKAGE_REGISTRY].

    none

  CMake variables defined in the Platform file
  [CMAKE_FIND_USE_CMAKE_SYSTEM_PATH].

    C:/Program Files
    C:/Program Files (x86)
    C:/Program Files (x86)/CMakeSFMLProject

  CMake System Package Registry
  [CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY].

    none

  Paths specified by the find_package PATHS option.

    none

  find_package considered the following locations for Vorbis's Config module:

    C:/Temp/CMakeSFML/build/CMakeFiles/pkgRedirects/VorbisConfig.cmake
    C:/Temp/CMakeSFML/build/CMakeFiles/pkgRedirects/vorbis-config.cmake
    C:/Program Files/PowerShell/7/VorbisConfig.cmake
    C:/Program Files/PowerShell/7/vorbis-config.cmake
    C:/VulkanSDK/1.3.250.1/Bin/VorbisConfig.cmake
    C:/VulkanSDK/1.3.250.1/Bin/vorbis-config.cmake
    C:/Windows/System32/VorbisConfig.cmake
    C:/Windows/System32/vorbis-config.cmake
    C:/Windows/VorbisConfig.cmake
    C:/Windows/vorbis-config.cmake
    C:/Windows/System32/wbem/VorbisConfig.cmake
    C:/Windows/System32/wbem/vorbis-config.cmake
    C:/Windows/System32/WindowsPowerShell/v1.0/VorbisConfig.cmake
    C:/Windows/System32/WindowsPowerShell/v1.0/vorbis-config.cmake
    C:/Windows/System32/OpenSSH/VorbisConfig.cmake
    C:/Windows/System32/OpenSSH/vorbis-config.cmake
    C:/Program Files/nodejs/VorbisConfig.cmake
    C:/Program Files/nodejs/vorbis-config.cmake
    C:/tools/VorbisConfig.cmake
    C:/tools/vorbis-config.cmake
    C:/Program Files/dotnet/VorbisConfig.cmake
    C:/Program Files/dotnet/vorbis-config.cmake
    C:/Program Files/doxygen/VorbisConfig.cmake
    C:/Program Files/doxygen/vorbis-config.cmake
    C:/Program Files/Git/cmd/VorbisConfig.cmake
    C:/Program Files/Git/cmd/vorbis-config.cmake
    C:/Program Files/CMake/VorbisConfig.cmake
    C:/Program Files/CMake/vorbis-config.cmake
    C:/Program Files/OpenCppCoverage/VorbisConfig.cmake
    C:/Program Files/OpenCppCoverage/vorbis-config.cmake
    C:/Program Files/VorbisConfig.cmake
    C:/Program Files/vorbis-config.cmake
    C:/Program Files/CMake/VorbisConfig.cmake
    C:/Program Files/CMake/vorbis-config.cmake
    C:/Program Files (x86)/VorbisConfig.cmake
    C:/Program Files (x86)/vorbis-config.cmake

  The file was not found.

Call Stack (most recent call first):
  C:/Temp/SFML/lib/cmake/SFML/SFMLConfig.cmake:124 (include)
  CMakeLists.txt:5 (find_package)

Expected Behavior

CMake configures successfully

Workaround

Running the following command will succeed with no issues:

cmake -S . -B build -DSFML_ROOT=C:/Temp/SFML

Details for --debug-find
Call Stack (most recent call first):
  C:/Temp/SFML/lib/cmake/Vorbis/VorbisConfig.cmake:28 (find_dependency)
  C:/Temp/SFML/lib/cmake/SFML/SFMLConfigDependencies.cmake:45 (find_package)
  C:/Temp/SFML/lib/cmake/SFML/SFMLConfig.cmake:124 (include)
  CMakeLists.txt:5 (find_package)


CMake Debug Log at C:/Temp/SFML/lib/cmake/SFML/SFMLConfigDependencies.cmake:45 (find_package):
  The internally managed CMAKE_FIND_PACKAGE_REDIRECTS_DIR.

    C:/Temp/CMakeSFML/build/CMakeFiles/pkgRedirects

  <PackageName>_ROOT CMake variable [CMAKE_FIND_USE_PACKAGE_ROOT_PATH].

    C:/Temp/SFML

  CMAKE_PREFIX_PATH variable [CMAKE_FIND_USE_CMAKE_PATH].

    none

  CMAKE_FRAMEWORK_PATH and CMAKE_APPBUNDLE_PATH variables
  [CMAKE_FIND_USE_CMAKE_PATH].

    none

  Env variable Vorbis_DIR [CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH].

    none

  CMAKE_PREFIX_PATH env variable [CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH].

    none

  CMAKE_FRAMEWORK_PATH and CMAKE_APPBUNDLE_PATH env variables
  [CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH].

    none

  Paths specified by the find_package HINTS option.

    none

  Standard system environment variables
  [CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH].

    C:/Program Files/PowerShell/7
    C:/VulkanSDK/1.3.250.1/Bin
    C:/Windows/System32
    C:/Windows
    C:/Windows/System32/wbem
    C:/Windows/System32/WindowsPowerShell/v1.0
    C:/Windows/System32/OpenSSH
    C:/tools
    C:/Program Files/dotnet
    C:/Temp/CMakeSFML/C
    C:/Program Files/doxygen
    C:/Program Files/Git/cmd
    C:/Program Files/CMake
    C:/Program Files/OpenCppCoverage

  CMake User Package Registry [CMAKE_FIND_USE_PACKAGE_REGISTRY].

    none

  CMake variables defined in the Platform file
  [CMAKE_FIND_USE_CMAKE_SYSTEM_PATH].

    C:/Program Files
    C:/Program Files (x86)
    C:/Program Files (x86)/CMakeSFMLProject

  CMake System Package Registry
  [CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY].

    none

  Paths specified by the find_package PATHS option.

    none

  find_package considered the following locations for Vorbis's Config module:

    C:/Temp/CMakeSFML/build/CMakeFiles/pkgRedirects/VorbisConfig.cmake
    C:/Temp/CMakeSFML/build/CMakeFiles/pkgRedirects/vorbis-config.cmake
    C:/Temp/SFML/VorbisConfig.cmake
    C:/Temp/SFML/vorbis-config.cmake
    C:/Temp/SFML/lib/cmake/Vorbis/VorbisConfig.cmake

  The file was found at

    C:/Temp/SFML/lib/cmake/Vorbis/VorbisConfig.cmake

does check the correct place with SFML_ROOT, but doesn’t do so for SFML_DIR

Apparently, that is because SFML maintainers chose to rely on SFML_ROOT and simply aren’t using SFML_DIR for anything, or at least that is what I see in their CMake config. On top of that, in the comments they are proposing to use find_package() without CONFIG option, which is somewhat confusing, since their package seems to provide a CMake config (although an “unusual” one).

In general, the *_DIR variables are what is used for packages discovery in CONFIG mode (aside from CMAKE_PREFIX_PATH, of course), so it might be that SFML maintainers intended to do it the way they did, but to me their package “config” looks more like a Find module, and so it should have been named accordingly (starting with Find and not ending with Config).

1 Like