How to find_package(... OPTIONAL) in CMake 3?

I would like to check whether Catch2 is installed, and if not then FetchContent it. CMake 4 has the OPTIONAL keyword to try find_package without throwing a warning. So, you can do something like this:

# get Catch2
if(TARGET Catch2::Catch2)
  message(STATUS "${PROJECT_NAME} > GOT Catch2 from parent project")

else()
  find_package(Catch2 3 OPTIONAL)
  message(STATUS "${PROJECT_NAME} > tried find_package(Catch2 3) ${Catch2_FOUND}")

  if(TARGET Catch2::Catch2)
    message(STATUS "${PROJECT_NAME} > Top level - got Catch2 by find_package")

  else()
    message(STATUS "${PROJECT_NAME} > Top level - FetchContent Catch2")

    include(FetchContent)
    FetchContent_Declare(
      Catch2
      GIT_REPOSITORY https://github.com/catchorg/Catch2.git
      GIT_TAG        v3.8.1 # or a later release
    )
    FetchContent_MakeAvailable(Catch2)
  endif()
endif()

But CMake 3 will throw an error:

find_package called with invalid argument “OPTIONAL”.

If you just omit OPTIONAL, then you will get a warning in the case when the package is not installed:

By not providing “FindCatch2.cmake” in CMAKE_MODULE_PATH

What is the right way to check whether FindCatch2.cmake is provided in the system?

You may use QUIET instead of OPTIONAL with all cmake versions.

Since CMake 3.24, FetchContent has built-in support for trying find_package() first before falling back to fetching the content with the supplied details. Add the FIND_PACKAGE_ARGS keyword to your FetchContent_Declare() call. For example:

include(FetchContent)
FetchContent_Declare(
  Catch2
  GIT_REPOSITORY    https://github.com/catchorg/Catch2.git
  GIT_TAG           v3.8.1 # or a later release
  FIND_PACKAGE_ARGS 3
)
FetchContent_MakeAvailable(Catch2)