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.

1 Like

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)
1 Like

Thanks a lot! I will mark the QUIET keyword as the solution, because it should cover more versions. (I think we have CMake 3.14 in one of situations.) But the FetchContent FIND_PACKAGE_ARGS is awesome.