1154 lines
		
	
	
	
		
			46 KiB
		
	
	
	
		
			CMake
		
	
	
	
	
	
			
		
		
	
	
			1154 lines
		
	
	
	
		
			46 KiB
		
	
	
	
		
			CMake
		
	
	
	
	
	
# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
 | 
						|
# file Copyright.txt or https://cmake.org/licensing for details.
 | 
						|
 | 
						|
#[=======================================================================[.rst:
 | 
						|
FetchContent
 | 
						|
------------------
 | 
						|
 | 
						|
.. only:: html
 | 
						|
 | 
						|
  .. contents::
 | 
						|
 | 
						|
Overview
 | 
						|
^^^^^^^^
 | 
						|
 | 
						|
This module enables populating content at configure time via any method
 | 
						|
supported by the :module:`ExternalProject` module.  Whereas
 | 
						|
:command:`ExternalProject_Add` downloads at build time, the
 | 
						|
``FetchContent`` module makes content available immediately, allowing the
 | 
						|
configure step to use the content in commands like :command:`add_subdirectory`,
 | 
						|
:command:`include` or :command:`file` operations.
 | 
						|
 | 
						|
Content population details would normally be defined separately from the
 | 
						|
command that performs the actual population.  This separation ensures that
 | 
						|
all of the dependency details are defined before anything may try to use those
 | 
						|
details to populate content.  This is particularly important in more complex
 | 
						|
project hierarchies where dependencies may be shared between multiple projects.
 | 
						|
 | 
						|
The following shows a typical example of declaring content details:
 | 
						|
 | 
						|
.. code-block:: cmake
 | 
						|
 | 
						|
  FetchContent_Declare(
 | 
						|
    googletest
 | 
						|
    GIT_REPOSITORY https://github.com/google/googletest.git
 | 
						|
    GIT_TAG        release-1.8.0
 | 
						|
  )
 | 
						|
 | 
						|
For most typical cases, populating the content can then be done with a single
 | 
						|
command like so:
 | 
						|
 | 
						|
.. code-block:: cmake
 | 
						|
 | 
						|
  FetchContent_MakeAvailable(googletest)
 | 
						|
 | 
						|
The above command not only populates the content, it also adds it to the main
 | 
						|
build (if possible) so that the main build can use the populated project's
 | 
						|
targets, etc.  In some cases, the main project may need to have more precise
 | 
						|
control over the population or may be required to explicitly define the
 | 
						|
population steps (e.g. if CMake versions earlier than 3.14 need to be
 | 
						|
supported).  The typical pattern of such custom steps looks like this:
 | 
						|
 | 
						|
.. code-block:: cmake
 | 
						|
 | 
						|
  FetchContent_GetProperties(googletest)
 | 
						|
  if(NOT googletest_POPULATED)
 | 
						|
    FetchContent_Populate(googletest)
 | 
						|
    add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR})
 | 
						|
  endif()
 | 
						|
 | 
						|
Regardless of which population method is used, when using the
 | 
						|
declare-populate pattern with a hierarchical project arrangement, projects at
 | 
						|
higher levels in the hierarchy are able to override the population details of
 | 
						|
content specified anywhere lower in the project hierarchy.  The ability to
 | 
						|
detect whether content has already been populated ensures that even if
 | 
						|
multiple child projects want certain content to be available, the first one
 | 
						|
to populate it wins.  The other child project can simply make use of the
 | 
						|
already available content instead of repeating the population for itself.
 | 
						|
See the :ref:`Examples <fetch-content-examples>` section which demonstrates
 | 
						|
this scenario.
 | 
						|
 | 
						|
The ``FetchContent`` module also supports defining and populating
 | 
						|
content in a single call, with no check for whether the content has been
 | 
						|
populated elsewhere in the project already.  This is a more low level
 | 
						|
operation and would not normally be the way the module is used, but it is
 | 
						|
sometimes useful as part of implementing some higher level feature or to
 | 
						|
populate some content in CMake's script mode.
 | 
						|
 | 
						|
 | 
						|
Commands
 | 
						|
^^^^^^^^
 | 
						|
 | 
						|
Declaring Content Details
 | 
						|
"""""""""""""""""""""""""
 | 
						|
 | 
						|
.. command:: FetchContent_Declare
 | 
						|
 | 
						|
  .. code-block:: cmake
 | 
						|
 | 
						|
    FetchContent_Declare(<name> <contentOptions>...)
 | 
						|
 | 
						|
  The ``FetchContent_Declare()`` function records the options that describe
 | 
						|
  how to populate the specified content, but if such details have already
 | 
						|
  been recorded earlier in this project (regardless of where in the project
 | 
						|
  hierarchy), this and all later calls for the same content ``<name>`` are
 | 
						|
  ignored.  This "first to record, wins" approach is what allows hierarchical
 | 
						|
  projects to have parent projects override content details of child projects.
 | 
						|
 | 
						|
  The content ``<name>`` can be any string without spaces, but good practice
 | 
						|
  would be to use only letters, numbers and underscores.  The name will be
 | 
						|
  treated case-insensitively and it should be obvious for the content it
 | 
						|
  represents, often being the name of the child project or the value given
 | 
						|
  to its top level :command:`project` command (if it is a CMake project).
 | 
						|
  For well-known public projects, the name should generally be the official
 | 
						|
  name of the project.  Choosing an unusual name makes it unlikely that other
 | 
						|
  projects needing that same content will use the same name, leading to
 | 
						|
  the content being populated multiple times.
 | 
						|
 | 
						|
  The ``<contentOptions>`` can be any of the download or update/patch options
 | 
						|
  that the :command:`ExternalProject_Add` command understands.  The configure,
 | 
						|
  build, install and test steps are explicitly disabled and therefore options
 | 
						|
  related to them will be ignored.  The ``SOURCE_SUBDIR`` option is an
 | 
						|
  exception, see :command:`FetchContent_MakeAvailable` for details on how that
 | 
						|
  affects behavior.
 | 
						|
 | 
						|
  In most cases, ``<contentOptions>`` will just be a couple of options defining
 | 
						|
  the download method and method-specific details like a commit tag or archive
 | 
						|
  hash.  For example:
 | 
						|
 | 
						|
  .. code-block:: cmake
 | 
						|
 | 
						|
    FetchContent_Declare(
 | 
						|
      googletest
 | 
						|
      GIT_REPOSITORY https://github.com/google/googletest.git
 | 
						|
      GIT_TAG        release-1.8.0
 | 
						|
    )
 | 
						|
 | 
						|
    FetchContent_Declare(
 | 
						|
      myCompanyIcons
 | 
						|
      URL      https://intranet.mycompany.com/assets/iconset_1.12.tar.gz
 | 
						|
      URL_HASH 5588a7b18261c20068beabfb4f530b87
 | 
						|
    )
 | 
						|
 | 
						|
    FetchContent_Declare(
 | 
						|
      myCompanyCertificates
 | 
						|
      SVN_REPOSITORY svn+ssh://svn.mycompany.com/srv/svn/trunk/certs
 | 
						|
      SVN_REVISION   -r12345
 | 
						|
    )
 | 
						|
 | 
						|
Populating The Content
 | 
						|
""""""""""""""""""""""
 | 
						|
 | 
						|
For most common scenarios, population means making content available to the
 | 
						|
main build according to previously declared details for that dependency.
 | 
						|
There are two main patterns for populating content, one based on calling
 | 
						|
:command:`FetchContent_GetProperties` and
 | 
						|
:command:`FetchContent_Populate` for more precise control and the other on
 | 
						|
calling :command:`FetchContent_MakeAvailable` for a simpler, more automated
 | 
						|
approach.  The former generally follows this canonical pattern:
 | 
						|
 | 
						|
.. _`fetch-content-canonical-pattern`:
 | 
						|
 | 
						|
.. code-block:: cmake
 | 
						|
 | 
						|
  # Check if population has already been performed
 | 
						|
  FetchContent_GetProperties(<name>)
 | 
						|
  string(TOLOWER "<name>" lcName)
 | 
						|
  if(NOT ${lcName}_POPULATED)
 | 
						|
    # Fetch the content using previously declared details
 | 
						|
    FetchContent_Populate(<name>)
 | 
						|
 | 
						|
    # Set custom variables, policies, etc.
 | 
						|
    # ...
 | 
						|
 | 
						|
    # Bring the populated content into the build
 | 
						|
    add_subdirectory(${${lcName}_SOURCE_DIR} ${${lcName}_BINARY_DIR})
 | 
						|
  endif()
 | 
						|
 | 
						|
The above is such a common pattern that, where no custom steps are needed
 | 
						|
between the calls to :command:`FetchContent_Populate` and
 | 
						|
:command:`add_subdirectory`, equivalent logic can be obtained by calling
 | 
						|
:command:`FetchContent_MakeAvailable` instead.  Where it meets the needs of
 | 
						|
the project, :command:`FetchContent_MakeAvailable` should be preferred, as it
 | 
						|
is simpler and provides additional features over the pattern above.
 | 
						|
 | 
						|
.. command:: FetchContent_Populate
 | 
						|
 | 
						|
  .. code-block:: cmake
 | 
						|
 | 
						|
    FetchContent_Populate( <name> )
 | 
						|
 | 
						|
  In most cases, the only argument given to ``FetchContent_Populate()`` is the
 | 
						|
  ``<name>``.  When used this way, the command assumes the content details have
 | 
						|
  been recorded by an earlier call to :command:`FetchContent_Declare`.  The
 | 
						|
  details are stored in a global property, so they are unaffected by things
 | 
						|
  like variable or directory scope.  Therefore, it doesn't matter where in the
 | 
						|
  project the details were previously declared, as long as they have been
 | 
						|
  declared before the call to ``FetchContent_Populate()``.  Those saved details
 | 
						|
  are then used to construct a call to :command:`ExternalProject_Add` in a
 | 
						|
  private sub-build to perform the content population immediately.  The
 | 
						|
  implementation of ``ExternalProject_Add()`` ensures that if the content has
 | 
						|
  already been populated in a previous CMake run, that content will be reused
 | 
						|
  rather than repopulating them again.  For the common case where population
 | 
						|
  involves downloading content, the cost of the download is only paid once.
 | 
						|
 | 
						|
  An internal global property records when a particular content population
 | 
						|
  request has been processed.  If ``FetchContent_Populate()`` is called more
 | 
						|
  than once for the same content name within a configure run, the second call
 | 
						|
  will halt with an error.  Projects can and should check whether content
 | 
						|
  population has already been processed with the
 | 
						|
  :command:`FetchContent_GetProperties` command before calling
 | 
						|
  ``FetchContent_Populate()``.
 | 
						|
 | 
						|
  ``FetchContent_Populate()`` will set three variables in the scope of the
 | 
						|
  caller; ``<lcName>_POPULATED``, ``<lcName>_SOURCE_DIR`` and
 | 
						|
  ``<lcName>_BINARY_DIR``, where ``<lcName>`` is the lowercased ``<name>``.
 | 
						|
  ``<lcName>_POPULATED`` will always be set to ``True`` by the call.
 | 
						|
  ``<lcName>_SOURCE_DIR`` is the location where the
 | 
						|
  content can be found upon return (it will have already been populated), while
 | 
						|
  ``<lcName>_BINARY_DIR`` is a directory intended for use as a corresponding
 | 
						|
  build directory.  The main use case for the two directory variables is to
 | 
						|
  call :command:`add_subdirectory` immediately after population, i.e.:
 | 
						|
 | 
						|
  .. code-block:: cmake
 | 
						|
 | 
						|
    FetchContent_Populate(FooBar ...)
 | 
						|
    add_subdirectory(${foobar_SOURCE_DIR} ${foobar_BINARY_DIR})
 | 
						|
 | 
						|
  The values of the three variables can also be retrieved from anywhere in the
 | 
						|
  project hierarchy using the :command:`FetchContent_GetProperties` command.
 | 
						|
 | 
						|
  A number of cache variables influence the behavior of all content population
 | 
						|
  performed using details saved from a :command:`FetchContent_Declare` call:
 | 
						|
 | 
						|
  ``FETCHCONTENT_BASE_DIR``
 | 
						|
    In most cases, the saved details do not specify any options relating to the
 | 
						|
    directories to use for the internal sub-build, final source and build areas.
 | 
						|
    It is generally best to leave these decisions up to the ``FetchContent``
 | 
						|
    module to handle on the project's behalf.  The ``FETCHCONTENT_BASE_DIR``
 | 
						|
    cache variable controls the point under which all content population
 | 
						|
    directories are collected, but in most cases developers would not need to
 | 
						|
    change this.  The default location is ``${CMAKE_BINARY_DIR}/_deps``, but if
 | 
						|
    developers change this value, they should aim to keep the path short and
 | 
						|
    just below the top level of the build tree to avoid running into path
 | 
						|
    length problems on Windows.
 | 
						|
 | 
						|
  ``FETCHCONTENT_QUIET``
 | 
						|
    The logging output during population can be quite verbose, making the
 | 
						|
    configure stage quite noisy.  This cache option (``ON`` by default) hides
 | 
						|
    all population output unless an error is encountered.  If experiencing
 | 
						|
    problems with hung downloads, temporarily switching this option off may
 | 
						|
    help diagnose which content population is causing the issue.
 | 
						|
 | 
						|
  ``FETCHCONTENT_FULLY_DISCONNECTED``
 | 
						|
    When this option is enabled, no attempt is made to download or update
 | 
						|
    any content.  It is assumed that all content has already been populated in
 | 
						|
    a previous run or the source directories have been pointed at existing
 | 
						|
    contents the developer has provided manually (using options described
 | 
						|
    further below).  When the developer knows that no changes have been made to
 | 
						|
    any content details, turning this option ``ON`` can significantly speed up
 | 
						|
    the configure stage.  It is ``OFF`` by default.
 | 
						|
 | 
						|
  ``FETCHCONTENT_UPDATES_DISCONNECTED``
 | 
						|
    This is a less severe download/update control compared to
 | 
						|
    ``FETCHCONTENT_FULLY_DISCONNECTED``.  Instead of bypassing all download and
 | 
						|
    update logic, the ``FETCHCONTENT_UPDATES_DISCONNECTED`` only disables the
 | 
						|
    update stage.  Therefore, if content has not been downloaded previously,
 | 
						|
    it will still be downloaded when this option is enabled.  This can speed up
 | 
						|
    the configure stage, but not as much as
 | 
						|
    ``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 (``<ucName>`` is the uppercased value of
 | 
						|
  ``<name>``):
 | 
						|
 | 
						|
  ``FETCHCONTENT_SOURCE_DIR_<ucName>``
 | 
						|
    If this is set, no download or update steps are performed for the specified
 | 
						|
    content and the ``<lcName>_SOURCE_DIR`` variable returned to the caller is
 | 
						|
    pointed at this location.  This gives developers a way to have a separate
 | 
						|
    checkout of the content that they can modify freely without interference
 | 
						|
    from the build.  The build simply uses that existing source, but it still
 | 
						|
    defines ``<lcName>_BINARY_DIR`` to point inside its own build area.
 | 
						|
    Developers are strongly encouraged to use this mechanism rather than
 | 
						|
    editing the sources populated in the default location, as changes to
 | 
						|
    sources in the default location can be lost when content population details
 | 
						|
    are changed by the project.
 | 
						|
 | 
						|
  ``FETCHCONTENT_UPDATES_DISCONNECTED_<ucName>``
 | 
						|
    This is the per-content equivalent of
 | 
						|
    ``FETCHCONTENT_UPDATES_DISCONNECTED``. If the global option or this option
 | 
						|
    is ``ON``, then updates will be disabled for the named content.
 | 
						|
    Disabling updates for individual content can be useful for content whose
 | 
						|
    details rarely change, while still leaving other frequently changing
 | 
						|
    content with updates enabled.
 | 
						|
 | 
						|
 | 
						|
  The ``FetchContent_Populate()`` command also supports a syntax allowing the
 | 
						|
  content details to be specified directly rather than using any saved
 | 
						|
  details.  This is more low-level and use of this form is generally to be
 | 
						|
  avoided in favour of using saved content details as outlined above.
 | 
						|
  Nevertheless, in certain situations it can be useful to invoke the content
 | 
						|
  population as an isolated operation (typically as part of implementing some
 | 
						|
  other higher level feature or when using CMake in script mode):
 | 
						|
 | 
						|
  .. code-block:: cmake
 | 
						|
 | 
						|
    FetchContent_Populate( <name>
 | 
						|
      [QUIET]
 | 
						|
      [SUBBUILD_DIR <subBuildDir>]
 | 
						|
      [SOURCE_DIR <srcDir>]
 | 
						|
      [BINARY_DIR <binDir>]
 | 
						|
      ...
 | 
						|
    )
 | 
						|
 | 
						|
  This form has a number of key differences to that where only ``<name>`` is
 | 
						|
  provided:
 | 
						|
 | 
						|
  - All required population details are assumed to have been provided directly
 | 
						|
    in the call to ``FetchContent_Populate()``. Any saved details for
 | 
						|
    ``<name>`` are ignored.
 | 
						|
  - No check is made for whether content for ``<name>`` has already been
 | 
						|
    populated.
 | 
						|
  - No global property is set to record that the population has occurred.
 | 
						|
  - No global properties record the source or binary directories used for the
 | 
						|
    populated content.
 | 
						|
  - The ``FETCHCONTENT_FULLY_DISCONNECTED`` and
 | 
						|
    ``FETCHCONTENT_UPDATES_DISCONNECTED`` cache variables are ignored.
 | 
						|
 | 
						|
  The ``<lcName>_SOURCE_DIR`` and ``<lcName>_BINARY_DIR`` variables are still
 | 
						|
  returned to the caller, but since these locations are not stored as global
 | 
						|
  properties when this form is used, they are only available to the calling
 | 
						|
  scope and below rather than the entire project hierarchy.  No
 | 
						|
  ``<lcName>_POPULATED`` variable is set in the caller's scope with this form.
 | 
						|
 | 
						|
  The supported options for ``FetchContent_Populate()`` are the same as those
 | 
						|
  for :command:`FetchContent_Declare()`.  Those few options shown just
 | 
						|
  above are either specific to ``FetchContent_Populate()`` or their behavior is
 | 
						|
  slightly modified from how :command:`ExternalProject_Add` treats them.
 | 
						|
 | 
						|
  ``QUIET``
 | 
						|
    The ``QUIET`` option can be given to hide the output associated with
 | 
						|
    populating the specified content.  If the population fails, the output will
 | 
						|
    be shown regardless of whether this option was given or not so that the
 | 
						|
    cause of the failure can be diagnosed.  The global ``FETCHCONTENT_QUIET``
 | 
						|
    cache variable has no effect on ``FetchContent_Populate()`` calls where the
 | 
						|
    content details are provided directly.
 | 
						|
 | 
						|
  ``SUBBUILD_DIR``
 | 
						|
    The ``SUBBUILD_DIR`` argument can be provided to change the location of the
 | 
						|
    sub-build created to perform the population.  The default value is
 | 
						|
    ``${CMAKE_CURRENT_BINARY_DIR}/<lcName>-subbuild`` and it would be unusual
 | 
						|
    to need to override this default.  If a relative path is specified, it will
 | 
						|
    be interpreted as relative to :variable:`CMAKE_CURRENT_BINARY_DIR`.
 | 
						|
    This option should not be confused with the ``SOURCE_SUBDIR`` option which
 | 
						|
    only affects the :command:`FetchContent_MakeAvailable` command.
 | 
						|
 | 
						|
  ``SOURCE_DIR``, ``BINARY_DIR``
 | 
						|
    The ``SOURCE_DIR`` and ``BINARY_DIR`` arguments are supported by
 | 
						|
    :command:`ExternalProject_Add`, but different default values are used by
 | 
						|
    ``FetchContent_Populate()``.  ``SOURCE_DIR`` defaults to
 | 
						|
    ``${CMAKE_CURRENT_BINARY_DIR}/<lcName>-src`` and ``BINARY_DIR`` defaults to
 | 
						|
    ``${CMAKE_CURRENT_BINARY_DIR}/<lcName>-build``.  If a relative path is
 | 
						|
    specified, it will be interpreted as relative to
 | 
						|
    :variable:`CMAKE_CURRENT_BINARY_DIR`.
 | 
						|
 | 
						|
  In addition to the above explicit options, any other unrecognized options are
 | 
						|
  passed through unmodified to :command:`ExternalProject_Add` to perform the
 | 
						|
  download, patch and update steps.  The following options are explicitly
 | 
						|
  prohibited (they are disabled by the ``FetchContent_Populate()`` command):
 | 
						|
 | 
						|
  - ``CONFIGURE_COMMAND``
 | 
						|
  - ``BUILD_COMMAND``
 | 
						|
  - ``INSTALL_COMMAND``
 | 
						|
  - ``TEST_COMMAND``
 | 
						|
 | 
						|
  If using ``FetchContent_Populate()`` within CMake's script mode, be aware
 | 
						|
  that the implementation sets up a sub-build which therefore requires a CMake
 | 
						|
  generator and build tool to be available. If these cannot be found by
 | 
						|
  default, then the :variable:`CMAKE_GENERATOR` and/or
 | 
						|
  :variable:`CMAKE_MAKE_PROGRAM` variables will need to be set appropriately
 | 
						|
  on the command line invoking the script.
 | 
						|
 | 
						|
 | 
						|
.. command:: FetchContent_GetProperties
 | 
						|
 | 
						|
  When using saved content details, a call to :command:`FetchContent_Populate`
 | 
						|
  records information in global properties which can be queried at any time.
 | 
						|
  This information includes the source and binary directories associated with
 | 
						|
  the content and also whether or not the content population has been processed
 | 
						|
  during the current configure run.
 | 
						|
 | 
						|
  .. code-block:: cmake
 | 
						|
 | 
						|
    FetchContent_GetProperties( <name>
 | 
						|
      [SOURCE_DIR <srcDirVar>]
 | 
						|
      [BINARY_DIR <binDirVar>]
 | 
						|
      [POPULATED <doneVar>]
 | 
						|
    )
 | 
						|
 | 
						|
  The ``SOURCE_DIR``, ``BINARY_DIR`` and ``POPULATED`` options can be used to
 | 
						|
  specify which properties should be retrieved.  Each option accepts a value
 | 
						|
  which is the name of the variable in which to store that property.  Most of
 | 
						|
  the time though, only ``<name>`` is given, in which case the call will then
 | 
						|
  set the same variables as a call to
 | 
						|
  :command:`FetchContent_Populate(name) <FetchContent_Populate>`.  This allows
 | 
						|
  the following canonical pattern to be used, which ensures that the relevant
 | 
						|
  variables will always be defined regardless of whether or not the population
 | 
						|
  has been performed elsewhere in the project already:
 | 
						|
 | 
						|
  .. code-block:: cmake
 | 
						|
 | 
						|
    FetchContent_GetProperties(foobar)
 | 
						|
    if(NOT foobar_POPULATED)
 | 
						|
      FetchContent_Populate(foobar)
 | 
						|
      ...
 | 
						|
    endif()
 | 
						|
 | 
						|
  The above pattern allows other parts of the overall project hierarchy to
 | 
						|
  re-use the same content and ensure that it is only populated once.
 | 
						|
 | 
						|
 | 
						|
.. command:: FetchContent_MakeAvailable
 | 
						|
 | 
						|
  .. code-block:: cmake
 | 
						|
 | 
						|
    FetchContent_MakeAvailable( <name1> [<name2>...] )
 | 
						|
 | 
						|
  This command implements the common pattern typically needed for most
 | 
						|
  dependencies.  It iterates over each of the named dependencies in turn
 | 
						|
  and for each one it loosely follows the
 | 
						|
  :ref:`canonical pattern <fetch-content-canonical-pattern>` as
 | 
						|
  presented at the beginning of this section.  An important difference is
 | 
						|
  that :command:`add_subdirectory` will only be called on the
 | 
						|
  populated content if there is a ``CMakeLists.txt`` file in its top level
 | 
						|
  source directory.  This allows the command to be used for dependencies
 | 
						|
  that make downloaded content available at a known location but which do
 | 
						|
  not need or support being added directly to the build.
 | 
						|
 | 
						|
  The ``SOURCE_SUBDIR`` option can be given in the declared details to
 | 
						|
  instruct ``FetchContent_MakeAvailable()`` to look for a ``CMakeLists.txt``
 | 
						|
  file in a subdirectory below the top level (i.e. the same way that
 | 
						|
  ``SOURCE_SUBDIR`` is used by the :command:`ExternalProject_Add` command).
 | 
						|
  ``SOURCE_SUBDIR`` must always be a relative path.  See the next section
 | 
						|
  for an example of this option.
 | 
						|
 | 
						|
 | 
						|
.. _`fetch-content-examples`:
 | 
						|
 | 
						|
Examples
 | 
						|
^^^^^^^^
 | 
						|
 | 
						|
This first fairly straightforward example ensures that some popular testing
 | 
						|
frameworks are available to the main build:
 | 
						|
 | 
						|
.. code-block:: cmake
 | 
						|
 | 
						|
  include(FetchContent)
 | 
						|
  FetchContent_Declare(
 | 
						|
    googletest
 | 
						|
    GIT_REPOSITORY https://github.com/google/googletest.git
 | 
						|
    GIT_TAG        release-1.8.0
 | 
						|
  )
 | 
						|
  FetchContent_Declare(
 | 
						|
    Catch2
 | 
						|
    GIT_REPOSITORY https://github.com/catchorg/Catch2.git
 | 
						|
    GIT_TAG        v2.5.0
 | 
						|
  )
 | 
						|
 | 
						|
  # After the following call, the CMake targets defined by googletest and
 | 
						|
  # Catch2 will be defined and available to the rest of the build
 | 
						|
  FetchContent_MakeAvailable(googletest Catch2)
 | 
						|
 | 
						|
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
 | 
						|
it also sets a variable which is meaningful to the subproject before pulling
 | 
						|
it into the main build:
 | 
						|
 | 
						|
.. code-block:: cmake
 | 
						|
 | 
						|
  include(FetchContent)
 | 
						|
  FetchContent_Declare(
 | 
						|
    protobuf
 | 
						|
    GIT_REPOSITORY https://github.com/protocolbuffers/protobuf.git
 | 
						|
    GIT_TAG        v3.12.0
 | 
						|
    SOURCE_SUBDIR  cmake
 | 
						|
  )
 | 
						|
  set(protobuf_BUILD_TESTS OFF)
 | 
						|
  FetchContent_MakeAvailable(protobuf)
 | 
						|
 | 
						|
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
 | 
						|
``projC`` can be built standalone and they also both depend on another project
 | 
						|
``projD``.  ``projB`` additionally depends on ``projE``.  This example assumes
 | 
						|
that all five projects are available on a company git server.  The
 | 
						|
``CMakeLists.txt`` of each project might have sections like the following:
 | 
						|
 | 
						|
*projA*:
 | 
						|
 | 
						|
.. code-block:: cmake
 | 
						|
 | 
						|
  include(FetchContent)
 | 
						|
  FetchContent_Declare(
 | 
						|
    projB
 | 
						|
    GIT_REPOSITORY git@mycompany.com:git/projB.git
 | 
						|
    GIT_TAG        4a89dc7e24ff212a7b5167bef7ab079d
 | 
						|
  )
 | 
						|
  FetchContent_Declare(
 | 
						|
    projC
 | 
						|
    GIT_REPOSITORY git@mycompany.com:git/projC.git
 | 
						|
    GIT_TAG        4ad4016bd1d8d5412d135cf8ceea1bb9
 | 
						|
  )
 | 
						|
  FetchContent_Declare(
 | 
						|
    projD
 | 
						|
    GIT_REPOSITORY git@mycompany.com:git/projD.git
 | 
						|
    GIT_TAG        origin/integrationBranch
 | 
						|
  )
 | 
						|
  FetchContent_Declare(
 | 
						|
    projE
 | 
						|
    GIT_REPOSITORY git@mycompany.com:git/projE.git
 | 
						|
    GIT_TAG        origin/release/2.3-rc1
 | 
						|
  )
 | 
						|
 | 
						|
  # Order is important, see notes in the discussion further below
 | 
						|
  FetchContent_MakeAvailable(projD projB projC)
 | 
						|
 | 
						|
*projB*:
 | 
						|
 | 
						|
.. code-block:: cmake
 | 
						|
 | 
						|
  include(FetchContent)
 | 
						|
  FetchContent_Declare(
 | 
						|
    projD
 | 
						|
    GIT_REPOSITORY git@mycompany.com:git/projD.git
 | 
						|
    GIT_TAG        20b415f9034bbd2a2e8216e9a5c9e632
 | 
						|
  )
 | 
						|
  FetchContent_Declare(
 | 
						|
    projE
 | 
						|
    GIT_REPOSITORY git@mycompany.com:git/projE.git
 | 
						|
    GIT_TAG        68e20f674a48be38d60e129f600faf7d
 | 
						|
  )
 | 
						|
 | 
						|
  FetchContent_MakeAvailable(projD projE)
 | 
						|
 | 
						|
*projC*:
 | 
						|
 | 
						|
.. code-block:: cmake
 | 
						|
 | 
						|
  include(FetchContent)
 | 
						|
  FetchContent_Declare(
 | 
						|
    projD
 | 
						|
    GIT_REPOSITORY git@mycompany.com:git/projD.git
 | 
						|
    GIT_TAG        7d9a17ad2c962aa13e2fbb8043fb6b8a
 | 
						|
  )
 | 
						|
 | 
						|
  # This particular version of projD requires workarounds
 | 
						|
  FetchContent_GetProperties(projD)
 | 
						|
  if(NOT projd_POPULATED)
 | 
						|
    FetchContent_Populate(projD)
 | 
						|
 | 
						|
    # Copy an additional/replacement file into the populated source
 | 
						|
    file(COPY someFile.c DESTINATION ${projd_SOURCE_DIR}/src)
 | 
						|
 | 
						|
    add_subdirectory(${projd_SOURCE_DIR} ${projd_BINARY_DIR})
 | 
						|
  endif()
 | 
						|
 | 
						|
A few key points should be noted in the above:
 | 
						|
 | 
						|
- ``projB`` and ``projC`` define different content details for ``projD``,
 | 
						|
  but ``projA`` also defines a set of content details for ``projD``.
 | 
						|
  Because ``projA`` will define them first, the details from ``projB`` and
 | 
						|
  ``projC`` will not be used.  The override details defined by ``projA``
 | 
						|
  are not required to match either of those from ``projB`` or ``projC``, but
 | 
						|
  it is up to the higher level project to ensure that the details it does
 | 
						|
  define still make sense for the child projects.
 | 
						|
- In the ``projA`` call to :command:`FetchContent_MakeAvailable`, ``projD``
 | 
						|
  is listed ahead of ``projB`` and ``projC`` to ensure that ``projA`` is in
 | 
						|
  control of how ``projD`` is populated.
 | 
						|
- While ``projA`` defines content details for ``projE``, it does not need
 | 
						|
  to explicitly call ``FetchContent_MakeAvailable(projE)`` or
 | 
						|
  ``FetchContent_Populate(projD)`` itself.  Instead, it leaves that to the
 | 
						|
  child ``projB``.  For higher level projects, it is often enough to just
 | 
						|
  define the override content details and leave the actual population to the
 | 
						|
  child projects.  This saves repeating the same thing at each level of the
 | 
						|
  project hierarchy unnecessarily.
 | 
						|
 | 
						|
 | 
						|
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
 | 
						|
a predictable location.  The next example ensures that a set of standard
 | 
						|
company toolchain files (and potentially even the toolchain binaries
 | 
						|
themselves) is available early enough to be used for that same build.
 | 
						|
 | 
						|
.. code-block:: cmake
 | 
						|
 | 
						|
  cmake_minimum_required(VERSION 3.14)
 | 
						|
 | 
						|
  include(FetchContent)
 | 
						|
  FetchContent_Declare(
 | 
						|
    mycom_toolchains
 | 
						|
    URL  https://intranet.mycompany.com//toolchains_1.3.2.tar.gz
 | 
						|
  )
 | 
						|
  FetchContent_MakeAvailable(mycom_toolchains)
 | 
						|
 | 
						|
  project(CrossCompileExample)
 | 
						|
 | 
						|
The project could be configured to use one of the downloaded toolchains like
 | 
						|
so:
 | 
						|
 | 
						|
.. code-block:: shell
 | 
						|
 | 
						|
  cmake -DCMAKE_TOOLCHAIN_FILE=_deps/mycom_toolchains-src/toolchain_arm.cmake /path/to/src
 | 
						|
 | 
						|
When CMake processes the ``CMakeLists.txt`` file, it will download and unpack
 | 
						|
the tarball into ``_deps/mycompany_toolchains-src`` relative to the build
 | 
						|
directory.  The :variable:`CMAKE_TOOLCHAIN_FILE` variable is not used until
 | 
						|
the :command:`project` command is reached, at which point CMake looks for the
 | 
						|
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
 | 
						|
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
 | 
						|
current working directory.
 | 
						|
 | 
						|
*getFirmware.cmake*:
 | 
						|
 | 
						|
.. code-block:: cmake
 | 
						|
 | 
						|
  # NOTE: Intended to be run in script mode with cmake -P
 | 
						|
  include(FetchContent)
 | 
						|
  FetchContent_Populate(
 | 
						|
    firmware
 | 
						|
    URL        https://mycompany.com/assets/firmware-1.23-arm.tar.gz
 | 
						|
    URL_HASH   MD5=68247684da89b608d466253762b0ff11
 | 
						|
    SOURCE_DIR firmware
 | 
						|
  )
 | 
						|
 | 
						|
#]=======================================================================]
 | 
						|
 | 
						|
#=======================================================================
 | 
						|
# Recording and retrieving content details for later population
 | 
						|
#=======================================================================
 | 
						|
 | 
						|
# Internal use, projects must not call this directly. It is
 | 
						|
# intended for use by FetchContent_Declare() only.
 | 
						|
#
 | 
						|
# Sets a content-specific global property (not meant for use
 | 
						|
# outside of functions defined here in this file) which can later
 | 
						|
# be retrieved using __FetchContent_getSavedDetails() with just the
 | 
						|
# same content name. If there is already a value stored in the
 | 
						|
# property, it is left unchanged and this call has no effect.
 | 
						|
# This allows parent projects to define the content details,
 | 
						|
# overriding anything a child project may try to set (properties
 | 
						|
# are not cached between runs, so the first thing to set it in a
 | 
						|
# build will be in control).
 | 
						|
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(__cmdArgs)
 | 
						|
    foreach(__item IN LISTS ARGN)
 | 
						|
      string(APPEND __cmdArgs " [==[${__item}]==]")
 | 
						|
    endforeach()
 | 
						|
    cmake_language(EVAL CODE
 | 
						|
      "set_property(GLOBAL PROPERTY ${propertyName} ${__cmdArgs})")
 | 
						|
  endif()
 | 
						|
 | 
						|
endfunction()
 | 
						|
 | 
						|
 | 
						|
# Internal use, projects must not call this directly. It is
 | 
						|
# intended for use by the FetchContent_Declare() function.
 | 
						|
#
 | 
						|
# Retrieves details saved for the specified content in an
 | 
						|
# earlier call to __FetchContent_declareDetails().
 | 
						|
function(__FetchContent_getSavedDetails contentName outVar)
 | 
						|
 | 
						|
  string(TOLOWER ${contentName} contentNameLower)
 | 
						|
  set(propertyName "_FetchContent_${contentNameLower}_savedDetails")
 | 
						|
  get_property(alreadyDefined GLOBAL PROPERTY ${propertyName} DEFINED)
 | 
						|
  if(NOT alreadyDefined)
 | 
						|
    message(FATAL_ERROR "No content details recorded for ${contentName}")
 | 
						|
  endif()
 | 
						|
  get_property(propertyValue GLOBAL PROPERTY ${propertyName})
 | 
						|
  set(${outVar} "${propertyValue}" PARENT_SCOPE)
 | 
						|
 | 
						|
endfunction()
 | 
						|
 | 
						|
 | 
						|
# Saves population details of the content, sets defaults for the
 | 
						|
# SOURCE_DIR and BUILD_DIR.
 | 
						|
function(FetchContent_Declare contentName)
 | 
						|
 | 
						|
  set(options "")
 | 
						|
  set(oneValueArgs SVN_REPOSITORY)
 | 
						|
  set(multiValueArgs "")
 | 
						|
 | 
						|
  cmake_parse_arguments(PARSE_ARGV 1 ARG
 | 
						|
    "${options}" "${oneValueArgs}" "${multiValueArgs}")
 | 
						|
 | 
						|
  unset(srcDirSuffix)
 | 
						|
  unset(svnRepoArgs)
 | 
						|
  if(ARG_SVN_REPOSITORY)
 | 
						|
    # Add a hash of the svn repository URL to the source dir. This works
 | 
						|
    # around the problem where if the URL changes, the download would
 | 
						|
    # fail because it tries to checkout/update rather than switch the
 | 
						|
    # old URL to the new one. We limit the hash to the first 7 characters
 | 
						|
    # so that the source path doesn't get overly long (which can be a
 | 
						|
    # problem on windows due to path length limits).
 | 
						|
    string(SHA1 urlSHA ${ARG_SVN_REPOSITORY})
 | 
						|
    string(SUBSTRING ${urlSHA} 0 7 urlSHA)
 | 
						|
    set(srcDirSuffix "-${urlSHA}")
 | 
						|
    set(svnRepoArgs  SVN_REPOSITORY ${ARG_SVN_REPOSITORY})
 | 
						|
  endif()
 | 
						|
 | 
						|
  string(TOLOWER ${contentName} contentNameLower)
 | 
						|
 | 
						|
  set(__argsQuoted)
 | 
						|
  foreach(__item IN LISTS ARG_UNPARSED_ARGUMENTS)
 | 
						|
    string(APPEND __argsQuoted " [==[${__item}]==]")
 | 
						|
  endforeach()
 | 
						|
  cmake_language(EVAL CODE "
 | 
						|
    __FetchContent_declareDetails(
 | 
						|
      ${contentNameLower}
 | 
						|
      SOURCE_DIR \"${FETCHCONTENT_BASE_DIR}/${contentNameLower}-src${srcDirSuffix}\"
 | 
						|
      BINARY_DIR \"${FETCHCONTENT_BASE_DIR}/${contentNameLower}-build\"
 | 
						|
      \${svnRepoArgs}
 | 
						|
      # List these last so they can override things we set above
 | 
						|
      ${__argsQuoted}
 | 
						|
    )"
 | 
						|
  )
 | 
						|
 | 
						|
endfunction()
 | 
						|
 | 
						|
 | 
						|
#=======================================================================
 | 
						|
# Set/get whether the specified content has been populated yet.
 | 
						|
# 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
 | 
						|
# record when FetchContent_Populate() is called for a particular
 | 
						|
# content name.
 | 
						|
function(__FetchContent_setPopulated contentName sourceDir binaryDir)
 | 
						|
 | 
						|
  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})
 | 
						|
 | 
						|
  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})
 | 
						|
 | 
						|
  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)
 | 
						|
 | 
						|
endfunction()
 | 
						|
 | 
						|
 | 
						|
# Set variables in the calling scope for any of the retrievable
 | 
						|
# properties. If no specific properties are requested, variables
 | 
						|
# will be set for all retrievable properties.
 | 
						|
#
 | 
						|
# This function is intended to also be used by projects as the canonical
 | 
						|
# way to detect whether they should call FetchContent_Populate()
 | 
						|
# and pull the populated source into the build with add_subdirectory(),
 | 
						|
# if they are using the populated content in that way.
 | 
						|
function(FetchContent_GetProperties contentName)
 | 
						|
 | 
						|
  string(TOLOWER ${contentName} contentNameLower)
 | 
						|
 | 
						|
  set(options "")
 | 
						|
  set(oneValueArgs SOURCE_DIR BINARY_DIR POPULATED)
 | 
						|
  set(multiValueArgs "")
 | 
						|
 | 
						|
  cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
 | 
						|
 | 
						|
  if(NOT ARG_SOURCE_DIR AND
 | 
						|
     NOT ARG_BINARY_DIR AND
 | 
						|
     NOT ARG_POPULATED)
 | 
						|
    # No specific properties requested, provide them all
 | 
						|
    set(ARG_SOURCE_DIR ${contentNameLower}_SOURCE_DIR)
 | 
						|
    set(ARG_BINARY_DIR ${contentNameLower}_BINARY_DIR)
 | 
						|
    set(ARG_POPULATED  ${contentNameLower}_POPULATED)
 | 
						|
  endif()
 | 
						|
 | 
						|
  set(prefix "_FetchContent_${contentNameLower}")
 | 
						|
 | 
						|
  if(ARG_SOURCE_DIR)
 | 
						|
    set(propertyName "${prefix}_sourceDir")
 | 
						|
    get_property(value GLOBAL PROPERTY ${propertyName})
 | 
						|
    if(value)
 | 
						|
      set(${ARG_SOURCE_DIR} ${value} PARENT_SCOPE)
 | 
						|
    endif()
 | 
						|
  endif()
 | 
						|
 | 
						|
  if(ARG_BINARY_DIR)
 | 
						|
    set(propertyName "${prefix}_binaryDir")
 | 
						|
    get_property(value GLOBAL PROPERTY ${propertyName})
 | 
						|
    if(value)
 | 
						|
      set(${ARG_BINARY_DIR} ${value} PARENT_SCOPE)
 | 
						|
    endif()
 | 
						|
  endif()
 | 
						|
 | 
						|
  if(ARG_POPULATED)
 | 
						|
    set(propertyName "${prefix}_populated")
 | 
						|
    get_property(value GLOBAL PROPERTY ${propertyName} DEFINED)
 | 
						|
    set(${ARG_POPULATED} ${value} PARENT_SCOPE)
 | 
						|
  endif()
 | 
						|
 | 
						|
endfunction()
 | 
						|
 | 
						|
 | 
						|
#=======================================================================
 | 
						|
# Performing the population
 | 
						|
#=======================================================================
 | 
						|
 | 
						|
# The value of contentName will always have been lowercased by the caller.
 | 
						|
# All other arguments are assumed to be options that are understood by
 | 
						|
# ExternalProject_Add(), except for QUIET and SUBBUILD_DIR.
 | 
						|
function(__FetchContent_directPopulate contentName)
 | 
						|
 | 
						|
  set(options
 | 
						|
      QUIET
 | 
						|
  )
 | 
						|
  set(oneValueArgs
 | 
						|
      SUBBUILD_DIR
 | 
						|
      SOURCE_DIR
 | 
						|
      BINARY_DIR
 | 
						|
      # We need special processing if DOWNLOAD_NO_EXTRACT is true
 | 
						|
      DOWNLOAD_NO_EXTRACT
 | 
						|
      # Prevent the following from being passed through
 | 
						|
      CONFIGURE_COMMAND
 | 
						|
      BUILD_COMMAND
 | 
						|
      INSTALL_COMMAND
 | 
						|
      TEST_COMMAND
 | 
						|
      # We force both of these to be ON since we are always executing serially
 | 
						|
      # and we want all steps to have access to the terminal in case they
 | 
						|
      # need input from the command line (e.g. ask for a private key password)
 | 
						|
      # or they want to provide timely progress. We silently absorb and
 | 
						|
      # discard these if they are set by the caller.
 | 
						|
      USES_TERMINAL_DOWNLOAD
 | 
						|
      USES_TERMINAL_UPDATE
 | 
						|
  )
 | 
						|
  set(multiValueArgs "")
 | 
						|
 | 
						|
  cmake_parse_arguments(PARSE_ARGV 1 ARG
 | 
						|
    "${options}" "${oneValueArgs}" "${multiValueArgs}")
 | 
						|
 | 
						|
  if(NOT ARG_SUBBUILD_DIR)
 | 
						|
    message(FATAL_ERROR "Internal error: SUBBUILD_DIR not set")
 | 
						|
  elseif(NOT IS_ABSOLUTE "${ARG_SUBBUILD_DIR}")
 | 
						|
    set(ARG_SUBBUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/${ARG_SUBBUILD_DIR}")
 | 
						|
  endif()
 | 
						|
 | 
						|
  if(NOT ARG_SOURCE_DIR)
 | 
						|
    message(FATAL_ERROR "Internal error: SOURCE_DIR not set")
 | 
						|
  elseif(NOT IS_ABSOLUTE "${ARG_SOURCE_DIR}")
 | 
						|
    set(ARG_SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/${ARG_SOURCE_DIR}")
 | 
						|
  endif()
 | 
						|
 | 
						|
  if(NOT ARG_BINARY_DIR)
 | 
						|
    message(FATAL_ERROR "Internal error: BINARY_DIR not set")
 | 
						|
  elseif(NOT IS_ABSOLUTE "${ARG_BINARY_DIR}")
 | 
						|
    set(ARG_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/${ARG_BINARY_DIR}")
 | 
						|
  endif()
 | 
						|
 | 
						|
  # Ensure the caller can know where to find the source and build directories
 | 
						|
  # with some convenient variables. Doing this here ensures the caller sees
 | 
						|
  # the correct result in the case where the default values are overridden by
 | 
						|
  # the content details set by the project.
 | 
						|
  set(${contentName}_SOURCE_DIR "${ARG_SOURCE_DIR}" PARENT_SCOPE)
 | 
						|
  set(${contentName}_BINARY_DIR "${ARG_BINARY_DIR}" PARENT_SCOPE)
 | 
						|
 | 
						|
  # The unparsed arguments may contain spaces, so build up ARG_EXTRA
 | 
						|
  # in such a way that it correctly substitutes into the generated
 | 
						|
  # CMakeLists.txt file with each argument quoted.
 | 
						|
  unset(ARG_EXTRA)
 | 
						|
  foreach(arg IN LISTS ARG_UNPARSED_ARGUMENTS)
 | 
						|
    set(ARG_EXTRA "${ARG_EXTRA} \"${arg}\"")
 | 
						|
  endforeach()
 | 
						|
 | 
						|
  if(ARG_DOWNLOAD_NO_EXTRACT)
 | 
						|
    set(ARG_EXTRA "${ARG_EXTRA} DOWNLOAD_NO_EXTRACT YES")
 | 
						|
    set(__FETCHCONTENT_COPY_FILE
 | 
						|
"
 | 
						|
ExternalProject_Get_Property(${contentName}-populate DOWNLOADED_FILE)
 | 
						|
get_filename_component(dlFileName \"\${DOWNLOADED_FILE}\" NAME)
 | 
						|
 | 
						|
ExternalProject_Add_Step(${contentName}-populate copyfile
 | 
						|
  COMMAND    \"${CMAKE_COMMAND}\" -E copy_if_different
 | 
						|
             \"<DOWNLOADED_FILE>\" \"${ARG_SOURCE_DIR}\"
 | 
						|
  DEPENDEES  patch
 | 
						|
  DEPENDERS  configure
 | 
						|
  BYPRODUCTS \"${ARG_SOURCE_DIR}/\${dlFileName}\"
 | 
						|
  COMMENT    \"Copying file to SOURCE_DIR\"
 | 
						|
)
 | 
						|
")
 | 
						|
  else()
 | 
						|
    unset(__FETCHCONTENT_COPY_FILE)
 | 
						|
  endif()
 | 
						|
 | 
						|
  # Hide output if requested, but save it to a variable in case there's an
 | 
						|
  # error so we can show the output upon failure. When not quiet, don't
 | 
						|
  # capture the output to a variable because the user may want to see the
 | 
						|
  # output as it happens (e.g. progress during long downloads). Combine both
 | 
						|
  # stdout and stderr in the one capture variable so the output stays in order.
 | 
						|
  if (ARG_QUIET)
 | 
						|
    set(outputOptions
 | 
						|
        OUTPUT_VARIABLE capturedOutput
 | 
						|
        ERROR_VARIABLE  capturedOutput
 | 
						|
    )
 | 
						|
  else()
 | 
						|
    set(capturedOutput)
 | 
						|
    set(outputOptions)
 | 
						|
    message(STATUS "Populating ${contentName}")
 | 
						|
  endif()
 | 
						|
 | 
						|
  if(CMAKE_GENERATOR)
 | 
						|
    set(subCMakeOpts "-G${CMAKE_GENERATOR}")
 | 
						|
    if(CMAKE_GENERATOR_PLATFORM)
 | 
						|
      list(APPEND subCMakeOpts "-A${CMAKE_GENERATOR_PLATFORM}")
 | 
						|
    endif()
 | 
						|
    if(CMAKE_GENERATOR_TOOLSET)
 | 
						|
      list(APPEND subCMakeOpts "-T${CMAKE_GENERATOR_TOOLSET}")
 | 
						|
    endif()
 | 
						|
 | 
						|
    if(CMAKE_MAKE_PROGRAM)
 | 
						|
      list(APPEND subCMakeOpts "-DCMAKE_MAKE_PROGRAM:FILEPATH=${CMAKE_MAKE_PROGRAM}")
 | 
						|
    endif()
 | 
						|
 | 
						|
  else()
 | 
						|
    # Likely we've been invoked via CMake's script mode where no
 | 
						|
    # generator is set (and hence CMAKE_MAKE_PROGRAM could not be
 | 
						|
    # trusted even if provided). We will have to rely on being
 | 
						|
    # able to find the default generator and build tool.
 | 
						|
    unset(subCMakeOpts)
 | 
						|
  endif()
 | 
						|
 | 
						|
  if(DEFINED CMAKE_EP_GIT_REMOTE_UPDATE_STRATEGY)
 | 
						|
    list(APPEND subCMakeOpts
 | 
						|
      "-DCMAKE_EP_GIT_REMOTE_UPDATE_STRATEGY=${CMAKE_EP_GIT_REMOTE_UPDATE_STRATEGY}")
 | 
						|
  endif()
 | 
						|
 | 
						|
  # Create and build a separate CMake project to carry out the population.
 | 
						|
  # If we've already previously done these steps, they will not cause
 | 
						|
  # anything to be updated, so extra rebuilds of the project won't occur.
 | 
						|
  # Make sure to pass through CMAKE_MAKE_PROGRAM in case the main project
 | 
						|
  # has this set to something not findable on the PATH.
 | 
						|
  configure_file("${CMAKE_CURRENT_FUNCTION_LIST_DIR}/FetchContent/CMakeLists.cmake.in"
 | 
						|
                 "${ARG_SUBBUILD_DIR}/CMakeLists.txt")
 | 
						|
  execute_process(
 | 
						|
    COMMAND ${CMAKE_COMMAND} ${subCMakeOpts} .
 | 
						|
    RESULT_VARIABLE result
 | 
						|
    ${outputOptions}
 | 
						|
    WORKING_DIRECTORY "${ARG_SUBBUILD_DIR}"
 | 
						|
  )
 | 
						|
  if(result)
 | 
						|
    if(capturedOutput)
 | 
						|
      message("${capturedOutput}")
 | 
						|
    endif()
 | 
						|
    message(FATAL_ERROR "CMake step for ${contentName} failed: ${result}")
 | 
						|
  endif()
 | 
						|
  execute_process(
 | 
						|
    COMMAND ${CMAKE_COMMAND} --build .
 | 
						|
    RESULT_VARIABLE result
 | 
						|
    ${outputOptions}
 | 
						|
    WORKING_DIRECTORY "${ARG_SUBBUILD_DIR}"
 | 
						|
  )
 | 
						|
  if(result)
 | 
						|
    if(capturedOutput)
 | 
						|
      message("${capturedOutput}")
 | 
						|
    endif()
 | 
						|
    message(FATAL_ERROR "Build step for ${contentName} failed: ${result}")
 | 
						|
  endif()
 | 
						|
 | 
						|
endfunction()
 | 
						|
 | 
						|
 | 
						|
option(FETCHCONTENT_FULLY_DISCONNECTED   "Disables all attempts to download or update content and assumes source dirs already exist")
 | 
						|
option(FETCHCONTENT_UPDATES_DISCONNECTED "Enables UPDATE_DISCONNECTED behavior for all content population")
 | 
						|
option(FETCHCONTENT_QUIET                "Enables QUIET option for all content population" ON)
 | 
						|
set(FETCHCONTENT_BASE_DIR "${CMAKE_BINARY_DIR}/_deps" CACHE PATH "Directory under which to collect all populated content")
 | 
						|
 | 
						|
# Populate the specified content using details stored from
 | 
						|
# an earlier call to FetchContent_Declare().
 | 
						|
function(FetchContent_Populate contentName)
 | 
						|
 | 
						|
  if(NOT contentName)
 | 
						|
    message(FATAL_ERROR "Empty contentName not allowed for FetchContent_Populate()")
 | 
						|
  endif()
 | 
						|
 | 
						|
  string(TOLOWER ${contentName} contentNameLower)
 | 
						|
 | 
						|
  if(ARGN)
 | 
						|
    # This is the direct population form with details fully specified
 | 
						|
    # as part of the call, so we already have everything we need
 | 
						|
    __FetchContent_directPopulate(
 | 
						|
      ${contentNameLower}
 | 
						|
      SUBBUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/${contentNameLower}-subbuild"
 | 
						|
      SOURCE_DIR   "${CMAKE_CURRENT_BINARY_DIR}/${contentNameLower}-src"
 | 
						|
      BINARY_DIR   "${CMAKE_CURRENT_BINARY_DIR}/${contentNameLower}-build"
 | 
						|
      ${ARGN}  # Could override any of the above ..._DIR variables
 | 
						|
    )
 | 
						|
 | 
						|
    # Pass source and binary dir variables back to the caller
 | 
						|
    set(${contentNameLower}_SOURCE_DIR "${${contentNameLower}_SOURCE_DIR}" PARENT_SCOPE)
 | 
						|
    set(${contentNameLower}_BINARY_DIR "${${contentNameLower}_BINARY_DIR}" PARENT_SCOPE)
 | 
						|
 | 
						|
    # Don't set global properties, or record that we did this population, since
 | 
						|
    # this was a direct call outside of the normal declared details form.
 | 
						|
    # We only want to save values in the global properties for content that
 | 
						|
    # honours the hierarchical details mechanism so that projects are not
 | 
						|
    # robbed of the ability to override details set in nested projects.
 | 
						|
    return()
 | 
						|
  endif()
 | 
						|
 | 
						|
  # No details provided, so assume they were saved from an earlier call
 | 
						|
  # to FetchContent_Declare(). Do a check that we haven't already
 | 
						|
  # 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}")
 | 
						|
  endif()
 | 
						|
 | 
						|
  string(TOUPPER ${contentName} contentNameUpper)
 | 
						|
  set(FETCHCONTENT_SOURCE_DIR_${contentNameUpper}
 | 
						|
      "${FETCHCONTENT_SOURCE_DIR_${contentNameUpper}}"
 | 
						|
      CACHE PATH "When not empty, overrides where to find pre-populated content for ${contentName}")
 | 
						|
 | 
						|
  if(FETCHCONTENT_SOURCE_DIR_${contentNameUpper})
 | 
						|
    # The source directory has been explicitly provided in the cache,
 | 
						|
    # so no population is required
 | 
						|
    set(${contentNameLower}_SOURCE_DIR "${FETCHCONTENT_SOURCE_DIR_${contentNameUpper}}")
 | 
						|
    set(${contentNameLower}_BINARY_DIR "${FETCHCONTENT_BASE_DIR}/${contentNameLower}-build")
 | 
						|
 | 
						|
  elseif(FETCHCONTENT_FULLY_DISCONNECTED)
 | 
						|
    # Bypass population and assume source is already there from a previous run
 | 
						|
    set(${contentNameLower}_SOURCE_DIR "${FETCHCONTENT_BASE_DIR}/${contentNameLower}-src")
 | 
						|
    set(${contentNameLower}_BINARY_DIR "${FETCHCONTENT_BASE_DIR}/${contentNameLower}-build")
 | 
						|
 | 
						|
  else()
 | 
						|
    # Support both a global "disconnect all updates" and a per-content
 | 
						|
    # update test (either one being set disables updates for this content).
 | 
						|
    option(FETCHCONTENT_UPDATES_DISCONNECTED_${contentNameUpper}
 | 
						|
           "Enables UPDATE_DISCONNECTED behavior just for population of ${contentName}")
 | 
						|
    if(FETCHCONTENT_UPDATES_DISCONNECTED OR
 | 
						|
       FETCHCONTENT_UPDATES_DISCONNECTED_${contentNameUpper})
 | 
						|
      set(disconnectUpdates True)
 | 
						|
    else()
 | 
						|
      set(disconnectUpdates False)
 | 
						|
    endif()
 | 
						|
 | 
						|
    if(FETCHCONTENT_QUIET)
 | 
						|
      set(quietFlag QUIET)
 | 
						|
    else()
 | 
						|
      unset(quietFlag)
 | 
						|
    endif()
 | 
						|
 | 
						|
    __FetchContent_getSavedDetails(${contentName} contentDetails)
 | 
						|
    if("${contentDetails}" STREQUAL "")
 | 
						|
      message(FATAL_ERROR "No details have been set for content: ${contentName}")
 | 
						|
    endif()
 | 
						|
 | 
						|
    set(__detailsQuoted)
 | 
						|
    foreach(__item IN LISTS contentDetails)
 | 
						|
      string(APPEND __detailsQuoted " [==[${__item}]==]")
 | 
						|
    endforeach()
 | 
						|
    cmake_language(EVAL CODE "
 | 
						|
      __FetchContent_directPopulate(
 | 
						|
        ${contentNameLower}
 | 
						|
        ${quietFlag}
 | 
						|
        UPDATE_DISCONNECTED ${disconnectUpdates}
 | 
						|
        SUBBUILD_DIR \"${FETCHCONTENT_BASE_DIR}/${contentNameLower}-subbuild\"
 | 
						|
        SOURCE_DIR   \"${FETCHCONTENT_BASE_DIR}/${contentNameLower}-src\"
 | 
						|
        BINARY_DIR   \"${FETCHCONTENT_BASE_DIR}/${contentNameLower}-build\"
 | 
						|
        # Put the saved details last so they can override any of the
 | 
						|
        # the options we set above (this can include SOURCE_DIR or
 | 
						|
        # BUILD_DIR)
 | 
						|
        ${__detailsQuoted}
 | 
						|
      )"
 | 
						|
    )
 | 
						|
  endif()
 | 
						|
 | 
						|
  __FetchContent_setPopulated(
 | 
						|
    ${contentName}
 | 
						|
    ${${contentNameLower}_SOURCE_DIR}
 | 
						|
    ${${contentNameLower}_BINARY_DIR}
 | 
						|
  )
 | 
						|
 | 
						|
  # Pass variables back to the caller. The variables passed back here
 | 
						|
  # must match what FetchContent_GetProperties() sets when it is called
 | 
						|
  # with just the content name.
 | 
						|
  set(${contentNameLower}_SOURCE_DIR "${${contentNameLower}_SOURCE_DIR}" PARENT_SCOPE)
 | 
						|
  set(${contentNameLower}_BINARY_DIR "${${contentNameLower}_BINARY_DIR}" PARENT_SCOPE)
 | 
						|
  set(${contentNameLower}_POPULATED  True PARENT_SCOPE)
 | 
						|
 | 
						|
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
 | 
						|
# that case). The command is implemented as a macro so that the variables
 | 
						|
# defined by the FetchContent_GetProperties() and FetchContent_Populate()
 | 
						|
# calls will be available to the caller.
 | 
						|
macro(FetchContent_MakeAvailable)
 | 
						|
 | 
						|
  foreach(contentName IN ITEMS ${ARGV})
 | 
						|
    string(TOLOWER ${contentName} contentNameLower)
 | 
						|
    FetchContent_GetProperties(${contentName})
 | 
						|
    if(NOT ${contentNameLower}_POPULATED)
 | 
						|
      FetchContent_Populate(${contentName})
 | 
						|
 | 
						|
      # Only try to call add_subdirectory() if the populated content
 | 
						|
      # can be treated that way. Protecting the call with the check
 | 
						|
      # allows this function to be used for projects that just want
 | 
						|
      # to ensure the content exists, such as to provide content at
 | 
						|
      # a known location. We check the saved details for an optional
 | 
						|
      # SOURCE_SUBDIR which can be used in the same way as its meaning
 | 
						|
      # for ExternalProject. It won't matter if it was passed through
 | 
						|
      # to the ExternalProject sub-build, since it would have been
 | 
						|
      # ignored there.
 | 
						|
      set(__fc_srcdir "${${contentNameLower}_SOURCE_DIR}")
 | 
						|
      __FetchContent_getSavedDetails(${contentName} contentDetails)
 | 
						|
      if("${contentDetails}" STREQUAL "")
 | 
						|
        message(FATAL_ERROR "No details have been set for content: ${contentName}")
 | 
						|
      endif()
 | 
						|
      cmake_parse_arguments(__fc_arg "" "SOURCE_SUBDIR" "" ${contentDetails})
 | 
						|
      if(NOT "${__fc_arg_SOURCE_SUBDIR}" STREQUAL "")
 | 
						|
        string(APPEND __fc_srcdir "/${__fc_arg_SOURCE_SUBDIR}")
 | 
						|
      endif()
 | 
						|
 | 
						|
      if(EXISTS ${__fc_srcdir}/CMakeLists.txt)
 | 
						|
        add_subdirectory(${__fc_srcdir} ${${contentNameLower}_BINARY_DIR})
 | 
						|
      endif()
 | 
						|
 | 
						|
      unset(__fc_srcdir)
 | 
						|
    endif()
 | 
						|
  endforeach()
 | 
						|
 | 
						|
endmacro()
 |