bjhend
bjhend

Reputation: 1713

How to execute CMake's default find module from my own find module with the same name?

For some reason I want to extend a find module (FindThreads in my case) to do some specific stuff if CMake's FindThreads fails. For the ordinary developer of other parts of our software system this should happen transparently, such that s/he could call find_package(Threads) as usual, so I don't want to give my own find module an exclusive name.

My idea is to add my own FindThreads.cmake in a folder contained in the CMAKE_MODULE_PATH. Because CMAKE_MODULE_PATH has priority find_package(Threads) will execute my own FindThreads.cmake.

But, inside my own FindThreads.cmake I need to execute find_package(Threads ...) such that it executes CMake's original FindThreads.cmake. How to do that?

If that fails my own FindThreads.cmake should try to add a specific Threads lib.

Unfortunately, there is no option NO_CMAKE_MODULE_PATH for find_package to fall back to CMake's own find modules and it seems not to be possible to pass a search path (for example ${CMAKE_ROOT}/Modules) to find_package to override CMAKE_MODULE_PATH.

Versions

Upvotes: 3

Views: 305

Answers (3)

Peter Kokot
Peter Kokot

Reputation: 46

When overriding upstream CMake find modules, it depends on what needs to be overridden. In most cases the include() can be used inside the local find module. For example, a local find module:

# cmake/modules/FindThreads.cmake

# Adjustments before including the upstream find module... For example,
# adding additional search paths, names etc.

# Find package with upstream CMake find module.
include(${CMAKE_ROOT}/Modules/FindThreads.cmake)

# Adjustments after including the upstream find module... For example,
# to add additional result variables etc.

Then local find module is used:

# CMakeLists.txt
# ...
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake/modules)
# ...
find_package(Threads)

In this example, the absolute path to the upstream find module is used to prevent the maximum nesting/recursion depth error on some systems, like macOS. Otherwise CMake would recursively try to include local find module if include(FindThreads) or find_package(Threads) would be used inside the local find module.

Upvotes: 0

MuellerSeb
MuellerSeb

Reputation: 859

You could create a macro like this:

FindPackageWrapper.cmake:

macro(find_package_wrapper MODULE_PATH)
  set(_OLD_CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}")
  set(CMAKE_MODULE_PATH "${MODULE_PATH}")
  find_package(${ARGN})
  set(CMAKE_MODULE_PATH "${_OLD_CMAKE_MODULE_PATH}")
  unset(_OLD_CMAKE_MODULE_PATH)
endmacro()

And then use it like this:

include(FindPackageWrapper.cmake)
find_package_wrapper(${CMAKE_ROOT}/Modules Threads ...)

The macro is needed to provided the created variables in the parent scope. In a function the find_package results would get lost.

Upvotes: 0

Tsyvarev
Tsyvarev

Reputation: 66061

You may set CMAKE_MODULE_PATH before find_package call and restore the variable after the call:

# Save old value of CMAKE_MODULE_PATH.
set(CMAKE_MODULE_PATH_OLD ${CMAKE_MODULE_PATH})
# Temporary replace CMAKE_MODULE_PATH
set(CMAKE_MODULE_PATH "${CMAKE_ROOT}/Modules")
# Call find_package() with specific CMAKE_MODULE_PATH set.
find_package(Threads ...)
# Restore CMAKE_MODULE_PATH
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH_OLD})

Note, that FindXXX.cmake is executed in the same scope as the caller code, so restoring CMAKE_MODULE_PATH variable is needed even if your script no longer calls find_package but simply returns.

Also, it is better to use some unique variable's name instead of CMAKE_MODULE_PATH_OLD: it is possible that caller already uses that variable for its own purposes. E.g. you may add some suffix to the variable's name which related to your organization or is unlikely to be used by others.

Upvotes: 3

Related Questions