ENH: Update CMake/ExternalData.cmake

ENH: Update CMake/ExternalData.cmake

To version in ITK, commit 1f9db57c6f0124074f6b882f1b5847d7f7ce26a5
from ITK master 2017-03-06.

Change-Id: I05de53ab405a07866809ee604e6938f4b73ad6dd

--- CMake/ExternalData.cmake
+++ CMake/ExternalData.cmake
@@ -1,174 +1,323 @@
-# - Manage data files stored outside source tree
-# Use this module to unambiguously reference data files stored outside the
-# source tree and fetch them at build time from arbitrary local and remote
-# content-addressed locations.  Functions provided by this module recognize
-# arguments with the syntax "DATA{<name>}" as references to external data,
-# replace them with full paths to local copies of those data, and create build
-# rules to fetch and update the local copies.
-#
-# The DATA{} syntax is literal and the <name> is a full or relative path
-# within the source tree.  The source tree must contain either a real data
-# file at <name> or a "content link" at <name><ext> containing a hash of the
-# real file using a hash algorithm corresponding to <ext>.  For example, the
-# argument "DATA{img.png}" may be satisfied by either a real "img.png" file in
-# the current source directory or a "img.png.md5" file containing its MD5 sum.
-#
-# The 'ExternalData_Expand_Arguments' function evaluates DATA{} references
-# in its arguments and constructs a new list of arguments:
-#  ExternalData_Expand_Arguments(
-#    <target>   # Name of data management target
-#    <outVar>   # Output variable
-#    [args...]  # Input arguments, DATA{} allowed
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#.rst:
+# ExternalData
+# ------------
+#
+# .. only:: html
+#
+#    .. contents::
+#
+# Manage data files stored outside source tree
+#
+# Introduction
+# ^^^^^^^^^^^^
+#
+# Use this module to unambiguously reference data files stored outside
+# the source tree and fetch them at build time from arbitrary local and
+# remote content-addressed locations.  Functions provided by this module
+# recognize arguments with the syntax ``DATA{<name>}`` as references to
+# external data, replace them with full paths to local copies of those
+# data, and create build rules to fetch and update the local copies.
+#
+# For example:
+#
+# .. code-block:: cmake
+#
+#  include(ExternalData)
+#  set(ExternalData_URL_TEMPLATES "file:///local/%(algo)/%(hash)"
+#                                 "file:////host/share/%(algo)/%(hash)"
+#                                 "http://data.org/%(algo)/%(hash)")
+#  ExternalData_Add_Test(MyData
+#    NAME MyTest
+#    COMMAND MyExe DATA{MyInput.png}
 #    )
-# It replaces each DATA{} reference in an argument with the full path of a
-# real data file on disk that will exist after the <target> builds.
-#
-# The 'ExternalData_Add_Test' function wraps around the CMake add_test()
-# command but supports DATA{} references in its arguments:
-#  ExternalData_Add_Test(
-#    <target>   # Name of data management target
-#    ...        # Arguments of add_test(), DATA{} allowed
-#    )
-# It passes its arguments through ExternalData_Expand_Arguments and then
-# invokes add_test() using the results.
-#
-# The 'ExternalData_Add_Target' function creates a custom target to manage
-# local instances of data files stored externally:
-#  ExternalData_Add_Target(
-#    <target>   # Name of data management target
-#    )
-# It creates custom commands in the target as necessary to make data files
-# available for each DATA{} reference previously evaluated by other functions
-# provided by this module.  A list of URL templates must be provided in the
-# variable ExternalData_URL_TEMPLATES using the placeholders "%(algo)" and
-# "%(hash)" in each template.  Data fetch rules try each URL template in order
-# by substituting the hash algorithm name for "%(algo)" and the hash value for
-# "%(hash)".
-#
-# The following hash algorithms are supported:
-#    %(algo)     <ext>     Description
-#    -------     -----     -----------
-#    MD5         .md5      Message-Digest Algorithm 5, RFC 1321
-# Note that the hashes are used only for unique data identification and
-# download verification.  This is not security software.
-#
-# Example usage:
-#   include(ExternalData)
-#   set(ExternalData_URL_TEMPLATES "file:///local/%(algo)/%(hash)"
-#                                  "http://data.org/%(algo)/%(hash)")
-#   ExternalData_Add_Test(MyData
-#     NAME MyTest
-#     COMMAND MyExe DATA{MyInput.png}
-#     )
-#   ExternalData_Add_Target(MyData)
-# When test "MyTest" runs the "DATA{MyInput.png}" argument will be replaced by
-# the full path to a real instance of the data file "MyInput.png" on disk.  If
-# the source tree contains a content link such as "MyInput.png.md5" then the
-# "MyData" target creates a real "MyInput.png" in the build tree.
-#
-# The DATA{} syntax can be told to fetch a file series using the form
-# "DATA{<name>,:}", where the ":" is literal.  If the source tree contains a
-# group of files or content links named like a series then a reference to one
-# member adds rules to fetch all of them.  Although all members of a series
-# are fetched, only the file originally named by the DATA{} argument is
-# substituted for it.  The default configuration recognizes file series names
-# ending with "#.ext", "_#.ext", ".#.ext", or "-#.ext" where "#" is a sequence
-# of decimal digits and ".ext" is any single extension.  Configure it with a
-# regex that parses <number> and <suffix> parts from the end of <name>:
+#  ExternalData_Add_Target(MyData)
+#
+# When test ``MyTest`` runs the ``DATA{MyInput.png}`` argument will be
+# replaced by the full path to a real instance of the data file
+# ``MyInput.png`` on disk.  If the source tree contains a content link
+# such as ``MyInput.png.md5`` then the ``MyData`` target creates a real
+# ``MyInput.png`` in the build tree.
+#
+# Module Functions
+# ^^^^^^^^^^^^^^^^
+#
+# .. command:: ExternalData_Expand_Arguments
+#
+#   The ``ExternalData_Expand_Arguments`` function evaluates ``DATA{}``
+#   references in its arguments and constructs a new list of arguments::
+#
+#     ExternalData_Expand_Arguments(
+#       <target>   # Name of data management target
+#       <outVar>   # Output variable
+#       [args...]  # Input arguments, DATA{} allowed
+#       )
+#
+#   It replaces each ``DATA{}`` reference in an argument with the full path of
+#   a real data file on disk that will exist after the ``<target>`` builds.
+#
+# .. command:: ExternalData_Add_Test
+#
+#   The ``ExternalData_Add_Test`` function wraps around the CMake
+#   :command:`add_test` command but supports ``DATA{}`` references in
+#   its arguments::
+#
+#     ExternalData_Add_Test(
+#       <target>   # Name of data management target
+#       ...        # Arguments of add_test(), DATA{} allowed
+#       )
+#
+#   It passes its arguments through ``ExternalData_Expand_Arguments`` and then
+#   invokes the :command:`add_test` command using the results.
+#
+# .. command:: ExternalData_Add_Target
+#
+#   The ``ExternalData_Add_Target`` function creates a custom target to
+#   manage local instances of data files stored externally::
+#
+#     ExternalData_Add_Target(
+#       <target>   # Name of data management target
+#       )
+#
+#   It creates custom commands in the target as necessary to make data
+#   files available for each ``DATA{}`` reference previously evaluated by
+#   other functions provided by this module.
+#   Data files may be fetched from one of the URL templates specified in
+#   the ``ExternalData_URL_TEMPLATES`` variable, or may be found locally
+#   in one of the paths specified in the ``ExternalData_OBJECT_STORES``
+#   variable.
+#
+# Module Variables
+# ^^^^^^^^^^^^^^^^
+#
+# The following variables configure behavior.  They should be set before
+# calling any of the functions provided by this module.
+#
+# .. variable:: ExternalData_BINARY_ROOT
+#
+#   The ``ExternalData_BINARY_ROOT`` variable may be set to the directory to
+#   hold the real data files named by expanded ``DATA{}`` references.  The
+#   default is ``CMAKE_BINARY_DIR``.  The directory layout will mirror that of
+#   content links under ``ExternalData_SOURCE_ROOT``.
+#
+# .. variable:: ExternalData_CUSTOM_SCRIPT_<key>
+#
+#   Specify a full path to a ``.cmake`` custom fetch script identified by
+#   ``<key>`` in entries of the ``ExternalData_URL_TEMPLATES`` list.
+#   See `Custom Fetch Scripts`_.
+#
+# .. variable:: ExternalData_LINK_CONTENT
+#
+#   The ``ExternalData_LINK_CONTENT`` variable may be set to the name of a
+#   supported hash algorithm to enable automatic conversion of real data
+#   files referenced by the ``DATA{}`` syntax into content links.  For each
+#   such ``<file>`` a content link named ``<file><ext>`` is created.  The
+#   original file is renamed to the form ``.ExternalData_<algo>_<hash>`` to
+#   stage it for future transmission to one of the locations in the list
+#   of URL templates (by means outside the scope of this module).  The
+#   data fetch rule created for the content link will use the staged
+#   object if it cannot be found using any URL template.
+#
+# .. variable:: ExternalData_NO_SYMLINKS
+#
+#   The real data files named by expanded ``DATA{}`` references may be made
+#   available under ``ExternalData_BINARY_ROOT`` using symbolic links on
+#   some platforms.  The ``ExternalData_NO_SYMLINKS`` variable may be set
+#   to disable use of symbolic links and enable use of copies instead.
+#
+# .. variable:: ExternalData_OBJECT_STORES
+#
+#   The ``ExternalData_OBJECT_STORES`` variable may be set to a list of local
+#   directories that store objects using the layout ``<dir>/%(algo)/%(hash)``.
+#   These directories will be searched first for a needed object.  If the
+#   object is not available in any store then it will be fetched remotely
+#   using the URL templates and added to the first local store listed.  If
+#   no stores are specified the default is a location inside the build
+#   tree.
+#
+# .. variable:: ExternalData_SERIES_PARSE
+#               ExternalData_SERIES_PARSE_PREFIX
+#               ExternalData_SERIES_PARSE_NUMBER
+#               ExternalData_SERIES_PARSE_SUFFIX
+#               ExternalData_SERIES_MATCH
+#
+#   See `Referencing File Series`_.
+#
+# .. variable:: ExternalData_SOURCE_ROOT
+#
+#   The ``ExternalData_SOURCE_ROOT`` variable may be set to the highest source
+#   directory containing any path named by a ``DATA{}`` reference.  The
+#   default is ``CMAKE_SOURCE_DIR``.  ``ExternalData_SOURCE_ROOT`` and
+#   ``CMAKE_SOURCE_DIR`` must refer to directories within a single source
+#   distribution (e.g.  they come together in one tarball).
+#
+# .. variable:: ExternalData_TIMEOUT_ABSOLUTE
+#
+#   The ``ExternalData_TIMEOUT_ABSOLUTE`` variable sets the download
+#   absolute timeout, in seconds, with a default of ``300`` seconds.
+#   Set to ``0`` to disable enforcement.
+#
+# .. variable:: ExternalData_TIMEOUT_INACTIVITY
+#
+#   The ``ExternalData_TIMEOUT_INACTIVITY`` variable sets the download
+#   inactivity timeout, in seconds, with a default of ``60`` seconds.
+#   Set to ``0`` to disable enforcement.
+#
+# .. variable:: ExternalData_URL_ALGO_<algo>_<key>
+#
+#   Specify a custom URL component to be substituted for URL template
+#   placeholders of the form ``%(algo:<key>)``, where ``<key>`` is a
+#   valid C identifier, when fetching an object referenced via hash
+#   algorithm ``<algo>``.  If not defined, the default URL component
+#   is just ``<algo>`` for any ``<key>``.
+#
+# .. variable:: ExternalData_URL_TEMPLATES
+#
+#   The ``ExternalData_URL_TEMPLATES`` may be set to provide a list of
+#   of URL templates using the placeholders ``%(algo)`` and ``%(hash)``
+#   in each template.  Data fetch rules try each URL template in order
+#   by substituting the hash algorithm name for ``%(algo)`` and the hash
+#   value for ``%(hash)``.  Alternatively one may use ``%(algo:<key>)``
+#   with ``ExternalData_URL_ALGO_<algo>_<key>`` variables to gain more
+#   flexibility in remote URLs.
+#
+# Referencing Files
+# ^^^^^^^^^^^^^^^^^
+#
+# Referencing Single Files
+# """"""""""""""""""""""""
+#
+# The ``DATA{}`` syntax is literal and the ``<name>`` is a full or relative path
+# within the source tree.  The source tree must contain either a real
+# data file at ``<name>`` or a "content link" at ``<name><ext>`` containing a
+# hash of the real file using a hash algorithm corresponding to ``<ext>``.
+# For example, the argument ``DATA{img.png}`` may be satisfied by either a
+# real ``img.png`` file in the current source directory or a ``img.png.md5``
+# file containing its MD5 sum.
+#
+# Multiple content links of the same name with different hash algorithms
+# are supported (e.g. ``img.png.sha256`` and ``img.png.sha1``) so long as
+# they all correspond to the same real file.  This allows objects to be
+# fetched from sources indexed by different hash algorithms.
+#
+#
+# Referencing File Series
+# """""""""""""""""""""""
+#
+# The ``DATA{}`` syntax can be told to fetch a file series using the form
+# ``DATA{<name>,:}``, where the ``:`` is literal.  If the source tree
+# contains a group of files or content links named like a series then a
+# reference to one member adds rules to fetch all of them.  Although all
+# members of a series are fetched, only the file originally named by the
+# ``DATA{}`` argument is substituted for it.  The default configuration
+# recognizes file series names ending with ``#.ext``, ``_#.ext``, ``.#.ext``,
+# or ``-#.ext`` where ``#`` is a sequence of decimal digits and ``.ext`` is
+# any single extension.  Configure it with a regex that parses ``<number>``
+# and ``<suffix>`` parts from the end of ``<name>``::
+#
 #  ExternalData_SERIES_PARSE = regex of the form (<number>)(<suffix>)$
-# For more complicated cases set:
+#
+# For more complicated cases set::
+#
 #  ExternalData_SERIES_PARSE = regex with at least two () groups
 #  ExternalData_SERIES_PARSE_PREFIX = <prefix> regex group number, if any
 #  ExternalData_SERIES_PARSE_NUMBER = <number> regex group number
 #  ExternalData_SERIES_PARSE_SUFFIX = <suffix> regex group number
+#
 # Configure series number matching with a regex that matches the
-# <number> part of series members named <prefix><number><suffix>:
+# ``<number>`` part of series members named ``<prefix><number><suffix>``::
+#
 #  ExternalData_SERIES_MATCH = regex matching <number> in all series members
-# Note that the <suffix> of a series does not include a hash-algorithm
+#
+# Note that the ``<suffix>`` of a series does not include a hash-algorithm
 # extension.
 #
-# The DATA{} syntax can alternatively match files associated with the named
-# file and contained in the same directory.  Associated files may be specified
-# by options using the syntax DATA{<name>,<opt1>,<opt2>,...}.  Each option may
-# specify one file by name or specify a regular expression to match file names
-# using the syntax REGEX:<regex>.  For example, the arguments
-#   DATA{MyData/MyInput.mhd,MyInput.img}                   # File pair
-#   DATA{MyData/MyFrames00.png,REGEX:MyFrames[0-9]+\\.png} # Series
-# will pass MyInput.mha and MyFrames00.png on the command line but ensure
-# that the associated files are present next to them.
-#
-# The DATA{} syntax may reference a directory using a trailing slash and a
-# list of associated files.  The form DATA{<name>/,<opt1>,<opt2>,...} adds
-# rules to fetch any files in the directory that match one of the associated
-# file options.  For example, the argument DATA{MyDataDir/,REGEX:.*} will pass
-# the full path to a MyDataDir directory on the command line and ensure that
-# the directory contains files corresponding to every file or content link in
-# the MyDataDir source directory.
-#
-# The variable ExternalData_LINK_CONTENT may be set to the name of a supported
-# hash algorithm to enable automatic conversion of real data files referenced
-# by the DATA{} syntax into content links.  For each such <file> a content
-# link named "<file><ext>" is created.  The original file is renamed to the
-# form ".ExternalData_<algo>_<hash>" to stage it for future transmission to
-# one of the locations in the list of URL templates (by means outside the
-# scope of this module).  The data fetch rule created for the content link
-# will use the staged object if it cannot be found using any URL template.
-#
-# The variable ExternalData_OBJECT_STORES may be set to a list of local
-# directories that store objects using the layout <dir>/%(algo)/%(hash).
-# These directories will be searched first for a needed object.  If the object
-# is not available in any store then it will be fetched remotely using the URL
-# templates and added to the first local store listed.  If no stores are
-# specified the default is a location inside the build tree.
-#
-# The variable ExternalData_SOURCE_ROOT may be set to the highest source
-# directory containing any path named by a DATA{} reference.  The default is
-# CMAKE_SOURCE_DIR.  ExternalData_SOURCE_ROOT and CMAKE_SOURCE_DIR must refer
-# to directories within a single source distribution (e.g. they come together
-# in one tarball).
-#
-# The variable ExternalData_BINARY_ROOT may be set to the directory to hold
-# the real data files named by expanded DATA{} references.  The default is
-# CMAKE_BINARY_DIR.  The directory layout will mirror that of content links
-# under ExternalData_SOURCE_ROOT.
-#
-# Variables ExternalData_TIMEOUT_INACTIVITY and ExternalData_TIMEOUT_ABSOLUTE
-# set the download inactivity and absolute timeouts, in seconds.  The defaults
-# are 60 seconds and 300 seconds, respectively.  Set either timeout to 0
-# seconds to disable enforcement.
-
-#=============================================================================
-# Copyright 2010-2013 Kitware, Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-#
-# * Redistributions of source code must retain the above copyright
-#   notice, this list of conditions and the following disclaimer.
-#
-# * Redistributions in binary form must reproduce the above copyright
-#   notice, this list of conditions and the following disclaimer in the
-#   documentation and/or other materials provided with the distribution.
-#
-# * Neither the names of Kitware, Inc., the Insight Software Consortium,
-#   nor the names of their contributors may be used to endorse or promote
-#   products derived from this software without specific prior written
-#   permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#=============================================================================
+# Referencing Associated Files
+# """"""""""""""""""""""""""""
+#
+# The ``DATA{}`` syntax can alternatively match files associated with the
+# named file and contained in the same directory.  Associated files may
+# be specified by options using the syntax
+# ``DATA{<name>,<opt1>,<opt2>,...}``.  Each option may specify one file by
+# name or specify a regular expression to match file names using the
+# syntax ``REGEX:<regex>``.  For example, the arguments::
+#
+#  DATA{MyData/MyInput.mhd,MyInput.img}                   # File pair
+#  DATA{MyData/MyFrames00.png,REGEX:MyFrames[0-9]+\\.png} # Series
+#
+# will pass ``MyInput.mha`` and ``MyFrames00.png`` on the command line but
+# ensure that the associated files are present next to them.
+#
+# Referencing Directories
+# """""""""""""""""""""""
+#
+# The ``DATA{}`` syntax may reference a directory using a trailing slash and
+# a list of associated files.  The form ``DATA{<name>/,<opt1>,<opt2>,...}``
+# adds rules to fetch any files in the directory that match one of the
+# associated file options.  For example, the argument
+# ``DATA{MyDataDir/,REGEX:.*}`` will pass the full path to a ``MyDataDir``
+# directory on the command line and ensure that the directory contains
+# files corresponding to every file or content link in the ``MyDataDir``
+# source directory.  In order to match associated files in subdirectories,
+# specify a ``RECURSE:`` option, e.g. ``DATA{MyDataDir/,RECURSE:,REGEX:.*}``.
+#
+# Hash Algorithms
+# ^^^^^^^^^^^^^^^
+#
+# The following hash algorithms are supported::
+#
+#  %(algo)     <ext>     Description
+#  -------     -----     -----------
+#  MD5         .md5      Message-Digest Algorithm 5, RFC 1321
+#  SHA1        .sha1     US Secure Hash Algorithm 1, RFC 3174
+#  SHA224      .sha224   US Secure Hash Algorithms, RFC 4634
+#  SHA256      .sha256   US Secure Hash Algorithms, RFC 4634
+#  SHA384      .sha384   US Secure Hash Algorithms, RFC 4634
+#  SHA512      .sha512   US Secure Hash Algorithms, RFC 4634
+#
+# Note that the hashes are used only for unique data identification and
+# download verification.
+#
+# .. _`ExternalData Custom Fetch Scripts`:
+#
+# Custom Fetch Scripts
+# ^^^^^^^^^^^^^^^^^^^^
+#
+# When a data file must be fetched from one of the URL templates
+# specified in the ``ExternalData_URL_TEMPLATES`` variable, it is
+# normally downloaded using the :command:`file(DOWNLOAD)` command.
+# One may specify usage of a custom fetch script by using a URL
+# template of the form ``ExternalDataCustomScript://<key>/<loc>``.
+# The ``<key>`` must be a C identifier, and the ``<loc>`` must
+# contain the ``%(algo)`` and ``%(hash)`` placeholders.
+# A variable corresponding to the key, ``ExternalData_CUSTOM_SCRIPT_<key>``,
+# must be set to the full path to a ``.cmake`` script file.  The script
+# will be included to perform the actual fetch, and provided with
+# the following variables:
+#
+# .. variable:: ExternalData_CUSTOM_LOCATION
+#
+#   When a custom fetch script is loaded, this variable is set to the
+#   location part of the URL, which will contain the substituted hash
+#   algorithm name and content hash value.
+#
+# .. variable:: ExternalData_CUSTOM_FILE
+#
+#   When a custom fetch script is loaded, this variable is set to the
+#   full path to a file in which the script must store the fetched
+#   content.  The name of the file is unspecified and should not be
+#   interpreted in any way.
+#
+# The custom fetch script is expected to store fetched content in the
+# file or set a variable:
+#
+# .. variable:: ExternalData_CUSTOM_ERROR
+#
+#   When a custom fetch script fails to fetch the requested content,
+#   it must set this variable to a short one-line message describing
+#   the reason for failure.

 function(ExternalData_add_test target)
   # Expand all arguments as a single string to preserve escaped semicolons.
@@ -177,19 +326,76 @@
 endfunction()

 function(ExternalData_add_target target)
-  if(NOT ExternalData_URL_TEMPLATES)
-    message(FATAL_ERROR "ExternalData_URL_TEMPLATES is not set!")
+  if(NOT ExternalData_URL_TEMPLATES AND NOT ExternalData_OBJECT_STORES)
+    message(FATAL_ERROR
+      "Neither ExternalData_URL_TEMPLATES nor ExternalData_OBJECT_STORES is set!")
   endif()
   if(NOT ExternalData_OBJECT_STORES)
     set(ExternalData_OBJECT_STORES ${CMAKE_BINARY_DIR}/ExternalData/Objects)
   endif()
+  set(_ExternalData_CONFIG_CODE "")
+
+  # Store custom script configuration.
+  foreach(url_template IN LISTS ExternalData_URL_TEMPLATES)
+    if("${url_template}" MATCHES "^ExternalDataCustomScript://([^/]*)/(.*)$")
+      set(key "${CMAKE_MATCH_1}")
+      if(key MATCHES "^[A-Za-z_][A-Za-z0-9_]*$")
+        if(ExternalData_CUSTOM_SCRIPT_${key})
+          if(IS_ABSOLUTE "${ExternalData_CUSTOM_SCRIPT_${key}}")
+            string(CONCAT _ExternalData_CONFIG_CODE "${_ExternalData_CONFIG_CODE}\n"
+              "set(ExternalData_CUSTOM_SCRIPT_${key} \"${ExternalData_CUSTOM_SCRIPT_${key}}\")")
+          else()
+            message(FATAL_ERROR
+              "No ExternalData_CUSTOM_SCRIPT_${key} is not set to a full path:\n"
+              " ${ExternalData_CUSTOM_SCRIPT_${key}}")
+          endif()
+        else()
+          message(FATAL_ERROR
+            "No ExternalData_CUSTOM_SCRIPT_${key} is set for URL template:\n"
+            " ${url_template}")
+        endif()
+      else()
+        message(FATAL_ERROR
+          "Bad ExternalDataCustomScript key '${key}' in URL template:\n"
+          " ${url_template}\n"
+          "The key must be a valid C identifier.")
+      endif()
+    endif()
+
+    # Store custom algorithm name to URL component maps.
+    if("${url_template}" MATCHES "%\\(algo:([^)]*)\\)")
+      set(key "${CMAKE_MATCH_1}")
+      if(key MATCHES "^[A-Za-z_][A-Za-z0-9_]*$")
+        string(REPLACE "|" ";" _algos "${_ExternalData_REGEX_ALGO}")
+        foreach(algo ${_algos})
+          if(DEFINED ExternalData_URL_ALGO_${algo}_${key})
+            set(_ExternalData_CONFIG_CODE
+              "${_ExternalData_CONFIG_CODE}\nset(ExternalData_URL_ALGO_${algo}_${key} \"${ExternalData_URL_ALGO_${algo}_${key}}\")")
+          endif()
+        endforeach()
+      else()
+        message(FATAL_ERROR
+          "Bad %(algo:${key}) in URL template:\n"
+          " ${url_template}\n"
+          "The transform name must be a valid C identifier.")
+      endif()
+    endif()
+  endforeach()
+
+  # Store configuration for use by build-time script.
   set(config ${CMAKE_CURRENT_BINARY_DIR}/${target}_config.cmake)
   configure_file(${_ExternalData_SELF_DIR}/ExternalData_config.cmake.in ${config} @ONLY)

   set(files "")

-  # Set "_ExternalData_FILE_${file}" for each output file to avoid duplicate
-  # rules.  Use local data first to prefer real files over content links.
+  # Set a "_ExternalData_FILE_${file}" variable for each output file to avoid
+  # duplicate entries within this target.  Set a directory property of the same
+  # name to avoid repeating custom commands with the same output in this directory.
+  # Repeating custom commands with the same output across directories or across
+  # targets in the same directory may be a race, but this is likely okay because
+  # we use atomic replacement of output files.
+  #
+  # Use local data first to prefer real files over content links.

   # Custom commands to copy or link local data.
   get_property(data_local GLOBAL PROPERTY _ExternalData_${target}_LOCAL)
@@ -199,16 +405,20 @@
     list(GET tuple 1 name)
     if(NOT DEFINED "_ExternalData_FILE_${file}")
       set("_ExternalData_FILE_${file}" 1)
-      add_custom_command(
-        COMMENT "Generating ${file}"
-        OUTPUT "${file}"
-        COMMAND ${CMAKE_COMMAND} -Drelative_top=${CMAKE_BINARY_DIR}
-                                 -Dfile=${file} -Dname=${name}
-                                 -DExternalData_ACTION=local
-                                 -DExternalData_CONFIG=${config}
-                                 -P ${_ExternalData_SELF}
-        MAIN_DEPENDENCY "${name}"
-        )
+      get_property(added DIRECTORY PROPERTY "_ExternalData_FILE_${file}")
+      if(NOT added)
+        set_property(DIRECTORY PROPERTY "_ExternalData_FILE_${file}" 1)
+        add_custom_command(
+          COMMENT "Generating ${file}"
+          OUTPUT "${file}"
+          COMMAND ${CMAKE_COMMAND} -Drelative_top=${CMAKE_BINARY_DIR}
+                                   -Dfile=${file} -Dname=${name}
+                                   -DExternalData_ACTION=local
+                                   -DExternalData_CONFIG=${config}
+                                   -P ${_ExternalData_SELF}
+          MAIN_DEPENDENCY "${name}"
+          )
+      endif()
       list(APPEND files "${file}")
     endif()
   endforeach()
@@ -219,27 +429,33 @@
     string(REPLACE "|" ";" tuple "${entry}")
     list(GET tuple 0 file)
     list(GET tuple 1 name)
-    list(GET tuple 2 ext)
-    set(stamp "${ext}-stamp")
+    list(GET tuple 2 exts)
+    string(REPLACE "+" ";" exts_list "${exts}")
+    list(GET exts_list 0 first_ext)
+    set(stamp "-hash-stamp")
     if(NOT DEFINED "_ExternalData_FILE_${file}")
       set("_ExternalData_FILE_${file}" 1)
-      add_custom_command(
-        # Users care about the data file, so hide the hash/timestamp file.
-        COMMENT "Generating ${file}"
-        # The hash/timestamp file is the output from the build perspective.
-        # List the real file as a second output in case it is a broken link.
-        # The files must be listed in this order so CMake can hide from the
-        # make tool that a symlink target may not be newer than the input.
-        OUTPUT "${file}${stamp}" "${file}"
-        # Run the data fetch/update script.
-        COMMAND ${CMAKE_COMMAND} -Drelative_top=${CMAKE_BINARY_DIR}
-                                 -Dfile=${file} -Dname=${name} -Dext=${ext}
-                                 -DExternalData_ACTION=fetch
-                                 -DExternalData_CONFIG=${config}
-                                 -P ${_ExternalData_SELF}
-        # Update whenever the object hash changes.
-        MAIN_DEPENDENCY "${name}${ext}"
-        )
+      get_property(added DIRECTORY PROPERTY "_ExternalData_FILE_${file}")
+      if(NOT added)
+        set_property(DIRECTORY PROPERTY "_ExternalData_FILE_${file}" 1)
+        add_custom_command(
+          # Users care about the data file, so hide the hash/timestamp file.
+          COMMENT "Generating ${file}"
+          # The hash/timestamp file is the output from the build perspective.
+          # List the real file as a second output in case it is a broken link.
+          # The files must be listed in this order so CMake can hide from the
+          # make tool that a symlink target may not be newer than the input.
+          OUTPUT "${file}${stamp}" "${file}"
+          # Run the data fetch/update script.
+          COMMAND ${CMAKE_COMMAND} -Drelative_top=${CMAKE_BINARY_DIR}
+                                   -Dfile=${file} -Dname=${name} -Dexts=${exts}
+                                   -DExternalData_ACTION=fetch
+                                   -DExternalData_CONFIG=${config}
+                                   -P ${_ExternalData_SELF}
+          # Update whenever the object hash changes.
+          MAIN_DEPENDENCY "${name}${first_ext}"
+          )
+      endif()
       list(APPEND files "${file}${stamp}")
     endif()
   endforeach()
@@ -266,8 +482,7 @@
       foreach(piece IN LISTS pieces)
         if("x${piece}" MATCHES "^x${data_regex}$")
           # Replace this DATA{}-piece with a file path.
-          string(REGEX REPLACE "${data_regex}" "\\1" data "${piece}")
-          _ExternalData_arg("${target}" "${piece}" "${data}" file)
+          _ExternalData_arg("${target}" "${piece}" "${CMAKE_MATCH_1}" file)
           set(outArg "${outArg}${file}")
         else()
           # No replacement needed for this piece.
@@ -288,17 +503,14 @@
 #-----------------------------------------------------------------------------
 # Private helper interface

-set(_ExternalData_REGEX_ALGO "MD5")
-set(_ExternalData_REGEX_EXT "md5")
+set(_ExternalData_REGEX_ALGO "MD5|SHA1|SHA224|SHA256|SHA384|SHA512")
+set(_ExternalData_REGEX_EXT "md5|sha1|sha224|sha256|sha384|sha512")
 set(_ExternalData_SELF "${CMAKE_CURRENT_LIST_FILE}")
 get_filename_component(_ExternalData_SELF_DIR "${_ExternalData_SELF}" PATH)

 function(_ExternalData_compute_hash var_hash algo file)
   if("${algo}" MATCHES "^${_ExternalData_REGEX_ALGO}$")
-    # TODO: Require CMake 2.8.7 to support other hashes with file(${algo} ...)
-    execute_process(COMMAND "${CMAKE_COMMAND}" -E md5sum "${file}"
-      OUTPUT_VARIABLE output)
-    string(SUBSTRING "${output}" 0 32 hash)
+    file("${algo}" "${file}" hash)
     set("${var_hash}" "${hash}" PARENT_SCOPE)
   else()
     message(FATAL_ERROR "Hash algorithm ${algo} unimplemented.")
@@ -399,19 +611,23 @@
   set(external "") # Entries external to the source tree.
   set(internal "") # Entries internal to the source tree.
   set(have_original ${data_is_directory})
+  set(have_original_as_dir 0)

   # Process options.
   set(series_option "")
+  set(recurse_option "")
   set(associated_files "")
   set(associated_regex "")
   foreach(opt ${options})
-    if("x${opt}" MATCHES "^xREGEX:[^:/]+$")
-      # Regular expression to match associated files.
-      string(REGEX REPLACE "^REGEX:" "" regex "${opt}")
-      list(APPEND associated_regex "${regex}")
-    elseif("x${opt}" MATCHES "^x:$")
+    # Regular expression to match associated files.
+    if("x${opt}" MATCHES "^xREGEX:([^:/]+)$")
+      list(APPEND associated_regex "${CMAKE_MATCH_1}")
+    elseif(opt STREQUAL ":")
       # Activate series matching.
       set(series_option "${opt}")
+    elseif(opt STREQUAL "RECURSE:")
+      # Activate recursive matching in directories.
+      set(recurse_option "${opt}")
     elseif("x${opt}" MATCHES "^[^][:/*?]+$")
       # Specific associated file.
       list(APPEND associated_files "${opt}")
@@ -427,6 +643,9 @@
     endif()
     if(associated_files OR associated_regex)
       message(FATAL_ERROR "Series option \"${series_option}\" not allowed with associated files.")
+    endif()
+    if(recurse_option)
+      message(FATAL_ERROR "Recurse option \"${recurse_option}\" allowed only with directories.")
     endif()
     # Load a whole file series.
     _ExternalData_arg_series()
@@ -440,6 +659,9 @@
         "must list associated files.")
     endif()
   else()
+    if(recurse_option)
+      message(FATAL_ERROR "Recurse option \"${recurse_option}\" allowed only with directories.")
+    endif()
     # Load the named data file.
     _ExternalData_arg_single()
     if(associated_files OR associated_regex)
@@ -449,11 +671,18 @@
   endif()

   if(NOT have_original)
-    message(FATAL_ERROR "Data file referenced by argument\n"
+    if(have_original_as_dir)
+      set(msg_kind FATAL_ERROR)
+      set(msg "that is directory instead of a file!")
+    else()
+      set(msg_kind AUTHOR_WARNING)
+      set(msg "that does not exist as a file (with or without an extension)!")
+    endif()
+    message(${msg_kind} "Data file referenced by argument\n"
       "  ${arg}\n"
       "corresponds to source tree path\n"
       "  ${reldata}\n"
-      "that does not exist as a file (with or without an extension)!")
+      "${msg}")
   endif()

   if(external)
@@ -480,11 +709,18 @@
     set(reldir "${reldir}/")
   endif()
   _ExternalData_exact_regex(reldir_regex "${reldir}")
+  if(recurse_option)
+    set(glob GLOB_RECURSE)
+    set(reldir_regex "${reldir_regex}(.+/)?")
+  else()
+    set(glob GLOB)
+  endif()

   # Find files named explicitly.
   foreach(file ${associated_files})
     _ExternalData_exact_regex(file_regex "${file}")
-    _ExternalData_arg_find_files("${reldir}${file}" "${reldir_regex}${file_regex}")
+    _ExternalData_arg_find_files(${glob} "${reldir}${file}"
+      "${reldir_regex}${file_regex}")
   endforeach()

   # Find files matching the given regular expressions.
@@ -494,13 +730,13 @@
     set(all "${all}${sep}${reldir_regex}${regex}")
     set(sep "|")
   endforeach()
-  _ExternalData_arg_find_files("${reldir}" "${all}")
+  _ExternalData_arg_find_files(${glob} "${reldir}" "${all}")
 endmacro()

 macro(_ExternalData_arg_single)
   # Match only the named data by itself.
   _ExternalData_exact_regex(data_regex "${reldata}")
-  _ExternalData_arg_find_files("${reldata}" "${data_regex}")
+  _ExternalData_arg_find_files(GLOB "${reldata}" "${data_regex}")
 endmacro()

 macro(_ExternalData_arg_series)
@@ -555,12 +791,16 @@
   # Then match base, number, and extension.
   _ExternalData_exact_regex(series_base "${relbase}")
   _ExternalData_exact_regex(series_ext "${ext}")
-  _ExternalData_arg_find_files("${relbase}*${ext}"
+  _ExternalData_arg_find_files(GLOB "${relbase}*${ext}"
     "${series_base}${series_match}${series_ext}")
 endmacro()

-function(_ExternalData_arg_find_files pattern regex)
-  file(GLOB globbed RELATIVE "${top_src}" "${top_src}/${pattern}*")
+function(_ExternalData_arg_find_files glob pattern regex)
+  cmake_policy(PUSH)
+  cmake_policy(SET CMP0009 NEW)
+  file(${glob} globbed RELATIVE "${top_src}" "${top_src}/${pattern}*")
+  cmake_policy(POP)
+  set(externals_count -1)
   foreach(entry IN LISTS globbed)
     if("x${entry}" MATCHES "^x(.*)(\\.(${_ExternalData_REGEX_EXT}))$")
       set(relname "${CMAKE_MATCH_1}")
@@ -570,27 +810,46 @@
       set(alg "")
     endif()
     if("x${relname}" MATCHES "^x${regex}$" # matches
-        AND NOT IS_DIRECTORY "${top_src}/${entry}" # not a directory
         AND NOT "x${relname}" MATCHES "(^x|/)\\.ExternalData_" # not staged obj
         )
-      set(name "${top_src}/${relname}")
-      set(file "${top_bin}/${relname}")
-      if(alg)
-        list(APPEND external "${file}|${name}|${alg}")
-      elseif(ExternalData_LINK_CONTENT)
-        _ExternalData_link_content("${name}" alg)
-        list(APPEND external "${file}|${name}|${alg}")
-      elseif(NOT top_same)
-        list(APPEND internal "${file}|${name}")
+      if(IS_DIRECTORY "${top_src}/${entry}")
+        if("${relname}" STREQUAL "${reldata}")
+          set(have_original_as_dir 1)
+        endif()
+      else()
+        set(name "${top_src}/${relname}")
+        set(file "${top_bin}/${relname}")
+        if(alg)
+          if(NOT "${external_${externals_count}_file_name}" STREQUAL "${file}|${name}")
+            # 0 works around negative number bug in older CMake
+            math(EXPR externals_count "0${externals_count} + 1")
+            set(external_${externals_count}_file_name "${file}|${name}")
+          endif()
+          list(APPEND external_${externals_count}_algs "${alg}")
+        elseif(ExternalData_LINK_CONTENT)
+          _ExternalData_link_content("${name}" alg)
+          list(APPEND external "${file}|${name}|${alg}")
+        elseif(NOT top_same)
+          list(APPEND internal "${file}|${name}")
+        endif()
+        if("${relname}" STREQUAL "${reldata}")
+          set(have_original 1)
+        endif()
       endif()
-      if("${relname}" STREQUAL "${reldata}")
-        set(have_original 1)
-      endif()
-    endif()
-  endforeach()
+    endif()
+  endforeach()
+  if(${externals_count} GREATER -1)
+    foreach(ii RANGE ${externals_count})
+      string(REPLACE ";" "+" algs_delim "${external_${ii}_algs}")
+      list(APPEND external "${external_${ii}_file_name}|${algs_delim}")
+      unset(external_${ii}_algs)
+      unset(external_${ii}_file_name)
+    endforeach()
+  endif()
   set(external "${external}" PARENT_SCOPE)
   set(internal "${internal}" PARENT_SCOPE)
   set(have_original "${have_original}" PARENT_SCOPE)
+  set(have_original_as_dir "${have_original_as_dir}" PARENT_SCOPE)
 endfunction()

 #-----------------------------------------------------------------------------
@@ -603,8 +862,9 @@
 if(ExternalData_CONFIG)
   include(${ExternalData_CONFIG})
 endif()
-if(NOT ExternalData_URL_TEMPLATES)
-  message(FATAL_ERROR "No ExternalData_URL_TEMPLATES set!")
+if(NOT ExternalData_URL_TEMPLATES AND NOT ExternalData_OBJECT_STORES)
+  message(FATAL_ERROR
+    "Neither ExternalData_URL_TEMPLATES nor ExternalData_OBJECT_STORES is set!")
 endif()

 function(_ExternalData_link_or_copy src dst)
@@ -613,7 +873,7 @@
   file(MAKE_DIRECTORY "${dst_dir}")
   _ExternalData_random(random)
   set(tmp "${dst}.tmp${random}")
-  if(UNIX)
+  if(UNIX AND NOT ExternalData_NO_SYMLINKS)
     # Create a symbolic link.
     set(tgt "${src}")
     if(relative_top)
@@ -679,13 +939,52 @@
   set("${msg_var}" "${msg}" PARENT_SCOPE)
 endfunction()

-function(_ExternalData_download_object name hash algo var_obj)
+function(_ExternalData_custom_fetch key loc file err_var msg_var)
+  if(NOT ExternalData_CUSTOM_SCRIPT_${key})
+    set(err 1)
+    set(msg "No ExternalData_CUSTOM_SCRIPT_${key} set!")
+  elseif(NOT EXISTS "${ExternalData_CUSTOM_SCRIPT_${key}}")
+    set(err 1)
+    set(msg "No '${ExternalData_CUSTOM_SCRIPT_${key}}' exists!")
+  else()
+    set(ExternalData_CUSTOM_LOCATION "${loc}")
+    set(ExternalData_CUSTOM_FILE "${file}")
+    unset(ExternalData_CUSTOM_ERROR)
+    include("${ExternalData_CUSTOM_SCRIPT_${key}}")
+    if(DEFINED ExternalData_CUSTOM_ERROR)
+      set(err 1)
+      set(msg "${ExternalData_CUSTOM_ERROR}")
+    else()
+      set(err 0)
+      set(msg "no error")
+    endif()
+  endif()
+  set("${err_var}" "${err}" PARENT_SCOPE)
+  set("${msg_var}" "${msg}" PARENT_SCOPE)
+endfunction()
+
+function(_ExternalData_get_from_object_store hash algo var_obj var_success)
   # Search all object stores for an existing object.
   foreach(dir ${ExternalData_OBJECT_STORES})
     set(obj "${dir}/${algo}/${hash}")
     if(EXISTS "${obj}")
       message(STATUS "Found object: \"${obj}\"")
       set("${var_obj}" "${obj}" PARENT_SCOPE)
+      set("${var_success}" 1 PARENT_SCOPE)
+      return()
+    endif()
+  endforeach()
+endfunction()
+
+function(_ExternalData_download_object name hash algo var_obj var_success var_errorMsg)
+  # Search all object stores for an existing object.
+  set(success 1)
+  foreach(dir ${ExternalData_OBJECT_STORES})
+    set(obj "${dir}/${algo}/${hash}")
+    if(EXISTS "${obj}")
+      message(STATUS "Found object: \"${obj}\"")
+      set("${var_obj}" "${obj}" PARENT_SCOPE)
+      set("${var_success}" "${success}" PARENT_SCOPE)
       return()
     endif()
   endforeach()
@@ -701,8 +1000,23 @@
   foreach(url_template IN LISTS ExternalData_URL_TEMPLATES)
     string(REPLACE "%(hash)" "${hash}" url_tmp "${url_template}")
     string(REPLACE "%(algo)" "${algo}" url "${url_tmp}")
-    message(STATUS "Fetching \"${url}\"")
-    _ExternalData_download_file("${url}" "${tmp}" err errMsg)
+    if(url MATCHES "^(.*)%\\(algo:([A-Za-z_][A-Za-z0-9_]*)\\)(.*)$")
+      set(lhs "${CMAKE_MATCH_1}")
+      set(key "${CMAKE_MATCH_2}")
+      set(rhs "${CMAKE_MATCH_3}")
+      if(DEFINED ExternalData_URL_ALGO_${algo}_${key})
+        set(url "${lhs}${ExternalData_URL_ALGO_${algo}_${key}}${rhs}")
+      else()
+        set(url "${lhs}${algo}${rhs}")
+      endif()
+    endif()
+    string(REGEX REPLACE "((https?|ftp)://)([^@]+@)?(.*)" "\\1\\4" secured_url "${url}")
+    message(STATUS "Fetching \"${secured_url}\"")
+    if(url MATCHES "^ExternalDataCustomScript://([A-Za-z_][A-Za-z0-9_]*)/(.*)$")
+      _ExternalData_custom_fetch("${CMAKE_MATCH_1}" "${CMAKE_MATCH_2}" "${tmp}" err errMsg)
+    else()
+      _ExternalData_download_file("${url}" "${tmp}" err errMsg)
+    endif()
     set(tried "${tried}\n  ${url}")
     if(err)
       set(tried "${tried} (${errMsg})")
@@ -725,6 +1039,7 @@
   get_filename_component(dir "${name}" PATH)
   set(staged "${dir}/.ExternalData_${algo}_${hash}")

+  set(success 1)
   if(found)
     file(RENAME "${tmp}" "${obj}")
     message(STATUS "Downloaded object: \"${obj}\"")
@@ -732,38 +1047,78 @@
     set(obj "${staged}")
     message(STATUS "Staged object: \"${obj}\"")
   else()
-    message(FATAL_ERROR "Object ${algo}=${hash} not found at:${tried}")
+    if(NOT tried)
+      set(tried "\n  (No ExternalData_URL_TEMPLATES given)")
+    endif()
+    set(success 0)
+    set("${var_errorMsg}" "Object ${algo}=${hash} not found at:${tried}" PARENT_SCOPE)
   endif()

   set("${var_obj}" "${obj}" PARENT_SCOPE)
+  set("${var_success}" "${success}" PARENT_SCOPE)
 endfunction()

 if("${ExternalData_ACTION}" STREQUAL "fetch")
-  foreach(v ExternalData_OBJECT_STORES file name ext)
+  foreach(v ExternalData_OBJECT_STORES file name exts)
     if(NOT DEFINED "${v}")
       message(FATAL_ERROR "No \"-D${v}=\" value provided!")
     endif()
   endforeach()

-  file(READ "${name}${ext}" hash)
-  string(STRIP "${hash}" hash)
-
-  if("${ext}" MATCHES "^\\.(${_ExternalData_REGEX_EXT})$")
-    string(TOUPPER "${CMAKE_MATCH_1}" algo)
-  else()
-    message(FATAL_ERROR "Unknown hash algorithm extension \"${ext}\"")
-  endif()
-
-  _ExternalData_download_object("${name}" "${hash}" "${algo}" obj)
-
+  string(REPLACE "+" ";" exts_list "${exts}")
+  set(succeeded 0)
+  set(errorMsg "")
+  set(hash_list )
+  set(algo_list )
+  set(hash )
+  set(algo )
+  foreach(ext ${exts_list})
+    file(READ "${name}${ext}" hash)
+    string(STRIP "${hash}" hash)
+
+    if("${ext}" MATCHES "^\\.(${_ExternalData_REGEX_EXT})$")
+      string(TOUPPER "${CMAKE_MATCH_1}" algo)
+    else()
+      message(FATAL_ERROR "Unknown hash algorithm extension \"${ext}\"")
+    endif()
+
+    list(APPEND hash_list ${hash})
+    list(APPEND algo_list ${algo})
+  endforeach()
+
+  list(LENGTH exts_list num_extensions)
+  math(EXPR exts_range "${num_extensions} - 1")
+  foreach(ii RANGE 0 ${exts_range})
+    list(GET hash_list ${ii} hash)
+    list(GET algo_list ${ii} algo)
+    _ExternalData_get_from_object_store("${hash}" "${algo}" obj succeeded)
+    if(succeeded)
+      break()
+    endif()
+
+  endforeach()
+  if(NOT succeeded)
+    foreach(ii RANGE 0 ${exts_range})
+      list(GET hash_list ${ii} hash)
+      list(GET algo_list ${ii} algo)
+      _ExternalData_download_object("${name}" "${hash}" "${algo}"
+        obj succeeded algoErrorMsg)
+      set(errorMsg "${errorMsg}\n${algoErrorMsg}")
+      if(succeeded)
+        break()
+      endif()
+    endforeach()
+  endif()
+  if(NOT succeeded)
+    message(FATAL_ERROR "${errorMsg}")
+  endif()
   # Check if file already corresponds to the object.
-  set(stamp "${ext}-stamp")
+  set(stamp "-hash-stamp")
   set(file_up_to_date 0)
   if(EXISTS "${file}" AND EXISTS "${file}${stamp}")
     file(READ "${file}${stamp}" f_hash)
     string(STRIP "${f_hash}" f_hash)
     if("${f_hash}" STREQUAL "${hash}")
-      #message(STATUS "File already corresponds to object")
       set(file_up_to_date 1)
     endif()
   endif()


COMP: Set CTEST_GIT_UPDATE_CUSTOM and added ctest_update() to SupelElastix root test, the same way as I did for the SuperBuild.

--- CTest.cmake
+++ CTest.cmake
@@ -36,6 +36,11 @@
     OUTPUT_VARIABLE SELX_GIT_BRANCH_NAME
 )

+if(NOT DEFINED CTEST_GIT_COMMAND)
+  find_program(CTEST_GIT_COMMAND NAMES git git.cmd)
+endif()
+set(CTEST_GIT_UPDATE_CUSTOM "${CTEST_GIT_COMMAND}" pull origin)
+
 set(CTEST_BUILD_NAME "${SELX_GIT_BRANCH_NAME};Tests;commit=SHA\\:${SELX_GIT_COMMIT_SHA}")

 set(CTEST_CMAKE_GENERATOR "Unix Makefiles")
@@ -48,6 +53,7 @@
 set(CTEST_CONFIGURE_COMMAND "${CTEST_CONFIGURE_COMMAND} \"${CTEST_SOURCE_DIRECTORY}\"")

 ctest_start("Nightly")
-# TODO Add ctest_update() to ensure that the commit SHA will be passed to CDash, and GitHub.
+# Added ctest_update() to ensure that the commit SHA will be passed to CDash, and GitHub.
+ctest_update()
 ctest_test()
 ctest_submit( PARTS Test )


Remove unused FFT superbuild logic branch

Change-Id: I9a39b54d3b72d5a47fcf074e4a4d2e84a20820f8

--- SuperBuild/SuperBuild.cmake
+++ SuperBuild/SuperBuild.cmake
@@ -241,9 +241,6 @@
 set(ITK_WRAPPING OFF CACHE BOOL "Turn OFF wrapping ITK with WrapITK")
 if(ITK_WRAPNG)
   list(APPEND ITK_DEPENDENCIES Swig)
-endif()
-if(ITK_USE_FFTW)
-  list(APPEND ITK_DEPENDENCIES fftw)
 endif()
 include(External_ITK)
 list(APPEND ${CMAKE_PROJECT_NAME}_DEPENDENCIES ITK)


Add TinyXML2 library setting.

Add TinyXML2 library setting.

--- tester/project.cmake
+++ tester/project.cmake
@@ -25,3 +25,7 @@
 list (APPEND _project_include_dirs ${UV_INCLUDE_DIRS})
 list (APPEND _project_ldflags      ${UV_LIBRARIES})

+# TinyXML2 setting.
+list (APPEND _project_include_dirs ${TINYXML2_INCLUDE_DIRS})
+list (APPEND _project_ldflags      ${TINYXML2_LIBRARIES})
+


COMP: Update to latest FindMPI.cmake, for proper MS-MPI support.

--- CMake/FindMPI.cmake
+++ CMake/FindMPI.cmake
@@ -216,13 +216,19 @@
     "$ENV{SystemDrive}/Program Files/Microsoft Compute Cluster Pack/Include"
     )

-  # TODO: How do we know whether we're building 32-bit vs. 64-bit for MS-MPI?
+  # Decide between 32-bit and 64-bit libraries for Microsoft's MPI
+  if (CMAKE_CL_64)
+    set(MS_MPI_ARCH_DIR amd64)
+  else (CMAKE_CL_64)
+    set(MS_MPI_ARCH_DIR i386)
+  endif (CMAKE_CL_64)
+
   find_library(MPI_LIBRARY
-    NAMES mpi mpich
+    NAMES mpi mpich msmpi
     PATHS /usr/lib /usr/local/lib /usr/local/mpi/lib
     "C:/Program Files/MPICH/SDK/Lib"
     "$ENV{SystemDrive}/Program Files/MPICH/SDK/Lib"
-    "$ENV{SystemDrive}/Program Files/Microsoft Compute Cluster Pack/Lib/i386"
+    "$ENV{SystemDrive}/Program Files/Microsoft Compute Cluster Pack/Lib/${MS_MPI_ARCH_DIR}"
     )
   find_library(MPI_LIBRARY
     NAMES mpich2
@@ -258,5 +264,9 @@
   set(MPI_FOUND FALSE)
 endif (MPI_INCLUDE_PATH AND MPI_LIBRARY)

+include(FindPackageHandleStandardArgs)
+# handle the QUIETLY and REQUIRED arguments
+find_package_handle_standard_args(MPI DEFAULT_MSG MPI_LIBRARY MPI_INCLUDE_PATH)
+
 mark_as_advanced(MPI_INCLUDE_PATH MPI_COMPILE_FLAGS MPI_LINK_FLAGS MPI_LIBRARY
   MPI_EXTRA_LIBRARY)


update pkgconfig install path

update pkgconfig install path

--- CreatePackage.cmake
+++ CreatePackage.cmake
@@ -18,7 +18,7 @@

 	configure_file("${THIS_FILE_DIR}/pkg-config.pc.in" "${THIS_OUTPUT_DIR}/${PROJECT_NAME}.pc" @ONLY)

-	install(FILES "${THIS_OUTPUT_DIR}/${PROJECT_NAME}.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
+	install(FILES "${THIS_OUTPUT_DIR}/${PROJECT_NAME}.pc" DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/pkgconfig")

 endmacro()


Don't list embedded_assets.s as an output for embedded_assets.zip custom command to prevent build system from deleting this file, that is only created during CMake configuration, when performing a clean build.

The embedded_assets.s is still touched to trigger a rebuilding of the corresponding OBJ, but it is created using file(GENERATE ...) instead of by the custom command.

--- embed_assets.cmake
+++ embed_assets.cmake
@@ -13,7 +13,7 @@
 macro(mirrage_embed_asset target src_files)
 	string (REPLACE ";" "$<SEMICOLON>" src_files_str "${src_files}")

-	add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/embedded_assets.zip" "${CMAKE_CURRENT_BINARY_DIR}/embedded_assets.s"
+	add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/embedded_assets.zip"
 		COMMAND ${CMAKE_COMMAND} -DSRC_FILES=${src_files_str} -DDST_DIR=${CMAKE_CURRENT_BINARY_DIR} -P ${MIRRAGE_ROOT_DIR}/copy_recursive.cmake
 		COMMAND ${CMAKE_COMMAND} -E touch "${CMAKE_CURRENT_BINARY_DIR}/embedded_assets.s"
 		DEPENDS ${ARGN}


COMP: fix detection of version number

COMP: fix detection of version number

--- CMake/FindOpenCV.cmake
+++ CMake/FindOpenCV.cmake
@@ -39,8 +39,23 @@
   if(NOT OpenCV_VERSION)
     file(READ "${opencv_INCLUDE_DIR}/opencv2/core/version.hpp" _header_content)

-    string(REGEX MATCH  ".*# *define +CV_VERSION_EPOCH +([0-9]+).*" matched ${_header_content})
-    if( matched)
+    # detect the type of version file (2.3.x , 2.4.x or 3.x)
+    string(REGEX MATCH  ".*# *define +CV_VERSION_EPOCH +([0-9]+).*" has_epoch ${_header_content})
+    string(REGEX MATCH  ".*# *define +CV_MAJOR_VERSION +([0-9]+).*" has_old_major ${_header_content})
+    string(REGEX MATCH  ".*# *define +CV_MINOR_VERSION +([0-9]+).*" has_old_minor ${_header_content})
+    string(REGEX MATCH  ".*# *define +CV_SUBMINOR_VERSION +([0-9]+).*" has_old_subminor ${_header_content})
+
+    if(has_old_major AND has_old_minor AND has_old_subminor)
+      #for opencv 2.3.x
+      string(REGEX REPLACE ".*# *define +CV_MAJOR_VERSION +([0-9]+).*" "\\1"
+        OpenCV_VERSION_MAJOR ${_header_content})
+      string(REGEX REPLACE ".*# *define +CV_MINOR_VERSION +([0-9]+).*" "\\1"
+        OpenCV_VERSION_MINOR ${_header_content})
+      string(REGEX REPLACE ".*# *define +CV_SUBMINOR_VERSION +([0-9]+).*" "\\1"
+        OpenCV_VERSION_PATCH ${_header_content})
+      set(OpenCV_VERSION_TWEAK)
+    elseif(has_epoch)
+      # for opencv 2.4.x
       string(REGEX REPLACE ".*# *define +CV_VERSION_EPOCH +([0-9]+).*" "\\1"
         OpenCV_VERSION_MAJOR ${_header_content})
       string(REGEX REPLACE ".*# *define +CV_VERSION_MAJOR +([0-9]+).*" "\\1"
@@ -50,12 +65,11 @@
       string(REGEX REPLACE ".*# *define +CV_VERSION_REVISION +([0-9]+).*" "\\1"
         OpenCV_VERSION_TWEAK ${_header_content})
     else()
-      #for opencv 2.3.x
-      string(REGEX REPLACE ".*# *define +CV_MAJOR_VERSION +([0-9]+).*" "\\1"
+      string(REGEX REPLACE ".*# *define +CV_VERSION_MAJOR +([0-9]+).*" "\\1"
         OpenCV_VERSION_MAJOR ${_header_content})
-      string(REGEX REPLACE ".*# *define +CV_MINOR_VERSION +([0-9]+).*" "\\1"
+      string(REGEX REPLACE ".*# *define +CV_VERSION_MINOR +([0-9]+).*" "\\1"
         OpenCV_VERSION_MINOR ${_header_content})
-      string(REGEX REPLACE ".*# *define +CV_SUBMINOR_VERSION +([0-9]+).*" "\\1"
+      string(REGEX REPLACE ".*# *define +CV_VERSION_REVISION +([0-9]+).*" "\\1"
         OpenCV_VERSION_PATCH ${_header_content})
       set(OpenCV_VERSION_TWEAK)
     endif()


CMake: Update subproject.cmake

CMake: Update subproject.cmake

--- CMake/subproject.cmake
+++ CMake/subproject.cmake
@@ -1,3 +1,25 @@
+# subproject.cmake:
+#
+#    Builds another dependant CMake project, unless the project was already built or installed systemwide.
+#
+#    It does this by first checking if project exists systemwide and uses that.
+#    If not, it checks if the project was already included and if it was, it does nothing.
+#    If both of the above are not true, another CMake project is build.
+#
+# Usually the subprojects are git submodules on git repository, so packagers can avoid linking subprojects and
+# instead always use systemwide libraries, by not downloading submodules. This will normally cause build to fail
+# if systemwide package was not found.
+#
+# Developers can control this behaviour with -DSOURCE_<SUBPROJECT>=ON|OFF option. It's usually useful to have
+# local development versions of everything when developing, and this option makes sure nothing is linked against
+# systemwide libraries.
+#
+# If subprojects are being linked locally, and subprojects include subprojects that were already included.
+# They will not include the subproject again. Instead they link against the already compiled subprojects.
+#
+# This is convenient for development, but not so covenient if you need to have different versions of submodules
+# in-tree for some reason. Rather than doing that I just suggest updating the codebase to work with same library versions.
+
 function(add_subproject name)
    if(ARGC GREATER 1)
       set(package_name ${ARGV1})


BUG: install rule for GreedyAtlas was working only if "make" was run from the outer DTIAtlasBuilder-build directory

--- SuperBuild/FindExternalTools.cmake
+++ SuperBuild/FindExternalTools.cmake
@@ -360,7 +360,7 @@
   -DatlasWerks_COMPILE_APP_TX_WERKS:BOOL=OFF
   -DatlasWerks_COMPILE_APP_UTILITIES:BOOL=OFF
   #There is no install in AtlasWerks. We only care about GreedyAtlas so we just copy it. We only do that on Linux since AtlasWerks does not work on the other plateform
-  INSTALL_COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/DTIAtlasBuilder-build/AtlasWerks-install/bin/ && ${CMAKE_COMMAND} -E copy Applications/Greedy/GreedyAtlas ${CMAKE_CURRENT_BINARY_DIR}/DTIAtlasBuilder-build/AtlasWerks-install/bin/
+  INSTALL_COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/DTIAtlasBuilder-build/AtlasWerks-install/bin/ && ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/AtlasWerks-build/Applications/Greedy/GreedyAtlas ${CMAKE_CURRENT_BINARY_DIR}/DTIAtlasBuilder-build/AtlasWerks-install/bin/
   DEPENDS ${ITK_DEPEND} ${VTK_DEPEND} FFTW CLAPACK # Not CMake Arg -> directly after CMakeArg in ExternalProject_Add()
   )
 set( Tools


Run item_tasks client test serially

Run item_tasks client test serially

--- plugins/item_tasks/plugin.cmake
+++ plugins/item_tasks/plugin.cmake
@@ -13,6 +13,10 @@
     tasks "${PROJECT_SOURCE_DIR}/plugins/${PLUGIN}/plugin_tests/tasks.js" PLUGIN ${PLUGIN}
     SETUP_MODULES "${CMAKE_CURRENT_LIST_DIR}/plugin_tests/mock_worker.py")

+if (BUILD_JAVASCRIPT_TESTS)
+    set_property(TEST web_client_item_tasks.tasks PROPERTY RUN_SERIAL ON)
+endif()
+
 add_eslint_test(${PLUGIN} "${PROJECT_SOURCE_DIR}/plugins/${PLUGIN}/web_client")
 add_eslint_test(${PLUGIN}-tests "${PROJECT_SOURCE_DIR}/plugins/${PLUGIN}/plugin_tests")
 add_puglint_test(${PLUGIN} "${PROJECT_SOURCE_DIR}/plugins/${PLUGIN}/web_client/templates")


Tools: Fix CMake menuconfig used with combination of MSYS and CMD

--- tools/cmake/kconfig.cmake
+++ tools/cmake/kconfig.cmake
@@ -9,6 +9,7 @@
         else()
             unset(WINPTY CACHE)  # in case previous CMake run was in a tty and this one is not
         endif()
+        unset(MCONF CACHE)  # needed when MSYS and CMD is intermixed (cache could contain an incompatible path)
         find_program(MCONF mconf-idf)

         # Fall back to the old binary which was called 'mconf' not 'mconf-idf'
@@ -30,7 +31,7 @@
                     "Consult the setup docs for ESP-IDF on Windows.")
             endif()
         elseif(WINPTY)
-            set(MCONF "${WINPTY}" "${MCONF}")
+            set(MCONF "\"${WINPTY}\" \"${MCONF}\"")
         endif()
     endif()

@@ -201,7 +202,8 @@
         "IDF_CMAKE=y"
         "KCONFIG_CONFIG=${sdkconfig}"
         ${mconf} ${root_kconfig}
-        VERBATIM
+        # VERBATIM cannot be used here because it cannot handle ${mconf}="winpty mconf-idf" and the escaping must be
+        # done manually
         USES_TERMINAL
         # additional run of confgen esures that the deprecated options will be inserted into sdkconfig (for backward
         # compatibility)


Default PCL to OFF on MSVC as well

Default PCL to OFF on MSVC as well

PCL was already defaulted to OFF on Linux, this changes the default to OFF on MSVC
as well. This can be reverted once the primary LibPack for Windows includes a version
of FLANN that compiles under C++17 (the last official release of FLANN, 1.9.1, does
not, but the HEAD in their Git repository does).

--- cMake/FreeCAD_Helpers/InitializeFreeCADBuildOptions.cmake
+++ cMake/FreeCAD_Helpers/InitializeFreeCADBuildOptions.cmake
@@ -150,7 +150,7 @@

     if(MSVC)
         option(BUILD_FEM_NETGEN "Build the FreeCAD FEM module with the NETGEN mesher" ON)
-        option(FREECAD_USE_PCL "Build the features that use PCL libs" ON)
+        option(FREECAD_USE_PCL "Build the features that use PCL libs" OFF) # 3/5/2021 current LibPack uses non-C++17 FLANN
         option(FREECAD_USE_3DCONNEXION "Use the 3D connexion SDK to support 3d mouse." ON)
     elseif(APPLE)
         find_library(3DCONNEXIONCLIENT_FRAMEWORK 3DconnexionClient)


i#1569 AArch64: Add AArch64 cross-compilation to test suite.

Review-URL: https://codereview.appspot.com/293920043

--- suite/runsuite.cmake
+++ suite/runsuite.cmake
@@ -281,6 +281,16 @@
     INTERNAL:BOOL=OFF
     CMAKE_TOOLCHAIN_FILE:PATH=${CTEST_SOURCE_DIRECTORY}/make/toolchain-arm32.cmake
     " OFF OFF "")
+  testbuild_ex("arm-debug-internal-64" OFF "
+    DEBUG:BOOL=ON
+    INTERNAL:BOOL=ON
+    CMAKE_TOOLCHAIN_FILE:PATH=${CTEST_SOURCE_DIRECTORY}/make/toolchain-arm64.cmake
+    " OFF OFF "")
+  testbuild_ex("arm-release-external-64" OFF "
+    DEBUG:BOOL=OFF
+    INTERNAL:BOOL=OFF
+    CMAKE_TOOLCHAIN_FILE:PATH=${CTEST_SOURCE_DIRECTORY}/make/toolchain-arm64.cmake
+    " OFF OFF "")

   # Android cross-compilation and running of tests using "adb shell"
   find_program(ADB adb DOC "adb Android utility")


i#2406 faster appveyor: disable vps for PR (#2452)

We skip the vps build on Appveyor to speed up PR's, using just the merge to
master to catch breakage in vps on Windows.

--- suite/runsuite.cmake
+++ suite/runsuite.cmake
@@ -271,13 +271,17 @@
         ${install_path_cache}
         ")
     endif (DO_ALL_BUILDS)
-    testbuild("vps-debug-internal-32" OFF "
-      VMAP:BOOL=OFF
-      VPS:BOOL=ON
-      DEBUG:BOOL=ON
-      INTERNAL:BOOL=ON
-      ${install_path_cache}
-      ")
+    # i#2406: we skip the vps build to speed up PR's, using just the merge to
+    # master to catch breakage in vps.
+    if (NOT DEFINED ENV{APPVEYOR_PULL_REQUEST_NUMBER})
+      testbuild("vps-debug-internal-32" OFF "
+        VMAP:BOOL=OFF
+        VPS:BOOL=ON
+        DEBUG:BOOL=ON
+        INTERNAL:BOOL=ON
+        ${install_path_cache}
+        ")
+    endif ()
     if (DO_ALL_BUILDS)
       testbuild("vps-release-external-32" OFF "
         VMAP:BOOL=OFF


Setting PATH before calling make for VP9 to solve issue #162.

--- SuperBuild/External_VP9.cmake
+++ SuperBuild/External_VP9.cmake
@@ -1,13 +1,17 @@
 cmake_minimum_required(VERSION 2.8.2)
+
 include(${CMAKE_ROOT}/Modules/ExternalProject.cmake)
 include(${OpenIGTLink_SOURCE_DIR}/SuperBuild/findVP9.cmake)
+
 SET(VP9_DEPENDENCIES)
 IF(NOT CMAKE_SYSTEM_NAME STREQUAL "Windows") # window os build doesn't need the yasm
-	INCLUDE(${OpenIGTLink_SOURCE_DIR}/SuperBuild/External_yasm.cmake)
+        INCLUDE(${OpenIGTLink_SOURCE_DIR}/SuperBuild/External_yasm.cmake)
 	IF(NOT YASM_FOUND)
-		LIST(APPEND VP9_DEPENDENCIES YASM)
+	  LIST(APPEND VP9_DEPENDENCIES YASM)
+	  message("VP9 dependencies modified." VP9_DEPENDENCIES)
 	ENDIF()
-ENDIF()
+ENDIF()
+
 IF(VP9_FOUND)
   IF(${OpenIGTLink_PROTOCOL_VERSION} LESS 3)
     MESSAGE(FATAL_ERROR "Video streaming requires a build of OpenIGTLink with v3 support enabled. Please set the OpenIGTLink_PROTOCOL_VERSION_3 to true.")
@@ -19,13 +23,13 @@
     SET (VP9_INCLUDE_DIR "${CMAKE_BINARY_DIR}/Deps/VP9/vpx" CACHE PATH "VP9 source directory" FORCE)
     SET (VP9_LIBRARY_DIR "${CMAKE_BINARY_DIR}/Deps/VP9" CACHE PATH "VP9 library directory" FORCE)
     ExternalProject_Add(VP9
-    	PREFIX "${CMAKE_BINARY_DIR}/Deps/VP9-prefix"
+      PREFIX "${CMAKE_BINARY_DIR}/Deps/VP9-prefix"
       GIT_REPOSITORY https://github.com/webmproject/libvpx/
       GIT_TAG v1.6.1
       SOURCE_DIR        "${CMAKE_BINARY_DIR}/Deps/VP9"
       CONFIGURE_COMMAND "${CMAKE_BINARY_DIR}/Deps/VP9/configure" --disable-examples --as=yasm --disable-tools --disable-docs --disable-vp8 --disable-libyuv --disable-unit_tests --disable-postproc WORKING_DIRECTORY "${VP9_LIBRARY_DIR}"
       BUILD_ALWAYS 1
-      BUILD_COMMAND make
+      BUILD_COMMAND PATH=${YASM_BINARY_DIR}:$ENV{PATH}; make
       BUILD_IN_SOURCE 1
       INSTALL_COMMAND   ""
       TEST_COMMAND      ""


Don't search for transient packages if version requirement is not met

--- FindLibraryPackage.cmake
+++ FindLibraryPackage.cmake
@@ -204,7 +204,57 @@

       set(${_flp_${name}_UC}_VERSION "${${_flp_${name}_UC}_VERSION_MAJOR}.${${_flp_${name}_UC}_VERSION_MINOR}.${${_flp_${name}_UC}_VERSION_PATCH}")
     endif()
-
+  else()
+    set(_flp_${name}_FAIL TRUE)
+    if(_flp_${name}_out)
+      message(${_flp_version_output_type}
+        "Can't find ${_flp_${name}_INCLUDE}/version.h(pp).")
+    endif()
+  endif()
+
+  # Version checking
+  if(${_flp_${name}_UC}_VERSION AND ${name}_FIND_VERSION)
+    if(${name}_FIND_VERSION_EXACT)
+      if(NOT ${name}_FIND_VERSION VERSION_EQUAL ${_flp_${name}_UC}_VERSION)
+        set(_flp_${name}_FAIL TRUE)
+        if(_flp_${name}_out)
+          message(${_flp_version_output_type}
+            "Version ${${name}_FIND_VERSION} of ${name} is required exactly. "
+            "Version ${${_flp_${name}_UC}_VERSION} was found in ${${_flp_${name}_UC}_INCLUDE_DIR}.")
+        endif()
+      endif()
+    else()
+      if( ${name}_FIND_VERSION VERSION_GREATER ${_flp_${name}_UC}_VERSION )
+        set(_flp_${name}_FAIL TRUE)
+        if(_flp_${name}_out)
+          message(${_flp_version_output_type}
+            "Version ${${name}_FIND_VERSION} or higher of ${name} is required. "
+            "Version ${${_flp_${name}_UC}_VERSION} was found in ${${_flp_${name}_UC}_INCLUDE_DIR}.")
+        endif()
+      endif()
+    endif()
+  endif()
+
+  # include
+  set(${_flp_${name}_UC}_INCLUDE_DIRS ${${_flp_${name}_UC}_INCLUDE_DIR})
+
+  # library
+  if(NOT _flp_${name}_NO_LIBRARY)
+    find_library(${_flp_${name}_UC}_LIBRARY ${name}
+      PATHS ${${_flp_${name}_UC}_INCLUDE_DIR}/.. PATH_SUFFIXES lib NO_DEFAULT_PATH)
+    set(${_flp_${name}_UC}_LIBRARIES ${${_flp_${name}_UC}_LIBRARY})
+
+    if(${name}_FIND_REQUIRED AND
+        ${_flp_${name}_UC}_LIBRARY MATCHES "${_flp_${name}_UC}_LIBRARY-NOTFOUND")
+      set(_flp_${name}_FAIL TRUE)
+      if(_flp_${name}_out)
+        message(${_flp_version_output_type}
+          "Missing the ${name} library in ${${_flp_${name}_UC}_INCLUDE_DIR}/../lib.")
+      endif()
+    endif()
+  endif()
+
+  if(NOT _flp_${name}_FAIL)
     # Find transient packages
     foreach(_flp_trans ${_flp_${name}_TRANSIENT})
       string(TOUPPER ${_flp_trans} _flp_${name}_TRANS)
@@ -247,54 +297,6 @@
           "${_flp_Version_file}.")
       endif()
     endforeach()
-  else()
-    set(_flp_${name}_FAIL TRUE)
-    if(_flp_${name}_out)
-      message(${_flp_version_output_type}
-        "Can't find ${_flp_${name}_INCLUDE}/version.h(pp).")
-    endif()
-  endif()
-
-  # Version checking
-  if(${_flp_${name}_UC}_VERSION AND ${name}_FIND_VERSION)
-    if(${name}_FIND_VERSION_EXACT)
-      if(NOT ${name}_FIND_VERSION VERSION_EQUAL ${_flp_${name}_UC}_VERSION)
-        set(_flp_${name}_FAIL TRUE)
-        if(_flp_${name}_out)
-          message(${_flp_version_output_type}
-            "Version ${${name}_FIND_VERSION} of ${name} is required exactly. "
-            "Version ${${_flp_${name}_UC}_VERSION} was found in ${${_flp_${name}_UC}_INCLUDE_DIR}.")
-        endif()
-      endif()
-    else()
-      if( ${name}_FIND_VERSION VERSION_GREATER ${_flp_${name}_UC}_VERSION )
-        set(_flp_${name}_FAIL TRUE)
-        if(_flp_${name}_out)
-          message(${_flp_version_output_type}
-            "Version ${${name}_FIND_VERSION} or higher of ${name} is required. "
-            "Version ${${_flp_${name}_UC}_VERSION} was found in ${${_flp_${name}_UC}_INCLUDE_DIR}.")
-        endif()
-      endif()
-    endif()
-  endif()
-
-  # include
-  set(${_flp_${name}_UC}_INCLUDE_DIRS ${${_flp_${name}_UC}_INCLUDE_DIR})
-
-  # library
-  if(NOT _flp_${name}_NO_LIBRARY)
-    find_library(${_flp_${name}_UC}_LIBRARY ${name}
-      PATHS ${${_flp_${name}_UC}_INCLUDE_DIR}/.. PATH_SUFFIXES lib NO_DEFAULT_PATH)
-    set(${_flp_${name}_UC}_LIBRARIES ${${_flp_${name}_UC}_LIBRARY})
-
-    if(${name}_FIND_REQUIRED AND
-        ${_flp_${name}_UC}_LIBRARY MATCHES "${_flp_${name}_UC}_LIBRARY-NOTFOUND")
-      set(_flp_${name}_FAIL TRUE)
-      if(_flp_${name}_out)
-        message(${_flp_version_output_type}
-          "Missing the ${name} library in ${${_flp_${name}_UC}_INCLUDE_DIR}/../lib.")
-      endif()
-    endif()
   endif()

   if(_flp_${name}_FAIL)


FLP: fix include dir cache unset, allow for version.h and .hpp naming

--- FindLibraryPackage.cmake
+++ FindLibraryPackage.cmake
@@ -29,7 +29,7 @@
 #
 # Module to find a standard library and includes. Intended to be used by
 # FindFoo.cmake scripts. Assumes the following layout:
-#   (root)/include/(name)/version.h
+#   (root)/include/(name)/version.h(pp)
 #      parsed for defines: NAME_VERSION_MAJOR, -_MINOR, -_PATCH, -_ABI
 #
 #
@@ -105,11 +105,21 @@
   string(TOUPPER ${_flp_${name}_INCLUDE} _flp_${name}_INCLUDE_UC)

   # might already be set from a previous run with a different/wrong version
-  unset(${_flp_NAME}_INCLUDE_DIR CACHE)
+  unset(${_flp_${name}_UC}_INCLUDE_DIR CACHE)

   find_path(${_flp_${name}_UC}_INCLUDE_DIR ${_flp_${name}_INCLUDE}/version.h
     HINTS "${${_flp_${name}_UC}_ROOT}/include" "$ENV{${_flp_${name}_UC}_ROOT}/include"
     PATHS /usr/include /usr/local/include /opt/local/include /opt/include)
+  set(_flp_Version_file
+    "${${_flp_${name}_UC}_INCLUDE_DIR}/${_flp_${name}_INCLUDE}/version.h")
+
+  if(NOT ${_flp_${name}_UC}_INCLUDE_DIR)
+    find_path(${_flp_${name}_UC}_INCLUDE_DIR ${_flp_${name}_INCLUDE}/version.hpp
+      HINTS "${${_flp_${name}_UC}_ROOT}/include" "$ENV{${_flp_${name}_UC}_ROOT}/include"
+      PATHS /usr/include /usr/local/include /opt/local/include /opt/include)
+    set(_flp_Version_file
+      "${${_flp_${name}_UC}_INCLUDE_DIR}/${_flp_${name}_INCLUDE}/version.hpp")
+  endif()

   if(${name}_FIND_REQUIRED)
     set(_flp_version_output_type FATAL_ERROR)
@@ -127,7 +137,6 @@

   # Try to ascertain the version...
   if(${_flp_${name}_UC}_INCLUDE_DIR)
-    set(_flp_Version_file "${${_flp_${name}_UC}_INCLUDE_DIR}/${_flp_${name}_INCLUDE}/version.h")
     if("${${_flp_${name}_UC}_INCLUDE_DIR}" MATCHES "\\.framework$" AND
         NOT EXISTS "${_flp_Version_file}")
       set(_flp_Version_file "${${_flp_${name}_UC}_INCLUDE_DIR}/Headers/version.h")
@@ -234,14 +243,14 @@
           "Can't figure out ${_flp_trans} version for "
           "${name} ${${_flp_${name}_UC}_VERSION}, use "
           "${_flp_${name}_UC}_${_flp_${name}_TRANS}_VERSION in "
-          "${_flp_${name}_INCLUDE}/version.h.")
+          "${_flp_Version_file}.")
       endif()
     endforeach()
   else()
     set(_flp_${name}_FAIL TRUE)
     if(_flp_${name}_out)
       message(${_flp_version_output_type}
-        "Can't find ${_flp_${name}_INCLUDE}/version.h.")
+        "Can't find ${_flp_${name}_INCLUDE}/version.h(pp).")
     endif()
   endif()


change CCPi CIL version

change CCPi CIL version

--- version_config.cmake
+++ version_config.cmake
@@ -154,15 +154,15 @@
 set(DEFAULT_JSON_TAG v3.7.3)

 # CCPi CIL
-set(CIL_VERSION "v19.10")
+set(CIL_VERSION "v20.04")
 set(DEFAULT_CCPi-Framework_URL https://github.com/vais-ral/CCPi-Framework.git)
-set(DEFAULT_CCPi-Framework_TAG ff08216d4e6fef84659b43155c5c52484b1dc543)
+set(DEFAULT_CCPi-Framework_TAG ${CIL_VERSION})
 set(DEFAULT_CCPi-Regularisation-Toolkit_URL https://github.com/vais-ral/CCPi-Regularisation-Toolkit.git )
-set(DEFAULT_CCPi-Regularisation-Toolkit_TAG db048a42018857c7aa30033e978a3600cbedb85f)
+set(DEFAULT_CCPi-Regularisation-Toolkit_TAG ${CIL_VERSION})
 set(DEFAULT_CCPi-FrameworkPlugins_URL https://github.com/vais-ral/CCPi-FrameworkPlugins.git)
-set(DEFAULT_CCPi-FrameworkPlugins_TAG "${CIL_VERSION}")
+set(DEFAULT_CCPi-FrameworkPlugins_TAG ${CIL_VERSION})
 set(DEFAULT_CCPi-Astra_URL https://github.com/vais-ral/CCPi-Astra.git)
-set(DEFAULT_CCPi-Astra_TAG 8c2493710f5eac1316945585fe6333ab56f9a2a1)
+set(DEFAULT_CCPi-Astra_TAG ${CIL_VERSION})

 option (DEVEL_BUILD "Developer Build" OFF)
 mark_as_advanced(DEVEL_BUILD)


Only use ASIO_INCLUDE_DIR if it is set

Only use ASIO_INCLUDE_DIR if it is set

CMake would complain if the ASIO_INCLDUE_DIR variable was not set, but
used as include directory.
So only use it when it really is set.

--- cmake/BALLConfigBoost.cmake
+++ cmake/BALLConfigBoost.cmake
@@ -25,6 +25,10 @@
 			SET(BALL_ASIO_NAMESPACE "asio")
 		ENDIF()
 	ENDIF()
-	SET(BOOST_INCLUDE_DIRS ${BOOST_INCLUDE_DIRS} ${ASIO_INCLUDE_DIR})
+	SET(BOOST_INCLUDE_DIRS ${BOOST_INCLUDE_DIRS})
+
+	IF(ASIO_INCLUDE_DIR)
+		SET(BOOST_INCLUDE_DIRS ${ASIO_INCLUDE_DIR})
+	ENDIF()
 ENDIF()


fixed missing -lpthreads.

fixed missing -lpthreads.

Signed-off-by: Étienne Schmitt <25d5031dc1a1d443222aec9a4e916501ae23c255@inria.fr>

--- cmake/CompilerOptions.cmake
+++ cmake/CompilerOptions.cmake
@@ -32,6 +32,9 @@
 endif(CGOGN_USE_TSAN)

 if (NOT MSVC)
+	find_package(Threads REQUIRED)
+	add_flags(CMAKE_CXX_FLAGS ${CMAKE_THREAD_LIBS_INIT})
+
 	# Warning flags
 	set(NORMAL_WARNINGS -Wall -Wextra)


Get rid of conan specific stuff

Get rid of conan specific stuff

--- cmake/DevBaseExternal.cmake
+++ cmake/DevBaseExternal.cmake
@@ -110,16 +110,7 @@

 if(DEVBASE_DOCOPT_REQUIRED)
-    if(CONAN_DOCOPT_ROOT)
-        find_package(docopt
-            REQUIRED
-            NO_DEFAULT_PATH
-            PATHS
-                ${CONAN_DOCOPT_ROOT}
-        )
-    else()
-        find_package(Docopt REQUIRED)
-    endif()
+    find_package(Docopt REQUIRED)
 endif()

@@ -264,16 +255,7 @@

 if(DEVBASE_NLOHMANN_JSON_REQUIRED)
-    if(CONAN_JSONFORMODERNCPP_ROOT)
-        find_package(nlohmann_json
-            REQUIRED
-            NO_DEFAULT_PATH
-            PATHS
-                ${CONAN_JSONFORMODERNCPP_ROOT}
-        )
-    else()
-        find_package(nlohmann_json REQUIRED)
-    endif()
+    find_package(nlohmann_json REQUIRED)
 endif()

@@ -357,16 +339,7 @@
 # call to CMake's FindPython. Otherwise find_package(PythonLibs) fails (at
 # least on macOS / MacPorts.
 if(DEVBASE_PYBIND11_REQUIRED)
-    if(CONAN_PYBIND11_ROOT)
-        find_package(pybind11
-            REQUIRED
-            NO_DEFAULT_PATH
-            PATHS
-                ${CONAN_PYBIND11_ROOT}
-        )
-    else()
-        find_package(pybind11 REQUIRED)
-    endif()
+    find_package(pybind11 REQUIRED)
 endif()


Better path definition for Pugixml.

Better path definition for Pugixml.

This allows rawspeed to be used as git submodule.

--- cmake/Modules/Pugixml.cmake
+++ cmake/Modules/Pugixml.cmake
@@ -3,7 +3,7 @@
 project(pugixml NONE)

 # Download and unpack pugixml at configure time
-configure_file(${CMAKE_SOURCE_DIR}/cmake/Modules/Pugixml.cmake.in ${CMAKE_BINARY_DIR}/pugixml/CMakeLists.txt @ONLY)
+configure_file(${CMAKE_CURRENT_LIST_DIR}/Pugixml.cmake.in ${CMAKE_BINARY_DIR}/pugixml/CMakeLists.txt @ONLY)

 execute_process(
   COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}"


cmake px4_add_module() make properties private

--- cmake/common/px4_base.cmake
+++ cmake/common/px4_base.cmake
@@ -205,12 +205,6 @@
 	set(STACK_MAIN_DEFAULT 1024)
 	set(PRIORITY_DEFAULT SCHED_PRIORITY_DEFAULT)

-	# default stack max to stack main
-	if(NOT STACK_MAIN AND STACK)
-		set(STACK_MAIN ${STACK})
-		message(AUTHOR_WARNING "STACK deprecated, USE STACK_MAIN instead!")
-	endif()
-
 	foreach(property MAIN STACK_MAIN PRIORITY)
 		if(NOT ${property})
 			set(${property} ${${property}_DEFAULT})
@@ -227,15 +221,18 @@
 	if(${OS} STREQUAL "qurt" )
 		set_property(TARGET ${MODULE} PROPERTY POSITION_INDEPENDENT_CODE TRUE)
 	elseif(${OS} STREQUAL "nuttx" )
-		list(APPEND COMPILE_FLAGS -Wframe-larger-than=${STACK_MAX})
+		target_compile_options(${MODULE} PRIVATE -Wframe-larger-than=${STACK_MAX})
 	endif()

 	if(MAIN)
-		set_target_properties(${MODULE} PROPERTIES
-			COMPILE_DEFINITIONS PX4_MAIN=${MAIN}_app_main)
-		add_definitions(-DMODULE_NAME="${MAIN}")
+		target_compile_definitions(${MODULE} PRIVATE PX4_MAIN=${MAIN}_app_main)
+		target_compile_definitions(${MODULE} PRIVATE MODULE_NAME="${MAIN}")
 	else()
-		add_definitions(-DMODULE_NAME="${MODULE}")
+		target_compile_definitions(${MODULE} PRIVATE MODULE_NAME="${MODULE}")
+	endif()
+
+	if(COMPILE_FLAGS)
+		target_compile_options(${MODULE} PRIVATE ${COMPILE_FLAGS})
 	endif()

 	if(INCLUDES)
@@ -247,7 +244,7 @@
 	endif()

 	# join list variables to get ready to send to compiler
-	foreach(prop LINK_FLAGS COMPILE_FLAGS)
+	foreach(prop LINK_FLAGS)
 		if(${prop})
 			px4_join(OUT ${prop} LIST ${${prop}} GLUE " ")
 		endif()
@@ -259,7 +256,7 @@
 	if(COMPILE_FLAGS AND ${_no_optimization_for_target})
 		px4_strip_optimization(COMPILE_FLAGS ${COMPILE_FLAGS})
 	endif()
-	foreach (prop COMPILE_FLAGS LINK_FLAGS STACK_MAIN MAIN PRIORITY)
+	foreach (prop LINK_FLAGS STACK_MAIN MAIN PRIORITY)
 		if (${prop})
 			set_target_properties(${MODULE} PROPERTIES ${prop} ${${prop}})
 		endif()


make mkldnn install optional so it won't fail if it is not included in build (#1091)

--- cmake/external_mkldnn.cmake
+++ cmake/external_mkldnn.cmake
@@ -110,4 +110,4 @@
     ${EXTERNAL_PROJECTS_ROOT}/mkldnn/lib/libmkldnn${CMAKE_SHARED_LIBRARY_SUFFIX}
     )

-install(DIRECTORY ${EXTERNAL_PROJECTS_ROOT}/mkldnn/lib/ DESTINATION ${NGRAPH_INSTALL_LIB})
+install(DIRECTORY ${EXTERNAL_PROJECTS_ROOT}/mkldnn/lib/ DESTINATION ${NGRAPH_INSTALL_LIB} OPTIONAL)


[CMake] Adjust export_executable_symbols to cope with non-target link libraries

export_executable_symbols looks though the link libraries of the executable in
order to figure out transitive dependencies, but in doing so it assumes that
all link libraries are also targets. This is not true as of r273302, so adjust
it to check if they actually are targets.

git-svn-id: 0ff597fd157e6f4fc38580e8d64ab130330d2411@274546 91177308-0d34-0410-b5e6-96231b3b80d8

--- cmake/modules/AddLLVM.cmake
+++ cmake/modules/AddLLVM.cmake
@@ -695,20 +695,22 @@
     set(link_libs ${new_libs})
     while(NOT "${new_libs}" STREQUAL "")
       foreach(lib ${new_libs})
-        get_target_property(lib_type ${lib} TYPE)
-        if("${lib_type}" STREQUAL "STATIC_LIBRARY")
-          list(APPEND static_libs ${lib})
-        else()
-          list(APPEND other_libs ${lib})
+        if(TARGET ${lib})
+          get_target_property(lib_type ${lib} TYPE)
+          if("${lib_type}" STREQUAL "STATIC_LIBRARY")
+            list(APPEND static_libs ${lib})
+          else()
+            list(APPEND other_libs ${lib})
+          endif()
+          get_target_property(transitive_libs ${lib} INTERFACE_LINK_LIBRARIES)
+          foreach(transitive_lib ${transitive_libs})
+            list(FIND link_libs ${transitive_lib} idx)
+            if(TARGET ${transitive_lib} AND idx EQUAL -1)
+              list(APPEND newer_libs ${transitive_lib})
+              list(APPEND link_libs ${transitive_lib})
+            endif()
+          endforeach(transitive_lib)
         endif()
-        get_target_property(transitive_libs ${lib} INTERFACE_LINK_LIBRARIES)
-        foreach(transitive_lib ${transitive_libs})
-          list(FIND link_libs ${transitive_lib} idx)
-          if(TARGET ${transitive_lib} AND idx EQUAL -1)
-            list(APPEND newer_libs ${transitive_lib})
-            list(APPEND link_libs ${transitive_lib})
-          endif()
-        endforeach(transitive_lib)
       endforeach(lib)
       set(new_libs ${newer_libs})
       set(newer_libs "")


CMAKE_BINARY_DIR may contain spaces

CMAKE_BINARY_DIR may contain spaces

CMAKE_BINARY_DIR may contain spaces, ensure the install command wraps this path in quotes.

--- standard/CombinedInstaller.cmake
+++ standard/CombinedInstaller.cmake
@@ -54,7 +54,7 @@
   if(CMAKE_CONFIGURATION_TYPES)
     default_value(ARG_CONFIGS ${CMAKE_CONFIGURATION_TYPES})
   endif()
-  default_value(ARG_WIXFILE ${CMAKE_BINARY_DIR}/CMakeFiles/standard_WixFile.wxs)
+  default_value(ARG_WIXFILE "${CMAKE_BINARY_DIR}/CMakeFiles/standard_WixFile.wxs")
   default_value(ARG_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.txt")
   default_value(ARG_README "${CMAKE_CURRENT_SOURCE_DIR}/README.md")

@@ -113,13 +113,13 @@
       list(
         APPEND
         CPACK_INSTALL_COMMANDS
-        "${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --config ${ONE_CONFIG}"
+        "${CMAKE_COMMAND} --build \"${CMAKE_BINARY_DIR}\" --config ${ONE_CONFIG}"
         "${CMAKE_COMMAND} -DBUILD_TYPE=${ONE_CONFIG} -P \\\"${SELF}/cmake_package.cmake\\\""
       )
     endforeach()
   else()
     set(CPACK_INSTALL_COMMANDS
-      "${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR}"
+      "${CMAKE_COMMAND} --build \"${CMAKE_BINARY_DIR}\""
       "${CMAKE_COMMAND} -P \\\"${SELF}/cmake_package.cmake\\\""
     )
   endif()


corrected project name

corrected project name

--- opengm.cmake
+++ opengm.cmake
@@ -17,7 +17,7 @@

 message ("Installing ${opengm_NAME} into FlyEM build area: ${BUILDEM_DIR} ...")
-ExternalProject_Add(${ann_NAME}
+ExternalProject_Add(${opengm_NAME}
     PREFIX              ${BUILDEM_DIR}
     URL                 ${opengm_URL}
     # URL_MD5             ${opengm_MD5}


python: eliminate -Wundef warning about NPY_INTERNAL_BUILD

numpy 1.13.0+

--- modules/python/common.cmake
+++ modules/python/common.cmake
@@ -118,6 +118,7 @@
 endif()

 ocv_warnings_disable(CMAKE_CXX_FLAGS -Woverloaded-virtual -Wunused-private-field)
+ocv_warnings_disable(CMAKE_CXX_FLAGS -Wundef) # accurate guard via #pragma doesn't work (C++ preprocessor doesn't handle #pragma)

 if(MSVC AND NOT BUILD_SHARED_LIBS)
   set_target_properties(${the_module} PROPERTIES LINK_FLAGS "/NODEFAULTLIB:atlthunk.lib /NODEFAULTLIB:atlsd.lib /DEBUG")


Perhaps bitness detection is an introspection

http://www.cmake.org/cmake/help/v3.0/command/find_library.html

--- build/cmake_modules/FindCryptoPP.cmake
+++ build/cmake_modules/FindCryptoPP.cmake
@@ -33,14 +33,16 @@
           set(PLATFORM Win32)
       endif()
       find_library(CRYPTO++_LIBRARIES_RELEASE NAMES cryptlib cryptopp
+          HINTS
+          ${PROJECT_SOURCE_DIR}/../../cryptopp/${PLATFORM}/Output/Release
           PATHS
           $ENV{CRYPTOPP}/Win32/Output/Release
-          ${PROJECT_SOURCE_DIR}/../../cryptopp/${PLATFORM}/Output/Release
       )
       find_library(CRYPTO++_LIBRARIES_DEBUG NAMES cryptlib cryptopp
+          HINTS
+          ${PROJECT_SOURCE_DIR}/../../cryptopp/${PLATFORM}/Output/Debug
           PATHS
           $ENV{CRYPTOPP}/Win32/Output/Debug
-          ${PROJECT_SOURCE_DIR}/../../cryptopp/${PLATFORM}/Output/Debug
       )
       set(CRYPTO++_LIBRARIES
           debug ${CRYPTO++_LIBRARIES_DEBUG}


Working on detecting hdf5 from modules

Working on detecting hdf5 from modules

Former-commit-id: b13b4a970afec0f1b14b2440f972bac84c7dd418

--- cmake-modules/Fetch_OpenBLAS.cmake
+++ cmake-modules/Fetch_OpenBLAS.cmake
@@ -193,8 +193,8 @@

 if (TARGET blas)
-    set(BLAS_LIBRARIES   ${OpenBLAS_LIBRARY} ${FC_LDLAGS})
-    set(LAPACK_LIBRARIES ${OpenBLAS_LIBRARY} ${FC_LDLAGS})
+    set(BLAS_LIBRARIES   ${OpenBLAS_LIBRARY})
+    set(LAPACK_LIBRARIES ${OpenBLAS_LIBRARY})
     include(cmake-modules/FindLAPACKE.cmake)
     if(TARGET lapacke)
         target_link_libraries(blas   INTERFACE lapacke)


Delete no longer needed cmake find module

--- cmake/Modules/FindOOMuseCore.cmake
+++ cmake/Modules/FindOOMuseCore.cmake
@@ -1,87 +0,0 @@
-## Copyright 2015 Eric W. Barndollar. All rights reserved.
-##
-## Licensed under the Apache License, Version 2.0 (the "License");
-## you may not use this file except in compliance with the License.
-## You may obtain a copy of the License at
-##
-##     http://www.apache.org/licenses/LICENSE-2.0
-##
-## Unless required by applicable law or agreed to in writing, software
-## distributed under the License is distributed on an "AS IS" BASIS,
-## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-## See the License for the specific language governing permissions and
-## limitations under the License.
-##
-## =============================================================================
-## Usage: Copy this file into your CMake project that uses oomuse-core under
-## cmake/Modules/ subfolders.
-##
-## Set input CMake cache variables using cmake-gui:
-##     OOMUSE_ROOT - Set this file path to the dir below the oomuse-core install
-##                   dir, e.g. C:/cmakeinstall or
-##                   /Users/<your-username>/cmakeinstall
-##     OOMUSE_CRT_LINKAGE - For Windows with the Microsoft Visual C++ compiler,
-##                          set to 'dynamic' or 'static' (without quotes) to
-##                          control C runtime library linkage. These correspond
-##                          to the /MD (or /MDd) and /MT (or /MTd) cl compiler
-##                          flags.
-##
-## In your root CMakeLists.txt, add this line before using oomuse-core:
-##     set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}
-##         "${CMAKE_SOURCE_DIR}/cmake/Modules/")
-##
-## Then find the OOMuseCore package:
-##     find_package(OOMuseCore REQUIRED)
-##
-## Finally, add the include dirs and link against the library for your target:
-##     set_property(TARGET <your-target>
-##         APPEND PROPERTY INCLUDE_DIRECTORIES ${OOMUSECORE_INCLUDE_DIRS})
-##     target_link_libraries(<your-target> ${OOMUSECORE_LIBRARIES})
-
-set(OOMUSE_ROOT "" CACHE FILEPATH
-    "Path of dir below installed oomuse-core, e.g. C:/cmakeinstall")
-set(OOMUSE_CRT_LINKAGE "dynamic" CACHE STRING
-    "'static' or 'dynamic' C runtime library linkage for Visual C++")
-
-
-# Find include directory for oomuse-core headers.
-find_path(OOMUSECORE_INCLUDE_DIR oomuse/core/int_types.h
-    HINTS $ENV{OOMUSE_ROOT}/oomuse-core/include
-          ${OOMUSE_ROOT}/oomuse-core/include)
-mark_as_advanced(OOMUSECORE_INCLUDE_DIR)
-
-
-# Find debug and release libraries for oomuse-core.
-if(MSVC AND (OOMUSE_CRT_LINKAGE STREQUAL "dynamic"))
-  set(oomuse_core_lib_name oomuse-core-md)
-else()
-  set(oomuse_core_lib_name oomuse-core)
-endif()
-
-find_library(OOMUSECORE_LIBRARY
-    NAMES ${oomuse_core_lib_name}
-    HINTS $ENV{OOMUSE_ROOT}/oomuse-core
-          ${OOMUSE_ROOT}/oomuse-core
-    PATH_SUFFIXES lib)
-find_library(OOMUSECORE_LIBRARY_DEBUG
-    NAMES ${oomuse_core_lib_name}-debug
-    HINTS $ENV{OOMUSE_ROOT}/oomuse-core
-          ${OOMUSE_ROOT}/oomuse-core
-    PATH_SUFFIXES lib)
-mark_as_advanced(OOMUSECORE_LIBRARY)
-mark_as_advanced(OOMUSECORE_LIBRARY_DEBUG)
-
-
-# Set OOMUSECORE_FOUND to true if everything above was found.
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(OOMuseCore DEFAULT_MSG
-    OOMUSECORE_INCLUDE_DIR OOMUSECORE_LIBRARY OOMUSECORE_LIBRARY_DEBUG)
-
-
-# Set output variables.
-if(OOMUSECORE_FOUND)
-  set(OOMUSECORE_INCLUDE_DIRS ${OOMUSECORE_INCLUDE_DIR})
-  set(OOMUSECORE_LIBRARIES
-      optimized ${OOMUSECORE_LIBRARY}
-      debug ${OOMUSECORE_LIBRARY_DEBUG})
-endif()


refs #6566 Compiling/configuring no longer changes XZ source files (it changes a copy)
This prevents unnecessarily modified files in svn/git

git-svn-id: b5c078ec0b4d3a50497e9dd3081db18a5b4f16e5@55400 c7de825b-a66e-492c-adef-691d508d4ae1

--- cmake_modules/TokuThirdParty.cmake
+++ cmake_modules/TokuThirdParty.cmake
@@ -51,13 +51,15 @@
   message(FATAL_ERROR "Can't find the xz sources.  Please check them out to ${XZ_SOURCE_DIR} or modify TOKU_SVNROOT (${TOKU_SVNROOT}) or XZ_SOURCE_DIR.")
 endif ()

+FILE(GLOB XZ_ALL_FILES ${XZ_SOURCE_DIR}/*)
 if (CMAKE_GENERATOR STREQUAL Ninja)
   ## ninja doesn't understand "$(MAKE)"
   ExternalProject_Add(build_lzma
     PREFIX xz
-    SOURCE_DIR "${XZ_SOURCE_DIR}"
+    DOWNLOAD_COMMAND
+        cd ${XZ_SOURCE_DIR} && cp -ru "${XZ_ALL_FILES}" "<SOURCE_DIR>/"
     CONFIGURE_COMMAND
-        "${XZ_SOURCE_DIR}/configure" ${xz_configure_opts}
+        "<SOURCE_DIR>/configure" ${xz_configure_opts}
         "--prefix=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/xz"
     BUILD_COMMAND
         make -C src/liblzma
@@ -69,9 +71,10 @@
   ## seem to break Xcode...
   ExternalProject_Add(build_lzma
     PREFIX xz
-    SOURCE_DIR "${XZ_SOURCE_DIR}"
+    DOWNLOAD_COMMAND
+        cd ${XZ_SOURCE_DIR} && cp -ru "${XZ_ALL_FILES}" "<SOURCE_DIR>/"
     CONFIGURE_COMMAND
-        "${XZ_SOURCE_DIR}/configure" ${xz_configure_opts}
+        "<SOURCE_DIR>/configure" ${xz_configure_opts}
         "--prefix=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/xz"
     BUILD_COMMAND
         $(MAKE) -C src/liblzma
@@ -79,6 +82,12 @@
         $(MAKE) -C src/liblzma install
     )
 endif ()
+FILE(GLOB_RECURSE XZ_ALL_FILES_RECURSIVE ${XZ_SOURCE_DIR}/*)
+ExternalProject_Add_Step(build_lzma reclone_src # Names of project and custom step
+    COMMENT "(re)cloning xz source..."     # Text printed when step executes
+    DEPENDERS download configure   # Steps that depend on this step
+    DEPENDS   ${XZ_ALL_FILES_RECURSIVE}   # Files on which this step depends
+)

 set_source_files_properties(
   "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/xz/include/lzma.h"


Use correct configuration for armel (Debian and Tizen)

Before options are mixed up for two platform.
coreclr already seperated them depending on target armel Linux.

Signed-off-by: Hyung-Kyu Choi <b24f6a1d8ab6a697998e8a2c60eb031a02db5070@samsung.com>

--- cross/armel/toolchain.cmake
+++ cross/armel/toolchain.cmake
@@ -4,6 +4,7 @@
 set(CMAKE_SYSTEM_VERSION 1)
 set(CMAKE_SYSTEM_PROCESSOR armv7l)

+# Specify the toolchain
 set(TOOLCHAIN "arm-linux-gnueabi")

 add_compile_options(-target armv7-linux-gnueabi)
@@ -11,6 +12,10 @@
 add_compile_options(-mfpu=vfpv3)
 add_compile_options(-mfloat-abi=softfp)
 add_compile_options(--sysroot=${CROSS_ROOTFS})
+
+set(CROSS_LINK_FLAGS "${CROSS_LINK_FLAGS} -target ${TOOLCHAIN}")
+set(CROSS_LINK_FLAGS "${CROSS_LINK_FLAGS} --sysroot=${CROSS_ROOTFS}")
+
 if("$ENV{__DistroRid}" MATCHES "tizen.*")
     include_directories(SYSTEM ${CROSS_ROOTFS}/usr/lib/gcc/armv7l-tizen-linux-gnueabi/4.9.2/include/c++/ ${CROSS_ROOTFS}/usr/lib/gcc/armv7l-tizen-linux-gnueabi/4.9.2/include/c++/armv7l-tizen-linux-gnueabi)
     add_compile_options(-Wno-deprecated-declarations) # compile-time option
@@ -20,16 +25,14 @@
     set(CROSS_LINK_FLAGS "${CROSS_LINK_FLAGS} -L${CROSS_ROOTFS}/lib")
     set(CROSS_LINK_FLAGS "${CROSS_LINK_FLAGS} -L${CROSS_ROOTFS}/usr/lib")
     set(CROSS_LINK_FLAGS "${CROSS_LINK_FLAGS} -L${CROSS_ROOTFS}/usr/lib/gcc/armv7l-tizen-linux-gnueabi/4.9.2")
+else()
+    # TODO: this setting assumes debian armel rootfs
+    include_directories(SYSTEM ${CROSS_ROOTFS}/usr/include/c++/4.9 ${CROSS_ROOTFS}/usr/include/${TOOLCHAIN}/c++/4.9 )
+    set(CROSS_LINK_FLAGS "${CROSS_LINK_FLAGS} -B${CROSS_ROOTFS}/usr/lib/gcc/${TOOLCHAIN}/4.9")
+    set(CROSS_LINK_FLAGS "${CROSS_LINK_FLAGS} -L${CROSS_ROOTFS}/usr/lib/${TOOLCHAIN}")
+    set(CROSS_LINK_FLAGS "${CROSS_LINK_FLAGS} -L${CROSS_ROOTFS}/lib/${TOOLCHAIN}")
+    set(CROSS_LINK_FLAGS "${CROSS_LINK_FLAGS} -L${CROSS_ROOTFS}/usr/lib/gcc/${TOOLCHAIN}/4.9")
 endif()
-
-# TODO: this setting assumes debian armel rootfs
-include_directories(SYSTEM ${CROSS_ROOTFS}/usr/include/c++/4.9 ${CROSS_ROOTFS}/usr/include/${TOOLCHAIN}/c++/4.9 )
-set(CROSS_LINK_FLAGS "${CROSS_LINK_FLAGS} -target ${TOOLCHAIN}")
-set(CROSS_LINK_FLAGS "${CROSS_LINK_FLAGS} -B${CROSS_ROOTFS}/usr/lib/gcc/${TOOLCHAIN}/4.9")
-set(CROSS_LINK_FLAGS "${CROSS_LINK_FLAGS} -L${CROSS_ROOTFS}/usr/lib/${TOOLCHAIN}")
-set(CROSS_LINK_FLAGS "${CROSS_LINK_FLAGS} -L${CROSS_ROOTFS}/lib/${TOOLCHAIN}")
-set(CROSS_LINK_FLAGS "${CROSS_LINK_FLAGS} -L${CROSS_ROOTFS}/usr/lib/gcc/${TOOLCHAIN}/4.9")
-set(CROSS_LINK_FLAGS "${CROSS_LINK_FLAGS} --sysroot=${CROSS_ROOTFS}")

 set(CMAKE_EXE_LINKER_FLAGS    "${CMAKE_EXE_LINKER_FLAGS}    ${CROSS_LINK_FLAGS}" CACHE STRING "" FORCE)
 set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${CROSS_LINK_FLAGS}" CACHE STRING "" FORCE)


Remove duplicates from list of available versions

--- cmake/modules/hunter_add_version.cmake
+++ cmake/modules/hunter_add_version.cmake
@@ -30,6 +30,10 @@
   # update HUNTER_<name>_VERSIONS (list of available versions)
   set(h_versions "HUNTER_${h_PACKAGE_NAME}_VERSIONS")
   list(APPEND ${h_versions} ${h_VERSION})
+
+  # 'hunter.cmake' may be loaded several times
+  list(REMOVE_DUPLICATES "${h_versions}")
+
   set(${h_versions} ${${h_versions}} PARENT_SCOPE)

   set(expected_version "HUNTER_${h_PACKAGE_NAME}_VERSION")


PostgreSQL: Missing hunter include. Fixed iOS and Android.

--- cmake/projects/PostgreSQL/hunter.cmake
+++ cmake/projects/PostgreSQL/hunter.cmake
@@ -8,6 +8,7 @@
 include(hunter_configuration_types)
 include(hunter_pick_scheme)
 include(hunter_download)
+include(hunter_cmake_args)

 hunter_add_version(
     PACKAGE_NAME


[INTERNAL] Removing unnecessary include paths from CMake scripts.

`external/include` and include paths in the build directory were added.
They are not needed any more and can be removed.

git-svn-id: a7f2a8f7432d210e972fb03898013d213e2b549b@12789 e6417c60-b987-48fd-844e-b20f0fcc1017

--- seqan/util/cmake/FindSeqAn.cmake
+++ seqan/util/cmake/FindSeqAn.cmake
@@ -207,10 +207,9 @@
     file (GLOB HEADERS ${PATH}/seqan/[A-z]*/[A-z]*.h)
     file (GLOB SUPER_HEADERS ${PATH}/seqan/[A-z]*.h)

-    set (SEQAN_INCLUDE_DIR_FOR_${TARGET_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/${REL_PATH} ${CMAKE_CURRENT_BINARY_DIR}/${REL_PATH} CACHE INTERNAL "asdf" FORCE)
+    set (SEQAN_INCLUDE_DIR_FOR_${TARGET_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/${REL_PATH} CACHE INTERNAL "asdf" FORCE)
     # message("SEQAN_INCLUDE_DIR_FOR_${TARGET_NAME} <- ${SEQAN_INCLUDE_DIR_FOR_${TARGET_NAME}}")
     include_directories(${CMAKE_CURRENT_SOURCE_DIR}/${REL_PATH})
-    include_directories(${CMAKE_CURRENT_BINARY_DIR}/${REL_PATH})

     set (SEQAN_LIBRARY_TARGETS ${TARGET_NAME} CACHE INTERNAL "asdf" FORCE)

@@ -396,7 +395,6 @@

 macro (seqan_find_dependencies)
   # Register external include directory.
-  include_directories(${SEQAN_ROOT_SOURCE_DIR}/external/include)

   find_package (ZLIB QUIET)
   if (ZLIB_FOUND)


Fixed build on Linux

Fixed build on Linux

--- src/cmake/core.cmake
+++ src/cmake/core.cmake
@@ -61,30 +61,32 @@
   ${basetypes_files_linux}
 )

-set(icu_ucsdet_files
-  core/basetypes/icu-ucsdet/cmemory.c
-  core/basetypes/icu-ucsdet/csdetect.cpp
-  core/basetypes/icu-ucsdet/csmatch.cpp
-  core/basetypes/icu-ucsdet/csr2022.cpp
-  core/basetypes/icu-ucsdet/csrecog.cpp
-  core/basetypes/icu-ucsdet/csrmbcs.cpp
-  core/basetypes/icu-ucsdet/csrsbcs.cpp
-  core/basetypes/icu-ucsdet/csrucode.cpp
-  core/basetypes/icu-ucsdet/csrutf8.cpp
-  core/basetypes/icu-ucsdet/cstring.c
-  core/basetypes/icu-ucsdet/inputext.cpp
-  core/basetypes/icu-ucsdet/uarrsort.c
-  core/basetypes/icu-ucsdet/ucln_cmn.cpp
-  core/basetypes/icu-ucsdet/ucln_in.cpp
-  core/basetypes/icu-ucsdet/ucsdet.cpp
-  core/basetypes/icu-ucsdet/udataswp.c
-  core/basetypes/icu-ucsdet/uenum.c
-  core/basetypes/icu-ucsdet/uinvchar.c
-  core/basetypes/icu-ucsdet/umutex.cpp
-  core/basetypes/icu-ucsdet/uobject.cpp
-  core/basetypes/icu-ucsdet/ustring.cpp
-  core/basetypes/icu-ucsdet/utrace.c
-)
+IF(APPLE)
+  set(icu_ucsdet_files
+    core/basetypes/icu-ucsdet/cmemory.c
+    core/basetypes/icu-ucsdet/csdetect.cpp
+    core/basetypes/icu-ucsdet/csmatch.cpp
+    core/basetypes/icu-ucsdet/csr2022.cpp
+    core/basetypes/icu-ucsdet/csrecog.cpp
+    core/basetypes/icu-ucsdet/csrmbcs.cpp
+    core/basetypes/icu-ucsdet/csrsbcs.cpp
+    core/basetypes/icu-ucsdet/csrucode.cpp
+    core/basetypes/icu-ucsdet/csrutf8.cpp
+    core/basetypes/icu-ucsdet/cstring.c
+    core/basetypes/icu-ucsdet/inputext.cpp
+    core/basetypes/icu-ucsdet/uarrsort.c
+    core/basetypes/icu-ucsdet/ucln_cmn.cpp
+    core/basetypes/icu-ucsdet/ucln_in.cpp
+    core/basetypes/icu-ucsdet/ucsdet.cpp
+    core/basetypes/icu-ucsdet/udataswp.c
+    core/basetypes/icu-ucsdet/uenum.c
+    core/basetypes/icu-ucsdet/uinvchar.c
+    core/basetypes/icu-ucsdet/umutex.cpp
+    core/basetypes/icu-ucsdet/uobject.cpp
+    core/basetypes/icu-ucsdet/ustring.cpp
+    core/basetypes/icu-ucsdet/utrace.c
+  )
+ENDIF()

 set(imap_files
   core/imap/MCIMAPFolder.cpp
@@ -153,9 +155,7 @@

 set(core_files
   ${basetypes_files}
-IF(APPLE)
   ${icu_ucsdet_files}
-ENDIF()
   ${abstract_files}
   ${imap_files}
   ${pop_files}


Fixed the `VC_MERGE_MODULE_NAME` variable situation

--- Tools/CMake/Config.cmake
+++ Tools/CMake/Config.cmake
@@ -131,16 +131,19 @@
   message(STATUS ${MSVC_TOOLSET_VERSION})
   message(STATUS ${MSVC_VERSION})

-  set(VC_MERGE_MODULE_NAME
-      "Microsoft_VC143_CRT_x64.msm"
-      CACHE STRING "Module Merge Name")
   if(MSVC_VERSION GREATER "1930")
+    set(VC_MERGE_MODULE_NAME
+        "Microsoft_VC143_CRT_x64.msm"
+        CACHE STRING "Module Merge Name")
     set(VC_TOOLS_REDIST_DIR_VARIABLE "%VCINSTALLDIR%")
     set(VC_TOOLS_REDIST_PATH "$ENV{VCINSTALLDIR}")
     set(VC_VARS_PATH_NATIVE
         "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Auxiliary\\Build"
     )
   elseif(MSVC_VERSION GREATER "1920")
+    set(VC_MERGE_MODULE_NAME
+        "Microsoft_VC142_CRT_x64.msm"
+        CACHE STRING "Module Merge Name")
     set(VC_TOOLS_REDIST_DIR_VARIABLE "%VCToolsRedistDir%")
     set(VC_TOOLS_REDIST_PATH "$ENV{VCToolsRedistDir}")
     set(VC_VARS_PATH_NATIVE


on the road to 3.8

on the road to 3.8

--- Numerics/cmake/SiconosVersion.cmake
+++ Numerics/cmake/SiconosVersion.cmake
@@ -1,3 +1,3 @@
 SET(MAJOR_VERSION 3)
-SET(MINOR_VERSION 7)
+SET(MINOR_VERSION 8)
 SET(PATCH_VERSION dev)


SuperBuild: upgrade itk 4.8.1 -> 4.10.0 (works with vs2015)

--- SuperBuild/CMake/External_itk.cmake
+++ SuperBuild/CMake/External_itk.cmake
@@ -132,13 +132,14 @@
   )

 #later used below for _SB_ITK_DIR and then in packaging
-set(ITK_SB_VERSION 4.8)
-set(ITK_SB_VERSION_FULL ${ITK_SB_VERSION}.1)
+set(ITK_SB_VERSION 4.10)
+set(ITK_SB_VERSION_FULL ${ITK_SB_VERSION}.0)
+set(_SB_ITK_DIR ${SB_INSTALL_PREFIX}/lib/cmake/ITK-${ITK_SB_VERSION})

 ExternalProject_Add(ITK
   PREFIX ITK
-  URL "http://sourceforge.net/projects/itk/files/itk/4.8/InsightToolkit-4.8.1.tar.gz/download"
-  URL_MD5 b1ed53604de854501cb61f34f410420e
+  URL "https://sourceforge.net/projects/itk/files/itk/4.10/InsightToolkit-4.10.0.tar.xz"
+  URL_MD5 15beb120e580ce85117496795746e628
   SOURCE_DIR ${ITK_SB_SRC}
   BINARY_DIR ${ITK_SB_BUILD_DIR}
   INSTALL_DIR ${SB_INSTALL_PREFIX}
@@ -161,6 +162,3 @@
   )

 SUPERBUILD_PATCH_SOURCE(ITK)
-
-
-set(_SB_ITK_DIR ${SB_INSTALL_PREFIX}/lib/cmake/ITK-${ITK_SB_VERSION})


BUG: Fix to check for empty additions to CMAKE_CXX_FLAGS.

--- itkCMakeOptions.cmake
+++ itkCMakeOptions.cmake
@@ -42,16 +42,16 @@
 ENDIF(CMAKE_COMPILER_IS_GNUCXX)

 # force the use of ansi cxx flags (i.e. -LANG:std on sgi )
-IF (CMAKE_ANSI_CXXFLAGS MATCHES "[^ ]")
+IF("x${CMAKE_ANSI_CXXFLAGS}" MATCHES "^x.*[^ ]")
   SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_ANSI_CXXFLAGS}")
-ENDIF (CMAKE_ANSI_CXXFLAGS MATCHES "[^ ]")
-IF (CMAKE_ANSI_CFLAGS MATCHES "[^ ]")
+ENDIF("x${CMAKE_ANSI_CXXFLAGS}" MATCHES "^x.*[^ ]")
+IF("x${CMAKE_ANSI_CFLAGS}" MATCHES "^x.*[^ ]")
   SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CMAKE_ANSI_CFLAGS}")
-ENDIF (CMAKE_ANSI_CFLAGS MATCHES "[^ ]")
+ENDIF("x${CMAKE_ANSI_CFLAGS}" MATCHES "^x.*[^ ]")

-IF(CMAKE_TEMPLATE_FLAGS MATCHES "[^ ]")
+IF("x${CMAKE_TEMPLATE_FLAGS}" MATCHES "^x.*[^ ]")
   SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_TEMPLATE_FLAGS}")
-ENDIF(CMAKE_TEMPLATE_FLAGS MATCHES "[^ ]")
+ENDIF("x${CMAKE_TEMPLATE_FLAGS}" MATCHES "^x.*[^ ]")

 IF(CMAKE_USE_PTHREADS)
     ADD_DEFINITIONS(-D_PTHREADS)


new CUDA arch

new CUDA arch

--- caffe/cmake/Cuda.cmake
+++ caffe/cmake/Cuda.cmake
@@ -4,7 +4,7 @@

 # Known NVIDIA GPU achitectures Caffe can be compiled for.
 # This list will be used for CUDA_ARCH_NAME = All option
-set(Caffe_known_gpu_archs "35 50 60 61 70 75")
+set(Caffe_known_gpu_archs "35 50 60 61 70 75 80 86")

 ################################################################################################
 # A function for automatic detection of GPUs installed  (if autodetection is enabled)


fix debug packages for redhat

fix debug packages for redhat

--- build/rpm/flexisip.spec.cmake
+++ build/rpm/flexisip.spec.cmake
@@ -109,6 +109,8 @@

 %prep
 %setup -n %{name}-%{version}-%build_number
+
+%flex_debug

 %build
 %{expand:%%%cmake_name} . -DCMAKE_INSTALL_LIBDIR:PATH=%{_libdir} -DCMAKE_PREFIX_PATH:PATH=%{_prefix} \


Well, no. We don't support libnetcdf_c++4. Major porting required

git-svn-id: 31d9d2f6432a47c86a3640814024c107794ea77c@29116 0785d39b-7218-0410-832d-ea1e28bc413d

--- deal.II/cmake/modules/FindNETCDF.cmake
+++ deal.II/cmake/modules/FindNETCDF.cmake
@@ -25,7 +25,7 @@

 SET_IF_EMPTY(NETCDF_DIR "$ENV{NETCDF_DIR}")

-FIND_PATH(NETCDF_INCLUDE_DIR netcdf.hh
+FIND_PATH(NETCDF_INCLUDE_DIR netcdfcpp.h
   HINTS
     ${NETCDF_DIR}
   PATH_SUFFIXES
@@ -39,7 +39,7 @@
 # - separate C++ and C library search
 #

-FIND_LIBRARY(NETCDF_CPLUSPLUS_LIBRARY NAMES netcdf_c++ netcdf_cpp netcdf_c++4
+FIND_LIBRARY(NETCDF_CPLUSPLUS_LIBRARY NAMES netcdf_c++ netcdf_cpp
   HINTS
     ${NETCDF_DIR}
   PATH_SUFFIXES