summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Auxiliary/bash-completion/cmake2
-rw-r--r--Help/manual/cmake-modules.7.rst1
-rw-r--r--Help/manual/cmake.1.rst5
-rw-r--r--Help/module/FetchContent.rst1
-rw-r--r--Help/release/dev/FetchContent.rst11
-rw-r--r--Help/release/dev/cmake-open.rst6
-rw-r--r--Modules/CMakeFindSublimeText2.cmake23
-rw-r--r--Modules/FetchContent.cmake914
-rw-r--r--Modules/FetchContent/CMakeLists.cmake.in21
-rw-r--r--Modules/FindOpenCL.cmake5
-rw-r--r--Modules/FindOpenMP.cmake28
-rw-r--r--Source/CMakeVersion.cmake2
-rw-r--r--Source/QtDialog/CMakeSetupDialog.cxx36
-rw-r--r--Source/QtDialog/CMakeSetupDialog.h1
-rw-r--r--Source/QtDialog/QCMake.cxx29
-rw-r--r--Source/QtDialog/QCMake.h8
-rw-r--r--Source/cmExternalMakefileProjectGenerator.cxx7
-rw-r--r--Source/cmExternalMakefileProjectGenerator.h3
-rw-r--r--Source/cmExtraSublimeTextGenerator.cxx23
-rw-r--r--Source/cmExtraSublimeTextGenerator.h3
-rw-r--r--Source/cmGlobalGenerator.cxx10
-rw-r--r--Source/cmGlobalGenerator.h6
-rw-r--r--Source/cmGlobalVisualStudioGenerator.cxx42
-rw-r--r--Source/cmGlobalVisualStudioGenerator.h3
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx73
-rw-r--r--Source/cmGlobalXCodeGenerator.h7
-rw-r--r--Source/cmLocalVisualStudio7Generator.cxx100
-rw-r--r--Source/cmLocalVisualStudio7Generator.h4
-rw-r--r--Source/cmLocalVisualStudioGenerator.h2
-rw-r--r--Source/cmVSSetupHelper.cxx60
-rw-r--r--Source/cmVSSetupHelper.h5
-rw-r--r--Source/cmVisualStudio10TargetGenerator.cxx16
-rw-r--r--Source/cmake.cxx43
-rw-r--r--Source/cmake.h3
-rw-r--r--Source/cmakemain.cxx43
-rw-r--r--Tests/RunCMake/CMakeLists.txt1
-rw-r--r--Tests/RunCMake/FetchContent/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/FetchContent/DirOverrides.cmake46
-rw-r--r--Tests/RunCMake/FetchContent/DirectIgnoresDetails-stdout.txt1
-rw-r--r--Tests/RunCMake/FetchContent/DirectIgnoresDetails.cmake12
-rw-r--r--Tests/RunCMake/FetchContent/DownloadTwice-result.txt1
-rw-r--r--Tests/RunCMake/FetchContent/DownloadTwice-stderr.txt1
-rw-r--r--Tests/RunCMake/FetchContent/DownloadTwice.cmake9
-rw-r--r--Tests/RunCMake/FetchContent/FirstDetailsWin-stdout.txt1
-rw-r--r--Tests/RunCMake/FetchContent/FirstDetailsWin.cmake16
-rw-r--r--Tests/RunCMake/FetchContent/GetProperties.cmake67
-rw-r--r--Tests/RunCMake/FetchContent/MissingDetails-result.txt1
-rw-r--r--Tests/RunCMake/FetchContent/MissingDetails-stderr.txt1
-rw-r--r--Tests/RunCMake/FetchContent/MissingDetails.cmake3
-rw-r--r--Tests/RunCMake/FetchContent/RunCMakeTest.cmake28
-rw-r--r--Tests/RunCMake/FetchContent/SameGenerator.cmake17
-rw-r--r--Tests/RunCMake/FetchContent/ScriptMode.cmake35
-rw-r--r--Tests/RunCMake/FetchContent/VarDefinitions.cmake75
-rw-r--r--Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-SOURCES-check.cmake3
-rw-r--r--Tests/RunCMake/TargetSources/ConfigNotAllowed-stderr.txt2
-rw-r--r--Tests/RunCMake/TargetSources/OriginDebugIDE-result.txt1
-rw-r--r--Tests/RunCMake/TargetSources/OriginDebugIDE-stderr.txt40
-rw-r--r--Tests/RunCMake/TargetSources/OriginDebugIDE.cmake4
-rw-r--r--Tests/RunCMake/TargetSources/RunCMakeTest.cmake4
59 files changed, 1731 insertions, 187 deletions
diff --git a/Auxiliary/bash-completion/cmake b/Auxiliary/bash-completion/cmake
index 0a862fa..5d67b0b 100644
--- a/Auxiliary/bash-completion/cmake
+++ b/Auxiliary/bash-completion/cmake
@@ -96,7 +96,7 @@ _cmake()
_filedir
return
;;
- --build)
+ --build|--open)
_filedir -d
return
;;
diff --git a/Help/manual/cmake-modules.7.rst b/Help/manual/cmake-modules.7.rst
index 8f4b252..9fd92ec 100644
--- a/Help/manual/cmake-modules.7.rst
+++ b/Help/manual/cmake-modules.7.rst
@@ -80,6 +80,7 @@ All Modules
/module/ExternalData
/module/ExternalProject
/module/FeatureSummary
+ /module/FetchContent
/module/FindALSA
/module/FindArmadillo
/module/FindASPELL
diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst
index 6a21683..ff8c6c7 100644
--- a/Help/manual/cmake.1.rst
+++ b/Help/manual/cmake.1.rst
@@ -11,6 +11,7 @@ Synopsis
cmake [<options>] (<path-to-source> | <path-to-existing-build>)
cmake [(-D <var>=<value>)...] -P <cmake-script-file>
cmake --build <dir> [<options>...] [-- <build-tool-options>...]
+ cmake --open <dir>
cmake -E <command> [<options>...]
cmake --find-package <options>...
@@ -51,6 +52,10 @@ Options
``--build <dir>``
See `Build Tool Mode`_.
+``--open <dir>``
+ Open the generated project in the associated application. This is
+ only supported by some generators.
+
``-N``
View mode only.
diff --git a/Help/module/FetchContent.rst b/Help/module/FetchContent.rst
new file mode 100644
index 0000000..c130a6d
--- /dev/null
+++ b/Help/module/FetchContent.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FetchContent.cmake
diff --git a/Help/release/dev/FetchContent.rst b/Help/release/dev/FetchContent.rst
new file mode 100644
index 0000000..3b12977
--- /dev/null
+++ b/Help/release/dev/FetchContent.rst
@@ -0,0 +1,11 @@
+FetchContent
+------------
+
+* A new :module:`FetchContent` module was added which supports populating
+ content at configure time using any of the download/update methods
+ supported by :command:`ExternalProject_Add`. This allows the content
+ to be used immediately during the configure stage, such as with
+ :command:`add_subdirectory`, etc. Hierarchical project structures are
+ well supported, allowing parent projects to override the content details
+ of child projects and ensuring content is not populated multiple times
+ throughout the whole project tree.
diff --git a/Help/release/dev/cmake-open.rst b/Help/release/dev/cmake-open.rst
new file mode 100644
index 0000000..a8f77ae
--- /dev/null
+++ b/Help/release/dev/cmake-open.rst
@@ -0,0 +1,6 @@
+cmake-open
+----------
+
+* The :manual:`cmake(1)` ``--open <dir>`` command line option can now
+ be used to open generated IDE projects like Visual Studio solutions
+ or Xcode projects.
diff --git a/Modules/CMakeFindSublimeText2.cmake b/Modules/CMakeFindSublimeText2.cmake
new file mode 100644
index 0000000..022d010
--- /dev/null
+++ b/Modules/CMakeFindSublimeText2.cmake
@@ -0,0 +1,23 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This file is included in CMakeSystemSpecificInformation.cmake if
+# the Sublime Text 2 extra generator has been selected.
+
+find_program(CMAKE_SUBLIMETEXT_EXECUTABLE
+ NAMES subl3 subl sublime_text
+ PATHS
+ "/Applications/Sublime Text.app/Contents/SharedSupport/bin"
+ "/Applications/Sublime Text 3.app/Contents/SharedSupport/bin"
+ "/Applications/Sublime Text 2.app/Contents/SharedSupport/bin"
+ "$ENV{HOME}/Applications/Sublime Text.app/Contents/SharedSupport/bin"
+ "$ENV{HOME}/Applications/Sublime Text 3.app/Contents/SharedSupport/bin"
+ "$ENV{HOME}/Applications/Sublime Text 2.app/Contents/SharedSupport/bin"
+ "/opt/sublime_text"
+ "/opt/sublime_text_3"
+ DOC "The Sublime Text executable")
+
+if(CMAKE_SUBLIMETEXT_EXECUTABLE)
+ set(CMAKE_OPEN_PROJECT_COMMAND "${CMAKE_SUBLIMETEXT_EXECUTABLE} --project <PROJECT_FILE>" )
+endif()
diff --git a/Modules/FetchContent.cmake b/Modules/FetchContent.cmake
new file mode 100644
index 0000000..132354f
--- /dev/null
+++ b/Modules/FetchContent.cmake
@@ -0,0 +1,914 @@
+# 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. Projects should also
+check whether the content has already been populated somewhere else in the
+project hierarchy. Typical usage would look something like this:
+
+.. code-block:: cmake
+
+ FetchContent_Declare(
+ googletest
+ GIT_REPOSITORY https://github.com/google/googletest.git
+ GIT_TAG release-1.8.0
+ )
+
+ FetchContent_GetProperties(googletest)
+ if(NOT googletest_POPULATED)
+ FetchContent_Populate(googletest)
+ add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR})
+ endif()
+
+When using the above pattern with a hierarchical project arrangement,
+projects at higher levels in the hierarchy are able to define or 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.
+
+
+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. 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
+^^^^^^^^^^^^^^^^^^^^^^
+
+.. 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`.
+
+ ``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.
+
+
+Retrieve Population Properties
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. 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)
+
+ # Set any custom variables, etc. here, then
+ # populate the content as part of this build
+
+ add_subdirectory(${foobar_SOURCE_DIR} ${foobar_BINARY_DIR})
+ 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.
+
+
+.. _`fetch-content-examples`:
+
+Examples
+^^^^^^^^
+
+Consider a project hierarchy where ``projA`` is the top level project and it
+depends on projects ``projB`` and ``projC``. Both ``projB`` and ``projC``
+can be built standalone and they also both depend on another project
+``projD``. For simplicity, this example will assume that all four 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_GetProperties(projB)
+ if(NOT projb_POPULATED)
+ FetchContent_Populate(projB)
+ add_subdirectory(${projb_SOURCE_DIR} ${projb_BINARY_DIR})
+ endif()
+
+ FetchContent_GetProperties(projC)
+ if(NOT projc_POPULATED)
+ FetchContent_Populate(projC)
+ add_subdirectory(${projc_SOURCE_DIR} ${projc_BINARY_DIR})
+ endif()
+
+*projB*:
+
+.. code-block:: cmake
+
+ include(FetchContent)
+ FetchContent_Declare(
+ projD
+ GIT_REPOSITORY git@mycompany.com/git/projD.git
+ GIT_TAG 20b415f9034bbd2a2e8216e9a5c9e632
+ )
+
+ FetchContent_GetProperties(projD)
+ if(NOT projd_POPULATED)
+ FetchContent_Populate(projD)
+ add_subdirectory(${projd_SOURCE_DIR} ${projd_BINARY_DIR})
+ endif()
+
+
+*projC*:
+
+.. code-block:: cmake
+
+ include(FetchContent)
+ FetchContent_Declare(
+ projD
+ GIT_REPOSITORY git@mycompany.com/git/projD.git
+ GIT_TAG 7d9a17ad2c962aa13e2fbb8043fb6b8a
+ )
+
+ FetchContent_GetProperties(projD)
+ if(NOT projd_POPULATED)
+ FetchContent_Populate(projD)
+ 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`` and
+ 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.
+- While ``projA`` defined content details for ``projD``, it did not need
+ to explicitly call ``FetchContent_Populate(projD)`` itself. Instead, it
+ leaves that to a child project to do (in this case it will be ``projB``
+ since it is added to the build ahead of ``projC``). If ``projA`` needed to
+ customize how the ``projD`` content was brought into the build as well
+ (e.g. define some CMake variables before calling
+ :command:`add_subdirectory` after populating), it would do the call to
+ ``FetchContent_Populate()``, etc. just as it did for the ``projB`` and
+ ``projC`` content. For higher level projects, it is usually 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.
+- Even though ``projA`` is the top level project in this example, it still
+ checks whether ``projB`` and ``projC`` have already been populated before
+ going ahead to do those populations. This makes ``projA`` able to be more
+ easily incorporated as a child of some other higher level project in the
+ future if required. Always protect a call to
+ :command:`FetchContent_Populate` with a check to
+ :command:`FetchContent_GetProperties`, even in what may be considered a top
+ level project at the time.
+
+
+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
+ )
+
+#]=======================================================================]
+
+
+set(__FetchContent_privateDir "${CMAKE_CURRENT_LIST_DIR}/FetchContent")
+
+#=======================================================================
+# 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_property(GLOBAL PROPERTY ${propertyName} ${ARGN})
+ 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(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ 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)
+ __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
+ ${ARG_UNPARSED_ARGUMENTS}
+ )
+
+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
+ # Prevent the following from being passed through
+ CONFIGURE_COMMAND
+ BUILD_COMMAND
+ INSTALL_COMMAND
+ TEST_COMMAND
+ )
+ set(multiValueArgs "")
+
+ cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ 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()
+
+ # 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(generatorOpts "-G${CMAKE_GENERATOR}")
+ if(CMAKE_GENERATOR_PLATFORM)
+ list(APPEND generatorOpts "-A${CMAKE_GENERATOR_PLATFORM}")
+ endif()
+ if(CMAKE_GENERATOR_TOOLSET)
+ list(APPEND generatorOpts "-T${CMAKE_GENERATOR_TOOLSET}")
+ endif()
+
+ list(APPEND generatorOpts "-DCMAKE_MAKE_PROGRAM:FILE=${CMAKE_MAKE_PROGRAM}")
+
+ 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(generatorOpts)
+ 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("${__FetchContent_privateDir}/CMakeLists.cmake.in"
+ "${ARG_SUBBUILD_DIR}/CMakeLists.txt")
+ execute_process(
+ COMMAND ${CMAKE_COMMAND} ${generatorOpts} .
+ 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()
+
+ __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)
+ ${contentDetails}
+ )
+ 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()
diff --git a/Modules/FetchContent/CMakeLists.cmake.in b/Modules/FetchContent/CMakeLists.cmake.in
new file mode 100644
index 0000000..9a7a771
--- /dev/null
+++ b/Modules/FetchContent/CMakeLists.cmake.in
@@ -0,0 +1,21 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION ${CMAKE_VERSION})
+
+# We name the project and the target for the ExternalProject_Add() call
+# to something that will highlight to the user what we are working on if
+# something goes wrong and an error message is produced.
+
+project(${contentName}-populate NONE)
+
+include(ExternalProject)
+ExternalProject_Add(${contentName}-populate
+ ${ARG_EXTRA}
+ SOURCE_DIR "${ARG_SOURCE_DIR}"
+ BINARY_DIR "${ARG_BINARY_DIR}"
+ CONFIGURE_COMMAND ""
+ BUILD_COMMAND ""
+ INSTALL_COMMAND ""
+ TEST_COMMAND ""
+)
diff --git a/Modules/FindOpenCL.cmake b/Modules/FindOpenCL.cmake
index b8a7d82..ba87086 100644
--- a/Modules/FindOpenCL.cmake
+++ b/Modules/FindOpenCL.cmake
@@ -120,9 +120,12 @@ else()
NAMES OpenCL
PATHS
ENV AMDAPPSDKROOT
+ ENV CUDA_PATH
PATH_SUFFIXES
lib/x86_64
- lib/x64)
+ lib/x64
+ lib
+ lib64)
endif()
set(OpenCL_LIBRARIES ${OpenCL_LIBRARY})
diff --git a/Modules/FindOpenMP.cmake b/Modules/FindOpenMP.cmake
index 1d6a039..a39a234 100644
--- a/Modules/FindOpenMP.cmake
+++ b/Modules/FindOpenMP.cmake
@@ -211,13 +211,27 @@ function(_OPENMP_GET_FLAGS LANG FLAG_MODE OPENMP_FLAG_VAR OPENMP_LIB_NAMES_VAR)
unset(_OPENMP_LIB_NAMES)
foreach(_OPENMP_IMPLICIT_LIB IN LISTS OpenMP_${LANG}_IMPLICIT_LIBRARIES)
- if(NOT "${_OPENMP_IMPLICIT_LIB}" IN_LIST CMAKE_${LANG}_IMPLICIT_LINK_LIBRARIES)
- find_library(OpenMP_${_OPENMP_IMPLICIT_LIB}_LIBRARY
- NAMES "${_OPENMP_IMPLICIT_LIB}"
- HINTS ${OpenMP_${LANG}_IMPLICIT_LINK_DIRS}
- )
- mark_as_advanced(OpenMP_${_OPENMP_IMPLICIT_LIB}_LIBRARY)
- list(APPEND _OPENMP_LIB_NAMES ${_OPENMP_IMPLICIT_LIB})
+ get_filename_component(_OPENMP_IMPLICIT_LIB_DIR "${_OPENMP_IMPLICIT_LIB}" DIRECTORY)
+ get_filename_component(_OPENMP_IMPLICIT_LIB_NAME "${_OPENMP_IMPLICIT_LIB}" NAME)
+ get_filename_component(_OPENMP_IMPLICIT_LIB_PLAIN "${_OPENMP_IMPLICIT_LIB}" NAME_WE)
+ string(REGEX REPLACE "([][+.*?()^$])" "\\\\\\1" _OPENMP_IMPLICIT_LIB_PLAIN_ESC "${_OPENMP_IMPLICIT_LIB_PLAIN}")
+ string(REGEX REPLACE "([][+.*?()^$])" "\\\\\\1" _OPENMP_IMPLICIT_LIB_PATH_ESC "${_OPENMP_IMPLICIT_LIB}")
+ if(NOT ( "${_OPENMP_IMPLICIT_LIB}" IN_LIST CMAKE_${LANG}_IMPLICIT_LINK_LIBRARIES
+ OR "${CMAKE_${LANG}_STANDARD_LIBRARIES}" MATCHES "(^| )(-Wl,)?(-l)?(${_OPENMP_IMPLICIT_LIB_PLAIN_ESC}|${_OPENMP_IMPLICIT_LIB_PATH_ESC})( |$)"
+ OR "${CMAKE_${LANG}_LINK_EXECUTABLE}" MATCHES "(^| )(-Wl,)?(-l)?(${_OPENMP_IMPLICIT_LIB_PLAIN_ESC}|${_OPENMP_IMPLICIT_LIB_PATH_ESC})( |$)" ) )
+ if(_OPENMP_IMPLICIT_LIB_DIR)
+ set(OpenMP_${_OPENMP_IMPLICIT_LIB_PLAIN}_LIBRARY "${_OPENMP_IMPLICIT_LIB}" CACHE FILEPATH
+ "Path to the ${_OPENMP_IMPLICIT_LIB_PLAIN} library for OpenMP")
+ else()
+ find_library(OpenMP_${_OPENMP_IMPLICIT_LIB_PLAIN}_LIBRARY
+ NAMES "${_OPENMP_IMPLICIT_LIB_NAME}"
+ DOC "Path to the ${_OPENMP_IMPLICIT_LIB_PLAIN} library for OpenMP"
+ HINTS ${OpenMP_${LANG}_IMPLICIT_LINK_DIRS}
+ CMAKE_FIND_ROOT_PATH_BOTH
+ )
+ endif()
+ mark_as_advanced(OpenMP_${_OPENMP_IMPLICIT_LIB_PLAIN}_LIBRARY)
+ list(APPEND _OPENMP_LIB_NAMES ${_OPENMP_IMPLICIT_LIB_PLAIN})
endif()
endforeach()
set("${OPENMP_LIB_NAMES_VAR}" "${_OPENMP_LIB_NAMES}" PARENT_SCOPE)
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index c984aad..d0d95b4 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,5 +1,5 @@
# CMake version number components.
set(CMake_VERSION_MAJOR 3)
set(CMake_VERSION_MINOR 10)
-set(CMake_VERSION_PATCH 20171016)
+set(CMake_VERSION_PATCH 20171019)
#set(CMake_VERSION_RC 1)
diff --git a/Source/QtDialog/CMakeSetupDialog.cxx b/Source/QtDialog/CMakeSetupDialog.cxx
index bbb2395..5be9ec3 100644
--- a/Source/QtDialog/CMakeSetupDialog.cxx
+++ b/Source/QtDialog/CMakeSetupDialog.cxx
@@ -188,6 +188,9 @@ CMakeSetupDialog::CMakeSetupDialog()
connect(this->Output, SIGNAL(customContextMenuRequested(const QPoint&)),
this, SLOT(doOutputContextMenu(const QPoint&)));
+ // disable open project button
+ this->OpenProjectButton->setDisabled(true);
+
// start the cmake worker thread
this->CMakeThread = new QCMakeThread(this);
QObject::connect(this->CMakeThread, SIGNAL(cmakeInitialized()), this,
@@ -249,6 +252,10 @@ void CMakeSetupDialog::initialize()
SIGNAL(outputMessage(QString)), this,
SLOT(message(QString)));
+ QObject::connect(this->CMakeThread->cmakeInstance(),
+ SIGNAL(openPossible(bool)), this->OpenProjectButton,
+ SLOT(setEnabled(bool)));
+
QObject::connect(this->groupedCheck, SIGNAL(toggled(bool)), this,
SLOT(setGroupedView(bool)));
QObject::connect(this->advancedCheck, SIGNAL(toggled(bool)), this,
@@ -492,24 +499,10 @@ void CMakeSetupDialog::doGenerate()
this->ConfigureNeeded = true;
}
-QString CMakeSetupDialog::getProjectFilename()
-{
- QStringList nameFilter;
- nameFilter << "*.sln"
- << "*.xcodeproj";
- QDir directory(this->BinaryDirectory->currentText());
- QStringList nlnFile = directory.entryList(nameFilter);
-
- if (nlnFile.count() == 1) {
- return this->BinaryDirectory->currentText() + "/" + nlnFile.at(0);
- }
-
- return QString();
-}
-
void CMakeSetupDialog::doOpenProject()
{
- QDesktopServices::openUrl(QUrl::fromLocalFile(this->getProjectFilename()));
+ QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(), "open",
+ Qt::QueuedConnection);
}
void CMakeSetupDialog::closeEvent(QCloseEvent* e)
@@ -630,11 +623,6 @@ void CMakeSetupDialog::updateBinaryDirectory(const QString& dir)
this->BinaryDirectory->setEditText(dir);
this->BinaryDirectory->blockSignals(false);
}
- if (!this->getProjectFilename().isEmpty()) {
- this->OpenProjectButton->setEnabled(true);
- } else {
- this->OpenProjectButton->setEnabled(false);
- }
}
void CMakeSetupDialog::doBinaryBrowse()
@@ -1039,9 +1027,6 @@ void CMakeSetupDialog::enterState(CMakeSetupDialog::State s)
this->GenerateButton->setEnabled(true);
this->GenerateAction->setEnabled(true);
this->ConfigureButton->setEnabled(true);
- if (!this->getProjectFilename().isEmpty()) {
- this->OpenProjectButton->setEnabled(true);
- }
this->ConfigureButton->setText(tr("&Configure"));
this->GenerateButton->setText(tr("&Generate"));
} else if (s == ReadyGenerate) {
@@ -1049,9 +1034,6 @@ void CMakeSetupDialog::enterState(CMakeSetupDialog::State s)
this->GenerateButton->setEnabled(true);
this->GenerateAction->setEnabled(true);
this->ConfigureButton->setEnabled(true);
- if (!this->getProjectFilename().isEmpty()) {
- this->OpenProjectButton->setEnabled(true);
- }
this->ConfigureButton->setText(tr("&Configure"));
this->GenerateButton->setText(tr("&Generate"));
}
diff --git a/Source/QtDialog/CMakeSetupDialog.h b/Source/QtDialog/CMakeSetupDialog.h
index 0da28d8..7b767e5 100644
--- a/Source/QtDialog/CMakeSetupDialog.h
+++ b/Source/QtDialog/CMakeSetupDialog.h
@@ -31,7 +31,6 @@ protected slots:
void initialize();
void doConfigure();
void doGenerate();
- QString getProjectFilename();
void doOpenProject();
void doInstallForCommandLine();
void doHelp();
diff --git a/Source/QtDialog/QCMake.cxx b/Source/QtDialog/QCMake.cxx
index d473d9b..7e94a27 100644
--- a/Source/QtDialog/QCMake.cxx
+++ b/Source/QtDialog/QCMake.cxx
@@ -115,6 +115,8 @@ void QCMake::setBinaryDirectory(const QString& _dir)
if (toolset) {
this->setToolset(QString::fromLocal8Bit(toolset));
}
+
+ checkOpenPossible();
}
}
@@ -183,6 +185,26 @@ void QCMake::generate()
#endif
emit this->generateDone(err);
+ checkOpenPossible();
+}
+
+void QCMake::open()
+{
+#ifdef Q_OS_WIN
+ UINT lastErrorMode = SetErrorMode(0);
+#endif
+
+ InterruptFlag = 0;
+ cmSystemTools::ResetErrorOccuredFlag();
+
+ auto successful = this->CMakeInstance->Open(
+ this->BinaryDirectory.toLocal8Bit().data(), false);
+
+#ifdef Q_OS_WIN
+ SetErrorMode(lastErrorMode);
+#endif
+
+ emit this->openDone(successful);
}
void QCMake::setProperties(const QCMakePropertyList& newProps)
@@ -450,3 +472,10 @@ void QCMake::setWarnUnusedMode(bool value)
{
this->WarnUnusedMode = value;
}
+
+void QCMake::checkOpenPossible()
+{
+ auto data = this->BinaryDirectory.toLocal8Bit().data();
+ auto possible = this->CMakeInstance->Open(data, true);
+ emit openPossible(possible);
+}
diff --git a/Source/QtDialog/QCMake.h b/Source/QtDialog/QCMake.h
index 3b8cea7..6fae7e3 100644
--- a/Source/QtDialog/QCMake.h
+++ b/Source/QtDialog/QCMake.h
@@ -80,6 +80,8 @@ public slots:
void configure();
/// generate the files
void generate();
+ /// open the project
+ void open();
/// set the property values
void setProperties(const QCMakePropertyList&);
/// interrupt the configure or generate process (if connecting, make a direct
@@ -111,6 +113,8 @@ public slots:
void setWarnUninitializedMode(bool value);
/// set whether to run cmake with warnings about unused variables
void setWarnUnusedMode(bool value);
+ /// check if project IDE open is possible and emit openPossible signal
+ void checkOpenPossible();
public:
/// get the list of cache properties
@@ -151,6 +155,10 @@ signals:
void debugOutputChanged(bool);
/// signal when the toolset changes
void toolsetChanged(const QString& toolset);
+ /// signal when open is done
+ void openDone(bool successful);
+ /// signal when open is done
+ void openPossible(bool possible);
protected:
cmake* CMakeInstance;
diff --git a/Source/cmExternalMakefileProjectGenerator.cxx b/Source/cmExternalMakefileProjectGenerator.cxx
index 825ec65..fecd821 100644
--- a/Source/cmExternalMakefileProjectGenerator.cxx
+++ b/Source/cmExternalMakefileProjectGenerator.cxx
@@ -24,6 +24,13 @@ std::string cmExternalMakefileProjectGenerator::CreateFullGeneratorName(
return fullName;
}
+bool cmExternalMakefileProjectGenerator::Open(
+ const std::string& /*bindir*/, const std::string& /*projectName*/,
+ bool /*dryRun*/)
+{
+ return false;
+}
+
cmExternalMakefileProjectGeneratorFactory::
cmExternalMakefileProjectGeneratorFactory(const std::string& n,
const std::string& doc)
diff --git a/Source/cmExternalMakefileProjectGenerator.h b/Source/cmExternalMakefileProjectGenerator.h
index a1734ee..7f332a8 100644
--- a/Source/cmExternalMakefileProjectGenerator.h
+++ b/Source/cmExternalMakefileProjectGenerator.h
@@ -55,6 +55,9 @@ public:
void SetName(const std::string& n) { Name = n; }
std::string GetName() const { return Name; }
+ virtual bool Open(const std::string& bindir, const std::string& projectName,
+ bool dryRun);
+
protected:
///! Contains the names of the global generators support by this generator.
std::vector<std::string> SupportedGlobalGenerators;
diff --git a/Source/cmExtraSublimeTextGenerator.cxx b/Source/cmExtraSublimeTextGenerator.cxx
index 73a9c85..3d72ae3 100644
--- a/Source/cmExtraSublimeTextGenerator.cxx
+++ b/Source/cmExtraSublimeTextGenerator.cxx
@@ -400,3 +400,26 @@ std::string cmExtraSublimeTextGenerator::ComputeDefines(
return definesString;
}
+
+bool cmExtraSublimeTextGenerator::Open(const std::string& bindir,
+ const std::string& projectName,
+ bool dryRun)
+{
+ const char* sublExecutable =
+ this->GlobalGenerator->GetCMakeInstance()->GetCacheDefinition(
+ "CMAKE_SUBLIMETEXT_EXECUTABLE");
+ if (!sublExecutable) {
+ return false;
+ }
+ if (cmSystemTools::IsNOTFOUND(sublExecutable)) {
+ return false;
+ }
+
+ std::string filename = bindir + "/" + projectName + ".sublime-project";
+ if (dryRun) {
+ return cmSystemTools::FileExists(filename, true);
+ }
+
+ return cmSystemTools::RunSingleCommand(
+ { sublExecutable, "--project", filename });
+}
diff --git a/Source/cmExtraSublimeTextGenerator.h b/Source/cmExtraSublimeTextGenerator.h
index 7fb304e..57ba1cf 100644
--- a/Source/cmExtraSublimeTextGenerator.h
+++ b/Source/cmExtraSublimeTextGenerator.h
@@ -65,6 +65,9 @@ private:
std::string ComputeDefines(cmSourceFile* source, cmLocalGenerator* lg,
cmGeneratorTarget* gtgt);
+ bool Open(const std::string& bindir, const std::string& projectName,
+ bool dryRun) override;
+
bool ExcludeBuildFolder;
std::string EnvSettings;
};
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index 05efff3..38669c9 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -1824,6 +1824,16 @@ int cmGlobalGenerator::Build(const std::string& /*unused*/,
return retVal;
}
+bool cmGlobalGenerator::Open(const std::string& bindir,
+ const std::string& projectName, bool dryRun)
+{
+ if (this->ExtraGenerator) {
+ return this->ExtraGenerator->Open(bindir, projectName, dryRun);
+ }
+
+ return false;
+}
+
std::string cmGlobalGenerator::GenerateCMakeBuildCommand(
const std::string& target, const std::string& config,
const std::string& native, bool ignoreErrors)
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
index 18ca682..04e9dc1 100644
--- a/Source/cmGlobalGenerator.h
+++ b/Source/cmGlobalGenerator.h
@@ -162,6 +162,12 @@ public:
std::vector<std::string> const& nativeOptions =
std::vector<std::string>());
+ /**
+ * Open a generated IDE project given the following information.
+ */
+ virtual bool Open(const std::string& bindir, const std::string& projectName,
+ bool dryRun);
+
virtual void GenerateBuildCommand(
std::vector<std::string>& makeCommand, const std::string& makeProgram,
const std::string& projectName, const std::string& projectDir,
diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx
index 0651536..99600df 100644
--- a/Source/cmGlobalVisualStudioGenerator.cxx
+++ b/Source/cmGlobalVisualStudioGenerator.cxx
@@ -4,7 +4,10 @@
#include "cmGlobalVisualStudioGenerator.h"
#include "cmsys/Encoding.hxx"
+#include <future>
#include <iostream>
+#include <objbase.h>
+#include <shellapi.h>
#include <windows.h>
#include "cmAlgorithms.h"
@@ -103,15 +106,6 @@ void cmGlobalVisualStudioGenerator::AddExtraIDETargets()
// Configure CMake Visual Studio macros, for this user on this version
// of Visual Studio.
this->ConfigureCMakeVisualStudioMacros();
-
- // Add CMakeLists.txt with custom command to rerun CMake.
- for (std::vector<cmLocalGenerator*>::const_iterator lgi =
- this->LocalGenerators.begin();
- lgi != this->LocalGenerators.end(); ++lgi) {
- cmLocalVisualStudioGenerator* lg =
- static_cast<cmLocalVisualStudioGenerator*>(*lgi);
- lg->AddCMakeListsRules();
- }
}
void cmGlobalVisualStudioGenerator::ComputeTargetObjectDirectory(
@@ -928,3 +922,33 @@ void cmGlobalVisualStudioGenerator::AddSymbolExportCommand(
commandLines, "Auto build dll exports", ".");
commands.push_back(command);
}
+
+static bool OpenSolution(std::string sln)
+{
+ HRESULT comInitialized =
+ CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
+ if (FAILED(comInitialized)) {
+ return false;
+ }
+
+ HINSTANCE hi =
+ ShellExecuteA(NULL, "open", sln.c_str(), NULL, NULL, SW_SHOWNORMAL);
+
+ CoUninitialize();
+
+ return reinterpret_cast<intptr_t>(hi) > 32;
+}
+
+bool cmGlobalVisualStudioGenerator::Open(const std::string& bindir,
+ const std::string& projectName,
+ bool dryRun)
+{
+ std::string buildDir = cmSystemTools::ConvertToOutputPath(bindir.c_str());
+ std::string sln = buildDir + "\\" + projectName + ".sln";
+
+ if (dryRun) {
+ return cmSystemTools::FileExists(sln, true);
+ }
+
+ return std::async(std::launch::async, OpenSolution, sln).get();
+}
diff --git a/Source/cmGlobalVisualStudioGenerator.h b/Source/cmGlobalVisualStudioGenerator.h
index 62bfd3b..55a6813 100644
--- a/Source/cmGlobalVisualStudioGenerator.h
+++ b/Source/cmGlobalVisualStudioGenerator.h
@@ -131,6 +131,9 @@ public:
std::vector<cmCustomCommand>& commands,
std::string const& configName);
+ bool Open(const std::string& bindir, const std::string& projectName,
+ bool dryRun) override;
+
protected:
virtual void AddExtraIDETargets();
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index c79ee47..78943e4 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -35,6 +35,11 @@
struct cmLinkImplementation;
+#if defined(CMAKE_BUILD_WITH_CMAKE) && defined(__APPLE__)
+#define HAVE_APPLICATION_SERVICES
+#include <ApplicationServices/ApplicationServices.h>
+#endif
+
#if defined(CMAKE_BUILD_WITH_CMAKE)
#include "cmXMLParser.h"
@@ -287,6 +292,35 @@ void cmGlobalXCodeGenerator::EnableLanguage(
this->ComputeArchitectures(mf);
}
+bool cmGlobalXCodeGenerator::Open(const std::string& bindir,
+ const std::string& projectName, bool dryRun)
+{
+ bool ret = false;
+
+#ifdef HAVE_APPLICATION_SERVICES
+ std::string url = bindir + "/" + projectName + ".xcodeproj";
+
+ if (dryRun) {
+ return cmSystemTools::FileExists(url, false);
+ }
+
+ CFStringRef cfStr = CFStringCreateWithCString(
+ kCFAllocatorDefault, url.c_str(), kCFStringEncodingUTF8);
+ if (cfStr) {
+ CFURLRef cfUrl = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, cfStr,
+ kCFURLPOSIXPathStyle, true);
+ if (cfUrl) {
+ OSStatus err = LSOpenCFURLRef(cfUrl, nullptr);
+ ret = err == noErr;
+ CFRelease(cfUrl);
+ }
+ CFRelease(cfStr);
+ }
+#endif
+
+ return ret;
+}
+
void cmGlobalXCodeGenerator::GenerateBuildCommand(
std::vector<std::string>& makeCommand, const std::string& makeProgram,
const std::string& projectName, const std::string& /*projectDir*/,
@@ -404,12 +438,6 @@ void cmGlobalXCodeGenerator::AddExtraTargets(
cmGeneratorTarget* allBuildGt = new cmGeneratorTarget(allbuild, root);
root->AddGeneratorTarget(allBuildGt);
- // Refer to the main build configuration file for easy editing.
- std::string listfile = root->GetCurrentSourceDirectory();
- listfile += "/";
- listfile += "CMakeLists.txt";
- allBuildGt->AddSource(listfile);
-
// Add XCODE depend helper
std::string dir = root->GetCurrentBinaryDirectory();
cmCustomCommandLine makeHelper;
@@ -479,12 +507,6 @@ void cmGlobalXCodeGenerator::AddExtraTargets(
!target->GetPropertyAsBool("EXCLUDE_FROM_ALL")) {
allbuild->AddUtility(target->GetName());
}
-
- // Refer to the build configuration file for easy editing.
- listfile = gen->GetCurrentSourceDirectory();
- listfile += "/";
- listfile += "CMakeLists.txt";
- target->AddSource(listfile);
}
}
}
@@ -962,6 +984,13 @@ bool cmGlobalXCodeGenerator::CreateXCodeTargets(
if (!gtgt->GetConfigCommonSourceFiles(classes)) {
return false;
}
+
+ // Add CMakeLists.txt file for user convenience.
+ std::string listfile =
+ gtgt->GetLocalGenerator()->GetCurrentSourceDirectory();
+ listfile += "/CMakeLists.txt";
+ classes.push_back(gtgt->Makefile->GetOrCreateSource(listfile));
+
std::sort(classes.begin(), classes.end(), cmSourceFilePathCompare());
gtgt->ComputeObjectMapping();
@@ -2265,6 +2294,12 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateUtilityTarget(
return nullptr;
}
+ // Add CMakeLists.txt file for user convenience.
+ std::string listfile =
+ gtgt->GetLocalGenerator()->GetCurrentSourceDirectory();
+ listfile += "/CMakeLists.txt";
+ sources.push_back(gtgt->Makefile->GetOrCreateSource(listfile));
+
for (std::vector<cmSourceFile*>::const_iterator i = sources.begin();
i != sources.end(); ++i) {
if (!(*i)->GetPropertyAsBool("GENERATED")) {
@@ -2706,6 +2741,20 @@ bool cmGlobalXCodeGenerator::CreateGroups(
std::string key = GetGroupMapKeyFromPath(gtgt, source);
this->GroupMap[key] = pbxgroup;
}
+
+ // Add CMakeLists.txt file for user convenience.
+ {
+ std::string listfile =
+ gtgt->GetLocalGenerator()->GetCurrentSourceDirectory();
+ listfile += "/CMakeLists.txt";
+ cmSourceFile* sf = gtgt->Makefile->GetOrCreateSource(listfile);
+ std::string const& source = sf->GetFullPath();
+ cmSourceGroup* sourceGroup =
+ mf->FindSourceGroup(source.c_str(), sourceGroups);
+ cmXCodeObject* pbxgroup = this->CreateOrGetPBXGroup(gtgt, sourceGroup);
+ std::string key = GetGroupMapKeyFromPath(gtgt, source);
+ this->GroupMap[key] = pbxgroup;
+ }
}
}
return true;
diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h
index e9ca91c..b758e97 100644
--- a/Source/cmGlobalXCodeGenerator.h
+++ b/Source/cmGlobalXCodeGenerator.h
@@ -55,6 +55,13 @@ public:
*/
void EnableLanguage(std::vector<std::string> const& languages, cmMakefile*,
bool optional) override;
+
+ /**
+ * Open a generated IDE project given the following information.
+ */
+ bool Open(const std::string& bindir, const std::string& projectName,
+ bool dryRun) override;
+
/**
* Try running cmake and building a file. This is used for dynalically
* loaded commands, not as part of the usual build process.
diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx
index d8030b7..beb80f2 100644
--- a/Source/cmLocalVisualStudio7Generator.cxx
+++ b/Source/cmLocalVisualStudio7Generator.cxx
@@ -36,6 +36,13 @@ private:
cmLocalVisualStudio7Generator* LocalGenerator;
};
+class cmLocalVisualStudio7Generator::AllConfigSources
+{
+public:
+ std::vector<cmGeneratorTarget::AllConfigSource> Sources;
+ std::map<cmSourceFile const*, size_t> Index;
+};
+
extern cmVS7FlagTable cmLocalVisualStudio7GeneratorFlagTable[];
static void cmConvertToWindowsSlash(std::string& s)
@@ -83,29 +90,6 @@ void cmLocalVisualStudio7Generator::Generate()
this->WriteStampFiles();
}
-void cmLocalVisualStudio7Generator::AddCMakeListsRules()
-{
- // Create the regeneration custom rule.
- if (!this->Makefile->IsOn("CMAKE_SUPPRESS_REGENERATION")) {
- // Create a rule to regenerate the build system when the target
- // specification source changes.
- if (cmSourceFile* sf = this->CreateVCProjBuildRule()) {
- // Add the rule to targets that need it.
- const std::vector<cmGeneratorTarget*>& tgts =
- this->GetGeneratorTargets();
- for (std::vector<cmGeneratorTarget*>::const_iterator l = tgts.begin();
- l != tgts.end(); ++l) {
- if ((*l)->GetType() == cmStateEnums::GLOBAL_TARGET) {
- continue;
- }
- if ((*l)->GetName() != CMAKE_CHECK_BUILD_SYSTEM_TARGET) {
- (*l)->AddSource(sf->GetFullPath());
- }
- }
- }
- }
-}
-
void cmLocalVisualStudio7Generator::FixGlobalTargets()
{
// Visual Studio .NET 2003 Service Pack 1 will not run post-build
@@ -239,19 +223,29 @@ void cmLocalVisualStudio7Generator::CreateSingleVCProj(
cmSourceFile* cmLocalVisualStudio7Generator::CreateVCProjBuildRule()
{
+ if (this->Makefile->IsOn("CMAKE_SUPPRESS_REGENERATION")) {
+ return nullptr;
+ }
+
+ std::string makefileIn = this->GetCurrentSourceDirectory();
+ makefileIn += "/";
+ makefileIn += "CMakeLists.txt";
+ makefileIn = cmSystemTools::CollapseFullPath(makefileIn);
+ if (cmSourceFile* file = this->Makefile->GetSource(makefileIn)) {
+ if (file->GetCustomCommand()) {
+ return file;
+ }
+ }
+ if (!cmSystemTools::FileExists(makefileIn)) {
+ return nullptr;
+ }
+
std::string stampName = this->GetCurrentBinaryDirectory();
stampName += "/";
stampName += cmake::GetCMakeFilesDirectoryPostSlash();
stampName += "generate.stamp";
cmCustomCommandLine commandLine;
commandLine.push_back(cmSystemTools::GetCMakeCommand());
- std::string makefileIn = this->GetCurrentSourceDirectory();
- makefileIn += "/";
- makefileIn += "CMakeLists.txt";
- makefileIn = cmSystemTools::CollapseFullPath(makefileIn.c_str());
- if (!cmSystemTools::FileExists(makefileIn.c_str())) {
- return 0;
- }
std::string comment = "Building Custom Rule ";
comment += makefileIn;
std::string args;
@@ -275,10 +269,13 @@ cmSourceFile* cmLocalVisualStudio7Generator::CreateVCProjBuildRule()
fullpathStampName.c_str(), listFiles, makefileIn.c_str(), commandLines,
comment.c_str(), no_working_directory, true, false);
if (cmSourceFile* file = this->Makefile->GetSource(makefileIn.c_str())) {
+ // Finalize the source file path now since we're adding this after
+ // the generator validated all project-named sources.
+ file->GetFullPath();
return file;
} else {
cmSystemTools::Error("Error adding rule for ", makefileIn.c_str());
- return 0;
+ return nullptr;
}
}
@@ -1368,13 +1365,26 @@ void cmLocalVisualStudio7Generator::WriteVCProjFile(std::ostream& fout,
// We may be modifying the source groups temporarily, so make a copy.
std::vector<cmSourceGroup> sourceGroups = this->Makefile->GetSourceGroups();
- std::vector<cmGeneratorTarget::AllConfigSource> const& sources =
- target->GetAllConfigSources();
- std::map<cmSourceFile const*, size_t> sourcesIndex;
+ AllConfigSources sources;
+ sources.Sources = target->GetAllConfigSources();
+
+ // Add CMakeLists.txt file with rule to re-run CMake for user convenience.
+ if (target->GetType() != cmStateEnums::GLOBAL_TARGET &&
+ target->GetName() != CMAKE_CHECK_BUILD_SYSTEM_TARGET) {
+ if (cmSourceFile const* sf = this->CreateVCProjBuildRule()) {
+ cmGeneratorTarget::AllConfigSource acs;
+ acs.Source = sf;
+ acs.Kind = cmGeneratorTarget::SourceKindCustomCommand;
+ for (size_t ci = 0; ci < configs.size(); ++ci) {
+ acs.Configs.push_back(ci);
+ }
+ sources.Sources.emplace_back(std::move(acs));
+ }
+ }
- for (size_t si = 0; si < sources.size(); ++si) {
- cmSourceFile const* sf = sources[si].Source;
- sourcesIndex[sf] = si;
+ for (size_t si = 0; si < sources.Sources.size(); ++si) {
+ cmSourceFile const* sf = sources.Sources[si].Source;
+ sources.Index[sf] = si;
if (!sf->GetObjectLibrary().empty()) {
if (this->FortranProject) {
// Intel Fortran does not support per-config source locations
@@ -1400,7 +1410,7 @@ void cmLocalVisualStudio7Generator::WriteVCProjFile(std::ostream& fout,
// Loop through every source group.
for (unsigned int i = 0; i < sourceGroups.size(); ++i) {
cmSourceGroup sg = sourceGroups[i];
- this->WriteGroup(&sg, target, fout, libName, configs, sourcesIndex);
+ this->WriteGroup(&sg, target, fout, libName, configs, sources);
}
fout << "\t</Files>\n";
@@ -1567,7 +1577,7 @@ std::string cmLocalVisualStudio7Generator::ComputeLongestObjectDirectory(
bool cmLocalVisualStudio7Generator::WriteGroup(
const cmSourceGroup* sg, cmGeneratorTarget* target, std::ostream& fout,
const std::string& libName, std::vector<std::string> const& configs,
- std::map<cmSourceFile const*, size_t> const& sourcesIndex)
+ AllConfigSources const& sources)
{
cmGlobalVisualStudio7Generator* gg =
static_cast<cmGlobalVisualStudio7Generator*>(this->GlobalGenerator);
@@ -1579,7 +1589,7 @@ bool cmLocalVisualStudio7Generator::WriteGroup(
std::ostringstream tmpOut;
for (unsigned int i = 0; i < children.size(); ++i) {
if (this->WriteGroup(&children[i], target, tmpOut, libName, configs,
- sourcesIndex)) {
+ sources)) {
hasChildrenWithSources = true;
}
}
@@ -1595,9 +1605,6 @@ bool cmLocalVisualStudio7Generator::WriteGroup(
this->WriteVCProjBeginGroup(fout, name.c_str(), "");
}
- std::vector<cmGeneratorTarget::AllConfigSource> const& sources =
- target->GetAllConfigSources();
-
// Loop through each source in the source group.
for (std::vector<const cmSourceFile*>::const_iterator sf =
sourceFiles.begin();
@@ -1608,10 +1615,11 @@ bool cmLocalVisualStudio7Generator::WriteGroup(
target->GetType() == cmStateEnums::GLOBAL_TARGET) {
// Look up the source kind and configs.
std::map<cmSourceFile const*, size_t>::const_iterator map_it =
- sourcesIndex.find(*sf);
+ sources.Index.find(*sf);
// The map entry must exist because we populated it earlier.
- assert(map_it != sourcesIndex.end());
- cmGeneratorTarget::AllConfigSource const& acs = sources[map_it->second];
+ assert(map_it != sources.Index.end());
+ cmGeneratorTarget::AllConfigSource const& acs =
+ sources.Sources[map_it->second];
FCInfo fcinfo(this, target, acs, configs);
diff --git a/Source/cmLocalVisualStudio7Generator.h b/Source/cmLocalVisualStudio7Generator.h
index 7a77574..48f2e1a 100644
--- a/Source/cmLocalVisualStudio7Generator.h
+++ b/Source/cmLocalVisualStudio7Generator.h
@@ -65,7 +65,6 @@ public:
virtual void ReadAndStoreExternalGUID(const std::string& name,
const char* path);
- virtual void AddCMakeListsRules();
protected:
void CreateSingleVCProj(const std::string& lname, cmGeneratorTarget* tgt);
@@ -117,10 +116,11 @@ private:
FCInfo& fcinfo);
void WriteTargetVersionAttribute(std::ostream& fout, cmGeneratorTarget* gt);
+ class AllConfigSources;
bool WriteGroup(const cmSourceGroup* sg, cmGeneratorTarget* target,
std::ostream& fout, const std::string& libName,
std::vector<std::string> const& configs,
- std::map<cmSourceFile const*, size_t> const& sourcesIndex);
+ AllConfigSources const& sources);
friend class cmLocalVisualStudio7GeneratorFCInfo;
friend class cmLocalVisualStudio7GeneratorInternals;
diff --git a/Source/cmLocalVisualStudioGenerator.h b/Source/cmLocalVisualStudioGenerator.h
index cba24fe..ace2f89 100644
--- a/Source/cmLocalVisualStudioGenerator.h
+++ b/Source/cmLocalVisualStudioGenerator.h
@@ -44,8 +44,6 @@ public:
virtual std::string ComputeLongestObjectDirectory(
cmGeneratorTarget const*) const = 0;
- virtual void AddCMakeListsRules() = 0;
-
virtual void ComputeObjectFilenames(
std::map<cmSourceFile const*, std::string>& mapping,
cmGeneratorTarget const* = 0);
diff --git a/Source/cmVSSetupHelper.cxx b/Source/cmVSSetupHelper.cxx
index 3c50403..ea13649 100644
--- a/Source/cmVSSetupHelper.cxx
+++ b/Source/cmVSSetupHelper.cxx
@@ -1,7 +1,10 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmVSSetupHelper.h"
+
#include "cmSystemTools.h"
+#include "cmsys/Encoding.hxx"
+#include "cmsys/FStream.hxx"
#ifndef VSSetupConstants
#define VSSetupConstants
@@ -41,14 +44,19 @@ const CLSID CLSID_SetupConfiguration = {
/* clang-format on */
#endif
-const WCHAR* VCToolsetComponent =
- L"Microsoft.VisualStudio.Component.VC.Tools.x86.x64";
const WCHAR* Win10SDKComponent =
L"Microsoft.VisualStudio.Component.Windows10SDK";
const WCHAR* Win81SDKComponent =
L"Microsoft.VisualStudio.Component.Windows81SDK";
const WCHAR* ComponentType = L"Component";
+std::string VSInstanceInfo::GetInstallLocation() const
+{
+ std::string loc = cmsys::Encoding::ToNarrow(this->VSInstallLocation);
+ cmSystemTools::ConvertToUnixSlashes(loc);
+ return loc;
+}
+
cmVSSetupAPIHelper::cmVSSetupAPIHelper()
: setupConfig(NULL)
, setupConfig2(NULL)
@@ -90,11 +98,11 @@ bool cmVSSetupAPIHelper::IsWin81SDKInstalled()
}
bool cmVSSetupAPIHelper::CheckInstalledComponent(
- SmartCOMPtr<ISetupPackageReference> package, bool& bVCToolset,
- bool& bWin10SDK, bool& bWin81SDK)
+ SmartCOMPtr<ISetupPackageReference> package, bool& bWin10SDK,
+ bool& bWin81SDK)
{
bool ret = false;
- bVCToolset = bWin10SDK = bWin81SDK = false;
+ bWin10SDK = bWin81SDK = false;
SmartBSTR bstrId;
if (FAILED(package->GetId(&bstrId))) {
return ret;
@@ -107,11 +115,6 @@ bool cmVSSetupAPIHelper::CheckInstalledComponent(
std::wstring id = std::wstring(bstrId);
std::wstring type = std::wstring(bstrType);
- if (id.compare(VCToolsetComponent) == 0 &&
- type.compare(ComponentType) == 0) {
- bVCToolset = true;
- ret = true;
- }
// Checks for any version of Win10 SDK. The version is appended at the end of
// the
@@ -135,7 +138,6 @@ bool cmVSSetupAPIHelper::CheckInstalledComponent(
bool cmVSSetupAPIHelper::GetVSInstanceInfo(
SmartCOMPtr<ISetupInstance2> pInstance, VSInstanceInfo& vsInstanceInfo)
{
- bool isVCToolSetInstalled = false;
if (pInstance == NULL)
return false;
@@ -174,6 +176,23 @@ bool cmVSSetupAPIHelper::GetVSInstanceInfo(
}
}
+ // Check if a compiler is installed with this instance.
+ {
+ std::string const vcRoot = vsInstanceInfo.GetInstallLocation();
+ std::string const vcToolsVersionFile =
+ vcRoot + "/VC/Auxiliary/Build/Microsoft.VCToolsVersion.default.txt";
+ std::string vcToolsVersion;
+ cmsys::ifstream fin(vcToolsVersionFile.c_str());
+ if (!fin || !cmSystemTools::GetLineFromStream(fin, vcToolsVersion)) {
+ return false;
+ }
+ vcToolsVersion = cmSystemTools::TrimWhitespace(vcToolsVersion);
+ std::string const vcToolsDir = vcRoot + "/VC/Tools/MSVC/" + vcToolsVersion;
+ if (!cmSystemTools::FileIsDirectory(vcToolsDir)) {
+ return false;
+ }
+ }
+
// Reboot may have been required before the product package was registered
// (last).
if ((eRegistered & state) == eRegistered) {
@@ -199,12 +218,11 @@ bool cmVSSetupAPIHelper::GetVSInstanceInfo(
package == NULL)
continue;
- bool vcToolsetInstalled = false, win10SDKInstalled = false,
- win81SDkInstalled = false;
- bool ret = CheckInstalledComponent(package, vcToolsetInstalled,
- win10SDKInstalled, win81SDkInstalled);
+ bool win10SDKInstalled = false;
+ bool win81SDkInstalled = false;
+ bool ret =
+ CheckInstalledComponent(package, win10SDKInstalled, win81SDkInstalled);
if (ret) {
- isVCToolSetInstalled |= vcToolsetInstalled;
vsInstanceInfo.IsWin10SDKInstalled |= win10SDKInstalled;
vsInstanceInfo.IsWin81SDKInstalled |= win81SDkInstalled;
}
@@ -213,7 +231,7 @@ bool cmVSSetupAPIHelper::GetVSInstanceInfo(
SafeArrayDestroy(lpsaPackages);
}
- return isVCToolSetInstalled;
+ return true;
}
bool cmVSSetupAPIHelper::GetVSInstanceInfo(std::string& vsInstallLocation)
@@ -222,9 +240,7 @@ bool cmVSSetupAPIHelper::GetVSInstanceInfo(std::string& vsInstallLocation)
bool isInstalled = this->EnumerateAndChooseVSInstance();
if (isInstalled) {
- std::string str(chosenInstanceInfo.VSInstallLocation.begin(),
- chosenInstanceInfo.VSInstallLocation.end());
- vsInstallLocation = str;
+ vsInstallLocation = chosenInstanceInfo.GetInstallLocation();
}
return isInstalled;
@@ -281,9 +297,7 @@ bool cmVSSetupAPIHelper::EnumerateAndChooseVSInstance()
if (isInstalled) {
if (!envVSCommonToolsDir.empty()) {
- std::string currentVSLocation(instanceInfo.VSInstallLocation.begin(),
- instanceInfo.VSInstallLocation.end());
- cmSystemTools::ConvertToUnixSlashes(currentVSLocation);
+ std::string currentVSLocation = instanceInfo.GetInstallLocation();
currentVSLocation += "/Common7/Tools";
if (cmSystemTools::ComparePath(currentVSLocation,
envVSCommonToolsDir)) {
diff --git a/Source/cmVSSetupHelper.h b/Source/cmVSSetupHelper.h
index d2f514c..74a7ec0 100644
--- a/Source/cmVSSetupHelper.h
+++ b/Source/cmVSSetupHelper.h
@@ -116,6 +116,8 @@ struct VSInstanceInfo
ullVersion = 0;
IsWin10SDKInstalled = IsWin81SDKInstalled = false;
}
+
+ std::string GetInstallLocation() const;
};
class cmVSSetupAPIHelper
@@ -134,8 +136,7 @@ private:
bool GetVSInstanceInfo(SmartCOMPtr<ISetupInstance2> instance2,
VSInstanceInfo& vsInstanceInfo);
bool CheckInstalledComponent(SmartCOMPtr<ISetupPackageReference> package,
- bool& bVCToolset, bool& bWin10SDK,
- bool& bWin81SDK);
+ bool& bWin10SDK, bool& bWin81SDK);
int ChooseVSInstance(const std::vector<VSInstanceInfo>& vecVSInstances);
bool EnumerateAndChooseVSInstance();
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index 0087957..1a1b1e2 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -1174,6 +1174,15 @@ void cmVisualStudio10TargetGenerator::WriteCustomCommands()
si != customCommands.end(); ++si) {
this->WriteCustomCommand(*si);
}
+
+ // Add CMakeLists.txt file with rule to re-run CMake for user convenience.
+ if (this->GeneratorTarget->GetType() != cmStateEnums::GLOBAL_TARGET &&
+ this->GeneratorTarget->GetName() != CMAKE_CHECK_BUILD_SYSTEM_TARGET) {
+ if (cmSourceFile const* sf =
+ this->LocalGenerator->CreateVCProjBuildRule()) {
+ this->WriteCustomCommand(sf);
+ }
+ }
}
void cmVisualStudio10TargetGenerator::WriteCustomCommand(
@@ -2648,6 +2657,13 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaOptions(
cudaOptions.AddFlag("CompileOut", "$(IntDir)%(Filename).ptx");
}
+ // CUDA automatically passes the proper '--machine' flag to nvcc
+ // for the current architecture, but does not reflect this default
+ // in the user-visible IDE settings. Set it explicitly.
+ if (this->Platform == "x64") {
+ cudaOptions.AddFlag("TargetMachinePlatform", "64");
+ }
+
// Convert the host compiler options to the toolset's abstractions
// using a secondary flag table.
cudaOptions.ClearTables();
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index fd7151f..d7ed772 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -2425,6 +2425,49 @@ int cmake::Build(const std::string& dir, const std::string& target,
nativeOptions);
}
+bool cmake::Open(const std::string& dir, bool dryRun)
+{
+ this->SetHomeDirectory("");
+ this->SetHomeOutputDirectory("");
+ if (!cmSystemTools::FileIsDirectory(dir)) {
+ std::cerr << "Error: " << dir << " is not a directory\n";
+ return false;
+ }
+
+ std::string cachePath = FindCacheFile(dir);
+ if (!this->LoadCache(cachePath)) {
+ std::cerr << "Error: could not load cache\n";
+ return false;
+ }
+ const char* genName = this->State->GetCacheEntryValue("CMAKE_GENERATOR");
+ if (!genName) {
+ std::cerr << "Error: could not find CMAKE_GENERATOR in Cache\n";
+ return false;
+ }
+ const char* extraGenName =
+ this->State->GetInitializedCacheValue("CMAKE_EXTRA_GENERATOR");
+ std::string fullName =
+ cmExternalMakefileProjectGenerator::CreateFullGeneratorName(
+ genName, extraGenName ? extraGenName : "");
+
+ std::unique_ptr<cmGlobalGenerator> gen(
+ this->CreateGlobalGenerator(fullName));
+ if (!gen.get()) {
+ std::cerr << "Error: could create CMAKE_GENERATOR \"" << fullName
+ << "\"\n";
+ return false;
+ }
+
+ const char* cachedProjectName =
+ this->State->GetCacheEntryValue("CMAKE_PROJECT_NAME");
+ if (!cachedProjectName) {
+ std::cerr << "Error: could not find CMAKE_PROJECT_NAME in Cache\n";
+ return false;
+ }
+
+ return gen->Open(dir, cachedProjectName, dryRun);
+}
+
void cmake::WatchUnusedCli(const std::string& var)
{
#ifdef CMAKE_BUILD_WITH_CMAKE
diff --git a/Source/cmake.h b/Source/cmake.h
index b31b6f5..ed3ebe0 100644
--- a/Source/cmake.h
+++ b/Source/cmake.h
@@ -401,6 +401,9 @@ public:
const std::string& config,
const std::vector<std::string>& nativeOptions, bool clean);
+ ///! run the --open option
+ bool Open(const std::string& dir, bool dryRun);
+
void UnwatchUnusedCli(const std::string& var);
void WatchUnusedCli(const std::string& var);
diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx
index a1dfc3e..59b908a 100644
--- a/Source/cmakemain.cxx
+++ b/Source/cmakemain.cxx
@@ -66,6 +66,7 @@ static const char* cmDocumentationOptions[][2] = {
{ "-E", "CMake command mode." },
{ "-L[A][H]", "List non-advanced cached variables." },
{ "--build <dir>", "Build a CMake-generated project binary tree." },
+ { "--open <dir>", "Open generated project in the associated application." },
{ "-N", "View mode only." },
{ "-P <file>", "Process script mode." },
{ "--find-package", "Run in pkg-config like mode." },
@@ -100,6 +101,7 @@ static int do_command(int ac, char const* const* av)
int do_cmake(int ac, char const* const* av);
static int do_build(int ac, char const* const* av);
+static int do_open(int ac, char const* const* av);
static cmMakefile* cmakemainGetMakefile(void* clientdata)
{
@@ -186,6 +188,9 @@ int main(int ac, char const* const* av)
if (strcmp(av[1], "--build") == 0) {
return do_build(ac, av);
}
+ if (strcmp(av[1], "--open") == 0) {
+ return do_open(ac, av);
+ }
if (strcmp(av[1], "-E") == 0) {
return do_command(ac, av);
}
@@ -423,3 +428,41 @@ static int do_build(int ac, char const* const* av)
return cm.Build(dir, target, config, nativeOptions, clean);
#endif
}
+
+static int do_open(int ac, char const* const* av)
+{
+#ifndef CMAKE_BUILD_WITH_CMAKE
+ std::cerr << "This cmake does not support --open\n";
+ return -1;
+#else
+ std::string dir;
+
+ enum Doing
+ {
+ DoingNone,
+ DoingDir,
+ };
+ Doing doing = DoingDir;
+ for (int i = 2; i < ac; ++i) {
+ switch (doing) {
+ case DoingDir:
+ dir = cmSystemTools::CollapseFullPath(av[i]);
+ doing = DoingNone;
+ break;
+ default:
+ std::cerr << "Unknown argument " << av[i] << std::endl;
+ dir.clear();
+ break;
+ }
+ }
+ if (dir.empty()) {
+ std::cerr << "Usage: cmake --open <dir>\n";
+ return 1;
+ }
+
+ cmake cm(cmake::RoleInternal);
+ cmSystemTools::SetMessageCallback(cmakemainMessageCallback, &cm);
+ cm.SetProgressCallback(cmakemainProgressCallback, &cm);
+ return cm.Open(dir, false) ? 0 : 1;
+#endif
+}
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index 57cc144..7eafa06 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -327,6 +327,7 @@ add_RunCMake_test(install)
add_RunCMake_test(CPackConfig)
add_RunCMake_test(CPackInstallProperties)
add_RunCMake_test(ExternalProject)
+add_RunCMake_test(FetchContent)
add_RunCMake_test(CTestCommandLine)
# Only run this test on unix platforms that support
# symbolic links
diff --git a/Tests/RunCMake/FetchContent/CMakeLists.txt b/Tests/RunCMake/FetchContent/CMakeLists.txt
new file mode 100644
index 0000000..d3137f6
--- /dev/null
+++ b/Tests/RunCMake/FetchContent/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.9)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/FetchContent/DirOverrides.cmake b/Tests/RunCMake/FetchContent/DirOverrides.cmake
new file mode 100644
index 0000000..50eef16
--- /dev/null
+++ b/Tests/RunCMake/FetchContent/DirOverrides.cmake
@@ -0,0 +1,46 @@
+include(FetchContent)
+
+# Test using saved details
+FetchContent_Declare(
+ t1
+ SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/savedSrc
+ DOWNLOAD_COMMAND ${CMAKE_COMMAND} -E make_directory <SOURCE_DIR>
+)
+FetchContent_Populate(t1)
+if(NOT IS_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/savedSrc)
+ message(FATAL_ERROR "Saved details SOURCE_DIR override failed")
+endif()
+
+# Test direct population
+FetchContent_Populate(
+ t2
+ SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/directSrc
+ DOWNLOAD_COMMAND ${CMAKE_COMMAND} -E make_directory <SOURCE_DIR>
+)
+if(NOT IS_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/directSrc)
+ message(FATAL_ERROR "Direct details SOURCE_DIR override failed")
+endif()
+
+# Ensure setting BINARY_DIR to SOURCE_DIR works (a technique to
+# prevent an unwanted separate BINARY_DIR from being created, which
+# ExternalProject_Add() does whether we like it or not)
+FetchContent_Declare(
+ t3
+ SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/savedNoBuildDir
+ BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/savedNoBuildDir
+ DOWNLOAD_COMMAND ${CMAKE_COMMAND} -E make_directory <SOURCE_DIR>
+)
+FetchContent_Populate(t3)
+if(IS_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/savedNobuildDir-build)
+ message(FATAL_ERROR "Saved details BINARY_DIR override failed")
+endif()
+
+FetchContent_Populate(
+ t4
+ SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/directNoBuildDir
+ BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/directNoBuildDir
+ DOWNLOAD_COMMAND ${CMAKE_COMMAND} -E make_directory <SOURCE_DIR>
+)
+if(IS_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/savedNobuildDir-build)
+ message(FATAL_ERROR "Direct details BINARY_DIR override failed")
+endif()
diff --git a/Tests/RunCMake/FetchContent/DirectIgnoresDetails-stdout.txt b/Tests/RunCMake/FetchContent/DirectIgnoresDetails-stdout.txt
new file mode 100644
index 0000000..6fa5a57
--- /dev/null
+++ b/Tests/RunCMake/FetchContent/DirectIgnoresDetails-stdout.txt
@@ -0,0 +1 @@
+Local details used
diff --git a/Tests/RunCMake/FetchContent/DirectIgnoresDetails.cmake b/Tests/RunCMake/FetchContent/DirectIgnoresDetails.cmake
new file mode 100644
index 0000000..0731b43
--- /dev/null
+++ b/Tests/RunCMake/FetchContent/DirectIgnoresDetails.cmake
@@ -0,0 +1,12 @@
+include(FetchContent)
+
+FetchContent_Declare(
+ t1
+ DOWNLOAD_COMMAND ${CMAKE_COMMAND} -E echo "Saved details used"
+)
+
+# No QUIET option given, so command output will be shown
+FetchContent_Populate(
+ t1
+ DOWNLOAD_COMMAND ${CMAKE_COMMAND} -E echo "Local details used"
+)
diff --git a/Tests/RunCMake/FetchContent/DownloadTwice-result.txt b/Tests/RunCMake/FetchContent/DownloadTwice-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/FetchContent/DownloadTwice-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/FetchContent/DownloadTwice-stderr.txt b/Tests/RunCMake/FetchContent/DownloadTwice-stderr.txt
new file mode 100644
index 0000000..96fed48
--- /dev/null
+++ b/Tests/RunCMake/FetchContent/DownloadTwice-stderr.txt
@@ -0,0 +1 @@
+Content t1 already populated in
diff --git a/Tests/RunCMake/FetchContent/DownloadTwice.cmake b/Tests/RunCMake/FetchContent/DownloadTwice.cmake
new file mode 100644
index 0000000..6863c30
--- /dev/null
+++ b/Tests/RunCMake/FetchContent/DownloadTwice.cmake
@@ -0,0 +1,9 @@
+include(FetchContent)
+
+FetchContent_Declare(
+ t1
+ DOWNLOAD_COMMAND ${CMAKE_COMMAND} -E echo "Download command executed"
+)
+
+FetchContent_Populate(t1)
+FetchContent_Populate(t1) # Triggers error
diff --git a/Tests/RunCMake/FetchContent/FirstDetailsWin-stdout.txt b/Tests/RunCMake/FetchContent/FirstDetailsWin-stdout.txt
new file mode 100644
index 0000000..7a8bf18
--- /dev/null
+++ b/Tests/RunCMake/FetchContent/FirstDetailsWin-stdout.txt
@@ -0,0 +1 @@
+First details used
diff --git a/Tests/RunCMake/FetchContent/FirstDetailsWin.cmake b/Tests/RunCMake/FetchContent/FirstDetailsWin.cmake
new file mode 100644
index 0000000..208b12d
--- /dev/null
+++ b/Tests/RunCMake/FetchContent/FirstDetailsWin.cmake
@@ -0,0 +1,16 @@
+include(FetchContent)
+
+# Need to see the download command output
+set(FETCHCONTENT_QUIET OFF)
+
+FetchContent_Declare(
+ t1
+ DOWNLOAD_COMMAND ${CMAKE_COMMAND} -E echo "First details used"
+)
+
+FetchContent_Declare(
+ t1
+ DOWNLOAD_COMMAND ${CMAKE_COMMAND} -E echo "Second details used"
+)
+
+FetchContent_Populate(t1)
diff --git a/Tests/RunCMake/FetchContent/GetProperties.cmake b/Tests/RunCMake/FetchContent/GetProperties.cmake
new file mode 100644
index 0000000..61c99fe
--- /dev/null
+++ b/Tests/RunCMake/FetchContent/GetProperties.cmake
@@ -0,0 +1,67 @@
+include(FetchContent)
+
+# First confirm properties are empty even before declare
+FetchContent_GetProperties(t1)
+if(t1_POPULATED)
+ message(FATAL_ERROR "Property says populated before doing anything")
+endif()
+if(t1_SOURCE_DIR)
+ message(FATAL_ERROR "SOURCE_DIR property not initially empty")
+endif()
+if(t1_BINARY_DIR)
+ message(FATAL_ERROR "BINARY_DIR property not initially empty")
+endif()
+
+# Declare, but no properties should change yet
+FetchContent_Declare(
+ t1
+ SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/savedSrc
+ BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/savedBin
+ DOWNLOAD_COMMAND ${CMAKE_COMMAND} -E echo "Do nothing"
+)
+
+FetchContent_GetProperties(t1)
+if(t1_POPULATED)
+ message(FATAL_ERROR "Property says populated after only declaring details")
+endif()
+if(t1_SOURCE_DIR)
+ message(FATAL_ERROR "SOURCE_DIR property not empty after declare")
+endif()
+if(t1_BINARY_DIR)
+ message(FATAL_ERROR "BINARY_DIR property not empty after declare")
+endif()
+
+# Populate should make all properties non-empty/set
+FetchContent_Populate(t1)
+
+FetchContent_GetProperties(t1)
+if(NOT t1_POPULATED)
+ message(FATAL_ERROR "Population did not set POPULATED property")
+endif()
+if(NOT "${t1_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}/savedSrc")
+ message(FATAL_ERROR "SOURCE_DIR property not correct after population: "
+ "${t1_SOURCE_DIR}\n"
+ " Expected: ${CMAKE_CURRENT_BINARY_DIR}/savedSrc")
+endif()
+if(NOT "${t1_BINARY_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}/savedBin")
+ message(FATAL_ERROR "BINARY_DIR property not correct after population: "
+ "${t1_BINARY_DIR}\n"
+ " Expected: ${CMAKE_CURRENT_BINARY_DIR}/savedBin")
+endif()
+
+# Verify we can retrieve properties individually too
+FetchContent_GetProperties(t1 POPULATED varPop)
+FetchContent_GetProperties(t1 SOURCE_DIR varSrc)
+FetchContent_GetProperties(t1 BINARY_DIR varBin)
+
+if(NOT varPop)
+ message(FATAL_ERROR "Failed to retrieve POPULATED property")
+endif()
+if(NOT "${varSrc}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}/savedSrc")
+ message(FATAL_ERROR "SOURCE_DIR property not retrieved correctly: ${varSrc}\n"
+ " Expected: ${CMAKE_CURRENT_BINARY_DIR}/savedSrc")
+endif()
+if(NOT "${varBin}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}/savedBin")
+ message(FATAL_ERROR "BINARY_DIR property not retrieved correctly: ${varBin}\n"
+ " Expected: ${CMAKE_CURRENT_BINARY_DIR}/savedBin")
+endif()
diff --git a/Tests/RunCMake/FetchContent/MissingDetails-result.txt b/Tests/RunCMake/FetchContent/MissingDetails-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/FetchContent/MissingDetails-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/FetchContent/MissingDetails-stderr.txt b/Tests/RunCMake/FetchContent/MissingDetails-stderr.txt
new file mode 100644
index 0000000..c4f1daf
--- /dev/null
+++ b/Tests/RunCMake/FetchContent/MissingDetails-stderr.txt
@@ -0,0 +1 @@
+No content details recorded for t1
diff --git a/Tests/RunCMake/FetchContent/MissingDetails.cmake b/Tests/RunCMake/FetchContent/MissingDetails.cmake
new file mode 100644
index 0000000..ba8d121
--- /dev/null
+++ b/Tests/RunCMake/FetchContent/MissingDetails.cmake
@@ -0,0 +1,3 @@
+include(FetchContent)
+
+FetchContent_Populate(t1)
diff --git a/Tests/RunCMake/FetchContent/RunCMakeTest.cmake b/Tests/RunCMake/FetchContent/RunCMakeTest.cmake
new file mode 100644
index 0000000..621fb8b
--- /dev/null
+++ b/Tests/RunCMake/FetchContent/RunCMakeTest.cmake
@@ -0,0 +1,28 @@
+include(RunCMake)
+
+unset(RunCMake_TEST_NO_CLEAN)
+
+run_cmake(MissingDetails)
+run_cmake(DirectIgnoresDetails)
+run_cmake(FirstDetailsWin)
+run_cmake(DownloadTwice)
+run_cmake(SameGenerator)
+run_cmake(VarDefinitions)
+run_cmake(GetProperties)
+run_cmake(DirOverrides)
+
+# We need to pass through CMAKE_GENERATOR and CMAKE_MAKE_PROGRAM
+# to ensure the test can run on machines where the build tool
+# isn't on the PATH. Some build slaves explicitly test with such
+# an arrangement (e.g. to test with spaces in the path). We also
+# pass through the platform and toolset for completeness, even
+# though we don't build anything, just in case this somehow affects
+# the way the build tool is invoked.
+run_cmake_command(ScriptMode
+ ${CMAKE_COMMAND}
+ -DCMAKE_GENERATOR=${RunCMake_GENERATOR}
+ -DCMAKE_GENERATOR_PLATFORM=${RunCMake_GENERATOR_PLATFORM}
+ -DCMAKE_GENERATOR_TOOLSET=${RunCMake_GENERATOR_TOOLSET}
+ -DCMAKE_MAKE_PROGRAM=${RunCMake_MAKE_PROGRAM}
+ -P ${CMAKE_CURRENT_LIST_DIR}/ScriptMode.cmake
+)
diff --git a/Tests/RunCMake/FetchContent/SameGenerator.cmake b/Tests/RunCMake/FetchContent/SameGenerator.cmake
new file mode 100644
index 0000000..58204ef
--- /dev/null
+++ b/Tests/RunCMake/FetchContent/SameGenerator.cmake
@@ -0,0 +1,17 @@
+include(FetchContent)
+
+FetchContent_Declare(
+ t1
+ DOWNLOAD_COMMAND ${CMAKE_COMMAND} -E echo "Download command executed"
+)
+
+FetchContent_Populate(t1)
+
+file(STRINGS "${FETCHCONTENT_BASE_DIR}/t1-subbuild/CMakeCache.txt"
+ matchLine REGEX "^CMAKE_GENERATOR:.*="
+ LIMIT_COUNT 1
+)
+if(NOT matchLine MATCHES "${CMAKE_GENERATOR}")
+ message(FATAL_ERROR "Generator line mismatch: ${matchLine}\n"
+ " Expected type: ${CMAKE_GENERATOR}")
+endif()
diff --git a/Tests/RunCMake/FetchContent/ScriptMode.cmake b/Tests/RunCMake/FetchContent/ScriptMode.cmake
new file mode 100644
index 0000000..0a93d62
--- /dev/null
+++ b/Tests/RunCMake/FetchContent/ScriptMode.cmake
@@ -0,0 +1,35 @@
+include(FetchContent)
+
+file(WRITE tmpFile.txt "Generated contents, not important")
+
+FetchContent_Populate(
+ t1
+ DOWNLOAD_COMMAND ${CMAKE_COMMAND} -E copy
+ ${CMAKE_CURRENT_BINARY_DIR}/tmpFile.txt
+ <SOURCE_DIR>/done1.txt
+)
+if(NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/t1-src/done1.txt)
+ message(FATAL_ERROR "Default SOURCE_DIR doesn't contain done1.txt")
+endif()
+
+FetchContent_Populate(
+ t2
+ SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/mysrc
+ DOWNLOAD_COMMAND ${CMAKE_COMMAND} -E copy
+ ${CMAKE_CURRENT_BINARY_DIR}/tmpFile.txt
+ <SOURCE_DIR>/done2.txt
+)
+if(NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/mysrc/done2.txt)
+ message(FATAL_ERROR "Specified SOURCE_DIR doesn't contain done2.txt")
+endif()
+
+FetchContent_Populate(
+ t3
+ SOURCE_DIR myrelsrc
+ DOWNLOAD_COMMAND ${CMAKE_COMMAND} -E copy
+ ${CMAKE_CURRENT_BINARY_DIR}/tmpFile.txt
+ <SOURCE_DIR>/done3.txt
+)
+if(NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/myrelsrc/done3.txt)
+ message(FATAL_ERROR "Relative SOURCE_DIR doesn't contain done3.txt")
+endif()
diff --git a/Tests/RunCMake/FetchContent/VarDefinitions.cmake b/Tests/RunCMake/FetchContent/VarDefinitions.cmake
new file mode 100644
index 0000000..4d2a929
--- /dev/null
+++ b/Tests/RunCMake/FetchContent/VarDefinitions.cmake
@@ -0,0 +1,75 @@
+unset(FETCHCONTENT_FULLY_DISCONNECTED CACHE)
+unset(FETCHCONTENT_UPDATES_DISCONNECTED CACHE)
+unset(FETCHCONTENT_QUIET CACHE)
+unset(FETCHCONTENT_BASE_DIR CACHE)
+
+include(FetchContent)
+
+# Each of the cache entries should be defined and have the
+# expected value. Be careful to check unset separately from a
+# false value, since unset also equates to false.
+if(FETCHCONTENT_FULLY_DISCONNECTED STREQUAL "")
+ message(FATAL_ERROR "FETCHCONTENT_FULLY_DISCONNECTED not defined")
+elseif(FETCHCONTENT_FULLY_DISCONNECTED)
+ message(FATAL_ERROR "FETCHCONTENT_FULLY_DISCONNECTED not defaulted to OFF")
+endif()
+
+if(FETCHCONTENT_UPDATES_DISCONNECTED STREQUAL "")
+ message(FATAL_ERROR "FETCHCONTENT_UPDATES_DISCONNECTED not defined")
+elseif(FETCHCONTENT_UPDATES_DISCONNECTED)
+ message(FATAL_ERROR "FETCHCONTENT_UPDATES_DISCONNECTED not defaulted to OFF")
+endif()
+
+if(FETCHCONTENT_QUIET STREQUAL "")
+ message(FATAL_ERROR "FETCHCONTENT_QUIET not defined")
+elseif(NOT FETCHCONTENT_QUIET)
+ message(FATAL_ERROR "FETCHCONTENT_QUIET not defaulted to ON")
+endif()
+
+if(NOT FETCHCONTENT_BASE_DIR STREQUAL "${CMAKE_BINARY_DIR}/_deps")
+ message(FATAL_ERROR "FETCHCONTENT_BASE_DIR has default value: "
+ "${FETCHCONTENT_BASE_DIR}\n Expected: ${CMAKE_BINARY_DIR}/_deps")
+endif()
+
+file(REMOVE_RECURSE ${FETCHCONTENT_BASE_DIR}/t1-subbuild)
+
+# Use uppercase T1 test name to confirm conversion to lowercase
+# for the t1_... variable names that get set
+FetchContent_Declare(
+ T1
+ DOWNLOAD_COMMAND ${CMAKE_COMMAND} -E echo "Download command executed"
+)
+FetchContent_Populate(T1)
+
+# Be careful to check both regular and cache variables. Since they have
+# the same name, we can only confirm them separately by using get_property().
+get_property(srcRegVarSet VARIABLE PROPERTY t1_SOURCE_DIR SET)
+get_property(bldRegVarSet VARIABLE PROPERTY t1_BINARY_DIR SET)
+
+get_property(srcCacheVarSet CACHE t1_SOURCE_DIR PROPERTY VALUE SET)
+get_property(bldCacheVarSet CACHE t1_BINARY_DIR PROPERTY VALUE SET)
+
+if(NOT srcRegVarSet)
+ message(FATAL_ERROR "t1_SOURCE_DIR regular variable not set")
+endif()
+if(NOT bldRegVarSet)
+ message(FATAL_ERROR "t1_BINARY_DIR regular variable not set")
+endif()
+if(srcCacheVarSet)
+ message(FATAL_ERROR "t1_SOURCE_DIR cache variable unexpectedly set")
+endif()
+if(bldCacheVarSet)
+ message(FATAL_ERROR "t1_BINARY_DIR cache variable unexpectedly set")
+endif()
+
+set(srcRegVar ${t1_SOURCE_DIR})
+set(bldRegVar ${t1_BINARY_DIR})
+
+if(NOT srcRegVar STREQUAL "${CMAKE_BINARY_DIR}/_deps/t1-src")
+ message(FATAL_ERROR "Unexpected t1_SOURCE_DIR value: ${srcRegVar}\n"
+ " Expected: ${CMAKE_BINARY_DIR}/_deps/t1-src")
+endif()
+if(NOT bldRegVar STREQUAL "${CMAKE_BINARY_DIR}/_deps/t1-build")
+ message(FATAL_ERROR "Unexpected t1_BINARY_DIR value: ${bldRegVar}\n"
+ " Expected: ${CMAKE_BINARY_DIR}/_deps/t1-build")
+endif()
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-SOURCES-check.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-SOURCES-check.cmake
index f1452b5..c1a0f5b 100644
--- a/Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-SOURCES-check.cmake
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-SOURCES-check.cmake
@@ -1,8 +1,5 @@
file(READ ${RunCMake_TEST_BINARY_DIR}/foo.txt foo_sources)
-# VS generators inject CMakeLists.txt as a source. Remove it.
-string(REGEX REPLACE ";[^;]*CMakeLists.txt$" "" foo_sources "${foo_sources}")
-
set(foo_expected "empty.c;empty2.c;empty3.c")
if(NOT foo_sources STREQUAL foo_expected)
set(RunCMake_TEST_FAILED "foo SOURCES was:\n [[${foo_sources}]]\nbut expected:\n [[${foo_expected}]]")
diff --git a/Tests/RunCMake/TargetSources/ConfigNotAllowed-stderr.txt b/Tests/RunCMake/TargetSources/ConfigNotAllowed-stderr.txt
index 1de5dd7..c6b75fc 100644
--- a/Tests/RunCMake/TargetSources/ConfigNotAllowed-stderr.txt
+++ b/Tests/RunCMake/TargetSources/ConfigNotAllowed-stderr.txt
@@ -6,9 +6,7 @@ CMake Error in CMakeLists.txt:
.*/Tests/RunCMake/TargetSources/empty_1.cpp
.*/Tests/RunCMake/TargetSources/empty_2.cpp
- .*/Tests/RunCMake/TargetSources/CMakeLists.txt
Config "Release":
.*/Tests/RunCMake/TargetSources/empty_1.cpp
- .*/Tests/RunCMake/TargetSources/CMakeLists.txt
diff --git a/Tests/RunCMake/TargetSources/OriginDebugIDE-result.txt b/Tests/RunCMake/TargetSources/OriginDebugIDE-result.txt
deleted file mode 100644
index 573541a..0000000
--- a/Tests/RunCMake/TargetSources/OriginDebugIDE-result.txt
+++ /dev/null
@@ -1 +0,0 @@
-0
diff --git a/Tests/RunCMake/TargetSources/OriginDebugIDE-stderr.txt b/Tests/RunCMake/TargetSources/OriginDebugIDE-stderr.txt
deleted file mode 100644
index 6fdcce7..0000000
--- a/Tests/RunCMake/TargetSources/OriginDebugIDE-stderr.txt
+++ /dev/null
@@ -1,40 +0,0 @@
-CMake Debug Log at OriginDebug.cmake:13 \(add_library\):
- Used sources for target OriginDebug:
-
- \* .*Tests/RunCMake/TargetSources/empty_2.cpp
-
-Call Stack \(most recent call first\):
- OriginDebugIDE.cmake:4 \(include\)
- CMakeLists.txt:3 \(include\)
-+
-CMake Debug Log at OriginDebug.cmake:16 \(set_property\):
- Used sources for target OriginDebug:
-
- \* .*Tests/RunCMake/TargetSources/empty_3.cpp
-
-Call Stack \(most recent call first\):
- OriginDebugIDE.cmake:4 \(include\)
- CMakeLists.txt:3 \(include\)
-+
-CMake Debug Log at OriginDebug.cmake:20 \(target_sources\):
- Used sources for target OriginDebug:
-
- \* .*Tests/RunCMake/TargetSources/empty_4.cpp
-
-Call Stack \(most recent call first\):
- OriginDebugIDE.cmake:4 \(include\)
- CMakeLists.txt:3 \(include\)
-+
-CMake Debug Log in CMakeLists.txt:
- Used sources for target OriginDebug:
-
- * .*CMakeLists.txt
-+
-CMake Debug Log at OriginDebug.cmake:14 \(target_link_libraries\):
- Used sources for target OriginDebug:
-
- \* .*Tests/RunCMake/TargetSources/empty_1.cpp
-
-Call Stack \(most recent call first\):
- OriginDebugIDE.cmake:4 \(include\)
- CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/TargetSources/OriginDebugIDE.cmake b/Tests/RunCMake/TargetSources/OriginDebugIDE.cmake
deleted file mode 100644
index a3cc3a8..0000000
--- a/Tests/RunCMake/TargetSources/OriginDebugIDE.cmake
+++ /dev/null
@@ -1,4 +0,0 @@
-
-# Separate test for the IDEs, because they show the CMakeLists.txt file
-# as a source file.
-include(${CMAKE_CURRENT_LIST_DIR}/OriginDebug.cmake)
diff --git a/Tests/RunCMake/TargetSources/RunCMakeTest.cmake b/Tests/RunCMake/TargetSources/RunCMakeTest.cmake
index bb55a6e..36d01de 100644
--- a/Tests/RunCMake/TargetSources/RunCMakeTest.cmake
+++ b/Tests/RunCMake/TargetSources/RunCMakeTest.cmake
@@ -2,11 +2,9 @@ include(RunCMake)
if(RunCMake_GENERATOR MATCHES "Visual Studio|Xcode")
run_cmake(ConfigNotAllowed)
- run_cmake(OriginDebugIDE)
-else()
- run_cmake(OriginDebug)
endif()
+run_cmake(OriginDebug)
run_cmake(CMP0026-LOCATION)
run_cmake(RelativePathInInterface)
run_cmake(ExportBuild)