FetchContent: Add support for SOURCE_SUBDIR

Fixes: #19875
This commit is contained in:
Craig Scott
2020-05-16 16:57:01 +10:00
parent ec1b3992db
commit 592085b94b
5 changed files with 81 additions and 14 deletions

View File

@@ -0,0 +1,6 @@
fetchcontent-SOURCE_SUBDIR
--------------------------
* The :command:`FetchContent_Declare` command now supports a ``SOURCE_SUBDIR``
option. It can be used to direct :command:`FetchContent_MakeAvailable`
to look in a different location for the ``CMakeLists.txt`` file.

View File

@@ -108,9 +108,13 @@ Declaring Content Details
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. 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:
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
@@ -164,8 +168,9 @@ approach. The former generally follows this canonical pattern:
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 (and should be preferred where
it meets the needs of the project).
: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
@@ -335,6 +340,8 @@ it meets the needs of the project).
``${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
@@ -409,15 +416,22 @@ it meets the needs of the project).
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 same
and for each one it loosely follows the
:ref:`canonical pattern <fetch-content-canonical-pattern>` as
presented at the beginning of this section. One small difference to
that pattern is that it will only call :command:`add_subdirectory` on the
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`:
@@ -445,6 +459,23 @@ frameworks are available to the main build:
# 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
@@ -1072,11 +1103,26 @@ macro(FetchContent_MakeAvailable)
# 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.
if(EXISTS ${${contentNameLower}_SOURCE_DIR}/CMakeLists.txt)
add_subdirectory(${${contentNameLower}_SOURCE_DIR}
${${contentNameLower}_BINARY_DIR})
# 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()

View File

@@ -1,2 +1,3 @@
Confirmation project has been added
.*Confirmation subproject has been added
.*Confirmation script has been called

View File

@@ -8,13 +8,22 @@ FetchContent_Declare(
WithoutProject
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/WithoutProject
)
FetchContent_Declare(
ProjectSubdir
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/WithoutProject
SOURCE_SUBDIR ProjectSubdir
)
# Order is important and will be verified by test output
FetchContent_MakeAvailable(WithProject WithoutProject)
FetchContent_MakeAvailable(WithProject WithoutProject ProjectSubdir)
get_property(addedWith GLOBAL PROPERTY FetchWithProject SET)
if(NOT addedWith)
message(SEND_ERROR "Subdir with CMakeLists.txt not added")
message(SEND_ERROR "Project with top level CMakeLists.txt not added")
endif()
get_property(addedSubdir GLOBAL PROPERTY FetchWithSubProject SET)
if(NOT addedSubdir)
message(SEND_ERROR "Project with CMakeLists.txt in subdir not added")
endif()
include(${withoutproject_SOURCE_DIR}/confirmMessage.cmake)

View File

@@ -0,0 +1,5 @@
cmake_minimum_required(VERSION 3.13)
project(ProjectSubdir LANGUAGES NONE)
set_property(GLOBAL PROPERTY FetchWithSubProject YES)
message(STATUS "Confirmation subproject has been added")