janitor

janitor
git clone https://git.prime8.dev/janitor.git
Log | Files | Refs | README | LICENSE

FetchContent.cmake (38023B)


      1 # Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
      2 # file Copyright.txt or https://cmake.org/licensing for details.
      3 
      4 #[=======================================================================[.rst:
      5 FetchContent
      6 ------------------
      7 
      8 .. only:: html
      9 
     10   .. contents::
     11 
     12 Overview
     13 ^^^^^^^^
     14 
     15 This module enables populating content at configure time via any method
     16 supported by the :module:`ExternalProject` module.  Whereas
     17 :command:`ExternalProject_Add` downloads at build time, the
     18 ``FetchContent`` module makes content available immediately, allowing the
     19 configure step to use the content in commands like :command:`add_subdirectory`,
     20 :command:`include` or :command:`file` operations.
     21 
     22 Content population details would normally be defined separately from the
     23 command that performs the actual population.  Projects should also
     24 check whether the content has already been populated somewhere else in the
     25 project hierarchy.  Typical usage would look something like this:
     26 
     27 .. code-block:: cmake
     28 
     29   FetchContent_Declare(
     30     googletest
     31     GIT_REPOSITORY https://github.com/google/googletest.git
     32     GIT_TAG        release-1.8.0
     33   )
     34 
     35   FetchContent_GetProperties(googletest)
     36   if(NOT googletest_POPULATED)
     37     FetchContent_Populate(googletest)
     38     add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR})
     39   endif()
     40 
     41 When using the above pattern with a hierarchical project arrangement,
     42 projects at higher levels in the hierarchy are able to define or override
     43 the population details of content specified anywhere lower in the project
     44 hierarchy.  The ability to detect whether content has already been
     45 populated ensures that even if multiple child projects want certain content
     46 to be available, the first one to populate it wins.  The other child project
     47 can simply make use of the already available content instead of repeating
     48 the population for itself.  See the
     49 :ref:`Examples <fetch-content-examples>` section which demonstrates
     50 this scenario.
     51 
     52 The ``FetchContent`` module also supports defining and populating
     53 content in a single call, with no check for whether the content has been
     54 populated elsewhere in the project already.  This is a more low level
     55 operation and would not normally be the way the module is used, but it is
     56 sometimes useful as part of implementing some higher level feature or to
     57 populate some content in CMake's script mode.
     58 
     59 
     60 Declaring Content Details
     61 ^^^^^^^^^^^^^^^^^^^^^^^^^
     62 
     63 .. command:: FetchContent_Declare
     64 
     65   .. code-block:: cmake
     66 
     67     FetchContent_Declare(<name> <contentOptions>...)
     68 
     69   The ``FetchContent_Declare()`` function records the options that describe
     70   how to populate the specified content, but if such details have already
     71   been recorded earlier in this project (regardless of where in the project
     72   hierarchy), this and all later calls for the same content ``<name>`` are
     73   ignored.  This "first to record, wins" approach is what allows hierarchical
     74   projects to have parent projects override content details of child projects.
     75 
     76   The content ``<name>`` can be any string without spaces, but good practice
     77   would be to use only letters, numbers and underscores.  The name will be
     78   treated case-insensitively and it should be obvious for the content it
     79   represents, often being the name of the child project or the value given
     80   to its top level :command:`project` command (if it is a CMake project).
     81   For well-known public projects, the name should generally be the official
     82   name of the project.  Choosing an unusual name makes it unlikely that other
     83   projects needing that same content will use the same name, leading to
     84   the content being populated multiple times.
     85 
     86   The ``<contentOptions>`` can be any of the download or update/patch options
     87   that the :command:`ExternalProject_Add` command understands.  The configure,
     88   build, install and test steps are explicitly disabled and therefore options
     89   related to them will be ignored.  In most cases, ``<contentOptions>`` will
     90   just be a couple of options defining the download method and method-specific
     91   details like a commit tag or archive hash.  For example:
     92 
     93   .. code-block:: cmake
     94 
     95     FetchContent_Declare(
     96       googletest
     97       GIT_REPOSITORY https://github.com/google/googletest.git
     98       GIT_TAG        release-1.8.0
     99     )
    100 
    101     FetchContent_Declare(
    102       myCompanyIcons
    103       URL      https://intranet.mycompany.com/assets/iconset_1.12.tar.gz
    104       URL_HASH 5588a7b18261c20068beabfb4f530b87
    105     )
    106 
    107     FetchContent_Declare(
    108       myCompanyCertificates
    109       SVN_REPOSITORY svn+ssh://svn.mycompany.com/srv/svn/trunk/certs
    110       SVN_REVISION   -r12345
    111     )
    112 
    113 Populating The Content
    114 ^^^^^^^^^^^^^^^^^^^^^^
    115 
    116 .. command:: FetchContent_Populate
    117 
    118   .. code-block:: cmake
    119 
    120     FetchContent_Populate( <name> )
    121 
    122   In most cases, the only argument given to ``FetchContent_Populate()`` is the
    123   ``<name>``.  When used this way, the command assumes the content details have
    124   been recorded by an earlier call to :command:`FetchContent_Declare`.  The
    125   details are stored in a global property, so they are unaffected by things
    126   like variable or directory scope.  Therefore, it doesn't matter where in the
    127   project the details were previously declared, as long as they have been
    128   declared before the call to ``FetchContent_Populate()``.  Those saved details
    129   are then used to construct a call to :command:`ExternalProject_Add` in a
    130   private sub-build to perform the content population immediately.  The
    131   implementation of ``ExternalProject_Add()`` ensures that if the content has
    132   already been populated in a previous CMake run, that content will be reused
    133   rather than repopulating them again.  For the common case where population
    134   involves downloading content, the cost of the download is only paid once.
    135 
    136   An internal global property records when a particular content population
    137   request has been processed.  If ``FetchContent_Populate()`` is called more
    138   than once for the same content name within a configure run, the second call
    139   will halt with an error.  Projects can and should check whether content
    140   population has already been processed with the
    141   :command:`FetchContent_GetProperties` command before calling
    142   ``FetchContent_Populate()``.
    143 
    144   ``FetchContent_Populate()`` will set three variables in the scope of the
    145   caller; ``<lcName>_POPULATED``, ``<lcName>_SOURCE_DIR`` and
    146   ``<lcName>_BINARY_DIR``, where ``<lcName>`` is the lowercased ``<name>``.
    147   ``<lcName>_POPULATED`` will always be set to ``True`` by the call.
    148   ``<lcName>_SOURCE_DIR`` is the location where the
    149   content can be found upon return (it will have already been populated), while
    150   ``<lcName>_BINARY_DIR`` is a directory intended for use as a corresponding
    151   build directory.  The main use case for the two directory variables is to
    152   call :command:`add_subdirectory` immediately after population, i.e.:
    153 
    154   .. code-block:: cmake
    155 
    156     FetchContent_Populate(FooBar ...)
    157     add_subdirectory(${foobar_SOURCE_DIR} ${foobar_BINARY_DIR})
    158 
    159   The values of the three variables can also be retrieved from anywhere in the
    160   project hierarchy using the :command:`FetchContent_GetProperties` command.
    161 
    162   A number of cache variables influence the behavior of all content population
    163   performed using details saved from a :command:`FetchContent_Declare` call:
    164 
    165   ``FETCHCONTENT_BASE_DIR``
    166     In most cases, the saved details do not specify any options relating to the
    167     directories to use for the internal sub-build, final source and build areas.
    168     It is generally best to leave these decisions up to the ``FetchContent``
    169     module to handle on the project's behalf.  The ``FETCHCONTENT_BASE_DIR``
    170     cache variable controls the point under which all content population
    171     directories are collected, but in most cases developers would not need to
    172     change this.  The default location is ``${CMAKE_BINARY_DIR}/_deps``, but if
    173     developers change this value, they should aim to keep the path short and
    174     just below the top level of the build tree to avoid running into path
    175     length problems on Windows.
    176 
    177   ``FETCHCONTENT_QUIET``
    178     The logging output during population can be quite verbose, making the
    179     configure stage quite noisy.  This cache option (``ON`` by default) hides
    180     all population output unless an error is encountered.  If experiencing
    181     problems with hung downloads, temporarily switching this option off may
    182     help diagnose which content population is causing the issue.
    183 
    184   ``FETCHCONTENT_FULLY_DISCONNECTED``
    185     When this option is enabled, no attempt is made to download or update
    186     any content.  It is assumed that all content has already been populated in
    187     a previous run or the source directories have been pointed at existing
    188     contents the developer has provided manually (using options described
    189     further below).  When the developer knows that no changes have been made to
    190     any content details, turning this option ``ON`` can significantly speed up
    191     the configure stage.  It is ``OFF`` by default.
    192 
    193   ``FETCHCONTENT_UPDATES_DISCONNECTED``
    194     This is a less severe download/update control compared to
    195     ``FETCHCONTENT_FULLY_DISCONNECTED``.  Instead of bypassing all download and
    196     update logic, the ``FETCHCONTENT_UPDATES_DISCONNECTED`` only disables the
    197     update stage.  Therefore, if content has not been downloaded previously,
    198     it will still be downloaded when this option is enabled.  This can speed up
    199     the configure stage, but not as much as
    200     ``FETCHCONTENT_FULLY_DISCONNECTED``.  It is ``OFF`` by default.
    201 
    202   In addition to the above cache variables, the following cache variables are
    203   also defined for each content name (``<ucName>`` is the uppercased value of
    204   ``<name>``):
    205 
    206   ``FETCHCONTENT_SOURCE_DIR_<ucName>``
    207     If this is set, no download or update steps are performed for the specified
    208     content and the ``<lcName>_SOURCE_DIR`` variable returned to the caller is
    209     pointed at this location.  This gives developers a way to have a separate
    210     checkout of the content that they can modify freely without interference
    211     from the build.  The build simply uses that existing source, but it still
    212     defines ``<lcName>_BINARY_DIR`` to point inside its own build area.
    213     Developers are strongly encouraged to use this mechanism rather than
    214     editing the sources populated in the default location, as changes to
    215     sources in the default location can be lost when content population details
    216     are changed by the project.
    217 
    218   ``FETCHCONTENT_UPDATES_DISCONNECTED_<ucName>``
    219     This is the per-content equivalent of
    220     ``FETCHCONTENT_UPDATES_DISCONNECTED``. If the global option or this option
    221     is ``ON``, then updates will be disabled for the named content.
    222     Disabling updates for individual content can be useful for content whose
    223     details rarely change, while still leaving other frequently changing
    224     content with updates enabled.
    225 
    226 
    227   The ``FetchContent_Populate()`` command also supports a syntax allowing the
    228   content details to be specified directly rather than using any saved
    229   details.  This is more low-level and use of this form is generally to be
    230   avoided in favour of using saved content details as outlined above.
    231   Nevertheless, in certain situations it can be useful to invoke the content
    232   population as an isolated operation (typically as part of implementing some
    233   other higher level feature or when using CMake in script mode):
    234 
    235   .. code-block:: cmake
    236 
    237     FetchContent_Populate( <name>
    238       [QUIET]
    239       [SUBBUILD_DIR <subBuildDir>]
    240       [SOURCE_DIR <srcDir>]
    241       [BINARY_DIR <binDir>]
    242       ...
    243     )
    244 
    245   This form has a number of key differences to that where only ``<name>`` is
    246   provided:
    247 
    248   - All required population details are assumed to have been provided directly
    249     in the call to ``FetchContent_Populate()``. Any saved details for
    250     ``<name>`` are ignored.
    251   - No check is made for whether content for ``<name>`` has already been
    252     populated.
    253   - No global property is set to record that the population has occurred.
    254   - No global properties record the source or binary directories used for the
    255     populated content.
    256   - The ``FETCHCONTENT_FULLY_DISCONNECTED`` and
    257     ``FETCHCONTENT_UPDATES_DISCONNECTED`` cache variables are ignored.
    258 
    259   The ``<lcName>_SOURCE_DIR`` and ``<lcName>_BINARY_DIR`` variables are still
    260   returned to the caller, but since these locations are not stored as global
    261   properties when this form is used, they are only available to the calling
    262   scope and below rather than the entire project hierarchy.  No
    263   ``<lcName>_POPULATED`` variable is set in the caller's scope with this form.
    264 
    265   The supported options for ``FetchContent_Populate()`` are the same as those
    266   for :command:`FetchContent_Declare()`.  Those few options shown just
    267   above are either specific to ``FetchContent_Populate()`` or their behavior is
    268   slightly modified from how :command:`ExternalProject_Add` treats them.
    269 
    270   ``QUIET``
    271     The ``QUIET`` option can be given to hide the output associated with
    272     populating the specified content.  If the population fails, the output will
    273     be shown regardless of whether this option was given or not so that the
    274     cause of the failure can be diagnosed.  The global ``FETCHCONTENT_QUIET``
    275     cache variable has no effect on ``FetchContent_Populate()`` calls where the
    276     content details are provided directly.
    277 
    278   ``SUBBUILD_DIR``
    279     The ``SUBBUILD_DIR`` argument can be provided to change the location of the
    280     sub-build created to perform the population.  The default value is
    281     ``${CMAKE_CURRENT_BINARY_DIR}/<lcName>-subbuild`` and it would be unusual
    282     to need to override this default.  If a relative path is specified, it will
    283     be interpreted as relative to :variable:`CMAKE_CURRENT_BINARY_DIR`.
    284 
    285   ``SOURCE_DIR``, ``BINARY_DIR``
    286     The ``SOURCE_DIR`` and ``BINARY_DIR`` arguments are supported by
    287     :command:`ExternalProject_Add`, but different default values are used by
    288     ``FetchContent_Populate()``.  ``SOURCE_DIR`` defaults to
    289     ``${CMAKE_CURRENT_BINARY_DIR}/<lcName>-src`` and ``BINARY_DIR`` defaults to
    290     ``${CMAKE_CURRENT_BINARY_DIR}/<lcName>-build``.  If a relative path is
    291     specified, it will be interpreted as relative to
    292     :variable:`CMAKE_CURRENT_BINARY_DIR`.
    293 
    294   In addition to the above explicit options, any other unrecognized options are
    295   passed through unmodified to :command:`ExternalProject_Add` to perform the
    296   download, patch and update steps.  The following options are explicitly
    297   prohibited (they are disabled by the ``FetchContent_Populate()`` command):
    298 
    299   - ``CONFIGURE_COMMAND``
    300   - ``BUILD_COMMAND``
    301   - ``INSTALL_COMMAND``
    302   - ``TEST_COMMAND``
    303 
    304   If using ``FetchContent_Populate()`` within CMake's script mode, be aware
    305   that the implementation sets up a sub-build which therefore requires a CMake
    306   generator and build tool to be available. If these cannot be found by
    307   default, then the :variable:`CMAKE_GENERATOR` and/or
    308   :variable:`CMAKE_MAKE_PROGRAM` variables will need to be set appropriately
    309   on the command line invoking the script.
    310 
    311 
    312 Retrieve Population Properties
    313 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    314 
    315 .. command:: FetchContent_GetProperties
    316 
    317   When using saved content details, a call to :command:`FetchContent_Populate`
    318   records information in global properties which can be queried at any time.
    319   This information includes the source and binary directories associated with
    320   the content and also whether or not the content population has been processed
    321   during the current configure run.
    322 
    323   .. code-block:: cmake
    324 
    325     FetchContent_GetProperties( <name>
    326       [SOURCE_DIR <srcDirVar>]
    327       [BINARY_DIR <binDirVar>]
    328       [POPULATED <doneVar>]
    329     )
    330 
    331   The ``SOURCE_DIR``, ``BINARY_DIR`` and ``POPULATED`` options can be used to
    332   specify which properties should be retrieved.  Each option accepts a value
    333   which is the name of the variable in which to store that property.  Most of
    334   the time though, only ``<name>`` is given, in which case the call will then
    335   set the same variables as a call to
    336   :command:`FetchContent_Populate(name) <FetchContent_Populate>`.  This allows
    337   the following canonical pattern to be used, which ensures that the relevant
    338   variables will always be defined regardless of whether or not the population
    339   has been performed elsewhere in the project already:
    340 
    341   .. code-block:: cmake
    342 
    343     FetchContent_GetProperties(foobar)
    344     if(NOT foobar_POPULATED)
    345       FetchContent_Populate(foobar)
    346 
    347       # Set any custom variables, etc. here, then
    348       # populate the content as part of this build
    349 
    350       add_subdirectory(${foobar_SOURCE_DIR} ${foobar_BINARY_DIR})
    351     endif()
    352 
    353   The above pattern allows other parts of the overall project hierarchy to
    354   re-use the same content and ensure that it is only populated once.
    355 
    356 
    357 .. _`fetch-content-examples`:
    358 
    359 Examples
    360 ^^^^^^^^
    361 
    362 Consider a project hierarchy where ``projA`` is the top level project and it
    363 depends on projects ``projB`` and ``projC``. Both ``projB`` and ``projC``
    364 can be built standalone and they also both depend on another project
    365 ``projD``.  For simplicity, this example will assume that all four projects
    366 are available on a company git server.  The ``CMakeLists.txt`` of each project
    367 might have sections like the following:
    368 
    369 *projA*:
    370 
    371 .. code-block:: cmake
    372 
    373   include(FetchContent)
    374   FetchContent_Declare(
    375     projB
    376     GIT_REPOSITORY git@mycompany.com/git/projB.git
    377     GIT_TAG        4a89dc7e24ff212a7b5167bef7ab079d
    378   )
    379   FetchContent_Declare(
    380     projC
    381     GIT_REPOSITORY git@mycompany.com/git/projC.git
    382     GIT_TAG        4ad4016bd1d8d5412d135cf8ceea1bb9
    383   )
    384   FetchContent_Declare(
    385     projD
    386     GIT_REPOSITORY git@mycompany.com/git/projD.git
    387     GIT_TAG        origin/integrationBranch
    388   )
    389 
    390   FetchContent_GetProperties(projB)
    391   if(NOT projb_POPULATED)
    392     FetchContent_Populate(projB)
    393     add_subdirectory(${projb_SOURCE_DIR} ${projb_BINARY_DIR})
    394   endif()
    395 
    396   FetchContent_GetProperties(projC)
    397   if(NOT projc_POPULATED)
    398     FetchContent_Populate(projC)
    399     add_subdirectory(${projc_SOURCE_DIR} ${projc_BINARY_DIR})
    400   endif()
    401 
    402 *projB*:
    403 
    404 .. code-block:: cmake
    405 
    406   include(FetchContent)
    407   FetchContent_Declare(
    408     projD
    409     GIT_REPOSITORY git@mycompany.com/git/projD.git
    410     GIT_TAG        20b415f9034bbd2a2e8216e9a5c9e632
    411   )
    412 
    413   FetchContent_GetProperties(projD)
    414   if(NOT projd_POPULATED)
    415     FetchContent_Populate(projD)
    416     add_subdirectory(${projd_SOURCE_DIR} ${projd_BINARY_DIR})
    417   endif()
    418 
    419 
    420 *projC*:
    421 
    422 .. code-block:: cmake
    423 
    424   include(FetchContent)
    425   FetchContent_Declare(
    426     projD
    427     GIT_REPOSITORY git@mycompany.com/git/projD.git
    428     GIT_TAG        7d9a17ad2c962aa13e2fbb8043fb6b8a
    429   )
    430 
    431   FetchContent_GetProperties(projD)
    432   if(NOT projd_POPULATED)
    433     FetchContent_Populate(projD)
    434     add_subdirectory(${projd_SOURCE_DIR} ${projd_BINARY_DIR})
    435   endif()
    436 
    437 A few key points should be noted in the above:
    438 
    439 - ``projB`` and ``projC`` define different content details for ``projD``,
    440   but ``projA`` also defines a set of content details for ``projD`` and
    441   because ``projA`` will define them first, the details from ``projB`` and
    442   ``projC`` will not be used.  The override details defined by ``projA``
    443   are not required to match either of those from ``projB`` or ``projC``, but
    444   it is up to the higher level project to ensure that the details it does
    445   define still make sense for the child projects.
    446 - While ``projA`` defined content details for ``projD``, it did not need
    447   to explicitly call ``FetchContent_Populate(projD)`` itself.  Instead, it
    448   leaves that to a child project to do (in this case it will be ``projB``
    449   since it is added to the build ahead of ``projC``).  If ``projA`` needed to
    450   customize how the ``projD`` content was brought into the build as well
    451   (e.g. define some CMake variables before calling
    452   :command:`add_subdirectory` after populating), it would do the call to
    453   ``FetchContent_Populate()``, etc. just as it did for the ``projB`` and
    454   ``projC`` content.  For higher level projects, it is usually enough to
    455   just define the override content details and leave the actual population
    456   to the child projects.  This saves repeating the same thing at each level
    457   of the project hierarchy unnecessarily.
    458 - Even though ``projA`` is the top level project in this example, it still
    459   checks whether ``projB`` and ``projC`` have already been populated before
    460   going ahead to do those populations.  This makes ``projA`` able to be more
    461   easily incorporated as a child of some other higher level project in the
    462   future if required.  Always protect a call to
    463   :command:`FetchContent_Populate` with a check to
    464   :command:`FetchContent_GetProperties`, even in what may be considered a top
    465   level project at the time.
    466 
    467 
    468 The following example demonstrates how one might download and unpack a
    469 firmware tarball using CMake's :manual:`script mode <cmake(1)>`.  The call to
    470 :command:`FetchContent_Populate` specifies all the content details and the
    471 unpacked firmware will be placed in a ``firmware`` directory below the
    472 current working directory.
    473 
    474 *getFirmware.cmake*:
    475 
    476 .. code-block:: cmake
    477 
    478   # NOTE: Intended to be run in script mode with cmake -P
    479   include(FetchContent)
    480   FetchContent_Populate(
    481     firmware
    482     URL        https://mycompany.com/assets/firmware-1.23-arm.tar.gz
    483     URL_HASH   MD5=68247684da89b608d466253762b0ff11
    484     SOURCE_DIR firmware
    485   )
    486 
    487 #]=======================================================================]
    488 
    489 
    490 set(__FetchContent_privateDir "${CMAKE_CURRENT_LIST_DIR}/FetchContent")
    491 
    492 #=======================================================================
    493 # Recording and retrieving content details for later population
    494 #=======================================================================
    495 
    496 # Internal use, projects must not call this directly. It is
    497 # intended for use by FetchContent_Declare() only.
    498 #
    499 # Sets a content-specific global property (not meant for use
    500 # outside of functions defined here in this file) which can later
    501 # be retrieved using __FetchContent_getSavedDetails() with just the
    502 # same content name. If there is already a value stored in the
    503 # property, it is left unchanged and this call has no effect.
    504 # This allows parent projects to define the content details,
    505 # overriding anything a child project may try to set (properties
    506 # are not cached between runs, so the first thing to set it in a
    507 # build will be in control).
    508 function(__FetchContent_declareDetails contentName)
    509 
    510   string(TOLOWER ${contentName} contentNameLower)
    511   set(propertyName "_FetchContent_${contentNameLower}_savedDetails")
    512   get_property(alreadyDefined GLOBAL PROPERTY ${propertyName} DEFINED)
    513   if(NOT alreadyDefined)
    514     define_property(GLOBAL PROPERTY ${propertyName}
    515       BRIEF_DOCS "Internal implementation detail of FetchContent_Populate()"
    516       FULL_DOCS  "Details used by FetchContent_Populate() for ${contentName}"
    517     )
    518     set_property(GLOBAL PROPERTY ${propertyName} ${ARGN})
    519   endif()
    520 
    521 endfunction()
    522 
    523 
    524 # Internal use, projects must not call this directly. It is
    525 # intended for use by the FetchContent_Declare() function.
    526 #
    527 # Retrieves details saved for the specified content in an
    528 # earlier call to __FetchContent_declareDetails().
    529 function(__FetchContent_getSavedDetails contentName outVar)
    530 
    531   string(TOLOWER ${contentName} contentNameLower)
    532   set(propertyName "_FetchContent_${contentNameLower}_savedDetails")
    533   get_property(alreadyDefined GLOBAL PROPERTY ${propertyName} DEFINED)
    534   if(NOT alreadyDefined)
    535     message(FATAL_ERROR "No content details recorded for ${contentName}")
    536   endif()
    537   get_property(propertyValue GLOBAL PROPERTY ${propertyName})
    538   set(${outVar} "${propertyValue}" PARENT_SCOPE)
    539 
    540 endfunction()
    541 
    542 
    543 # Saves population details of the content, sets defaults for the
    544 # SOURCE_DIR and BUILD_DIR.
    545 function(FetchContent_Declare contentName)
    546 
    547   set(options "")
    548   set(oneValueArgs SVN_REPOSITORY)
    549   set(multiValueArgs "")
    550 
    551   cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
    552 
    553   unset(srcDirSuffix)
    554   unset(svnRepoArgs)
    555   if(ARG_SVN_REPOSITORY)
    556     # Add a hash of the svn repository URL to the source dir. This works
    557     # around the problem where if the URL changes, the download would
    558     # fail because it tries to checkout/update rather than switch the
    559     # old URL to the new one. We limit the hash to the first 7 characters
    560     # so that the source path doesn't get overly long (which can be a
    561     # problem on windows due to path length limits).
    562     string(SHA1 urlSHA ${ARG_SVN_REPOSITORY})
    563     string(SUBSTRING ${urlSHA} 0 7 urlSHA)
    564     set(srcDirSuffix "-${urlSHA}")
    565     set(svnRepoArgs  SVN_REPOSITORY ${ARG_SVN_REPOSITORY})
    566   endif()
    567 
    568   string(TOLOWER ${contentName} contentNameLower)
    569   __FetchContent_declareDetails(
    570     ${contentNameLower}
    571     SOURCE_DIR "${FETCHCONTENT_BASE_DIR}/${contentNameLower}-src${srcDirSuffix}"
    572     BINARY_DIR "${FETCHCONTENT_BASE_DIR}/${contentNameLower}-build"
    573     ${svnRepoArgs}
    574     # List these last so they can override things we set above
    575     ${ARG_UNPARSED_ARGUMENTS}
    576   )
    577 
    578 endfunction()
    579 
    580 
    581 #=======================================================================
    582 # Set/get whether the specified content has been populated yet.
    583 # The setter also records the source and binary dirs used.
    584 #=======================================================================
    585 
    586 # Internal use, projects must not call this directly. It is
    587 # intended for use by the FetchContent_Populate() function to
    588 # record when FetchContent_Populate() is called for a particular
    589 # content name.
    590 function(__FetchContent_setPopulated contentName sourceDir binaryDir)
    591 
    592   string(TOLOWER ${contentName} contentNameLower)
    593   set(prefix "_FetchContent_${contentNameLower}")
    594 
    595   set(propertyName "${prefix}_sourceDir")
    596   define_property(GLOBAL PROPERTY ${propertyName}
    597     BRIEF_DOCS "Internal implementation detail of FetchContent_Populate()"
    598     FULL_DOCS  "Details used by FetchContent_Populate() for ${contentName}"
    599   )
    600   set_property(GLOBAL PROPERTY ${propertyName} ${sourceDir})
    601 
    602   set(propertyName "${prefix}_binaryDir")
    603   define_property(GLOBAL PROPERTY ${propertyName}
    604     BRIEF_DOCS "Internal implementation detail of FetchContent_Populate()"
    605     FULL_DOCS  "Details used by FetchContent_Populate() for ${contentName}"
    606   )
    607   set_property(GLOBAL PROPERTY ${propertyName} ${binaryDir})
    608 
    609   set(propertyName "${prefix}_populated")
    610   define_property(GLOBAL PROPERTY ${propertyName}
    611     BRIEF_DOCS "Internal implementation detail of FetchContent_Populate()"
    612     FULL_DOCS  "Details used by FetchContent_Populate() for ${contentName}"
    613   )
    614   set_property(GLOBAL PROPERTY ${propertyName} True)
    615 
    616 endfunction()
    617 
    618 
    619 # Set variables in the calling scope for any of the retrievable
    620 # properties. If no specific properties are requested, variables
    621 # will be set for all retrievable properties.
    622 #
    623 # This function is intended to also be used by projects as the canonical
    624 # way to detect whether they should call FetchContent_Populate()
    625 # and pull the populated source into the build with add_subdirectory(),
    626 # if they are using the populated content in that way.
    627 function(FetchContent_GetProperties contentName)
    628 
    629   string(TOLOWER ${contentName} contentNameLower)
    630 
    631   set(options "")
    632   set(oneValueArgs SOURCE_DIR BINARY_DIR POPULATED)
    633   set(multiValueArgs "")
    634 
    635   cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
    636 
    637   if(NOT ARG_SOURCE_DIR AND
    638      NOT ARG_BINARY_DIR AND
    639      NOT ARG_POPULATED)
    640     # No specific properties requested, provide them all
    641     set(ARG_SOURCE_DIR ${contentNameLower}_SOURCE_DIR)
    642     set(ARG_BINARY_DIR ${contentNameLower}_BINARY_DIR)
    643     set(ARG_POPULATED  ${contentNameLower}_POPULATED)
    644   endif()
    645 
    646   set(prefix "_FetchContent_${contentNameLower}")
    647 
    648   if(ARG_SOURCE_DIR)
    649     set(propertyName "${prefix}_sourceDir")
    650     get_property(value GLOBAL PROPERTY ${propertyName})
    651     if(value)
    652       set(${ARG_SOURCE_DIR} ${value} PARENT_SCOPE)
    653     endif()
    654   endif()
    655 
    656   if(ARG_BINARY_DIR)
    657     set(propertyName "${prefix}_binaryDir")
    658     get_property(value GLOBAL PROPERTY ${propertyName})
    659     if(value)
    660       set(${ARG_BINARY_DIR} ${value} PARENT_SCOPE)
    661     endif()
    662   endif()
    663 
    664   if(ARG_POPULATED)
    665     set(propertyName "${prefix}_populated")
    666     get_property(value GLOBAL PROPERTY ${propertyName} DEFINED)
    667     set(${ARG_POPULATED} ${value} PARENT_SCOPE)
    668   endif()
    669 
    670 endfunction()
    671 
    672 
    673 #=======================================================================
    674 # Performing the population
    675 #=======================================================================
    676 
    677 # The value of contentName will always have been lowercased by the caller.
    678 # All other arguments are assumed to be options that are understood by
    679 # ExternalProject_Add(), except for QUIET and SUBBUILD_DIR.
    680 function(__FetchContent_directPopulate contentName)
    681 
    682   set(options
    683       QUIET
    684   )
    685   set(oneValueArgs
    686       SUBBUILD_DIR
    687       SOURCE_DIR
    688       BINARY_DIR
    689       # Prevent the following from being passed through
    690       CONFIGURE_COMMAND
    691       BUILD_COMMAND
    692       INSTALL_COMMAND
    693       TEST_COMMAND
    694   )
    695   set(multiValueArgs "")
    696 
    697   cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
    698 
    699   if(NOT ARG_SUBBUILD_DIR)
    700     message(FATAL_ERROR "Internal error: SUBBUILD_DIR not set")
    701   elseif(NOT IS_ABSOLUTE "${ARG_SUBBUILD_DIR}")
    702     set(ARG_SUBBUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/${ARG_SUBBUILD_DIR}")
    703   endif()
    704 
    705   if(NOT ARG_SOURCE_DIR)
    706     message(FATAL_ERROR "Internal error: SOURCE_DIR not set")
    707   elseif(NOT IS_ABSOLUTE "${ARG_SOURCE_DIR}")
    708     set(ARG_SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/${ARG_SOURCE_DIR}")
    709   endif()
    710 
    711   if(NOT ARG_BINARY_DIR)
    712     message(FATAL_ERROR "Internal error: BINARY_DIR not set")
    713   elseif(NOT IS_ABSOLUTE "${ARG_BINARY_DIR}")
    714     set(ARG_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/${ARG_BINARY_DIR}")
    715   endif()
    716 
    717   # Ensure the caller can know where to find the source and build directories
    718   # with some convenient variables. Doing this here ensures the caller sees
    719   # the correct result in the case where the default values are overridden by
    720   # the content details set by the project.
    721   set(${contentName}_SOURCE_DIR "${ARG_SOURCE_DIR}" PARENT_SCOPE)
    722   set(${contentName}_BINARY_DIR "${ARG_BINARY_DIR}" PARENT_SCOPE)
    723 
    724   # The unparsed arguments may contain spaces, so build up ARG_EXTRA
    725   # in such a way that it correctly substitutes into the generated
    726   # CMakeLists.txt file with each argument quoted.
    727   unset(ARG_EXTRA)
    728   foreach(arg IN LISTS ARG_UNPARSED_ARGUMENTS)
    729     set(ARG_EXTRA "${ARG_EXTRA} \"${arg}\"")
    730   endforeach()
    731 
    732   # Hide output if requested, but save it to a variable in case there's an
    733   # error so we can show the output upon failure. When not quiet, don't
    734   # capture the output to a variable because the user may want to see the
    735   # output as it happens (e.g. progress during long downloads). Combine both
    736   # stdout and stderr in the one capture variable so the output stays in order.
    737   if (ARG_QUIET)
    738     set(outputOptions
    739         OUTPUT_VARIABLE capturedOutput
    740         ERROR_VARIABLE  capturedOutput
    741     )
    742   else()
    743     set(capturedOutput)
    744     set(outputOptions)
    745     message(STATUS "Populating ${contentName}")
    746   endif()
    747 
    748   if(CMAKE_GENERATOR)
    749     set(generatorOpts "-G${CMAKE_GENERATOR}")
    750     if(CMAKE_GENERATOR_PLATFORM)
    751       list(APPEND generatorOpts "-A${CMAKE_GENERATOR_PLATFORM}")
    752     endif()
    753     if(CMAKE_GENERATOR_TOOLSET)
    754       list(APPEND generatorOpts "-T${CMAKE_GENERATOR_TOOLSET}")
    755     endif()
    756 
    757     if(CMAKE_MAKE_PROGRAM)
    758       list(APPEND generatorOpts "-DCMAKE_MAKE_PROGRAM:FILEPATH=${CMAKE_MAKE_PROGRAM}")
    759     endif()
    760 
    761   else()
    762     # Likely we've been invoked via CMake's script mode where no
    763     # generator is set (and hence CMAKE_MAKE_PROGRAM could not be
    764     # trusted even if provided). We will have to rely on being
    765     # able to find the default generator and build tool.
    766     unset(generatorOpts)
    767   endif()
    768 
    769   # Create and build a separate CMake project to carry out the population.
    770   # If we've already previously done these steps, they will not cause
    771   # anything to be updated, so extra rebuilds of the project won't occur.
    772   # Make sure to pass through CMAKE_MAKE_PROGRAM in case the main project
    773   # has this set to something not findable on the PATH.
    774   configure_file("${__FetchContent_privateDir}/CMakeLists.cmake.in"
    775                  "${ARG_SUBBUILD_DIR}/CMakeLists.txt")
    776   execute_process(
    777     COMMAND ${CMAKE_COMMAND} ${generatorOpts} .
    778     RESULT_VARIABLE result
    779     ${outputOptions}
    780     WORKING_DIRECTORY "${ARG_SUBBUILD_DIR}"
    781   )
    782   if(result)
    783     if(capturedOutput)
    784       message("${capturedOutput}")
    785     endif()
    786     message(FATAL_ERROR "CMake step for ${contentName} failed: ${result}")
    787   endif()
    788   execute_process(
    789     COMMAND ${CMAKE_COMMAND} --build .
    790     RESULT_VARIABLE result
    791     ${outputOptions}
    792     WORKING_DIRECTORY "${ARG_SUBBUILD_DIR}"
    793   )
    794   if(result)
    795     if(capturedOutput)
    796       message("${capturedOutput}")
    797     endif()
    798     message(FATAL_ERROR "Build step for ${contentName} failed: ${result}")
    799   endif()
    800 
    801 endfunction()
    802 
    803 
    804 option(FETCHCONTENT_FULLY_DISCONNECTED   "Disables all attempts to download or update content and assumes source dirs already exist")
    805 option(FETCHCONTENT_UPDATES_DISCONNECTED "Enables UPDATE_DISCONNECTED behavior for all content population")
    806 option(FETCHCONTENT_QUIET                "Enables QUIET option for all content population" ON)
    807 set(FETCHCONTENT_BASE_DIR "${CMAKE_BINARY_DIR}/_deps" CACHE PATH "Directory under which to collect all populated content")
    808 
    809 # Populate the specified content using details stored from
    810 # an earlier call to FetchContent_Declare().
    811 function(FetchContent_Populate contentName)
    812 
    813   if(NOT contentName)
    814     message(FATAL_ERROR "Empty contentName not allowed for FetchContent_Populate()")
    815   endif()
    816 
    817   string(TOLOWER ${contentName} contentNameLower)
    818 
    819   if(ARGN)
    820     # This is the direct population form with details fully specified
    821     # as part of the call, so we already have everything we need
    822     __FetchContent_directPopulate(
    823       ${contentNameLower}
    824       SUBBUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/${contentNameLower}-subbuild"
    825       SOURCE_DIR   "${CMAKE_CURRENT_BINARY_DIR}/${contentNameLower}-src"
    826       BINARY_DIR   "${CMAKE_CURRENT_BINARY_DIR}/${contentNameLower}-build"
    827       ${ARGN}  # Could override any of the above ..._DIR variables
    828     )
    829 
    830     # Pass source and binary dir variables back to the caller
    831     set(${contentNameLower}_SOURCE_DIR "${${contentNameLower}_SOURCE_DIR}" PARENT_SCOPE)
    832     set(${contentNameLower}_BINARY_DIR "${${contentNameLower}_BINARY_DIR}" PARENT_SCOPE)
    833 
    834     # Don't set global properties, or record that we did this population, since
    835     # this was a direct call outside of the normal declared details form.
    836     # We only want to save values in the global properties for content that
    837     # honours the hierarchical details mechanism so that projects are not
    838     # robbed of the ability to override details set in nested projects.
    839     return()
    840   endif()
    841 
    842   # No details provided, so assume they were saved from an earlier call
    843   # to FetchContent_Declare(). Do a check that we haven't already
    844   # populated this content before in case the caller forgot to check.
    845   FetchContent_GetProperties(${contentName})
    846   if(${contentNameLower}_POPULATED)
    847     message(FATAL_ERROR "Content ${contentName} already populated in ${${contentNameLower}_SOURCE_DIR}")
    848   endif()
    849 
    850   string(TOUPPER ${contentName} contentNameUpper)
    851   set(FETCHCONTENT_SOURCE_DIR_${contentNameUpper}
    852       "${FETCHCONTENT_SOURCE_DIR_${contentNameUpper}}"
    853       CACHE PATH "When not empty, overrides where to find pre-populated content for ${contentName}")
    854 
    855   if(FETCHCONTENT_SOURCE_DIR_${contentNameUpper})
    856     # The source directory has been explicitly provided in the cache,
    857     # so no population is required
    858     set(${contentNameLower}_SOURCE_DIR "${FETCHCONTENT_SOURCE_DIR_${contentNameUpper}}")
    859     set(${contentNameLower}_BINARY_DIR "${FETCHCONTENT_BASE_DIR}/${contentNameLower}-build")
    860 
    861   elseif(FETCHCONTENT_FULLY_DISCONNECTED)
    862     # Bypass population and assume source is already there from a previous run
    863     set(${contentNameLower}_SOURCE_DIR "${FETCHCONTENT_BASE_DIR}/${contentNameLower}-src")
    864     set(${contentNameLower}_BINARY_DIR "${FETCHCONTENT_BASE_DIR}/${contentNameLower}-build")
    865 
    866   else()
    867     # Support both a global "disconnect all updates" and a per-content
    868     # update test (either one being set disables updates for this content).
    869     option(FETCHCONTENT_UPDATES_DISCONNECTED_${contentNameUpper}
    870            "Enables UPDATE_DISCONNECTED behavior just for population of ${contentName}")
    871     if(FETCHCONTENT_UPDATES_DISCONNECTED OR
    872        FETCHCONTENT_UPDATES_DISCONNECTED_${contentNameUpper})
    873       set(disconnectUpdates True)
    874     else()
    875       set(disconnectUpdates False)
    876     endif()
    877 
    878     if(FETCHCONTENT_QUIET)
    879       set(quietFlag QUIET)
    880     else()
    881       unset(quietFlag)
    882     endif()
    883 
    884     __FetchContent_getSavedDetails(${contentName} contentDetails)
    885     if("${contentDetails}" STREQUAL "")
    886       message(FATAL_ERROR "No details have been set for content: ${contentName}")
    887     endif()
    888 
    889     __FetchContent_directPopulate(
    890       ${contentNameLower}
    891       ${quietFlag}
    892       UPDATE_DISCONNECTED ${disconnectUpdates}
    893       SUBBUILD_DIR "${FETCHCONTENT_BASE_DIR}/${contentNameLower}-subbuild"
    894       SOURCE_DIR   "${FETCHCONTENT_BASE_DIR}/${contentNameLower}-src"
    895       BINARY_DIR   "${FETCHCONTENT_BASE_DIR}/${contentNameLower}-build"
    896       # Put the saved details last so they can override any of the
    897       # the options we set above (this can include SOURCE_DIR or
    898       # BUILD_DIR)
    899       ${contentDetails}
    900     )
    901   endif()
    902 
    903   __FetchContent_setPopulated(
    904     ${contentName}
    905     ${${contentNameLower}_SOURCE_DIR}
    906     ${${contentNameLower}_BINARY_DIR}
    907   )
    908 
    909   # Pass variables back to the caller. The variables passed back here
    910   # must match what FetchContent_GetProperties() sets when it is called
    911   # with just the content name.
    912   set(${contentNameLower}_SOURCE_DIR "${${contentNameLower}_SOURCE_DIR}" PARENT_SCOPE)
    913   set(${contentNameLower}_BINARY_DIR "${${contentNameLower}_BINARY_DIR}" PARENT_SCOPE)
    914   set(${contentNameLower}_POPULATED  True PARENT_SCOPE)
    915 
    916 endfunction()