mirror of
https://github.com/Kitware/CMake.git
synced 2025-12-30 18:29:37 -06:00
Packages: Integrate FetchContent and find_package()
Allow FetchContent_MakeAvailable() to try a call to find_package() first, or redirect a find_package() call to FetchContent_MakeAvailable(). The user can set variables to control which of these are allowed or tried by default. Fixes: #21687
This commit is contained in:
@@ -11,7 +11,7 @@ and load its package-specific details.
|
||||
Search Modes
|
||||
^^^^^^^^^^^^
|
||||
|
||||
The command has two very distinct ways of conducting the search:
|
||||
The command has a few modes by which it searches for packages:
|
||||
|
||||
**Module mode**
|
||||
In this mode, CMake searches for a file called ``Find<PackageName>.cmake``,
|
||||
@@ -54,7 +54,17 @@ The command has two very distinct ways of conducting the search:
|
||||
Config mode is supported by both the :ref:`basic <Basic Signature>` and
|
||||
:ref:`full <Full Signature>` command signatures.
|
||||
|
||||
The command arguments determine which of the above modes is used. When the
|
||||
**FetchContent redirection mode**
|
||||
.. versionadded:: 3.24
|
||||
A call to ``find_package()`` can be redirected internally to a package
|
||||
provided by the :module:`FetchContent` module. To the caller, the behavior
|
||||
will appear similar to Config mode, except that the search logic is
|
||||
by-passed and the component information is not used. See
|
||||
:command:`FetchContent_Declare` and :command:`FetchContent_MakeAvailable`
|
||||
for further details.
|
||||
|
||||
When not redirected to a package provided by :module:`FetchContent`, the
|
||||
command arguments determine whether Module or Config mode is used. When the
|
||||
`basic signature`_ is used, the command searches in Module mode first.
|
||||
If the package is not found, the search falls back to Config mode.
|
||||
A user may set the :variable:`CMAKE_FIND_PACKAGE_PREFER_CONFIG` variable
|
||||
@@ -64,7 +74,7 @@ forced to use only Module mode with a ``MODULE`` keyword. If the
|
||||
`full signature`_ is used, the command only searches in Config mode.
|
||||
|
||||
Where possible, user code should generally look for packages using the
|
||||
`basic signature`_, since that allows the package to be found with either mode.
|
||||
`basic signature`_, since that allows the package to be found with any mode.
|
||||
Project maintainers wishing to provide a config package should understand
|
||||
the bigger picture, as explained in :ref:`Full Signature` and all subsequent
|
||||
sections on this page.
|
||||
@@ -189,9 +199,12 @@ proceeds at once with Config mode search.
|
||||
|
||||
Config mode search attempts to locate a configuration file provided by the
|
||||
package to be found. A cache entry called ``<PackageName>_DIR`` is created to
|
||||
hold the directory containing the file. By default the command
|
||||
searches for a package with the name ``<PackageName>``. If the ``NAMES`` option
|
||||
is given the names following it are used instead of ``<PackageName>``.
|
||||
hold the directory containing the file. By default, the command searches for
|
||||
a package with the name ``<PackageName>``. If the ``NAMES`` option is given,
|
||||
the names following it are used instead of ``<PackageName>``. The names are
|
||||
also considered when determining whether to redirect the call to a package
|
||||
provided by :module:`FetchContent`.
|
||||
|
||||
The command searches for a file called ``<PackageName>Config.cmake`` or
|
||||
``<lowercasePackageName>-config.cmake`` for each name specified.
|
||||
A replacement set of possible configuration file names may be given
|
||||
@@ -228,6 +241,14 @@ Config Mode Search Procedure
|
||||
whether the :ref:`full <full signature>` or :ref:`basic <basic signature>`
|
||||
signature was given.
|
||||
|
||||
.. versionadded:: 3.24
|
||||
All calls to ``find_package()`` (even in Module mode) first look for a config
|
||||
package file in the :variable:`CMAKE_FIND_PACKAGE_REDIRECTS_DIR` directory.
|
||||
The :module:`FetchContent` module, or even the project itself, may write files
|
||||
to that location to redirect ``find_package()`` calls to content already
|
||||
provided by the project. If no config package file is found in that location,
|
||||
the search proceeds with the logic described below.
|
||||
|
||||
CMake constructs a set of possible installation prefixes for the
|
||||
package. Under each prefix several directories are searched for a
|
||||
configuration file. The tables below show the directories searched.
|
||||
@@ -398,7 +419,8 @@ to resolve symbolic links and store the real path to the file.
|
||||
Every non-REQUIRED ``find_package`` call can be disabled or made REQUIRED:
|
||||
|
||||
* Setting the :variable:`CMAKE_DISABLE_FIND_PACKAGE_<PackageName>` variable
|
||||
to ``TRUE`` disables the package.
|
||||
to ``TRUE`` disables the package. This also disables redirection to a
|
||||
package provided by :module:`FetchContent`.
|
||||
|
||||
* Setting the :variable:`CMAKE_REQUIRE_FIND_PACKAGE_<PackageName>` variable
|
||||
to ``TRUE`` makes the package REQUIRED.
|
||||
@@ -421,8 +443,8 @@ version (see :ref:`format specification <FIND_PACKAGE_VERSION_FORMAT>`). If the
|
||||
``EXACT`` option is given, only a version of the package claiming an exact match
|
||||
of the requested version may be found. CMake does not establish any
|
||||
convention for the meaning of version numbers. Package version
|
||||
numbers are checked by "version" files provided by the packages
|
||||
themselves. For a candidate package configuration file
|
||||
numbers are checked by "version" files provided by the packages themselves
|
||||
or by :module:`FetchContent`. For a candidate package configuration file
|
||||
``<config-file>.cmake`` the corresponding version file is located next
|
||||
to it and named either ``<config-file>-version.cmake`` or
|
||||
``<config-file>Version.cmake``. If no such version file is available
|
||||
|
||||
@@ -59,6 +59,7 @@ Variables that Provide Information
|
||||
/variable/CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES
|
||||
/variable/CMAKE_FIND_DEBUG_MODE
|
||||
/variable/CMAKE_FIND_PACKAGE_NAME
|
||||
/variable/CMAKE_FIND_PACKAGE_REDIRECTS_DIR
|
||||
/variable/CMAKE_FIND_PACKAGE_SORT_DIRECTION
|
||||
/variable/CMAKE_FIND_PACKAGE_SORT_ORDER
|
||||
/variable/CMAKE_GENERATOR
|
||||
|
||||
17
Help/release/dev/FetchContent_find_package_integration.rst
Normal file
17
Help/release/dev/FetchContent_find_package_integration.rst
Normal file
@@ -0,0 +1,17 @@
|
||||
FetchContent_find_package_integration
|
||||
-------------------------------------
|
||||
|
||||
* Integration has been added between the :module:`FetchContent` module and the
|
||||
:command:`find_package` command, enabling the following new capabilities:
|
||||
|
||||
* :command:`FetchContent_MakeAvailable` can now try to satisfy a dependency
|
||||
by calling :command:`find_package` first. A new
|
||||
:variable:`FETCHCONTENT_TRY_FIND_PACKAGE_MODE` variable controls whether
|
||||
this is done by default for all dependencies, is opt-in per dependency,
|
||||
or is disabled entirely.
|
||||
|
||||
* :command:`find_package` can be re-routed to call
|
||||
:command:`FetchContent_MakeAvailable` instead. A new read-only
|
||||
:variable:`CMAKE_FIND_PACKAGE_REDIRECTS_DIR` variable points to a
|
||||
directory where config package files can be located to facilitate these
|
||||
re-routed calls.
|
||||
27
Help/variable/CMAKE_FIND_PACKAGE_REDIRECTS_DIR.rst
Normal file
27
Help/variable/CMAKE_FIND_PACKAGE_REDIRECTS_DIR.rst
Normal file
@@ -0,0 +1,27 @@
|
||||
CMAKE_FIND_PACKAGE_REDIRECTS_DIR
|
||||
--------------------------------
|
||||
|
||||
.. versionadded:: 3.24
|
||||
|
||||
This read-only variable specifies a directory that the :command:`find_package`
|
||||
command will check first before searching anywhere else for a module or config
|
||||
package file. A config package file in this directory will always be found in
|
||||
preference to any other Find module file or config package file.
|
||||
|
||||
The primary purpose of this variable is to facilitate integration between
|
||||
:command:`find_package` and :command:`FetchContent_MakeAvailable`. The latter
|
||||
command may create files in the ``CMAKE_FIND_PACKAGE_REDIRECTS_DIR`` directory
|
||||
when it populates a dependency. This allows subsequent calls to
|
||||
:command:`find_package` for the same dependency to re-use the populated
|
||||
contents instead of trying to satisfy the dependency from somewhere external
|
||||
to the build. Projects may also want to write files into this directory in
|
||||
some situations (see :ref:`FetchContent-find_package-integration` for examples).
|
||||
|
||||
The directory that ``CMAKE_FIND_PACKAGE_REDIRECTS_DIR`` points to will always
|
||||
be erased and recreated empty at the start of every CMake run. Any files
|
||||
written into this directory during the CMake run will be lost the next time
|
||||
CMake configures the project.
|
||||
|
||||
``CMAKE_FIND_PACKAGE_REDIRECTS_DIR`` is only set in CMake project mode.
|
||||
It is not set when CMake is run in script mode
|
||||
(i.e. :manual:`cmake -P ... <cmake(1)>`).
|
||||
@@ -102,7 +102,12 @@ Commands
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
FetchContent_Declare(<name> <contentOptions>...)
|
||||
FetchContent_Declare(
|
||||
<name>
|
||||
<contentOptions>...
|
||||
[OVERRIDE_FIND_PACKAGE |
|
||||
FIND_PACKAGE_ARGS args...]
|
||||
)
|
||||
|
||||
The ``FetchContent_Declare()`` function records the options that describe
|
||||
how to populate the specified content. If such details have already
|
||||
@@ -169,6 +174,36 @@ Commands
|
||||
they do for :command:`ExternalProject_Add`. Previously, these variables
|
||||
were ignored by the ``FetchContent`` module.
|
||||
|
||||
.. versionadded:: 3.24
|
||||
|
||||
``FIND_PACKAGE_ARGS``
|
||||
This option is for scenarios where the
|
||||
:command:`FetchContent_MakeAvailable` command may first try a call to
|
||||
:command:`find_package` to satisfy the dependency for ``<name>``.
|
||||
By default, such a call would be simply ``find_package(<name>)``, but
|
||||
``FIND_PACKAGE_ARGS`` can be used to provide additional arguments to be
|
||||
appended after the ``<name>``. ``FIND_PACKAGE_ARGS`` can also be given
|
||||
with nothing after it, which indicates that :command:`find_package` can
|
||||
still be called if :variable:`FETCHCONTENT_TRY_FIND_PACKAGE_MODE` is
|
||||
set to ``OPT_IN`` or is not set.
|
||||
|
||||
Everything after the ``FIND_PACKAGE_ARGS`` keyword is appended to the
|
||||
:command:`find_package` call, so all other ``<contentOptions>`` must
|
||||
come before the ``FIND_PACKAGE_ARGS`` keyword.
|
||||
``OVERRIDE_FIND_PACKAGE`` cannot be used when ``FIND_PACKAGE_ARGS`` is
|
||||
given.
|
||||
|
||||
``OVERRIDE_FIND_PACKAGE``
|
||||
When a ``FetchContent_Declare(<name> ...)`` call includes this option,
|
||||
subsequent calls to ``find_package(<name> ...)`` will ensure that
|
||||
``FetchContent_MakeAvailable(<name>)`` has been called, then use the
|
||||
config package files in the :variable:`CMAKE_FIND_PACKAGE_REDIRECTS_DIR`
|
||||
directory (which are usually created by ``FetchContent_MakeAvailable()``).
|
||||
This effectively makes :command:`FetchContent_MakeAvailable` override
|
||||
:command:`find_package` for the named dependency, allowing the former to
|
||||
satisfy the package requirements of the latter. ``FIND_PACKAGE_ARGS``
|
||||
cannot be used when ``OVERRIDE_FIND_PACKAGE`` is given.
|
||||
|
||||
.. command:: FetchContent_MakeAvailable
|
||||
|
||||
.. versionadded:: 3.14
|
||||
@@ -177,9 +212,22 @@ Commands
|
||||
|
||||
FetchContent_MakeAvailable(<name1> [<name2>...])
|
||||
|
||||
This command ensures that each of the named dependencies are populated and
|
||||
potentially added to the build by the time it returns. It iterates over
|
||||
the list, and for each dependency, the following logic is applied:
|
||||
This command ensures that each of the named dependencies are made available
|
||||
to the project by the time it returns. There must have been a call to
|
||||
:command:`FetchContent_Declare` for each dependency, and the first such call
|
||||
will control how that dependency will be made available, as described below.
|
||||
|
||||
.. versionadded:: 3.24
|
||||
If permitted, :command:`find_package(<name> [<args>...]) <find_package>`
|
||||
will be called, where ``<args>...`` may be provided by the
|
||||
``FIND_PACKAGE_ARGS`` option in :command:`FetchContent_Declare`.
|
||||
The value of the :variable:`FETCHCONTENT_TRY_FIND_PACKAGE_MODE` variable
|
||||
at the time :command:`FetchContent_Declare` was called determines whether
|
||||
``FetchContent_MakeAvailable()`` can call :command:`find_package`.
|
||||
|
||||
If :command:`find_package` was unsuccessful or was not allowed to be called,
|
||||
``FetchContent_MakeAvailable()`` then uses the following logic to make the
|
||||
dependency available:
|
||||
|
||||
* If the dependency has already been populated earlier in this run, set
|
||||
the ``<lowercaseName>_POPULATED``, ``<lowercaseName>_SOURCE_DIR`` and
|
||||
@@ -194,6 +242,37 @@ Commands
|
||||
the declared details and use content provided at the specified location
|
||||
instead.
|
||||
|
||||
* .. versionadded:: 3.24
|
||||
|
||||
Ensure the :variable:`CMAKE_FIND_PACKAGE_REDIRECTS_DIR` directory
|
||||
contains a ``<lowercaseName>-config.cmake`` and a
|
||||
``<lowercaseName>-config-version.cmake`` file (or equivalently
|
||||
``<name>Config.cmake`` and ``<name>ConfigVersion.cmake``).
|
||||
The directory that the :variable:`CMAKE_FIND_PACKAGE_REDIRECTS_DIR`
|
||||
variable points to is cleared at the start of every CMake run.
|
||||
If no config file exists when :command:`FetchContent_Populate` returns,
|
||||
a minimal one will be written which :command:`includes <include>` any
|
||||
``<lowercaseName>-extra.cmake`` or ``<name>Extra.cmake`` file with the
|
||||
``OPTIONAL`` flag (so the files can be missing and won't generate a
|
||||
warning). Similarly, if no config version file exists, a very simple
|
||||
one will be written which sets ``PACKAGE_VERSION_COMPATIBLE`` to true.
|
||||
CMake cannot automatically determine an arbitrary dependency's version,
|
||||
so it cannot set ``PACKAGE_VERSION`` or ``PACKAGE_VERSION_EXACT``.
|
||||
When a dependency is pulled in via :command:`add_subdirectory` in the
|
||||
next step, it may choose to overwrite the generated config version file
|
||||
in :variable:`CMAKE_FIND_PACKAGE_REDIRECTS_DIR` with one that also sets
|
||||
``PACKAGE_VERSION``, and if appropriate, ``PACKAGE_VERSION_EXACT``.
|
||||
The dependency may also write a ``<lowercaseName>-extra.cmake`` or
|
||||
``<name>Extra.cmake`` file to perform custom processing or define any
|
||||
variables that their normal (installed) package config file would
|
||||
otherwise usually define (many projects don't do any custom processing
|
||||
or set any variables and therefore have no need to do this).
|
||||
If required, the main project can write these files instead if the
|
||||
dependency project doesn't do so. This allows the main project to
|
||||
add missing details from older dependencies that haven't or can't be
|
||||
updated to support this functionality.
|
||||
See `Integrating With find_package()`_ for examples.
|
||||
|
||||
* If the top directory of the populated content contains a ``CMakeLists.txt``
|
||||
file, call :command:`add_subdirectory` to add it to the main build.
|
||||
It is not an error for there to be no ``CMakeLists.txt`` file, which
|
||||
@@ -437,8 +516,10 @@ Variables
|
||||
|
||||
A number of cache variables can influence the behavior where details from a
|
||||
:command:`FetchContent_Declare` call are used to populate content.
|
||||
The variables are all intended for the developer to customize behavior and
|
||||
should not normally be set by the project.
|
||||
|
||||
.. note::
|
||||
All of these variables are intended for the developer to customize behavior.
|
||||
They should not normally be set by the project.
|
||||
|
||||
.. variable:: FETCHCONTENT_BASE_DIR
|
||||
|
||||
@@ -481,8 +562,53 @@ should not normally be set by the project.
|
||||
This can speed up the configure stage, but not as much as
|
||||
:variable:`FETCHCONTENT_FULLY_DISCONNECTED`. It is ``OFF`` by default.
|
||||
|
||||
In addition to the above cache variables, the following cache variables are
|
||||
also defined for each content name:
|
||||
.. variable:: FETCHCONTENT_TRY_FIND_PACKAGE_MODE
|
||||
|
||||
.. versionadded:: 3.24
|
||||
|
||||
This variable modifies the details that :command:`FetchContent_Declare`
|
||||
records for a given dependency. While it ultimately controls the behavior
|
||||
of :command:`FetchContent_MakeAvailable`, it is the variable's value when
|
||||
:command:`FetchContent_Declare` is called that gets used. It makes no
|
||||
difference what the variable is set to when
|
||||
:command:`FetchContent_MakeAvailable` is called. Since the variable should
|
||||
only be set by the user and not by projects directly, it will typically have
|
||||
the same value throughout anyway, so this distinction is not usually
|
||||
noticeable.
|
||||
|
||||
``FETCHCONTENT_TRY_FIND_PACKAGE_MODE`` ultimately controls whether
|
||||
:command:`FetchContent_MakeAvailable` is allowed to call
|
||||
:command:`find_package` to satisfy a dependency. The variable can be set
|
||||
to one of the following values:
|
||||
|
||||
``OPT_IN``
|
||||
:command:`FetchContent_MakeAvailable` will only call
|
||||
:command:`find_package` if the :command:`FetchContent_Declare` call
|
||||
included a ``FIND_PACKAGE_ARGS`` keyword. This is also the default
|
||||
behavior if ``FETCHCONTENT_TRY_FIND_PACKAGE_MODE`` is not set.
|
||||
|
||||
``ALWAYS``
|
||||
:command:`find_package` will be called by
|
||||
:command:`FetchContent_MakeAvailable` regardless of whether the
|
||||
:command:`FetchContent_Declare` call included a ``FIND_PACKAGE_ARGS``
|
||||
keyword or not. If no ``FIND_PACKAGE_ARGS`` keyword was given, the
|
||||
behavior will be as though ``FIND_PACKAGE_ARGS`` had been provided,
|
||||
with no additional arguments after it.
|
||||
|
||||
``NEVER``
|
||||
:command:`FetchContent_MakeAvailable` will not call
|
||||
:command:`find_package`. Any ``FIND_PACKAGE_ARGS`` given to the
|
||||
:command:`FetchContent_Declare` call will be ignored.
|
||||
|
||||
As a special case, if the :variable:`FETCHCONTENT_SOURCE_DIR_<uppercaseName>`
|
||||
variable has a non-empty value for a dependency, it is assumed that the
|
||||
user is overriding all other methods of making that dependency available.
|
||||
``FETCHCONTENT_TRY_FIND_PACKAGE_MODE`` will have no effect on that
|
||||
dependency and :command:`FetchContent_MakeAvailable` will not try to call
|
||||
:command:`find_package` for it.
|
||||
|
||||
In addition to the above, the following variables are also defined for each
|
||||
content name:
|
||||
|
||||
.. variable:: FETCHCONTENT_SOURCE_DIR_<uppercaseName>
|
||||
|
||||
@@ -511,6 +637,9 @@ also defined for each content name:
|
||||
Examples
|
||||
^^^^^^^^
|
||||
|
||||
Typical Case
|
||||
""""""""""""
|
||||
|
||||
This first fairly straightforward example ensures that some popular testing
|
||||
frameworks are available to the main build:
|
||||
|
||||
@@ -532,6 +661,135 @@ frameworks are available to the main build:
|
||||
# Catch2 will be available to the rest of the build
|
||||
FetchContent_MakeAvailable(googletest Catch2)
|
||||
|
||||
.. _FetchContent-find_package-integration:
|
||||
|
||||
Integrating With find_package()
|
||||
"""""""""""""""""""""""""""""""
|
||||
|
||||
For the previous example, if the user wanted to try to find ``googletest``
|
||||
and ``Catch2`` via :command:`find_package` first before trying to download
|
||||
and build them from source, they could set the
|
||||
:variable:`FETCHCONTENT_TRY_FIND_PACKAGE_MODE` variable to ``ALWAYS``.
|
||||
This would also affect any other calls to :command:`FetchContent_Declare`
|
||||
throughout the project, which might not be acceptable. The behavior can be
|
||||
enabled for just these two dependencies instead by adding ``FIND_PACKAGE_ARGS``
|
||||
to the declared details and leaving
|
||||
:variable:`FETCHCONTENT_TRY_FIND_PACKAGE_MODE` unset, or set to ``OPT_IN``:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
googletest
|
||||
GIT_REPOSITORY https://github.com/google/googletest.git
|
||||
GIT_TAG 703bd9caab50b139428cea1aaff9974ebee5742e # release-1.10.0
|
||||
FIND_PACKAGE_ARGS NAMES gtest
|
||||
)
|
||||
FetchContent_Declare(
|
||||
Catch2
|
||||
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
|
||||
GIT_TAG de6fe184a9ac1a06895cdd1c9b437f0a0bdf14ad # v2.13.4
|
||||
FIND_PACKAGE_ARGS
|
||||
)
|
||||
|
||||
# This will try calling find_package() first for both dependencies
|
||||
FetchContent_MakeAvailable(googletest Catch2)
|
||||
|
||||
For ``Catch2``, no additional arguments to :command:`find_package` are needed,
|
||||
so no additional arguments are provided after the ``FIND_PACKAGE_ARGS``
|
||||
keyword. For ``googletest``, its package is more commonly called ``gtest``,
|
||||
so arguments are added to support it being found by that name.
|
||||
|
||||
If the user wanted to disable :command:`FetchContent_MakeAvailable` from
|
||||
calling :command:`find_package` for any dependency, even if it provided
|
||||
``FIND_PACKAGE_ARGS`` in its declared details, they could set
|
||||
:variable:`FETCHCONTENT_TRY_FIND_PACKAGE_MODE` to ``NEVER``.
|
||||
|
||||
If the project wanted to indicate that these two dependencies should be
|
||||
downloaded and built from source and that :command:`find_package` calls
|
||||
should be redirected to use the built dependencies, the
|
||||
``OVERRIDE_FIND_PACKAGE`` option should be used when declaring the content
|
||||
details:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
googletest
|
||||
GIT_REPOSITORY https://github.com/google/googletest.git
|
||||
GIT_TAG 703bd9caab50b139428cea1aaff9974ebee5742e # release-1.10.0
|
||||
OVERRIDE_FIND_PACKAGE
|
||||
)
|
||||
FetchContent_Declare(
|
||||
Catch2
|
||||
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
|
||||
GIT_TAG de6fe184a9ac1a06895cdd1c9b437f0a0bdf14ad # v2.13.4
|
||||
OVERRIDE_FIND_PACKAGE
|
||||
)
|
||||
|
||||
# The following will automatically forward through to FetchContent_MakeAvailable()
|
||||
find_package(googletest)
|
||||
find_package(Catch2)
|
||||
|
||||
CMake provides a FindGTest module which defines some variables that older
|
||||
projects may use instead of linking to the imported targets. To support
|
||||
those cases, we can provide an extras file. In keeping with the
|
||||
"first to define, wins" philosophy of ``FetchContent``, we only write out
|
||||
that file if something else hasn't already done so.
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
FetchContent_MakeAvailable(googletest)
|
||||
|
||||
if(NOT EXISTS ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/googletest-extras.cmake AND
|
||||
NOT EXISTS ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/googletestExtras.cmake)
|
||||
file(WRITE ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/googletest-extras.cmake
|
||||
[=[
|
||||
if("${GTEST_LIBRARIES}" STREQUAL "" AND TARGET GTest::gtest)
|
||||
set(GTEST_LIBRARIES GTest::gtest)
|
||||
endif()
|
||||
if("${GTEST_MAIN_LIBRARIES}" STREQUAL "" AND TARGET GTest::gtest_main)
|
||||
set(GTEST_MAIN_LIBRARIES GTest::gtest_main)
|
||||
endif()
|
||||
if("${GTEST_BOTH_LIBRARIES}" STREQUAL "")
|
||||
set(GTEST_BOTH_LIBRARIES ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES})
|
||||
endif()
|
||||
]=]
|
||||
endif()
|
||||
|
||||
Projects will also likely be using ``find_package(GTest)`` rather than
|
||||
``find_package(googletest)``, but it is possible to make use of the
|
||||
:variable:`CMAKE_FIND_PACKAGE_REDIRECTS_DIR` area to pull in the latter as
|
||||
a dependency of the former. This is likely to be sufficient to satisfy
|
||||
a typical ``find_package(GTest)`` call.
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
FetchContent_MakeAvailable(googletest)
|
||||
|
||||
if(NOT EXISTS ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/gtest-config.cmake AND
|
||||
NOT EXISTS ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/GTestConfig.cmake)
|
||||
file(WRITE ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/gtest-config.cmake
|
||||
[=[
|
||||
include(CMakeFindDependencyMacro)
|
||||
find_dependency(googletest)
|
||||
]=]
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/gtest-config-version.cmake AND
|
||||
NOT EXISTS ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/GTestConfigVersion.cmake)
|
||||
file(WRITE ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/gtest-config-version.cmake
|
||||
[=[
|
||||
include(${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/googletest-config-version.cmake OPTIONAL)
|
||||
if(NOT PACKAGE_VERSION_COMPATIBLE)
|
||||
include(${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/googletestConfigVersion.cmake OPTIONAL)
|
||||
endif()
|
||||
]=]
|
||||
endif()
|
||||
|
||||
Overriding Where To Find CMakeLists.txt
|
||||
"""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
If the sub-project's ``CMakeLists.txt`` file is not at the top level of its
|
||||
source tree, the ``SOURCE_SUBDIR`` option can be used to tell ``FetchContent``
|
||||
where to find it. The following example shows how to use that option and
|
||||
@@ -550,6 +808,9 @@ it into the main build:
|
||||
set(protobuf_BUILD_TESTS OFF)
|
||||
FetchContent_MakeAvailable(protobuf)
|
||||
|
||||
Complex Dependency Hierarchies
|
||||
""""""""""""""""""""""""""""""
|
||||
|
||||
In more complex project hierarchies, the dependency relationships can be more
|
||||
complicated. Consider a hierarchy where ``projA`` is the top level project and
|
||||
it depends directly on projects ``projB`` and ``projC``. Both ``projB`` and
|
||||
@@ -647,6 +908,8 @@ A few key points should be noted in the above:
|
||||
child projects. This saves repeating the same thing at each level of the
|
||||
project hierarchy unnecessarily.
|
||||
|
||||
Populating Content Without Adding It To The Build
|
||||
"""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
Projects don't always need to add the populated content to the build.
|
||||
Sometimes the project just wants to make the downloaded content available at
|
||||
@@ -682,7 +945,10 @@ named toolchain file relative to the build directory. Because the tarball has
|
||||
already been downloaded and unpacked by then, the toolchain file will be in
|
||||
place, even the very first time that ``cmake`` is run in the build directory.
|
||||
|
||||
Lastly, the following example demonstrates how one might download and unpack a
|
||||
Populating Content In CMake Script Mode
|
||||
"""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
This last example demonstrates how one might download and unpack a
|
||||
firmware tarball using CMake's :manual:`script mode <cmake(1)>`. The call to
|
||||
:command:`FetchContent_Populate` specifies all the content details and the
|
||||
unpacked firmware will be placed in a ``firmware`` directory below the
|
||||
@@ -722,19 +988,79 @@ current working directory.
|
||||
function(__FetchContent_declareDetails contentName)
|
||||
|
||||
string(TOLOWER ${contentName} contentNameLower)
|
||||
set(propertyName "_FetchContent_${contentNameLower}_savedDetails")
|
||||
get_property(alreadyDefined GLOBAL PROPERTY ${propertyName} DEFINED)
|
||||
if(NOT alreadyDefined)
|
||||
define_property(GLOBAL PROPERTY ${propertyName}
|
||||
BRIEF_DOCS "Internal implementation detail of FetchContent_Populate()"
|
||||
FULL_DOCS "Details used by FetchContent_Populate() for ${contentName}"
|
||||
set(savedDetailsPropertyName "_FetchContent_${contentNameLower}_savedDetails")
|
||||
get_property(alreadyDefined GLOBAL PROPERTY ${savedDetailsPropertyName} DEFINED)
|
||||
if(alreadyDefined)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if("${FETCHCONTENT_TRY_FIND_PACKAGE_MODE}" STREQUAL "ALWAYS")
|
||||
set(__tryFindPackage TRUE)
|
||||
set(__tryFindPackageAllowed TRUE)
|
||||
elseif("${FETCHCONTENT_TRY_FIND_PACKAGE_MODE}" STREQUAL "NEVER")
|
||||
set(__tryFindPackage FALSE)
|
||||
set(__tryFindPackageAllowed FALSE)
|
||||
elseif("${FETCHCONTENT_TRY_FIND_PACKAGE_MODE}" STREQUAL "OPT_IN" OR
|
||||
NOT DEFINED FETCHCONTENT_TRY_FIND_PACKAGE_MODE)
|
||||
set(__tryFindPackage FALSE)
|
||||
set(__tryFindPackageAllowed TRUE)
|
||||
else()
|
||||
message(FATAL_ERROR
|
||||
"Unsupported value for FETCHCONTENT_TRY_FIND_PACKAGE_MODE: "
|
||||
"${FETCHCONTENT_TRY_FIND_PACKAGE_MODE}"
|
||||
)
|
||||
set(__cmdArgs)
|
||||
foreach(__item IN LISTS ARGN)
|
||||
string(APPEND __cmdArgs " [==[${__item}]==]")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
set(__cmdArgs)
|
||||
set(__findPackageArgs)
|
||||
foreach(__item IN LISTS ARGN)
|
||||
if(DEFINED __findPackageArgs)
|
||||
# All remaining args are for find_package()
|
||||
string(APPEND __findPackageArgs " [==[${__item}]==]")
|
||||
continue()
|
||||
endif()
|
||||
|
||||
# Still processing non-find_package() args
|
||||
if(__item STREQUAL "FIND_PACKAGE_ARGS")
|
||||
if(__tryFindPackageAllowed)
|
||||
set(__tryFindPackage TRUE)
|
||||
endif()
|
||||
# All arguments after this keyword are for find_package(). Define the
|
||||
# variable but with an empty value initially. This allows us to check
|
||||
# at the start of the loop whether to store remaining items in this
|
||||
# variable or not. Note that there could be no more args, which is still
|
||||
# a valid case because we automatically provide ${contentName} as the
|
||||
# package name and there may not need to be any further arguments.
|
||||
set(__findPackageArgs "")
|
||||
continue() # Don't store this item
|
||||
elseif(__item STREQUAL "OVERRIDE_FIND_PACKAGE")
|
||||
set(__tryFindPackageAllowed FALSE)
|
||||
# Define a separate dedicated property for find_package() to check
|
||||
# in its implementation. This will be a placeholder until FetchContent
|
||||
# actually does the population. After that, we will have created a
|
||||
# stand-in config file that find_package() will pick up instead.
|
||||
set(propertyName "_FetchContent_${contentNameLower}_override_find_package")
|
||||
define_property(GLOBAL PROPERTY ${propertyName})
|
||||
set_property(GLOBAL PROPERTY ${propertyName} TRUE)
|
||||
endif()
|
||||
|
||||
string(APPEND __cmdArgs " [==[${__item}]==]")
|
||||
endforeach()
|
||||
|
||||
define_property(GLOBAL PROPERTY ${savedDetailsPropertyName})
|
||||
cmake_language(EVAL CODE
|
||||
"set_property(GLOBAL PROPERTY ${savedDetailsPropertyName} ${__cmdArgs})"
|
||||
)
|
||||
|
||||
if(__tryFindPackage AND __tryFindPackageAllowed)
|
||||
set(propertyName "_FetchContent_${contentNameLower}_find_package_args")
|
||||
define_property(GLOBAL PROPERTY ${propertyName})
|
||||
if(NOT QUIET IN_LIST __findPackageArgs)
|
||||
list(INSERT __findPackageArgs 0 QUIET)
|
||||
endif()
|
||||
cmake_language(EVAL CODE
|
||||
"set_property(GLOBAL PROPERTY ${propertyName} ${__cmdArgs})")
|
||||
"set_property(GLOBAL PROPERTY ${propertyName} ${__findPackageArgs})"
|
||||
)
|
||||
endif()
|
||||
|
||||
endfunction()
|
||||
@@ -763,6 +1089,15 @@ endfunction()
|
||||
# SOURCE_DIR and BUILD_DIR.
|
||||
function(FetchContent_Declare contentName)
|
||||
|
||||
# Always check this even if we won't save these details.
|
||||
# This helps projects catch errors earlier.
|
||||
if("OVERRIDE_FIND_PACKAGE" IN_LIST ARGN AND "FIND_PACKAGE_ARGS" IN_LIST ARGN)
|
||||
message(FATAL_ERROR
|
||||
"Cannot specify both OVERRIDE_FIND_PACKAGE and FIND_PACKAGE_ARGS "
|
||||
"when declaring details for ${contentName}"
|
||||
)
|
||||
endif()
|
||||
|
||||
set(options "")
|
||||
set(oneValueArgs SVN_REPOSITORY)
|
||||
set(multiValueArgs "")
|
||||
@@ -810,35 +1145,35 @@ endfunction()
|
||||
# The setter also records the source and binary dirs used.
|
||||
#=======================================================================
|
||||
|
||||
# Internal use, projects must not call this directly. It is
|
||||
# intended for use by the FetchContent_Populate() function to
|
||||
# Internal use, projects must not call this directly. It is intended
|
||||
# for use by things like the FetchContent_Populate() function to
|
||||
# record when FetchContent_Populate() is called for a particular
|
||||
# content name.
|
||||
function(__FetchContent_setPopulated contentName sourceDir binaryDir)
|
||||
function(__FetchContent_setPopulated contentName)
|
||||
|
||||
cmake_parse_arguments(PARSE_ARGV 1 arg
|
||||
""
|
||||
"SOURCE_DIR;BINARY_DIR"
|
||||
""
|
||||
)
|
||||
if(NOT "${arg_UNPARSED_ARGUMENTS}" STREQUAL "")
|
||||
message(FATAL_ERROR "Unsupported arguments: ${arg_UNPARSED_ARGUMENTS}")
|
||||
endif()
|
||||
|
||||
string(TOLOWER ${contentName} contentNameLower)
|
||||
set(prefix "_FetchContent_${contentNameLower}")
|
||||
|
||||
set(propertyName "${prefix}_sourceDir")
|
||||
define_property(GLOBAL PROPERTY ${propertyName}
|
||||
BRIEF_DOCS "Internal implementation detail of FetchContent_Populate()"
|
||||
FULL_DOCS "Details used by FetchContent_Populate() for ${contentName}"
|
||||
)
|
||||
set_property(GLOBAL PROPERTY ${propertyName} ${sourceDir})
|
||||
define_property(GLOBAL PROPERTY ${propertyName})
|
||||
set_property(GLOBAL PROPERTY ${propertyName} "${arg_SOURCE_DIR}")
|
||||
|
||||
set(propertyName "${prefix}_binaryDir")
|
||||
define_property(GLOBAL PROPERTY ${propertyName}
|
||||
BRIEF_DOCS "Internal implementation detail of FetchContent_Populate()"
|
||||
FULL_DOCS "Details used by FetchContent_Populate() for ${contentName}"
|
||||
)
|
||||
set_property(GLOBAL PROPERTY ${propertyName} ${binaryDir})
|
||||
define_property(GLOBAL PROPERTY ${propertyName})
|
||||
set_property(GLOBAL PROPERTY ${propertyName} "${arg_BINARY_DIR}")
|
||||
|
||||
set(propertyName "${prefix}_populated")
|
||||
define_property(GLOBAL PROPERTY ${propertyName}
|
||||
BRIEF_DOCS "Internal implementation detail of FetchContent_Populate()"
|
||||
FULL_DOCS "Details used by FetchContent_Populate() for ${contentName}"
|
||||
)
|
||||
set_property(GLOBAL PROPERTY ${propertyName} True)
|
||||
define_property(GLOBAL PROPERTY ${propertyName})
|
||||
set_property(GLOBAL PROPERTY ${propertyName} TRUE)
|
||||
|
||||
endfunction()
|
||||
|
||||
@@ -1134,7 +1469,15 @@ function(FetchContent_Populate contentName)
|
||||
# populated this content before in case the caller forgot to check.
|
||||
FetchContent_GetProperties(${contentName})
|
||||
if(${contentNameLower}_POPULATED)
|
||||
message(FATAL_ERROR "Content ${contentName} already populated in ${${contentNameLower}_SOURCE_DIR}")
|
||||
if("${${contentNameLower}_SOURCE_DIR}" STREQUAL "")
|
||||
message(FATAL_ERROR
|
||||
"Content ${contentName} already populated by find_package()"
|
||||
)
|
||||
else()
|
||||
message(FATAL_ERROR
|
||||
"Content ${contentName} already populated in ${${contentNameLower}_SOURCE_DIR}"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
__FetchContent_getSavedDetails(${contentName} contentDetails)
|
||||
@@ -1212,7 +1555,9 @@ function(FetchContent_Populate contentName)
|
||||
|
||||
set(__detailsQuoted)
|
||||
foreach(__item IN LISTS contentDetails)
|
||||
string(APPEND __detailsQuoted " [==[${__item}]==]")
|
||||
if(NOT __item STREQUAL "OVERRIDE_FIND_PACKAGE")
|
||||
string(APPEND __detailsQuoted " [==[${__item}]==]")
|
||||
endif()
|
||||
endforeach()
|
||||
cmake_language(EVAL CODE "
|
||||
__FetchContent_directPopulate(
|
||||
@@ -1232,8 +1577,8 @@ function(FetchContent_Populate contentName)
|
||||
|
||||
__FetchContent_setPopulated(
|
||||
${contentName}
|
||||
${${contentNameLower}_SOURCE_DIR}
|
||||
${${contentNameLower}_BINARY_DIR}
|
||||
SOURCE_DIR "${${contentNameLower}_SOURCE_DIR}"
|
||||
BINARY_DIR "${${contentNameLower}_BINARY_DIR}"
|
||||
)
|
||||
|
||||
# Pass variables back to the caller. The variables passed back here
|
||||
@@ -1245,6 +1590,53 @@ function(FetchContent_Populate contentName)
|
||||
|
||||
endfunction()
|
||||
|
||||
function(__FetchContent_setupFindPackageRedirection contentName)
|
||||
|
||||
__FetchContent_getSavedDetails(${contentName} contentDetails)
|
||||
|
||||
string(TOLOWER ${contentName} contentNameLower)
|
||||
get_property(wantFindPackage GLOBAL PROPERTY
|
||||
_FetchContent_${contentNameLower}_find_package_args
|
||||
DEFINED
|
||||
)
|
||||
|
||||
if(NOT wantFindPackage AND NOT OVERRIDE_FIND_PACKAGE IN_LIST contentDetails)
|
||||
# No find_package() redirection allowed
|
||||
return()
|
||||
endif()
|
||||
|
||||
# We write out dep-config.cmake and dep-config-version.cmake file name
|
||||
# forms here because they are forced to lowercase. FetchContent
|
||||
# dependency names are case-insensitive, but find_package() config files
|
||||
# are only case-insensitive for the -config and -config-version forms,
|
||||
# not the Config and ConfigVersion forms.
|
||||
set(inFileDir ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/FetchContent)
|
||||
set(configFilePrefix1 "${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/${contentName}Config")
|
||||
set(configFilePrefix2 "${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/${contentNameLower}-config")
|
||||
if(NOT EXISTS "${configFilePrefix1}.cmake" AND
|
||||
NOT EXISTS "${configFilePrefix2}.cmake")
|
||||
configure_file(${inFileDir}/package-config.cmake.in
|
||||
"${configFilePrefix2}.cmake" @ONLY
|
||||
)
|
||||
endif()
|
||||
if(NOT EXISTS "${configFilePrefix1}Version.cmake" AND
|
||||
NOT EXISTS "${configFilePrefix2}-version.cmake")
|
||||
configure_file(${inFileDir}/package-config-version.cmake.in
|
||||
"${configFilePrefix2}-version.cmake" @ONLY
|
||||
)
|
||||
endif()
|
||||
|
||||
# Now that we've created the redirected package config files, prevent
|
||||
# find_package() from delegating to FetchContent and let it find these
|
||||
# config files through its normal processing.
|
||||
set(propertyName "${prefix}_override_find_package")
|
||||
set(GLOBAL PROPERTY ${propertyName} FALSE)
|
||||
set(${contentName}_DIR "${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}"
|
||||
CACHE INTERNAL "Redirected by FetchContent"
|
||||
)
|
||||
|
||||
endfunction()
|
||||
|
||||
# Arguments are assumed to be the names of dependencies that have been
|
||||
# declared previously and should be populated. It is not an error if
|
||||
# any of them have already been populated (they will just be skipped in
|
||||
@@ -1255,9 +1647,48 @@ macro(FetchContent_MakeAvailable)
|
||||
|
||||
foreach(__cmake_contentName IN ITEMS ${ARGV})
|
||||
string(TOLOWER ${__cmake_contentName} __cmake_contentNameLower)
|
||||
|
||||
# If user specified FETCHCONTENT_SOURCE_DIR_... for this dependency, that
|
||||
# overrides everything else and we shouldn't try to use find_package().
|
||||
string(TOUPPER ${__cmake_contentName} __cmake_contentNameUpper)
|
||||
if("${FETCHCONTENT_SOURCE_DIR_${__cmake_contentNameUpper}}" STREQUAL "")
|
||||
# Check if we've been asked to try find_package() first, even if we
|
||||
# have already populated this dependency. If we previously tried to
|
||||
# use find_package() for this and it succeeded, those things might
|
||||
# no longer be in scope, so we have to do it again.
|
||||
set(__cmake_fpArgsPropName "_FetchContent_${__cmake_contentNameLower}_find_package_args")
|
||||
get_property(__cmake_haveFpArgs GLOBAL PROPERTY ${__cmake_fpArgsPropName} DEFINED)
|
||||
if(__cmake_haveFpArgs)
|
||||
message(VERBOSE "Trying find_package(${__cmake_contentName} ...) before FetchContent")
|
||||
get_property(__cmake_fpArgs GLOBAL PROPERTY ${__cmake_fpArgsPropName})
|
||||
|
||||
# This call could lead to FetchContent_MakeAvailable() being called for
|
||||
# a nested dependency and it may occur in the current variable scope.
|
||||
# We have to save/restore the variables we need to preserve.
|
||||
list(APPEND __cmake_fcCurrentNameStack
|
||||
${__cmake_contentName}
|
||||
${__cmake_contentNameLower}
|
||||
)
|
||||
find_package(${__cmake_contentName} ${__cmake_fpArgs})
|
||||
list(POP_BACK __cmake_fcCurrentNameStack
|
||||
__cmake_contentNameLower
|
||||
__cmake_contentName
|
||||
)
|
||||
|
||||
if(${__cmake_contentName}_FOUND)
|
||||
set(${__cmake_contentNameLower}_SOURCE_DIR "")
|
||||
set(${__cmake_contentNameLower}_BINARY_DIR "")
|
||||
set(${__cmake_contentNameLower}_POPULATED TRUE)
|
||||
__FetchContent_setPopulated(${__cmake_contentName})
|
||||
continue()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
FetchContent_GetProperties(${__cmake_contentName})
|
||||
if(NOT ${__cmake_contentNameLower}_POPULATED)
|
||||
FetchContent_Populate(${__cmake_contentName})
|
||||
__FetchContent_setupFindPackageRedirection(${__cmake_contentName})
|
||||
|
||||
# Only try to call add_subdirectory() if the populated content
|
||||
# can be treated that way. Protecting the call with the check
|
||||
@@ -1283,13 +1714,13 @@ macro(FetchContent_MakeAvailable)
|
||||
endif()
|
||||
|
||||
unset(__cmake_srcdir)
|
||||
unset(__cmake_contentDetails)
|
||||
unset(__cmake_arg_SOURCE_SUBDIR)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# clear local variables to prevent leaking into the caller's scope
|
||||
unset(__cmake_contentName)
|
||||
unset(__cmake_contentNameLower)
|
||||
unset(__cmake_contentDetails)
|
||||
unset(__cmake_arg_SOURCE_SUBDIR)
|
||||
|
||||
endmacro()
|
||||
|
||||
5
Modules/FetchContent/package-config-version.cmake.in
Normal file
5
Modules/FetchContent/package-config-version.cmake.in
Normal file
@@ -0,0 +1,5 @@
|
||||
# Automatically generated by CMake's FetchContent module.
|
||||
# Do not edit this file, it will be regenerated every time CMake runs.
|
||||
|
||||
# Version not available, assuming it is compatible
|
||||
set(PACKAGE_VERSION_COMPATIBLE TRUE)
|
||||
11
Modules/FetchContent/package-config.cmake.in
Normal file
11
Modules/FetchContent/package-config.cmake.in
Normal file
@@ -0,0 +1,11 @@
|
||||
# Automatically generated by CMake's FetchContent module.
|
||||
# Do not edit this file, it will be regenerated every time CMake runs.
|
||||
|
||||
# Projects or the dependencies themselves can provide the following files.
|
||||
# The files should define any additional commands or variables that the
|
||||
# dependency would normally provide but which won't be available globally
|
||||
# if the dependency is brought into the build via FetchContent instead.
|
||||
# For dependencies that only provide imported targets and no commands,
|
||||
# these typically won't be needed.
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/@contentNameLower@-extra.cmake" OPTIONAL)
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/@contentName@Extra.cmake" OPTIONAL)
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "cmsys/String.h"
|
||||
|
||||
#include "cmAlgorithms.h"
|
||||
#include "cmListFileCache.h"
|
||||
#include "cmMakefile.h"
|
||||
#include "cmMessageType.h"
|
||||
#include "cmPolicies.h"
|
||||
@@ -42,6 +43,8 @@
|
||||
class cmExecutionStatus;
|
||||
class cmFileList;
|
||||
|
||||
cmFindPackageCommand::PathLabel
|
||||
cmFindPackageCommand::PathLabel::PackageRedirect("PACKAGE_REDIRECT");
|
||||
cmFindPackageCommand::PathLabel cmFindPackageCommand::PathLabel::UserRegistry(
|
||||
"PACKAGE_REGISTRY");
|
||||
cmFindPackageCommand::PathLabel cmFindPackageCommand::PathLabel::Builds(
|
||||
@@ -109,8 +112,10 @@ void cmFindPackageCommand::AppendSearchPathGroups()
|
||||
{
|
||||
std::vector<cmFindCommon::PathLabel>* labels;
|
||||
|
||||
// Update the All group with new paths
|
||||
// Update the All group with new paths. Note that package redirection must
|
||||
// take precedence over everything else, so it has to be first in the array.
|
||||
labels = &this->PathGroupLabelMap[PathGroup::All];
|
||||
labels->insert(labels->begin(), PathLabel::PackageRedirect);
|
||||
labels->insert(
|
||||
std::find(labels->begin(), labels->end(), PathLabel::CMakeSystem),
|
||||
PathLabel::UserRegistry);
|
||||
@@ -121,6 +126,8 @@ void cmFindPackageCommand::AppendSearchPathGroups()
|
||||
PathLabel::SystemRegistry);
|
||||
|
||||
// Create the new path objects
|
||||
this->LabeledPaths.insert(
|
||||
std::make_pair(PathLabel::PackageRedirect, cmSearchPath(this)));
|
||||
this->LabeledPaths.insert(
|
||||
std::make_pair(PathLabel::UserRegistry, cmSearchPath(this)));
|
||||
this->LabeledPaths.insert(
|
||||
@@ -552,9 +559,62 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
|
||||
|
||||
this->SetModuleVariables(components);
|
||||
|
||||
// See if we have been told to delegate to FetchContent or some other
|
||||
// redirected config package first. We have to check all names that
|
||||
// find_package() may look for, but only need to invoke the override for the
|
||||
// first one that matches.
|
||||
auto overrideNames = this->Names;
|
||||
if (overrideNames.empty()) {
|
||||
overrideNames.push_back(this->Name);
|
||||
}
|
||||
bool forceConfigMode = false;
|
||||
const auto redirectsDir =
|
||||
this->Makefile->GetSafeDefinition("CMAKE_FIND_PACKAGE_REDIRECTS_DIR");
|
||||
for (const auto& overrideName : overrideNames) {
|
||||
const auto nameLower = cmSystemTools::LowerCase(overrideName);
|
||||
const auto delegatePropName =
|
||||
cmStrCat("_FetchContent_", nameLower, "_override_find_package");
|
||||
const cmValue delegateToFetchContentProp =
|
||||
this->Makefile->GetState()->GetGlobalProperty(delegatePropName);
|
||||
if (delegateToFetchContentProp.IsOn()) {
|
||||
// When this property is set, the FetchContent module has already been
|
||||
// included at least once, so we know the FetchContent_MakeAvailable()
|
||||
// command will be defined. Any future find_package() calls after this
|
||||
// one for this package will by-pass this once-only delegation.
|
||||
// The following call will typically create a <name>-config.cmake file
|
||||
// in the redirectsDir, which we still want to process like any other
|
||||
// config file to ensure we follow normal find_package() processing.
|
||||
cmListFileFunction func(
|
||||
"FetchContent_MakeAvailable", 0, 0,
|
||||
{ cmListFileArgument(overrideName, cmListFileArgument::Unquoted, 0) });
|
||||
if (!this->Makefile->ExecuteCommand(func, this->Status)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (cmSystemTools::FileExists(
|
||||
cmStrCat(redirectsDir, '/', nameLower, "-config.cmake")) ||
|
||||
cmSystemTools::FileExists(
|
||||
cmStrCat(redirectsDir, '/', overrideName, "Config.cmake"))) {
|
||||
// Force the use of this redirected config package file, regardless of
|
||||
// the type of find_package() call. Files in the redirectsDir must always
|
||||
// take priority over everything else.
|
||||
forceConfigMode = true;
|
||||
this->UseConfigFiles = true;
|
||||
this->UseFindModules = false;
|
||||
this->Names.clear();
|
||||
this->Names.emplace_back(overrideName); // Force finding this one
|
||||
this->Variable = cmStrCat(this->Name, "_DIR");
|
||||
this->SetConfigDirCacheVariable(redirectsDir);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// See if there is a Find<PackageName>.cmake module.
|
||||
bool loadedPackage = false;
|
||||
if (this->Makefile->IsOn("CMAKE_FIND_PACKAGE_PREFER_CONFIG")) {
|
||||
if (forceConfigMode) {
|
||||
loadedPackage = this->FindPackageUsingConfigMode();
|
||||
} else if (this->Makefile->IsOn("CMAKE_FIND_PACKAGE_PREFER_CONFIG")) {
|
||||
if (this->UseConfigFiles && this->FindPackageUsingConfigMode()) {
|
||||
loadedPackage = true;
|
||||
} else {
|
||||
@@ -1164,19 +1224,24 @@ bool cmFindPackageCommand::FindConfig()
|
||||
} else {
|
||||
init = this->Variable + "-NOTFOUND";
|
||||
}
|
||||
// We force the value since we do not get here if it was already set.
|
||||
this->SetConfigDirCacheVariable(init);
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
void cmFindPackageCommand::SetConfigDirCacheVariable(const std::string& value)
|
||||
{
|
||||
std::string help =
|
||||
cmStrCat("The directory containing a CMake configuration file for ",
|
||||
this->Name, '.');
|
||||
// We force the value since we do not get here if it was already set.
|
||||
this->Makefile->AddCacheDefinition(this->Variable, init, help.c_str(),
|
||||
this->Makefile->AddCacheDefinition(this->Variable, value, help.c_str(),
|
||||
cmStateEnums::PATH, true);
|
||||
if (this->Makefile->GetPolicyStatus(cmPolicies::CMP0126) ==
|
||||
cmPolicies::NEW &&
|
||||
this->Makefile->IsNormalDefinitionSet(this->Variable)) {
|
||||
this->Makefile->AddDefinition(this->Variable, init);
|
||||
this->Makefile->AddDefinition(this->Variable, value);
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
bool cmFindPackageCommand::FindPrefixedConfig()
|
||||
@@ -1327,6 +1392,8 @@ inline std::size_t collectPathsForDebug(std::string& buffer,
|
||||
|
||||
void cmFindPackageCommand::ComputePrefixes()
|
||||
{
|
||||
this->FillPrefixesPackageRedirect();
|
||||
|
||||
if (!this->NoDefaultPath) {
|
||||
if (!this->NoPackageRootPath) {
|
||||
this->FillPrefixesPackageRoot();
|
||||
@@ -1360,6 +1427,23 @@ void cmFindPackageCommand::ComputePrefixes()
|
||||
this->ComputeFinalPaths(IgnorePaths::No);
|
||||
}
|
||||
|
||||
void cmFindPackageCommand::FillPrefixesPackageRedirect()
|
||||
{
|
||||
cmSearchPath& paths = this->LabeledPaths[PathLabel::PackageRedirect];
|
||||
|
||||
const auto redirectDir =
|
||||
this->Makefile->GetDefinition("CMAKE_FIND_PACKAGE_REDIRECTS_DIR");
|
||||
if (redirectDir && !redirectDir->empty()) {
|
||||
paths.AddPath(*redirectDir);
|
||||
}
|
||||
if (this->DebugMode) {
|
||||
std::string debugBuffer =
|
||||
"The internally managed CMAKE_FIND_PACKAGE_REDIRECTS_DIR.\n";
|
||||
collectPathsForDebug(debugBuffer, paths);
|
||||
this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
void cmFindPackageCommand::FillPrefixesPackageRoot()
|
||||
{
|
||||
cmSearchPath& paths = this->LabeledPaths[PathLabel::PackageRoot];
|
||||
|
||||
@@ -76,6 +76,7 @@ private:
|
||||
: cmFindCommon::PathLabel(label)
|
||||
{
|
||||
}
|
||||
static PathLabel PackageRedirect;
|
||||
static PathLabel UserRegistry;
|
||||
static PathLabel Builds;
|
||||
static PathLabel SystemRegistry;
|
||||
@@ -119,8 +120,10 @@ private:
|
||||
};
|
||||
bool ReadListFile(const std::string& f, PolicyScopeRule psr);
|
||||
void StoreVersionFound();
|
||||
void SetConfigDirCacheVariable(const std::string& value);
|
||||
|
||||
void ComputePrefixes();
|
||||
void FillPrefixesPackageRedirect();
|
||||
void FillPrefixesPackageRoot();
|
||||
void FillPrefixesCMakeEnvironment();
|
||||
void FillPrefixesCMakeVariable();
|
||||
|
||||
@@ -2103,6 +2103,21 @@ int cmake::ActualConfigure()
|
||||
cmStateEnums::INTERNAL);
|
||||
}
|
||||
|
||||
// We want to create the package redirects directory as early as possible,
|
||||
// but not before pre-configure checks have passed. This ensures we get
|
||||
// errors about inappropriate source/binary directories first.
|
||||
const auto redirectsDir =
|
||||
cmStrCat(this->GetHomeOutputDirectory(), "/CMakeFiles/pkgRedirects");
|
||||
cmSystemTools::RemoveADirectory(redirectsDir);
|
||||
if (!cmSystemTools::MakeDirectory(redirectsDir)) {
|
||||
cmSystemTools::Error(
|
||||
"Unable to (re)create the private pkgRedirects directory:\n" +
|
||||
redirectsDir);
|
||||
return -1;
|
||||
}
|
||||
this->AddCacheEntry("CMAKE_FIND_PACKAGE_REDIRECTS_DIR", redirectsDir,
|
||||
"Value Computed by CMake.", cmStateEnums::STATIC);
|
||||
|
||||
// no generator specified on the command line
|
||||
if (!this->GlobalGenerator) {
|
||||
cmValue genName = this->State->GetInitializedCacheValue("CMAKE_GENERATOR");
|
||||
|
||||
@@ -784,6 +784,7 @@ if(CMake_TEST_RunCMake_ExternalProject_DOWNLOAD_SERVER_TIMEOUT)
|
||||
endif()
|
||||
add_RunCMake_test(ExternalProject)
|
||||
add_RunCMake_test(FetchContent)
|
||||
add_RunCMake_test(FetchContent_find_package)
|
||||
set(CTestCommandLine_ARGS -DPython_EXECUTABLE=${Python_EXECUTABLE})
|
||||
if(NOT CMake_TEST_EXTERNAL_CMAKE)
|
||||
list(APPEND CTestCommandLine_ARGS -DTEST_AFFINITY=$<TARGET_FILE:testAffinity>)
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.13...3.23)
|
||||
project(AddedProject LANGUAGES NONE)
|
||||
|
||||
message(STATUS "Confirmation project has been added")
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1,3 @@
|
||||
CMake Error at .*/FetchContent.cmake:[0-9]+ \(message\):
|
||||
Cannot specify both OVERRIDE_FIND_PACKAGE and FIND_PACKAGE_ARGS when
|
||||
declaring details for AddedProject
|
||||
@@ -0,0 +1,9 @@
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(
|
||||
AddedProject
|
||||
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/AddedProject
|
||||
# The following two args are mutually exclusive
|
||||
OVERRIDE_FIND_PACKAGE
|
||||
FIND_PACKAGE_ARGS
|
||||
)
|
||||
@@ -0,0 +1,3 @@
|
||||
file(WRITE "${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/dummy_file.txt"
|
||||
"This file should be deleted the next time CMake runs"
|
||||
)
|
||||
@@ -0,0 +1,9 @@
|
||||
file(GLOB contents LIST_DIRECTORIES true "${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/*")
|
||||
|
||||
if(NOT contents STREQUAL "")
|
||||
list(JOIN contents "\n" fileList)
|
||||
message(FATAL_ERROR
|
||||
"CMAKE_FIND_PACKAGE_REDIRECTS_DIR is not empty:\n"
|
||||
"${fileList}"
|
||||
)
|
||||
endif()
|
||||
@@ -0,0 +1,18 @@
|
||||
if(NOT DEFINED CMAKE_FIND_PACKAGE_REDIRECTS_DIR)
|
||||
message(FATAL_ERROR "CMAKE_FIND_PACKAGE_REDIRECTS_DIR is not defined")
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_FIND_PACKAGE_REDIRECTS_DIR STREQUAL "${CMAKE_BINARY_DIR}/CMakeFiles/pkgRedirects")
|
||||
message(FATAL_ERROR
|
||||
"CMAKE_FIND_PACKAGE_REDIRECTS_DIR has wrong value\n"
|
||||
" Expected: ${CMAKE_BINARY_DIR}/CMakeFiles/pkgRedirects\n"
|
||||
" Actual: ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS "${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}")
|
||||
message(FATAL_ERROR
|
||||
"Directory CMAKE_FIND_PACKAGE_REDIRECTS_DIR points to does not exist:\n"
|
||||
"${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}"
|
||||
)
|
||||
endif()
|
||||
7
Tests/RunCMake/FetchContent_find_package/CMakeLists.txt
Normal file
7
Tests/RunCMake/FetchContent_find_package/CMakeLists.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.23)
|
||||
project(${RunCMake_TEST} NONE)
|
||||
|
||||
# Tests assume no previous downloads in the output directory
|
||||
file(REMOVE_RECURSE ${CMAKE_CURRENT_BINARY_DIR}/_deps)
|
||||
|
||||
include(${RunCMake_TEST}.cmake)
|
||||
@@ -0,0 +1 @@
|
||||
message(FATAL_ERROR "Unexpectedly added directory via FetchContent_MakeAvailable()")
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1 @@
|
||||
No content details recorded for t1
|
||||
@@ -0,0 +1,3 @@
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Populate(t1)
|
||||
@@ -0,0 +1,2 @@
|
||||
set(AddedProject_FOUND TRUE)
|
||||
message(STATUS "Loaded AddedProject from package config")
|
||||
@@ -0,0 +1,2 @@
|
||||
set(FirstProject_FOUND TRUE)
|
||||
message(STATUS "Loaded FirstProject from package config")
|
||||
@@ -0,0 +1 @@
|
||||
message(FATAL_ERROR "Unexpectedly found SecondProject via find_package()")
|
||||
@@ -0,0 +1 @@
|
||||
message(FATAL_ERROR "First project used Find module")
|
||||
@@ -0,0 +1 @@
|
||||
message(FATAL_ERROR "Second project used Find module")
|
||||
@@ -0,0 +1,3 @@
|
||||
Confirmation project has been added
|
||||
(-- )?Lowercase extra file was read
|
||||
(-- )?Uppercase extra file was read
|
||||
@@ -0,0 +1,20 @@
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(
|
||||
AddedProject
|
||||
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/AddedProject
|
||||
OVERRIDE_FIND_PACKAGE
|
||||
)
|
||||
|
||||
# The default generated config package files are expected to include these when present
|
||||
file(WRITE ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/AddedProjectExtra.cmake [[
|
||||
message(STATUS "Uppercase extra file was read")
|
||||
]]
|
||||
)
|
||||
file(WRITE ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/addedproject-extra.cmake [[
|
||||
message(STATUS "Lowercase extra file was read")
|
||||
]]
|
||||
)
|
||||
|
||||
# This is expected to be re-routed to a FetchContent_MakeAvailable() call
|
||||
find_package(AddedProject REQUIRED)
|
||||
@@ -0,0 +1,3 @@
|
||||
Loaded AddedProject from package config
|
||||
.*Loaded AddedProject from package config
|
||||
.*Loaded AddedProject from package config
|
||||
@@ -0,0 +1,15 @@
|
||||
include(FetchContent)
|
||||
|
||||
set(CMAKE_PREFIX_PATH ${CMAKE_CURRENT_LIST_DIR}/PackageConfigs)
|
||||
|
||||
FetchContent_Declare(
|
||||
AddedProject
|
||||
# Ensure failure if we don't re-route to find_package()
|
||||
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/FatalIfAdded
|
||||
FIND_PACKAGE_ARGS REQUIRED
|
||||
)
|
||||
|
||||
# Cycle through a few calls to exercise global property changes
|
||||
FetchContent_MakeAvailable(AddedProject)
|
||||
find_package(AddedProject REQUIRED)
|
||||
FetchContent_MakeAvailable(AddedProject) # Will re-route to find_package() again
|
||||
@@ -0,0 +1,4 @@
|
||||
.*-- Number of arguments: 6
|
||||
.*-- Argument 3: 'before'
|
||||
.*-- Argument 4: ''
|
||||
.*-- Argument 5: 'after'
|
||||
@@ -0,0 +1,13 @@
|
||||
include(FetchContent)
|
||||
|
||||
# Need to see the download command output
|
||||
set(FETCHCONTENT_QUIET OFF)
|
||||
|
||||
FetchContent_Declare(
|
||||
t1
|
||||
DOWNLOAD_COMMAND ${CMAKE_COMMAND} -P
|
||||
${CMAKE_CURRENT_LIST_DIR}/countArgs.cmake
|
||||
before "" after
|
||||
)
|
||||
|
||||
FetchContent_Populate(t1)
|
||||
@@ -0,0 +1,4 @@
|
||||
(-- )?ConfigForm1 override successful
|
||||
(-- )?ConfigForm2 override successful
|
||||
(-- )?ConfigForm1_VERSION = 1.8
|
||||
(-- )?ConfigForm2_VERSION = 1.9.7
|
||||
@@ -0,0 +1,40 @@
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(
|
||||
ConfigForm1
|
||||
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/FatalIfAdded
|
||||
FIND_PACKAGE_ARGS 1.8 EXACT REQUIRED
|
||||
)
|
||||
file(WRITE ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/ConfigForm1Config.cmake [[
|
||||
set(ConfigForm1_FOUND TRUE)
|
||||
message(STATUS "ConfigForm1 override successful")
|
||||
]]
|
||||
)
|
||||
file(WRITE ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/ConfigForm1ConfigVersion.cmake [[
|
||||
set(PACKAGE_VERSION 1.8)
|
||||
set(PACKAGE_VERSION_EXACT TRUE)
|
||||
set(PACKAGE_VERSION_COMPATIBLE TRUE)
|
||||
]]
|
||||
)
|
||||
|
||||
FetchContent_Declare(
|
||||
ConfigForm2
|
||||
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/FatalIfAdded
|
||||
FIND_PACKAGE_ARGS 1.8 REQUIRED
|
||||
)
|
||||
file(WRITE ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/configform2-config.cmake [[
|
||||
set(ConfigForm2_FOUND TRUE)
|
||||
message(STATUS "ConfigForm2 override successful")
|
||||
]]
|
||||
)
|
||||
file(WRITE ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/configform2-config-version.cmake [[
|
||||
set(PACKAGE_VERSION 1.9.7)
|
||||
set(PACKAGE_VERSION_EXACT FALSE)
|
||||
set(PACKAGE_VERSION_COMPATIBLE TRUE)
|
||||
]]
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(ConfigForm1 ConfigForm2)
|
||||
|
||||
message(STATUS "ConfigForm1_VERSION = ${ConfigForm1_VERSION}")
|
||||
message(STATUS "ConfigForm2_VERSION = ${ConfigForm2_VERSION}")
|
||||
@@ -0,0 +1,9 @@
|
||||
(-- )?find_package\(FirstProject\):
|
||||
(-- )?Confirmation project has been added
|
||||
(-- )?FirstProject_FOUND = 1
|
||||
(-- )?FetchContent_MakeAvailable\(FirstProject\):
|
||||
(-- )?FetchContent_MakeAvailable\(SecondProject\):
|
||||
(-- )?Confirmation project has been added
|
||||
(-- )?find_package\(SecondProject\):
|
||||
(-- )?SecondProject_FOUND = 1
|
||||
(-- )?End of test
|
||||
@@ -0,0 +1,39 @@
|
||||
include(FetchContent)
|
||||
|
||||
set(CMAKE_PREFIX_PATH ${CMAKE_CURRENT_LIST_DIR}/PackageConfigs)
|
||||
|
||||
FetchContent_Declare(
|
||||
FirstProject
|
||||
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/AddedProject
|
||||
OVERRIDE_FIND_PACKAGE
|
||||
)
|
||||
FetchContent_Declare(
|
||||
SecondProject
|
||||
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/AddedProject
|
||||
# Allow a call to find_package() that we know will fail.
|
||||
# This enables redirection of calls to find_package(SecondProject)
|
||||
# after FetchContent_MakeAvailable() populates.
|
||||
FIND_PACKAGE_ARGS NAMES I_do_not_exist
|
||||
)
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/PackageFindModules)
|
||||
|
||||
# Re-directs to FetchContent_MakeAvailable()
|
||||
message(STATUS "find_package(FirstProject):")
|
||||
find_package(FirstProject REQUIRED MODULE)
|
||||
message(STATUS "FirstProject_FOUND = ${FirstProject_FOUND}")
|
||||
|
||||
# Does nothing, already populated
|
||||
message(STATUS "FetchContent_MakeAvailable(FirstProject):")
|
||||
FetchContent_MakeAvailable(FirstProject)
|
||||
|
||||
# Populates as normal
|
||||
message(STATUS "FetchContent_MakeAvailable(SecondProject):")
|
||||
FetchContent_MakeAvailable(SecondProject)
|
||||
|
||||
# Redirects to config package file created by previous command
|
||||
message(STATUS "find_package(SecondProject):")
|
||||
find_package(SecondProject REQUIRED MODULE)
|
||||
message(STATUS "SecondProject_FOUND = ${FirstProject_FOUND}")
|
||||
|
||||
message(STATUS "End of test")
|
||||
22
Tests/RunCMake/FetchContent_find_package/RunCMakeTest.cmake
Normal file
22
Tests/RunCMake/FetchContent_find_package/RunCMakeTest.cmake
Normal file
@@ -0,0 +1,22 @@
|
||||
include(RunCMake)
|
||||
|
||||
unset(RunCMake_TEST_NO_CLEAN)
|
||||
|
||||
function(run_FetchContent_pkgRedirects)
|
||||
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CMAKE_FIND_PACKAGE_REDIRECTS_DIR-AlwaysEmptied-build)
|
||||
run_cmake(CMAKE_FIND_PACKAGE_REDIRECTS_DIR-AlwaysEmptied-Setup)
|
||||
set(RunCMake_TEST_NO_CLEAN 1)
|
||||
run_cmake(CMAKE_FIND_PACKAGE_REDIRECTS_DIR-AlwaysEmptied)
|
||||
endfunction()
|
||||
|
||||
run_cmake(CMAKE_FIND_PACKAGE_REDIRECTS_DIR-Exists)
|
||||
run_FetchContent_pkgRedirects()
|
||||
run_cmake(BadArgs_find_package)
|
||||
run_cmake(PreferFetchContent)
|
||||
run_cmake(Prefer_find_package)
|
||||
run_cmake(ProjectProvidesPackageConfigFiles)
|
||||
run_cmake(Try_find_package-ALWAYS)
|
||||
run_cmake(Try_find_package-NEVER)
|
||||
run_cmake(Try_find_package-OPT_IN)
|
||||
run_cmake(Try_find_package-BOGUS)
|
||||
run_cmake(Redirect_find_package_MODULE)
|
||||
@@ -0,0 +1,2 @@
|
||||
Loaded FirstProject from package config
|
||||
(-- )?Confirmation project has been added
|
||||
@@ -0,0 +1,18 @@
|
||||
include(FetchContent)
|
||||
|
||||
set(CMAKE_PREFIX_PATH ${CMAKE_CURRENT_LIST_DIR}/PackageConfigs)
|
||||
set(FETCHCONTENT_TRY_FIND_PACKAGE_MODE ALWAYS)
|
||||
|
||||
FetchContent_Declare(
|
||||
FirstProject
|
||||
# Ensure failure if we don't re-route to find_package()
|
||||
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/FatalIfAdded
|
||||
)
|
||||
|
||||
FetchContent_Declare(
|
||||
SecondProject
|
||||
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/AddedProject
|
||||
OVERRIDE_FIND_PACKAGE # Takes precedence over ALWAYS mode
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(FirstProject SecondProject)
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1,2 @@
|
||||
CMake Error at .*/FetchContent.cmake:[0-9]+ \(message\):
|
||||
Unsupported value for FETCHCONTENT_TRY_FIND_PACKAGE_MODE: BOGUS
|
||||
@@ -0,0 +1,8 @@
|
||||
include(FetchContent)
|
||||
|
||||
set(FETCHCONTENT_TRY_FIND_PACKAGE_MODE BOGUS)
|
||||
|
||||
FetchContent_Declare(
|
||||
AddedProject
|
||||
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/AddedProject
|
||||
)
|
||||
@@ -0,0 +1 @@
|
||||
Confirmation project has been added
|
||||
@@ -0,0 +1,12 @@
|
||||
include(FetchContent)
|
||||
|
||||
set(CMAKE_PREFIX_PATH ${CMAKE_CURRENT_LIST_DIR}/PackageConfigs)
|
||||
set(FETCHCONTENT_TRY_FIND_PACKAGE_MODE NEVER)
|
||||
|
||||
FetchContent_Declare(
|
||||
AddedProject
|
||||
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/AddedProject
|
||||
FIND_PACKAGE_ARGS REQUIRED
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(AddedProject)
|
||||
@@ -0,0 +1,2 @@
|
||||
Loaded FirstProject from package config
|
||||
(-- )?Confirmation project has been added
|
||||
@@ -0,0 +1,20 @@
|
||||
include(FetchContent)
|
||||
|
||||
set(CMAKE_PREFIX_PATH ${CMAKE_CURRENT_LIST_DIR}/PackageConfigs)
|
||||
set(FETCHCONTENT_TRY_FIND_PACKAGE_MODE OPT_IN)
|
||||
|
||||
# With opt-in, should call find_package()
|
||||
FetchContent_Declare(
|
||||
FirstProject
|
||||
# Ensure failure if we don't re-route to find_package()
|
||||
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/FatalIfAdded
|
||||
FIND_PACKAGE_ARGS REQUIRED
|
||||
)
|
||||
|
||||
# Without opt-in, shouldn't call find_package()
|
||||
FetchContent_Declare(
|
||||
SecondProject
|
||||
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/AddedProject
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(FirstProject SecondProject)
|
||||
@@ -6,6 +6,11 @@
|
||||
|
||||
The file was not found.
|
||||
|
||||
The internally managed CMAKE_FIND_PACKAGE_REDIRECTS_DIR.
|
||||
|
||||
[^
|
||||
]*/Tests/RunCMake/find_package/FromPATHEnv-build/CMakeFiles/pkgRedirects
|
||||
|
||||
<PackageName>_ROOT CMake variable \[CMAKE_FIND_USE_PACKAGE_ROOT_PATH\].
|
||||
|
||||
none
|
||||
@@ -68,6 +73,10 @@
|
||||
find_package considered the following locations for Resolved's Config
|
||||
module:
|
||||
|
||||
[^
|
||||
]*/Tests/RunCMake/find_package/FromPATHEnv-build/CMakeFiles/pkgRedirects/ResolvedConfig.cmake
|
||||
[^
|
||||
]*/Tests/RunCMake/find_package/FromPATHEnv-build/CMakeFiles/pkgRedirects/resolved-config.cmake
|
||||
[^
|
||||
]*/Tests/RunCMake/find_package/PackageRoot/ResolvedConfig.cmake
|
||||
|
||||
|
||||
@@ -6,6 +6,11 @@
|
||||
|
||||
The file was not found.
|
||||
|
||||
The internally managed CMAKE_FIND_PACKAGE_REDIRECTS_DIR.
|
||||
|
||||
[^
|
||||
]*/Tests/RunCMake/find_package/FromPATHEnvDebugPkg-build/CMakeFiles/pkgRedirects
|
||||
|
||||
<PackageName>_ROOT CMake variable \[CMAKE_FIND_USE_PACKAGE_ROOT_PATH\].
|
||||
|
||||
none
|
||||
@@ -68,6 +73,10 @@
|
||||
find_package considered the following locations for Resolved's Config
|
||||
module:
|
||||
|
||||
[^
|
||||
]*/Tests/RunCMake/find_package/FromPATHEnvDebugPkg-build/CMakeFiles/pkgRedirects/ResolvedConfig.cmake
|
||||
[^
|
||||
]*/Tests/RunCMake/find_package/FromPATHEnvDebugPkg-build/CMakeFiles/pkgRedirects/resolved-config.cmake
|
||||
[^
|
||||
]*/Tests/RunCMake/find_package/PackageRoot/ResolvedConfig.cmake
|
||||
|
||||
|
||||
@@ -97,6 +97,11 @@ Call Stack \(most recent call first\):
|
||||
FindBar processed here.
|
||||
+
|
||||
CMake Debug Log at ModuleModeDebugPkg/FindFoo.cmake:[0-9]+ \(find_package\):
|
||||
The internally managed CMAKE_FIND_PACKAGE_REDIRECTS_DIR.
|
||||
|
||||
[^
|
||||
]*/Tests/RunCMake/find_package/ModuleModeDebugPkg-build/CMakeFiles/pkgRedirects
|
||||
|
||||
Paths specified by the find_package HINTS option.
|
||||
|
||||
none
|
||||
@@ -107,6 +112,11 @@ CMake Debug Log at ModuleModeDebugPkg/FindFoo.cmake:[0-9]+ \(find_package\):
|
||||
|
||||
find_package considered the following locations for Zot's Config module:
|
||||
|
||||
[^
|
||||
]*/Tests/RunCMake/find_package/ModuleModeDebugPkg-build/CMakeFiles/pkgRedirects/ZotConfig.cmake
|
||||
[^
|
||||
]*/Tests/RunCMake/find_package/ModuleModeDebugPkg-build/CMakeFiles/pkgRedirects/zot-config.cmake
|
||||
|
||||
The file was not found.
|
||||
|
||||
Call Stack \(most recent call first\):
|
||||
|
||||
Reference in New Issue
Block a user