Switch to imported SuiteSparse, CXSparse, and METIS targets

These changes allow the use of a SuiteSparse CMake package from
https://github.com/sergiud/SuiteSparse that allows native compilation of
SuiteSparse using CMake on a variety of platforms Packages generated
using official SuiteSparse makefiles can still be used without
modifications. The find module remains agnostic to specific CMake
package implementation.

CMake packages have the advantage that they are self-contained and
relocatable. The latter is particularly useful in cross-compilation
scenarios.

Fixes #728

Change-Id: I089d5c6f87c05b1530a5ab9a36dff2fcbe82d13d
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4fac3ba..7f88fb4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -257,40 +257,35 @@
   list(APPEND CERES_COMPILE_OPTIONS CERES_NO_LAPACK)
 endif (LAPACK)
 
+# Set the install path for the installed CeresConfig.cmake configuration file
+# relative to CMAKE_INSTALL_PREFIX.
+set(RELATIVE_CMAKECONFIG_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/Ceres)
+
 if (SUITESPARSE)
   # By default, if SuiteSparse and all dependencies are found, Ceres is
   # built with SuiteSparse support.
 
   # Check for SuiteSparse and dependencies.
-  find_package(SuiteSparse)
-  if (SUITESPARSE_FOUND)
-    # On Ubuntu the system install of SuiteSparse (v3.4.0) up to at least
-    # Ubuntu 13.10 cannot be used to link shared libraries.
-    if (BUILD_SHARED_LIBS AND
-        SUITESPARSE_IS_BROKEN_SHARED_LINKING_UBUNTU_SYSTEM_VERSION)
-      message(FATAL_ERROR "You are attempting to build Ceres as a shared "
-        "library on Ubuntu using a system package install of SuiteSparse "
-        "3.4.0. This package is broken and does not support the "
-        "construction of shared libraries (you can still build Ceres as "
-        "a static library).  If you wish to build a shared version of Ceres "
-        "you should uninstall the system install of SuiteSparse "
-        "(libsuitesparse-dev) and perform a source install of SuiteSparse "
-        "(we recommend that you use the latest version), "
-        "see http://ceres-solver.org/building.html for more information.")
-    endif (BUILD_SHARED_LIBS AND
-      SUITESPARSE_IS_BROKEN_SHARED_LINKING_UBUNTU_SYSTEM_VERSION)
-
+  find_package(SuiteSparse 4.0 COMPONENTS CHOLMOD SPQR)
+  if (SuiteSparse_FOUND)
+    set(SuiteSparse_DEPENDENCY "find_dependency(SuiteSparse ${SuiteSparse_VERSION})")
     # By default, if all of SuiteSparse's dependencies are found, Ceres is
     # built with SuiteSparse support.
-    message("-- Found SuiteSparse ${SUITESPARSE_VERSION}, "
+    message("-- Found SuiteSparse ${SuiteSparse_VERSION}, "
             "building with SuiteSparse.")
-  else (SUITESPARSE_FOUND)
+
+    if (SuiteSparse_NO_CMAKE OR NOT SuiteSparse_DIR)
+      install(FILES ${Ceres_SOURCE_DIR}/cmake/FindSuiteSparse.cmake
+                    ${Ceres_SOURCE_DIR}/cmake/FindMETIS.cmake
+              DESTINATION ${RELATIVE_CMAKECONFIG_INSTALL_DIR})
+    endif (SuiteSparse_NO_CMAKE OR NOT SuiteSparse_DIR)
+  else (SuiteSparse_FOUND)
     # Disable use of SuiteSparse if it cannot be found and continue.
     message("-- Did not find all SuiteSparse dependencies, disabling "
       "SuiteSparse support.")
     update_cache_variable(SUITESPARSE OFF)
     list(APPEND CERES_COMPILE_OPTIONS CERES_NO_SUITESPARSE)
-  endif (SUITESPARSE_FOUND)
+  endif (SuiteSparse_FOUND)
 else (SUITESPARSE)
   message("-- Building without SuiteSparse.")
   list(APPEND CERES_COMPILE_OPTIONS CERES_NO_SUITESPARSE)
@@ -300,26 +295,26 @@
 if (CXSPARSE)
   # Don't search with REQUIRED as we can continue without CXSparse.
   find_package(CXSparse)
-  if (CXSPARSE_FOUND)
+  if (CXSparse_FOUND)
+    set(CXSparse_DEPENDENCY "find_dependency(CXSparse ${CXSparse_VERSION})")
     # By default, if CXSparse and all dependencies are found, Ceres is
     # built with CXSparse support.
-    message("-- Found CXSparse version: ${CXSPARSE_VERSION}, "
+    message("-- Found CXSparse version: ${CXSparse_VERSION}, "
       "building with CXSparse.")
-  else (CXSPARSE_FOUND)
+
+    if (CXSparse_NO_CMAKE OR NOT CXSparse_DIR)
+      install(FILES ${Ceres_SOURCE_DIR}/cmake/FindCXSparse.cmake
+              DESTINATION ${RELATIVE_CMAKECONFIG_INSTALL_DIR})
+    endif (CXSparse_NO_CMAKE OR NOT CXSparse_DIR)
+  else (CXSparse_FOUND)
     # Disable use of CXSparse if it cannot be found and continue.
     message("-- Did not find CXSparse, Building without CXSparse.")
     update_cache_variable(CXSPARSE OFF)
     list(APPEND CERES_COMPILE_OPTIONS CERES_NO_CXSPARSE)
-  endif (CXSPARSE_FOUND)
+  endif (CXSparse_FOUND)
 else (CXSPARSE)
   message("-- Building without CXSparse.")
   list(APPEND CERES_COMPILE_OPTIONS CERES_NO_CXSPARSE)
-  # Mark as advanced (remove from default GUI view) the CXSparse search
-  # variables in case user enabled CXSPARSE, FindCXSparse did not find it, so
-  # made search variables visible in GUI for user to set, but then user disables
-  # CXSPARSE instead of setting them.
-  mark_as_advanced(FORCE CXSPARSE_INCLUDE_DIR
-                         CXSPARSE_LIBRARY)
 endif (CXSPARSE)
 
 if (ACCELERATESPARSE)
@@ -712,10 +707,6 @@
 
 # Install method #1: Put Ceres in CMAKE_INSTALL_PREFIX: /usr/local or equivalent.
 
-# Set the install path for the installed CeresConfig.cmake configuration file
-# relative to CMAKE_INSTALL_PREFIX.
-set(RELATIVE_CMAKECONFIG_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/Ceres)
-
 # This "exports" for installation all targets which have been put into the
 # export set "CeresExport". This generates a CeresTargets.cmake file which,
 # when read in by a client project as part of find_package(Ceres) creates
diff --git a/cmake/CeresConfig.cmake.in b/cmake/CeresConfig.cmake.in
index 907646f..4745483 100644
--- a/cmake/CeresConfig.cmake.in
+++ b/cmake/CeresConfig.cmake.in
@@ -173,11 +173,15 @@
 endif(CERES_WAS_INSTALLED)
 
 # Set the version.
-set(CERES_VERSION @CERES_VERSION@ )
+set(CERES_VERSION @CERES_VERSION@)
 
 include(CMakeFindDependencyMacro)
 find_dependency(Threads)
 
+# Optional dependencies
+@CXSparse_DEPENDENCY@
+@SuiteSparse_DEPENDENCY@
+
 # As imported CMake targets are not re-exported when a dependent target is
 # exported, we must invoke find_package(XXX) here to reload the definition
 # of their targets.  Without this, the dependency target names (e.g.
diff --git a/cmake/FindCXSparse.cmake b/cmake/FindCXSparse.cmake
index 8b380c9..94a56b3 100644
--- a/cmake/FindCXSparse.cmake
+++ b/cmake/FindCXSparse.cmake
@@ -1,5 +1,5 @@
 # Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2015 Google Inc. All rights reserved.
+# Copyright 2022 Google Inc. All rights reserved.
 # http://ceres-solver.org/
 #
 # Redistribution and use in source and binary forms, with or without
@@ -29,63 +29,86 @@
 # Author: alexs.mac@gmail.com (Alex Stewart)
 #
 
-# FindCXSparse.cmake - Find CXSparse libraries & dependencies.
-#
-# This module defines the following variables which should be referenced
-# by the caller to use the library.
-#
-# CXSPARSE_FOUND: TRUE iff CXSparse and all dependencies have been found.
-# CXSPARSE_INCLUDE_DIRS: Include directories for CXSparse.
-# CXSPARSE_LIBRARIES: Libraries for CXSparse and all dependencies.
-#
-# CXSPARSE_VERSION: Extracted from cs.h.
-# CXSPARSE_MAIN_VERSION: Equal to 3 if CXSPARSE_VERSION = 3.1.2
-# CXSPARSE_SUB_VERSION: Equal to 1 if CXSPARSE_VERSION = 3.1.2
-# CXSPARSE_SUBSUB_VERSION: Equal to 2 if CXSPARSE_VERSION = 3.1.2
-#
-# The following variables control the behaviour of this module:
-#
-# CXSPARSE_INCLUDE_DIR_HINTS: List of additional directories in which to
-#                             search for CXSparse includes,
-#                             e.g: /timbuktu/include.
-# CXSPARSE_LIBRARY_DIR_HINTS: List of additional directories in which to
-#                             search for CXSparse libraries, e.g: /timbuktu/lib.
-#
-# The following variables are also defined by this module, but in line with
-# CMake recommended FindPackage() module style should NOT be referenced directly
-# by callers (use the plural variables detailed above instead).  These variables
-# do however affect the behaviour of the module via FIND_[PATH/LIBRARY]() which
-# are NOT re-called (i.e. search for library is not repeated) if these variables
-# are set with valid values _in the CMake cache_. This means that if these
-# variables are set directly in the cache, either by the user in the CMake GUI,
-# or by the user passing -DVAR=VALUE directives to CMake when called (which
-# explicitly defines a cache variable), then they will be used verbatim,
-# bypassing the HINTS variables and other hard-coded search locations.
-#
-# CXSPARSE_INCLUDE_DIR: Include directory for CXSparse, not including the
-#                       include directory of any dependencies.
-# CXSPARSE_LIBRARY: CXSparse library, not including the libraries of any
-#                   dependencies.
+#[=======================================================================[.rst:
+FindCXSparse
+============
+
+Find CXSparse and its dependencies.
+
+This module defines the following variables which should be referenced by the
+caller to use the library.
+
+``CXSparse_FOUND``
+    ``TRUE`` iff CXSparse and all dependencies have been found.
+
+``CXSparse_VERSION``
+    Extracted from ``cs.h``.
+
+``CXSparse_VERSION_MAJOR``
+    Equal to 3 if ``CXSparse_VERSION`` = 3.1.2
+
+``CXSparse_VERSION_MINOR``
+    Equal to 1 if ``CXSparse_VERSION`` = 3.1.2
+
+``CXSparse_VERSION_PATCH``
+    Equal to 2 if ``CXSparse_VERSION`` = 3.1.2
+
+The following variables control the behaviour of this module:
+
+``CXSparse_NO_CMAKE``
+  Do not attempt to use the native CXSparse CMake package configuration.
+
+Targets
+-------
+
+The following target defines CXSparse.
+
+``CXSparse::CXSparse``
+    The main CXSparse to be linked against.
+
+The following variables are also defined by this module, but in line with CMake
+recommended ``find_package`` module style should NOT be referenced directly by
+callers (use the plural variables detailed above instead).  These variables do
+however affect the behaviour of the module via ``find_[path/library]()`` which
+are NOT re-called (i.e., search for library is not repeated) if these variables
+are set with valid values *in the CMake cache*. This means that if these
+variables are set directly in the cache, either by the user in the CMake GUI, or
+by the user passing ``-DVAR=VALUE`` directives to CMake when called (which
+explicitly defines a cache variable), then they will be used verbatim, bypassing
+the ``HINTS`` variables and other hard-coded search locations.
+
+``CXSparse_INCLUDE_DIR``
+    Include directory for CXSparse, not including the include directory of any
+    dependencies.
+
+``CXSparse_LIBRARY``
+    CXSparse library, not including the libraries of any dependencies.
+]=======================================================================]
+
+if (NOT CXSparse_NO_CMAKE)
+  find_package (CXSparse NO_MODULE QUIET)
+endif (NOT CXSparse_NO_CMAKE)
+
+if (CXSparse_FOUND)
+  return ()
+endif (CXSparse_FOUND)
 
 # Reset CALLERS_CMAKE_FIND_LIBRARY_PREFIXES to its value when
 # FindCXSparse was invoked.
-macro(CXSPARSE_RESET_FIND_LIBRARY_PREFIX)
+macro(CXSparse_RESET_FIND_LIBRARY_PREFIX)
   if (MSVC)
     set(CMAKE_FIND_LIBRARY_PREFIXES "${CALLERS_CMAKE_FIND_LIBRARY_PREFIXES}")
   endif (MSVC)
-endmacro(CXSPARSE_RESET_FIND_LIBRARY_PREFIX)
+endmacro(CXSparse_RESET_FIND_LIBRARY_PREFIX)
 
 # Called if we failed to find CXSparse or any of it's required dependencies,
 # unsets all public (designed to be used externally) variables and reports
 # error message at priority depending upon [REQUIRED/QUIET/<NONE>] argument.
-macro(CXSPARSE_REPORT_NOT_FOUND REASON_MSG)
-  unset(CXSPARSE_FOUND)
-  unset(CXSPARSE_INCLUDE_DIRS)
-  unset(CXSPARSE_LIBRARIES)
+macro(CXSparse_REPORT_NOT_FOUND REASON_MSG)
   # Make results of search visible in the CMake GUI if CXSparse has not
   # been found so that user does not have to toggle to advanced view.
-  mark_as_advanced(CLEAR CXSPARSE_INCLUDE_DIR
-                         CXSPARSE_LIBRARY)
+  mark_as_advanced(CLEAR CXSparse_INCLUDE_DIR
+                         CXSparse_LIBRARY)
 
   cxsparse_reset_find_library_prefix()
 
@@ -101,16 +124,10 @@
     message("-- Failed to find CXSparse - " ${REASON_MSG} ${ARGN})
   endif ()
   return()
-endmacro(CXSPARSE_REPORT_NOT_FOUND)
-
-# Protect against any alternative find_package scripts for this library having
-# been called previously (in a client project) which set CXSPARSE_FOUND, but not
-# the other variables we require / set here which could cause the search logic
-# here to fail.
-unset(CXSPARSE_FOUND)
+endmacro(CXSparse_REPORT_NOT_FOUND)
 
 # Handle possible presence of lib prefix for libraries on MSVC, see
-# also CXSPARSE_RESET_FIND_LIBRARY_PREFIX().
+# also CXSparse_RESET_FIND_LIBRARY_PREFIX().
 if (MSVC)
   # Preserve the caller's original values for CMAKE_FIND_LIBRARY_PREFIXES
   # s/t we can set it back before returning.
@@ -120,142 +137,104 @@
   set(CMAKE_FIND_LIBRARY_PREFIXES "lib" "" "${CMAKE_FIND_LIBRARY_PREFIXES}")
 endif (MSVC)
 
-# On macOS, add the Homebrew prefix (with appropriate suffixes) to the
-# respective HINTS directories (after any user-specified locations).  This
-# handles Homebrew installations into non-standard locations (not /usr/local).
-# We do not use CMAKE_PREFIX_PATH for this as given the search ordering of
-# find_xxx(), doing so would override any user-specified HINTS locations with
-# the Homebrew version if it exists.
-if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
-  find_program(HOMEBREW_EXECUTABLE brew)
-  mark_as_advanced(FORCE HOMEBREW_EXECUTABLE)
-  if (HOMEBREW_EXECUTABLE)
-    # Detected a Homebrew install, query for its install prefix.
-    execute_process(COMMAND ${HOMEBREW_EXECUTABLE} --prefix
-      OUTPUT_VARIABLE HOMEBREW_INSTALL_PREFIX
-      OUTPUT_STRIP_TRAILING_WHITESPACE)
-    message(STATUS "Detected Homebrew with install prefix: "
-      "${HOMEBREW_INSTALL_PREFIX}, adding to CMake search paths.")
-    list(APPEND CXSPARSE_INCLUDE_DIR_HINTS "${HOMEBREW_INSTALL_PREFIX}/include")
-    list(APPEND CXSPARSE_LIBRARY_DIR_HINTS "${HOMEBREW_INSTALL_PREFIX}/lib")
-  endif()
-endif()
-
-# Search user-installed locations first, so that we prefer user installs
-# to system installs where both exist.
-#
-# TODO: Add standard Windows search locations for CXSparse.
-list(APPEND CXSPARSE_CHECK_INCLUDE_DIRS
-  /usr/local/include
-  /usr/local/homebrew/include # Mac OS X
-  /opt/local/var/macports/software # Mac OS X.
-  /opt/local/include
-  /usr/include)
-list(APPEND CXSPARSE_CHECK_LIBRARY_DIRS
-  /usr/local/lib
-  /usr/local/homebrew/lib # Mac OS X.
-  /opt/local/lib
-  /usr/lib)
 # Additional suffixes to try appending to each search path.
-list(APPEND CXSPARSE_CHECK_PATH_SUFFIXES
+list(APPEND CXSparse_CHECK_PATH_SUFFIXES
   suitesparse) # Linux/Windows
 
 # Search supplied hint directories first if supplied.
-find_path(CXSPARSE_INCLUDE_DIR
+find_path(CXSparse_INCLUDE_DIR
   NAMES cs.h
-  HINTS ${CXSPARSE_INCLUDE_DIR_HINTS}
-  PATHS ${CXSPARSE_CHECK_INCLUDE_DIRS}
-  PATH_SUFFIXES ${CXSPARSE_CHECK_PATH_SUFFIXES})
-if (NOT CXSPARSE_INCLUDE_DIR OR
-    NOT EXISTS ${CXSPARSE_INCLUDE_DIR})
+  PATH_SUFFIXES ${CXSparse_CHECK_PATH_SUFFIXES})
+if (NOT CXSparse_INCLUDE_DIR OR
+    NOT EXISTS ${CXSparse_INCLUDE_DIR})
   cxsparse_report_not_found(
-    "Could not find CXSparse include directory, set CXSPARSE_INCLUDE_DIR "
+    "Could not find CXSparse include directory, set CXSparse_INCLUDE_DIR "
     "to directory containing cs.h")
-endif (NOT CXSPARSE_INCLUDE_DIR OR
-       NOT EXISTS ${CXSPARSE_INCLUDE_DIR})
+endif (NOT CXSparse_INCLUDE_DIR OR
+       NOT EXISTS ${CXSparse_INCLUDE_DIR})
 
-find_library(CXSPARSE_LIBRARY NAMES cxsparse
-  HINTS ${CXSPARSE_LIBRARY_DIR_HINTS}
-  PATHS ${CXSPARSE_CHECK_LIBRARY_DIRS}
-  PATH_SUFFIXES ${CXSPARSE_CHECK_PATH_SUFFIXES})
-if (NOT CXSPARSE_LIBRARY OR
-    NOT EXISTS ${CXSPARSE_LIBRARY})
+find_library(CXSparse_LIBRARY NAMES cxsparse
+  PATH_SUFFIXES ${CXSparse_CHECK_PATH_SUFFIXES})
+
+if (NOT CXSparse_LIBRARY OR
+    NOT EXISTS ${CXSparse_LIBRARY})
   cxsparse_report_not_found(
-    "Could not find CXSparse library, set CXSPARSE_LIBRARY "
+    "Could not find CXSparse library, set CXSparse_LIBRARY "
     "to full path to libcxsparse.")
-endif (NOT CXSPARSE_LIBRARY OR
-       NOT EXISTS ${CXSPARSE_LIBRARY})
+endif (NOT CXSparse_LIBRARY OR
+       NOT EXISTS ${CXSparse_LIBRARY})
 
-# Mark internally as found, then verify. CXSPARSE_REPORT_NOT_FOUND() unsets
+# Mark internally as found, then verify. CXSparse_REPORT_NOT_FOUND() unsets
 # if called.
-set(CXSPARSE_FOUND TRUE)
+set(CXSparse_FOUND TRUE)
 
 # Extract CXSparse version from cs.h
-if (CXSPARSE_INCLUDE_DIR)
-  set(CXSPARSE_VERSION_FILE ${CXSPARSE_INCLUDE_DIR}/cs.h)
-  if (NOT EXISTS ${CXSPARSE_VERSION_FILE})
+if (CXSparse_INCLUDE_DIR)
+  set(CXSparse_VERSION_FILE ${CXSparse_INCLUDE_DIR}/cs.h)
+  if (NOT EXISTS ${CXSparse_VERSION_FILE})
     cxsparse_report_not_found(
-      "Could not find file: ${CXSPARSE_VERSION_FILE} "
+      "Could not find file: ${CXSparse_VERSION_FILE} "
       "containing version information in CXSparse install located at: "
-      "${CXSPARSE_INCLUDE_DIR}.")
-  else (NOT EXISTS ${CXSPARSE_VERSION_FILE})
-    file(READ ${CXSPARSE_INCLUDE_DIR}/cs.h CXSPARSE_VERSION_FILE_CONTENTS)
+      "${CXSparse_INCLUDE_DIR}.")
+  else (NOT EXISTS ${CXSparse_VERSION_FILE})
+    file(READ ${CXSparse_INCLUDE_DIR}/cs.h CXSparse_VERSION_FILE_CONTENTS)
 
     string(REGEX MATCH "#define CS_VER [0-9]+"
-      CXSPARSE_MAIN_VERSION "${CXSPARSE_VERSION_FILE_CONTENTS}")
+      CXSparse_VERSION_MAJOR "${CXSparse_VERSION_FILE_CONTENTS}")
     string(REGEX REPLACE "#define CS_VER ([0-9]+)" "\\1"
-      CXSPARSE_MAIN_VERSION "${CXSPARSE_MAIN_VERSION}")
+      CXSparse_VERSION_MAJOR "${CXSparse_VERSION_MAJOR}")
 
     string(REGEX MATCH "#define CS_SUBVER [0-9]+"
-      CXSPARSE_SUB_VERSION "${CXSPARSE_VERSION_FILE_CONTENTS}")
+      CXSparse_VERSION_MINOR "${CXSparse_VERSION_FILE_CONTENTS}")
     string(REGEX REPLACE "#define CS_SUBVER ([0-9]+)" "\\1"
-      CXSPARSE_SUB_VERSION "${CXSPARSE_SUB_VERSION}")
+      CXSparse_VERSION_MINOR "${CXSparse_VERSION_MINOR}")
 
     string(REGEX MATCH "#define CS_SUBSUB [0-9]+"
-      CXSPARSE_SUBSUB_VERSION "${CXSPARSE_VERSION_FILE_CONTENTS}")
+      CXSparse_VERSION_PATCH "${CXSparse_VERSION_FILE_CONTENTS}")
     string(REGEX REPLACE "#define CS_SUBSUB ([0-9]+)" "\\1"
-      CXSPARSE_SUBSUB_VERSION "${CXSPARSE_SUBSUB_VERSION}")
+      CXSparse_VERSION_PATCH "${CXSparse_VERSION_PATCH}")
 
     # This is on a single line s/t CMake does not interpret it as a list of
     # elements and insert ';' separators which would result in 3.;1.;2 nonsense.
-    set(CXSPARSE_VERSION "${CXSPARSE_MAIN_VERSION}.${CXSPARSE_SUB_VERSION}.${CXSPARSE_SUBSUB_VERSION}")
-  endif (NOT EXISTS ${CXSPARSE_VERSION_FILE})
-endif (CXSPARSE_INCLUDE_DIR)
+    set(CXSparse_VERSION "${CXSparse_VERSION_MAJOR}.${CXSparse_VERSION_MINOR}.${CXSparse_VERSION_PATCH}")
+    set(CXSparse_VERSION_COMPONENTS 3)
+  endif (NOT EXISTS ${CXSparse_VERSION_FILE})
+endif (CXSparse_INCLUDE_DIR)
 
-# Catch the case when the caller has set CXSPARSE_LIBRARY in the cache / GUI and
+# Catch the case when the caller has set CXSparse_LIBRARY in the cache / GUI and
 # thus FIND_LIBRARY was not called, but specified library is invalid, otherwise
 # we would report CXSparse as found.
 # TODO: This regex for CXSparse library is pretty primitive, we use lowercase
 #       for comparison to handle Windows using CamelCase library names, could
 #       this check be better?
-string(TOLOWER "${CXSPARSE_LIBRARY}" LOWERCASE_CXSPARSE_LIBRARY)
-if (CXSPARSE_LIBRARY AND
-    EXISTS ${CXSPARSE_LIBRARY} AND
-    NOT "${LOWERCASE_CXSPARSE_LIBRARY}" MATCHES ".*cxsparse[^/]*")
+string(TOLOWER "${CXSparse_LIBRARY}" LOWERCASE_CXSparse_LIBRARY)
+if (CXSparse_LIBRARY AND
+    EXISTS ${CXSparse_LIBRARY} AND
+    NOT "${LOWERCASE_CXSparse_LIBRARY}" MATCHES ".*cxsparse[^/]*")
   cxsparse_report_not_found(
-    "Caller defined CXSPARSE_LIBRARY: "
-    "${CXSPARSE_LIBRARY} does not match CXSparse.")
-endif (CXSPARSE_LIBRARY AND
-       EXISTS ${CXSPARSE_LIBRARY} AND
-       NOT "${LOWERCASE_CXSPARSE_LIBRARY}" MATCHES ".*cxsparse[^/]*")
-
-# Set standard CMake FindPackage variables if found.
-if (CXSPARSE_FOUND)
-  set(CXSPARSE_INCLUDE_DIRS ${CXSPARSE_INCLUDE_DIR})
-  set(CXSPARSE_LIBRARIES ${CXSPARSE_LIBRARY})
-endif (CXSPARSE_FOUND)
+    "Caller defined CXSparse_LIBRARY: "
+    "${CXSparse_LIBRARY} does not match CXSparse.")
+endif (CXSparse_LIBRARY AND
+       EXISTS ${CXSparse_LIBRARY} AND
+       NOT "${LOWERCASE_CXSparse_LIBRARY}" MATCHES ".*cxsparse[^/]*")
 
 cxsparse_reset_find_library_prefix()
 
+mark_as_advanced(CXSparse_INCLUDE_DIR CXSparse_LIBRARY)
+
 # Handle REQUIRED / QUIET optional arguments and version.
 include(FindPackageHandleStandardArgs)
 find_package_handle_standard_args(CXSparse
-  REQUIRED_VARS CXSPARSE_INCLUDE_DIRS CXSPARSE_LIBRARIES
-  VERSION_VAR CXSPARSE_VERSION)
+  REQUIRED_VARS CXSparse_INCLUDE_DIR CXSparse_LIBRARY
+  VERSION_VAR CXSparse_VERSION)
 
-# Only mark internal variables as advanced if we found CXSparse, otherwise
-# leave them visible in the standard GUI for the user to set manually.
-if (CXSPARSE_FOUND)
-  mark_as_advanced(FORCE CXSPARSE_INCLUDE_DIR
-                         CXSPARSE_LIBRARY)
-endif (CXSPARSE_FOUND)
+if (CXSparse_FOUND)
+  if (NOT TARGET CXSparse::CXSparse)
+    add_library (CXSparse::CXSparse IMPORTED UNKNOWN)
+  endif (NOT TARGET CXSparse::CXSparse)
+
+  set_property (TARGET CXSparse::CXSparse PROPERTY
+    IMPORTED_LOCATION ${CXSparse_LIBRARY})
+  set_property (TARGET CXSparse::CXSparse PROPERTY
+    INTERFACE_INCLUDE_DIRECTORIES ${CXSparse_INCLUDE_DIR})
+endif (CXSparse_FOUND)
diff --git a/cmake/FindMETIS.cmake b/cmake/FindMETIS.cmake
new file mode 100644
index 0000000..5f41792
--- /dev/null
+++ b/cmake/FindMETIS.cmake
@@ -0,0 +1,110 @@
+#
+# Copyright (c) 2022 Sergiu Deitsch
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTMETISLAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+#[=======================================================================[.rst:
+Module for locating METIS
+=========================
+
+Read-only variables:
+
+``METIS_FOUND``
+  Indicates whether the library has been found.
+
+``METIS_VERSION``
+  Indicates library version.
+
+Targets
+-------
+
+``METIS::METIS``
+  Specifies targets that should be passed to target_link_libararies.
+]=======================================================================]
+
+include (FindPackageHandleStandardArgs)
+
+find_path (METIS_INCLUDE_DIR NAMES metis.h
+  PATH_SUFFIXES include
+  DOC "METIS include directory")
+find_library (METIS_LIBRARY_DEBUG NAMES metis
+  PATH_SUFFIXES Debug
+  DOC "METIS debug library")
+find_library (METIS_LIBRARY_RELEASE NAMES metis
+  PATH_SUFFIXES Release
+  DOC "METIS release library")
+
+if (METIS_LIBRARY_RELEASE)
+  if (METIS_LIBRARY_DEBUG)
+    set (METIS_LIBRARY debug ${METIS_LIBRARY_DEBUG} optimized
+      ${METIS_LIBRARY_RELEASE} CACHE STRING "METIS library")
+  else (METIS_LIBRARY_DEBUG)
+    set (METIS_LIBRARY ${METIS_LIBRARY_RELEASE} CACHE FILEPATH "METIS library")
+  endif (METIS_LIBRARY_DEBUG)
+elseif (METIS_LIBRARY_DEBUG)
+  set (METIS_LIBRARY ${METIS_LIBRARY_DEBUG} CACHE FILEPATH "METIS library")
+endif (METIS_LIBRARY_RELEASE)
+
+set (_METIS_VERSION_HEADER ${METIS_INCLUDE_DIR}/metis.h)
+
+if (EXISTS ${_METIS_VERSION_HEADER})
+  file (READ ${_METIS_VERSION_HEADER} _METIS_VERSION_CONTENTS)
+
+  string (REGEX REPLACE ".*#define METIS_VER_MAJOR[ \t]+([0-9]+).*" "\\1"
+    METIS_VERSION_MAJOR "${_METIS_VERSION_CONTENTS}")
+  string (REGEX REPLACE ".*#define METIS_VER_MINOR[ \t]+([0-9]+).*" "\\1"
+    METIS_VERSION_MINOR "${_METIS_VERSION_CONTENTS}")
+  string (REGEX REPLACE ".*#define METIS_VER_SUBMINOR[ \t]+([0-9]+).*" "\\1"
+    METIS_VERSION_PATCH "${_METIS_VERSION_CONTENTS}")
+
+  set (METIS_VERSION
+    ${METIS_VERSION_MAJOR}.${METIS_VERSION_MINOR}.${METIS_VERSION_PATCH})
+  set (METIS_VERSION_COMPONENTS 3)
+endif (EXISTS ${_METIS_VERSION_HEADER})
+
+mark_as_advanced (METIS_INCLUDE_DIR METIS_LIBRARY_DEBUG METIS_LIBRARY_RELEASE
+  METIS_LIBRARY)
+
+if (NOT TARGET METIS::METIS)
+  if (METIS_INCLUDE_DIR OR METIS_LIBRARY)
+    add_library (METIS::METIS IMPORTED UNKNOWN)
+  endif (METIS_INCLUDE_DIR OR METIS_LIBRARY)
+endif (NOT TARGET METIS::METIS)
+
+if (METIS_INCLUDE_DIR)
+  set_property (TARGET METIS::METIS PROPERTY INTERFACE_INCLUDE_DIRECTORIES
+    ${METIS_INCLUDE_DIR})
+endif (METIS_INCLUDE_DIR)
+
+if (METIS_LIBRARY_RELEASE)
+  set_property (TARGET METIS::METIS PROPERTY IMPORTED_LOCATION_RELEASE
+    ${METIS_LIBRARY_RELEASE})
+  set_property (TARGET METIS::METIS APPEND PROPERTY IMPORTED_CONFIGURATIONS
+    RELEASE)
+endif (METIS_LIBRARY_RELEASE)
+
+if (METIS_LIBRARY_DEBUG)
+  set_property (TARGET METIS::METIS PROPERTY IMPORTED_LOCATION_DEBUG
+    ${METIS_LIBRARY_DEBUG})
+  set_property (TARGET METIS::METIS APPEND PROPERTY IMPORTED_CONFIGURATIONS
+    DEBUG)
+endif (METIS_LIBRARY_DEBUG)
+
+find_package_handle_standard_args (METIS REQUIRED_VARS
+  METIS_INCLUDE_DIR METIS_LIBRARY VERSION_VAR METIS_VERSION)
diff --git a/cmake/FindSuiteSparse.cmake b/cmake/FindSuiteSparse.cmake
index aad8904..452ffa1 100644
--- a/cmake/FindSuiteSparse.cmake
+++ b/cmake/FindSuiteSparse.cmake
@@ -1,5 +1,5 @@
 # Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2015 Google Inc. All rights reserved.
+# Copyright 2022 Google Inc. All rights reserved.
 # http://ceres-solver.org/
 #
 # Redistribution and use in source and binary forms, with or without
@@ -29,103 +29,114 @@
 # Author: alexs.mac@gmail.com (Alex Stewart)
 #
 
-# FindSuiteSparse.cmake - Find SuiteSparse libraries & dependencies.
-#
-# This module defines the following variables:
-#
-# SUITESPARSE_FOUND: TRUE iff SuiteSparse and all dependencies have been found.
-# SUITESPARSE_INCLUDE_DIRS: Include directories for all SuiteSparse components.
-# SUITESPARSE_LIBRARIES: Libraries for all SuiteSparse component libraries and
-#                        dependencies.
-# SUITESPARSE_VERSION: Extracted from UFconfig.h (<= v3) or
-#                      SuiteSparse_config.h (>= v4).
-# SUITESPARSE_MAIN_VERSION: Equal to 4 if SUITESPARSE_VERSION = 4.2.1
-# SUITESPARSE_SUB_VERSION: Equal to 2 if SUITESPARSE_VERSION = 4.2.1
-# SUITESPARSE_SUBSUB_VERSION: Equal to 1 if SUITESPARSE_VERSION = 4.2.1
-#
-# SUITESPARSE_IS_BROKEN_SHARED_LINKING_UBUNTU_SYSTEM_VERSION: TRUE iff running
-#     on Ubuntu, SUITESPARSE_VERSION is 3.4.0 and found SuiteSparse is a system
-#     install, in which case found version of SuiteSparse cannot be used to link
-#     a shared library due to a bug (static linking is unaffected).
-#
-# The following variables control the behaviour of this module:
-#
-# SUITESPARSE_INCLUDE_DIR_HINTS: List of additional directories in which to
-#                                search for SuiteSparse includes,
-#                                e.g: /timbuktu/include.
-# SUITESPARSE_LIBRARY_DIR_HINTS: List of additional directories in which to
-#                                search for SuiteSparse libraries,
-#                                e.g: /timbuktu/lib.
-#
-# The following variables define the presence / includes & libraries for the
-# SuiteSparse components searched for, the SUITESPARSE_XX variables are the
-# union of the variables for all components.
-#
-# == Symmetric Approximate Minimum Degree (AMD)
-# AMD_FOUND
-# AMD_INCLUDE_DIR
-# AMD_LIBRARY
-#
-# == Constrained Approximate Minimum Degree (CAMD)
-# CAMD_FOUND
-# CAMD_INCLUDE_DIR
-# CAMD_LIBRARY
-#
-# == Column Approximate Minimum Degree (COLAMD)
-# COLAMD_FOUND
-# COLAMD_INCLUDE_DIR
-# COLAMD_LIBRARY
-#
-# Constrained Column Approximate Minimum Degree (CCOLAMD)
-# CCOLAMD_FOUND
-# CCOLAMD_INCLUDE_DIR
-# CCOLAMD_LIBRARY
-#
-# == Sparse Supernodal Cholesky Factorization and Update/Downdate (CHOLMOD)
-# CHOLMOD_FOUND
-# CHOLMOD_INCLUDE_DIR
-# CHOLMOD_LIBRARY
-#
-# == Multifrontal Sparse QR (SuiteSparseQR)
-# SUITESPARSEQR_FOUND
-# SUITESPARSEQR_INCLUDE_DIR
-# SUITESPARSEQR_LIBRARY
-#
-# == Common configuration for all but CSparse (SuiteSparse version >= 4).
-# SUITESPARSE_CONFIG_FOUND
-# SUITESPARSE_CONFIG_INCLUDE_DIR
-# SUITESPARSE_CONFIG_LIBRARY
-#
-# == Common configuration for all but CSparse (SuiteSparse version < 4).
-# UFCONFIG_FOUND
-# UFCONFIG_INCLUDE_DIR
-#
-# Optional SuiteSparse Dependencies:
-#
-# == Serial Graph Partitioning and Fill-reducing Matrix Ordering (METIS)
-# METIS_FOUND
-# METIS_LIBRARY
+#[=======================================================================[.rst:
+FindSuiteSparse
+===============
+
+Module for locating SuiteSparse libraries and its dependencies.
+
+This module defines the following variables:
+
+``SuiteSparse_FOUND``
+   ``TRUE`` iff SuiteSparse and all dependencies have been found.
+
+``SuiteSparse_VERSION``
+   Extracted from ``SuiteSparse_config.h`` (>= v4).
+
+``SuiteSparse_VERSION_MAJOR``
+    Equal to 4 if ``SuiteSparse_VERSION`` = 4.2.1
+
+``SuiteSparse_VERSION_MINOR``
+    Equal to 2 if ``SuiteSparse_VERSION`` = 4.2.1
+
+``SuiteSparse_VERSION_PATCH``
+    Equal to 1 if ``SuiteSparse_VERSION`` = 4.2.1
+
+The following variables control the behaviour of this module:
+
+``SuiteSparse_NO_CMAKE``
+  Do not attempt to use the native SuiteSparse CMake package configuration.
+
+
+Targets
+-------
+
+The following targets define the SuiteSparse components searched for.
+
+``SuiteSparse::AMD``
+    Symmetric Approximate Minimum Degree (AMD)
+
+``SuiteSparse::CAMD``
+    Constrained Approximate Minimum Degree (CAMD)
+
+``SuiteSparse::COLAMD``
+    Column Approximate Minimum Degree (COLAMD)
+
+``SuiteSparse::CCOLAMD``
+    Constrained Column Approximate Minimum Degree (CCOLAMD)
+
+``SuiteSparse::CHOLMOD``
+    Sparse Supernodal Cholesky Factorization and Update/Downdate (CHOLMOD)
+
+``SuiteSparse::SPQR``
+    Multifrontal Sparse QR (SuiteSparseQR)
+
+``SuiteSparse::Config``
+    Common configuration for all but CSparse (SuiteSparse version >= 4).
+
+Optional SuiteSparse dependencies:
+
+``METIS::METIS``
+    Serial Graph Partitioning and Fill-reducing Matrix Ordering (METIS)
+]=======================================================================]
+
+if (NOT SuiteSparse_NO_CMAKE)
+  find_package (SuiteSparse NO_MODULE QUIET)
+endif (NOT SuiteSparse_NO_CMAKE)
+
+if (SuiteSparse_FOUND)
+  return ()
+endif (SuiteSparse_FOUND)
+
+if (NOT SuiteSparse_FIND_COMPONENTS)
+  set (SuiteSparse_FIND_COMPONENTS
+    AMD
+    CAMD
+    CCOLAMD
+    CHOLMOD
+    COLAMD
+    SPQR
+  )
+endif (NOT SuiteSparse_FIND_COMPONENTS)
+
+include (CheckLibraryExists)
+
+# CHOLMOD depends on AMD, CAMD, CCOLAMD, and COLAMD
+if (CHOLMOD IN_LIST SuiteSparse_FIND_COMPONENTS)
+  list (APPEND SuiteSparse_FIND_COMPONENTS AMD CAMD CCOLAMD COLAMD)
+endif (CHOLMOD IN_LIST SuiteSparse_FIND_COMPONENTS)
+
+# SPQR depends on CHOLMOD
+if (SPQR IN_LIST SuiteSparse_FIND_COMPONENTS)
+  list (APPEND SuiteSparse_FIND_COMPONENTS CHOLMOD)
+endif (SPQR IN_LIST SuiteSparse_FIND_COMPONENTS)
+
+# Do note list components multiple times
+list (REMOVE_DUPLICATES SuiteSparse_FIND_COMPONENTS)
 
 # Reset CALLERS_CMAKE_FIND_LIBRARY_PREFIXES to its value when
 # FindSuiteSparse was invoked.
-macro(SUITESPARSE_RESET_FIND_LIBRARY_PREFIX)
+macro(SuiteSparse_RESET_FIND_LIBRARY_PREFIX)
   if (MSVC)
     set(CMAKE_FIND_LIBRARY_PREFIXES "${CALLERS_CMAKE_FIND_LIBRARY_PREFIXES}")
   endif (MSVC)
-endmacro(SUITESPARSE_RESET_FIND_LIBRARY_PREFIX)
+endmacro(SuiteSparse_RESET_FIND_LIBRARY_PREFIX)
 
 # Called if we failed to find SuiteSparse or any of it's required dependencies,
 # unsets all public (designed to be used externally) variables and reports
 # error message at priority depending upon [REQUIRED/QUIET/<NONE>] argument.
-macro(SUITESPARSE_REPORT_NOT_FOUND REASON_MSG)
-  unset(SUITESPARSE_FOUND)
-  unset(SUITESPARSE_INCLUDE_DIRS)
-  unset(SUITESPARSE_LIBRARIES)
-  unset(SUITESPARSE_VERSION)
-  unset(SUITESPARSE_MAIN_VERSION)
-  unset(SUITESPARSE_SUB_VERSION)
-  unset(SUITESPARSE_SUBSUB_VERSION)
-  # Do NOT unset SUITESPARSE_FOUND_REQUIRED_VARS here, as it is used by
+macro(SuiteSparse_REPORT_NOT_FOUND REASON_MSG)
+  # Do NOT unset SuiteSparse_FOUND_REQUIRED_VARS here, as it is used by
   # FindPackageHandleStandardArgs() to generate the automatic error message on
   # failure which highlights which components are missing.
 
@@ -146,16 +157,10 @@
   # Do not call return(), s/t we keep processing if not called with REQUIRED
   # and report all missing components, rather than bailing after failing to find
   # the first.
-endmacro(SUITESPARSE_REPORT_NOT_FOUND)
-
-# Protect against any alternative find_package scripts for this library having
-# been called previously (in a client project) which set SUITESPARSE_FOUND, but
-# not the other variables we require / set here which could cause the search
-# logic here to fail.
-unset(SUITESPARSE_FOUND)
+endmacro(SuiteSparse_REPORT_NOT_FOUND)
 
 # Handle possible presence of lib prefix for libraries on MSVC, see
-# also SUITESPARSE_RESET_FIND_LIBRARY_PREFIX().
+# also SuiteSparse_RESET_FIND_LIBRARY_PREFIX().
 if (MSVC)
   # Preserve the caller's original values for CMAKE_FIND_LIBRARY_PREFIXES
   # s/t we can set it back before returning.
@@ -165,45 +170,8 @@
   set(CMAKE_FIND_LIBRARY_PREFIXES "lib" "" "${CMAKE_FIND_LIBRARY_PREFIXES}")
 endif (MSVC)
 
-# On macOS, add the Homebrew prefix (with appropriate suffixes) to the
-# respective HINTS directories (after any user-specified locations).  This
-# handles Homebrew installations into non-standard locations (not /usr/local).
-# We do not use CMAKE_PREFIX_PATH for this as given the search ordering of
-# find_xxx(), doing so would override any user-specified HINTS locations with
-# the Homebrew version if it exists.
-if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
-  find_program(HOMEBREW_EXECUTABLE brew)
-  mark_as_advanced(FORCE HOMEBREW_EXECUTABLE)
-  if (HOMEBREW_EXECUTABLE)
-    # Detected a Homebrew install, query for its install prefix.
-    execute_process(COMMAND ${HOMEBREW_EXECUTABLE} --prefix
-      OUTPUT_VARIABLE HOMEBREW_INSTALL_PREFIX
-      OUTPUT_STRIP_TRAILING_WHITESPACE)
-    message(STATUS "Detected Homebrew with install prefix: "
-      "${HOMEBREW_INSTALL_PREFIX}, adding to CMake search paths.")
-    list(APPEND SUITESPARSE_INCLUDE_DIR_HINTS "${HOMEBREW_INSTALL_PREFIX}/include")
-    list(APPEND SUITESPARSE_LIBRARY_DIR_HINTS "${HOMEBREW_INSTALL_PREFIX}/lib")
-  endif()
-endif()
-
-# Specify search directories for include files and libraries (this is the union
-# of the search directories for all OSs).  Search user-specified hint
-# directories first if supplied, and search user-installed locations first
-# so that we prefer user installs to system installs where both exist.
-list(APPEND SUITESPARSE_CHECK_INCLUDE_DIRS
-  /opt/local/include
-  /opt/local/include/ufsparse # Mac OS X
-  /usr/local/homebrew/include # Mac OS X
-  /usr/local/include
-  /usr/include)
-list(APPEND SUITESPARSE_CHECK_LIBRARY_DIRS
-  /opt/local/lib
-  /opt/local/lib/ufsparse # Mac OS X
-  /usr/local/homebrew/lib # Mac OS X
-  /usr/local/lib
-  /usr/lib)
 # Additional suffixes to try appending to each search path.
-list(APPEND SUITESPARSE_CHECK_PATH_SUFFIXES
+list(APPEND SuiteSparse_CHECK_PATH_SUFFIXES
   suitesparse) # Windows/Ubuntu
 
 # Wrappers to find_path/library that pass the SuiteSparse search hints/paths.
@@ -215,59 +183,65 @@
   include(CMakeParseArguments)
   set(OPTIONS REQUIRED)
   set(MULTI_VALUE_ARGS FILES LIBRARIES)
-  cmake_parse_arguments(SUITESPARSE_FIND_${COMPONENT}
+  cmake_parse_arguments(SuiteSparse_FIND_${COMPONENT}
     "${OPTIONS}" "" "${MULTI_VALUE_ARGS}" ${ARGN})
 
-  if (SUITESPARSE_FIND_${COMPONENT}_REQUIRED)
-    list(APPEND SUITESPARSE_FOUND_REQUIRED_VARS ${COMPONENT}_FOUND)
+  if (SuiteSparse_FIND_${COMPONENT}_REQUIRED)
+    list(APPEND SuiteSparse_FOUND_REQUIRED_VARS SuiteSparse_${COMPONENT}_FOUND)
   endif()
 
-  set(${COMPONENT}_FOUND TRUE)
-  if (SUITESPARSE_FIND_${COMPONENT}_FILES)
-    find_path(${COMPONENT}_INCLUDE_DIR
-      NAMES ${SUITESPARSE_FIND_${COMPONENT}_FILES}
-      HINTS ${SUITESPARSE_INCLUDE_DIR_HINTS}
-      PATHS ${SUITESPARSE_CHECK_INCLUDE_DIRS}
-      PATH_SUFFIXES ${SUITESPARSE_CHECK_PATH_SUFFIXES})
-    if (${COMPONENT}_INCLUDE_DIR)
+  set(SuiteSparse_${COMPONENT}_FOUND TRUE)
+  if (SuiteSparse_FIND_${COMPONENT}_FILES)
+    find_path(SuiteSparse_${COMPONENT}_INCLUDE_DIR
+      NAMES ${SuiteSparse_FIND_${COMPONENT}_FILES}
+      PATH_SUFFIXES ${SuiteSparse_CHECK_PATH_SUFFIXES})
+    if (SuiteSparse_${COMPONENT}_INCLUDE_DIR)
       message(STATUS "Found ${COMPONENT} headers in: "
-        "${${COMPONENT}_INCLUDE_DIR}")
-      mark_as_advanced(${COMPONENT}_INCLUDE_DIR)
+        "${SuiteSparse_${COMPONENT}_INCLUDE_DIR}")
+      mark_as_advanced(SuiteSparse_${COMPONENT}_INCLUDE_DIR)
     else()
       # Specified headers not found.
-      set(${COMPONENT}_FOUND FALSE)
-      if (SUITESPARSE_FIND_${COMPONENT}_REQUIRED)
+      set(SuiteSparse_${COMPONENT}_FOUND FALSE)
+      if (SuiteSparse_FIND_${COMPONENT}_REQUIRED)
         suitesparse_report_not_found(
           "Did not find ${COMPONENT} header (required SuiteSparse component).")
       else()
         message(STATUS "Did not find ${COMPONENT} header (optional "
           "SuiteSparse component).")
         # Hide optional vars from CMake GUI even if not found.
-        mark_as_advanced(${COMPONENT}_INCLUDE_DIR)
+        mark_as_advanced(SuiteSparse_${COMPONENT}_INCLUDE_DIR)
       endif()
     endif()
   endif()
 
-  if (SUITESPARSE_FIND_${COMPONENT}_LIBRARIES)
-    find_library(${COMPONENT}_LIBRARY
-      NAMES ${SUITESPARSE_FIND_${COMPONENT}_LIBRARIES}
-      HINTS ${SUITESPARSE_LIBRARY_DIR_HINTS}
-      PATHS ${SUITESPARSE_CHECK_LIBRARY_DIRS}
-      PATH_SUFFIXES ${SUITESPARSE_CHECK_PATH_SUFFIXES})
-    if (${COMPONENT}_LIBRARY)
-      message(STATUS "Found ${COMPONENT} library: ${${COMPONENT}_LIBRARY}")
-      mark_as_advanced(${COMPONENT}_LIBRARY)
+  if (SuiteSparse_FIND_${COMPONENT}_LIBRARIES)
+    find_library(SuiteSparse_${COMPONENT}_LIBRARY
+      NAMES ${SuiteSparse_FIND_${COMPONENT}_LIBRARIES}
+      PATH_SUFFIXES ${SuiteSparse_CHECK_PATH_SUFFIXES})
+    if (SuiteSparse_${COMPONENT}_LIBRARY)
+      message(STATUS "Found ${COMPONENT} library: ${SuiteSparse_${COMPONENT}_LIBRARY}")
+      mark_as_advanced(SuiteSparse_${COMPONENT}_LIBRARY)
+
+      if(NOT TARGET SuiteSparse::${COMPONENT})
+        add_library(SuiteSparse::${COMPONENT} IMPORTED UNKNOWN)
+      endif()
+      set_property(TARGET SuiteSparse::${COMPONENT} PROPERTY
+        INTERFACE_INCLUDE_DIRECTORIES ${SuiteSparse_${COMPONENT}_INCLUDE_DIR})
+      set_property(TARGET SuiteSparse::${COMPONENT} PROPERTY
+        IMPORTED_LOCATION_RELEASE ${SuiteSparse_${COMPONENT}_LIBRARY})
+      set_property(TARGET SuiteSparse::${COMPONENT} APPEND PROPERTY
+        IMPORTED_CONFIGURATIONS RELEASE)
     else ()
       # Specified libraries not found.
-      set(${COMPONENT}_FOUND FALSE)
-      if (SUITESPARSE_FIND_${COMPONENT}_REQUIRED)
+      set(SuiteSparse_${COMPONENT}_FOUND FALSE)
+      if (SuiteSparse_FIND_${COMPONENT}_REQUIRED)
         suitesparse_report_not_found(
           "Did not find ${COMPONENT} library (required SuiteSparse component).")
       else()
         message(STATUS "Did not find ${COMPONENT} library (optional SuiteSparse "
           "dependency)")
         # Hide optional vars from CMake GUI even if not found.
-        mark_as_advanced(${COMPONENT}_LIBRARY)
+        mark_as_advanced(SuiteSparse_${COMPONENT}_LIBRARY)
       endif()
     endif()
   endif()
@@ -277,7 +251,7 @@
 # automatic failure message generated by FindPackageHandleStandardArgs()
 # when not all required components are found is helpful, we maintain a list
 # of all variables that must be defined for SuiteSparse to be considered found.
-unset(SUITESPARSE_FOUND_REQUIRED_VARS)
+unset(SuiteSparse_FOUND_REQUIRED_VARS)
 
 # BLAS.
 find_package(BLAS QUIET)
@@ -285,7 +259,7 @@
   suitesparse_report_not_found(
     "Did not find BLAS library (required for SuiteSparse).")
 endif (NOT BLAS_FOUND)
-list(APPEND SUITESPARSE_FOUND_REQUIRED_VARS BLAS_FOUND)
+list(APPEND SuiteSparse_FOUND_REQUIRED_VARS BLAS_FOUND)
 
 # LAPACK.
 find_package(LAPACK QUIET)
@@ -293,16 +267,22 @@
   suitesparse_report_not_found(
     "Did not find LAPACK library (required for SuiteSparse).")
 endif (NOT LAPACK_FOUND)
-list(APPEND SUITESPARSE_FOUND_REQUIRED_VARS LAPACK_FOUND)
+list(APPEND SuiteSparse_FOUND_REQUIRED_VARS LAPACK_FOUND)
 
-suitesparse_find_component(AMD REQUIRED FILES amd.h LIBRARIES amd)
-suitesparse_find_component(CAMD REQUIRED FILES camd.h LIBRARIES camd)
-suitesparse_find_component(COLAMD REQUIRED FILES colamd.h LIBRARIES colamd)
-suitesparse_find_component(CCOLAMD REQUIRED FILES ccolamd.h LIBRARIES ccolamd)
-suitesparse_find_component(CHOLMOD REQUIRED FILES cholmod.h LIBRARIES cholmod)
-suitesparse_find_component(
-  SUITESPARSEQR REQUIRED FILES SuiteSparseQR.hpp LIBRARIES spqr)
-if (SUITESPARSEQR_FOUND)
+foreach (component IN LISTS SuiteSparse_FIND_COMPONENTS)
+  string (TOLOWER ${component} component_lower)
+
+  if (component STREQUAL "SPQR")
+    set (component_header SuiteSparseQR.hpp)
+  else (component STREQUAL "SPQR")
+    set (component_header ${component_lower}.h)
+  endif (component STREQUAL "SPQR")
+
+  suitesparse_find_component(${component} REQUIRED FILES ${component_header}
+    LIBRARIES ${component_lower})
+endforeach (component IN LISTS SuiteSparse_FIND_COMPONENTS)
+
+if (TARGET SuiteSparse::SPQR)
   # SuiteSparseQR may be compiled with Intel Threading Building Blocks,
   # we assume that if TBB is installed, SuiteSparseQR was compiled with
   # support for it, this will do no harm if it wasn't.
@@ -314,218 +294,165 @@
       "compiled with TBB.")
     # Add the TBB libraries to the SuiteSparseQR libraries (the only
     # libraries to optionally depend on TBB).
-    list(APPEND SUITESPARSEQR_LIBRARY ${TBB_LIBRARIES})
-  else()
+    if (TARGET TBB::tbb)
+      # Native TBB package configuration provides an imported target. Use it if
+      # available.
+      set_property (TARGET SuiteSparse::SPQR APPEND PROPERTY
+        INTERFACE_LINK_LIBRARIES TBB::tbb)
+    else (TARGET TBB::tbb)
+      set_property (TARGET SuiteSparse::SPQR APPEND PROPERTY
+        INTERFACE_INCLUDE_DIRECTORIES ${TBB_INCLUDE_DIRS})
+      set_property (TARGET SuiteSparse::SPQR APPEND PROPERTY
+        INTERFACE_LINK_LIBRARIES ${TBB_LIBRARIES})
+    endif (TARGET TBB::tbb)
+  else (TBB_FOUND)
     message(STATUS "Did not find Intel TBB library, assuming SuiteSparseQR was "
       "not compiled with TBB.")
-  endif()
-endif(SUITESPARSEQR_FOUND)
+  endif (TBB_FOUND)
+endif (TARGET SuiteSparse::SPQR)
 
-# UFconfig / SuiteSparse_config.
+# SuiteSparse_config.
 #
 # If SuiteSparse version is >= 4 then SuiteSparse_config is required.
-# For SuiteSparse 3, UFconfig.h is required.
 suitesparse_find_component(
-  SUITESPARSE_CONFIG FILES SuiteSparse_config.h LIBRARIES suitesparseconfig)
+  Config FILES SuiteSparse_config.h LIBRARIES suitesparseconfig)
 
-if (SUITESPARSE_CONFIG_FOUND)
+check_library_exists(rt shm_open "" HAVE_LIBRT)
+
+if (TARGET SuiteSparse::Config)
   # SuiteSparse_config (SuiteSparse version >= 4) requires librt library for
   # timing by default when compiled on Linux or Unix, but not on OSX (which
   # does not have librt).
-  if (CMAKE_SYSTEM_NAME MATCHES "Linux" OR UNIX AND NOT APPLE)
-    suitesparse_find_component(LIBRT LIBRARIES rt)
-    if (LIBRT_FOUND)
-      message(STATUS "Adding librt: ${LIBRT_LIBRARY} to "
-        "SuiteSparse_config libraries (required on Linux & Unix [not OSX] if "
-        "SuiteSparse is compiled with timing).")
-      list(APPEND SUITESPARSE_CONFIG_LIBRARY ${LIBRT_LIBRARY})
-    else()
-      message(STATUS "Could not find librt, but found SuiteSparse_config, "
-        "assuming that SuiteSparse was compiled without timing.")
-    endif ()
-  endif (CMAKE_SYSTEM_NAME MATCHES "Linux" OR UNIX AND NOT APPLE)
-else()
-  # Failed to find SuiteSparse_config (>= v4 installs), instead look for
-  # UFconfig header which should be present in < v4 installs.
-  suitesparse_find_component(UFCONFIG FILES UFconfig.h)
-endif ()
+  if (HAVE_LIBRT)
+    message(STATUS "Adding librt to "
+      "SuiteSparse_config libraries (required on Linux & Unix [not OSX] if "
+      "SuiteSparse is compiled with timing).")
+    set_property (TARGET SuiteSparse::Config APPEND PROPERTY
+      INTERFACE_LINK_LIBRARIES $<LINK_ONLY:rt>)
+  else (HAVE_LIBRT)
+    message(STATUS "Could not find librt, but found SuiteSparse_config, "
+      "assuming that SuiteSparse was compiled without timing.")
+  endif (HAVE_LIBRT)
 
-if (NOT SUITESPARSE_CONFIG_FOUND AND
-    NOT UFCONFIG_FOUND)
-  suitesparse_report_not_found(
-    "Failed to find either: SuiteSparse_config header & library (should be "
-    "present in all SuiteSparse >= v4 installs), or UFconfig header (should "
-    "be present in all SuiteSparse < v4 installs).")
-endif()
+  # Add BLAS and LAPACK as dependencies of SuiteSparse::Config for convenience
+  # given that all components depend on it.
+  if (BLAS_FOUND)
+    if (TARGET BLAS::BLAS)
+      set_property (TARGET SuiteSparse::Config APPEND PROPERTY
+        INTERFACE_LINK_LIBRARIES $<LINK_ONLY:BLAS::BLAS>)
+    else (TARGET BLAS::BLAS)
+      set_property (TARGET SuiteSparse::Config APPEND PROPERTY
+        INTERFACE_LINK_LIBRARIES ${BLAS_LIBRARIES})
+    endif (TARGET BLAS::BLAS)
+  endif (BLAS_FOUND)
 
-# Extract the SuiteSparse version from the appropriate header (UFconfig.h for
-# <= v3, SuiteSparse_config.h for >= v4).
-list(APPEND SUITESPARSE_FOUND_REQUIRED_VARS SUITESPARSE_VERSION)
+  if (LAPACK_FOUND)
+    if (TARGET LAPACK::LAPACK)
+      set_property (TARGET SuiteSparse::Config APPEND PROPERTY
+        INTERFACE_LINK_LIBRARIES $<LINK_ONLY:LAPACK::LAPACK>)
+    else (TARGET LAPACK::LAPACK)
+      set_property (TARGET SuiteSparse::Config APPEND PROPERTY
+        INTERFACE_LINK_LIBRARIES ${LAPACK_LIBRARIES})
+    endif (TARGET LAPACK::LAPACK)
+  endif (LAPACK_FOUND)
 
-if (UFCONFIG_FOUND)
-  # SuiteSparse version <= 3.
-  set(SUITESPARSE_VERSION_FILE ${UFCONFIG_INCLUDE_DIR}/UFconfig.h)
-  if (NOT EXISTS ${SUITESPARSE_VERSION_FILE})
-    suitesparse_report_not_found(
-      "Could not find file: ${SUITESPARSE_VERSION_FILE} containing version "
-      "information for <= v3 SuiteSparse installs, but UFconfig was found "
-      "(only present in <= v3 installs).")
-  else (NOT EXISTS ${SUITESPARSE_VERSION_FILE})
-    file(READ ${SUITESPARSE_VERSION_FILE} UFCONFIG_CONTENTS)
-
-    string(REGEX MATCH "#define SUITESPARSE_MAIN_VERSION [0-9]+"
-      SUITESPARSE_MAIN_VERSION "${UFCONFIG_CONTENTS}")
-    string(REGEX REPLACE "#define SUITESPARSE_MAIN_VERSION ([0-9]+)" "\\1"
-      SUITESPARSE_MAIN_VERSION "${SUITESPARSE_MAIN_VERSION}")
-
-    string(REGEX MATCH "#define SUITESPARSE_SUB_VERSION [0-9]+"
-      SUITESPARSE_SUB_VERSION "${UFCONFIG_CONTENTS}")
-    string(REGEX REPLACE "#define SUITESPARSE_SUB_VERSION ([0-9]+)" "\\1"
-      SUITESPARSE_SUB_VERSION "${SUITESPARSE_SUB_VERSION}")
-
-    string(REGEX MATCH "#define SUITESPARSE_SUBSUB_VERSION [0-9]+"
-      SUITESPARSE_SUBSUB_VERSION "${UFCONFIG_CONTENTS}")
-    string(REGEX REPLACE "#define SUITESPARSE_SUBSUB_VERSION ([0-9]+)" "\\1"
-      SUITESPARSE_SUBSUB_VERSION "${SUITESPARSE_SUBSUB_VERSION}")
-
-    # This is on a single line s/t CMake does not interpret it as a list of
-    # elements and insert ';' separators which would result in 4.;2.;1 nonsense.
-    set(SUITESPARSE_VERSION
-      "${SUITESPARSE_MAIN_VERSION}.${SUITESPARSE_SUB_VERSION}.${SUITESPARSE_SUBSUB_VERSION}")
-  endif (NOT EXISTS ${SUITESPARSE_VERSION_FILE})
-endif (UFCONFIG_FOUND)
-
-if (SUITESPARSE_CONFIG_FOUND)
   # SuiteSparse version >= 4.
-  set(SUITESPARSE_VERSION_FILE
-    ${SUITESPARSE_CONFIG_INCLUDE_DIR}/SuiteSparse_config.h)
-  if (NOT EXISTS ${SUITESPARSE_VERSION_FILE})
+  set(SuiteSparse_VERSION_FILE
+    ${SuiteSparse_Config_INCLUDE_DIR}/SuiteSparse_config.h)
+  if (NOT EXISTS ${SuiteSparse_VERSION_FILE})
     suitesparse_report_not_found(
-      "Could not find file: ${SUITESPARSE_VERSION_FILE} containing version "
+      "Could not find file: ${SuiteSparse_VERSION_FILE} containing version "
       "information for >= v4 SuiteSparse installs, but SuiteSparse_config was "
       "found (only present in >= v4 installs).")
-  else (NOT EXISTS ${SUITESPARSE_VERSION_FILE})
-    file(READ ${SUITESPARSE_VERSION_FILE} SUITESPARSE_CONFIG_CONTENTS)
+  else (NOT EXISTS ${SuiteSparse_VERSION_FILE})
+    file(READ ${SuiteSparse_VERSION_FILE} Config_CONTENTS)
 
     string(REGEX MATCH "#define SUITESPARSE_MAIN_VERSION [0-9]+"
-      SUITESPARSE_MAIN_VERSION "${SUITESPARSE_CONFIG_CONTENTS}")
+      SuiteSparse_VERSION_MAJOR "${Config_CONTENTS}")
     string(REGEX REPLACE "#define SUITESPARSE_MAIN_VERSION ([0-9]+)" "\\1"
-      SUITESPARSE_MAIN_VERSION "${SUITESPARSE_MAIN_VERSION}")
+      SuiteSparse_VERSION_MAJOR "${SuiteSparse_VERSION_MAJOR}")
 
     string(REGEX MATCH "#define SUITESPARSE_SUB_VERSION [0-9]+"
-      SUITESPARSE_SUB_VERSION "${SUITESPARSE_CONFIG_CONTENTS}")
+      SuiteSparse_VERSION_MINOR "${Config_CONTENTS}")
     string(REGEX REPLACE "#define SUITESPARSE_SUB_VERSION ([0-9]+)" "\\1"
-      SUITESPARSE_SUB_VERSION "${SUITESPARSE_SUB_VERSION}")
+      SuiteSparse_VERSION_MINOR "${SuiteSparse_VERSION_MINOR}")
 
     string(REGEX MATCH "#define SUITESPARSE_SUBSUB_VERSION [0-9]+"
-      SUITESPARSE_SUBSUB_VERSION "${SUITESPARSE_CONFIG_CONTENTS}")
+      SuiteSparse_VERSION_PATCH "${Config_CONTENTS}")
     string(REGEX REPLACE "#define SUITESPARSE_SUBSUB_VERSION ([0-9]+)" "\\1"
-      SUITESPARSE_SUBSUB_VERSION "${SUITESPARSE_SUBSUB_VERSION}")
+      SuiteSparse_VERSION_PATCH "${SuiteSparse_VERSION_PATCH}")
 
     # This is on a single line s/t CMake does not interpret it as a list of
     # elements and insert ';' separators which would result in 4.;2.;1 nonsense.
-    set(SUITESPARSE_VERSION
-      "${SUITESPARSE_MAIN_VERSION}.${SUITESPARSE_SUB_VERSION}.${SUITESPARSE_SUBSUB_VERSION}")
-  endif (NOT EXISTS ${SUITESPARSE_VERSION_FILE})
-endif (SUITESPARSE_CONFIG_FOUND)
+    set(SuiteSparse_VERSION
+      "${SuiteSparse_VERSION_MAJOR}.${SuiteSparse_VERSION_MINOR}.${SuiteSparse_VERSION_PATCH}")
+    set(SuiteSparse_VERSION_COMPONENTS 3)
+  endif (NOT EXISTS ${SuiteSparse_VERSION_FILE})
+endif (TARGET SuiteSparse::Config)
 
 # METIS (Optional dependency).
-suitesparse_find_component(METIS LIBRARIES metis)
+find_package (METIS)
 
-# Only mark SuiteSparse as found if all required components and dependencies
-# have been found.
-set(SUITESPARSE_FOUND TRUE)
-foreach(REQUIRED_VAR ${SUITESPARSE_FOUND_REQUIRED_VARS})
-  if (NOT ${REQUIRED_VAR})
-    set(SUITESPARSE_FOUND FALSE)
-  endif (NOT ${REQUIRED_VAR})
-endforeach(REQUIRED_VAR ${SUITESPARSE_FOUND_REQUIRED_VARS})
+# CHOLMOD requires AMD CAMD CCOLAMD COLAMD
+if (TARGET SuiteSparse::CHOLMOD)
+  # METIS is optional
+  if (TARGET METIS::METIS)
+    set_property (TARGET SuiteSparse::CHOLMOD APPEND PROPERTY
+      INTERFACE_LINK_LIBRARIES METIS::METIS)
+  endif (TARGET METIS::METIS)
 
-if (SUITESPARSE_FOUND)
-  list(APPEND SUITESPARSE_INCLUDE_DIRS
-    ${AMD_INCLUDE_DIR}
-    ${CAMD_INCLUDE_DIR}
-    ${COLAMD_INCLUDE_DIR}
-    ${CCOLAMD_INCLUDE_DIR}
-    ${CHOLMOD_INCLUDE_DIR}
-    ${SUITESPARSEQR_INCLUDE_DIR})
-  # Handle config separately, as otherwise at least one of them will be set
-  # to NOTFOUND which would cause any check on SUITESPARSE_INCLUDE_DIRS to fail.
-  if (SUITESPARSE_CONFIG_FOUND)
-    list(APPEND SUITESPARSE_INCLUDE_DIRS
-      ${SUITESPARSE_CONFIG_INCLUDE_DIR})
-  endif (SUITESPARSE_CONFIG_FOUND)
-  if (UFCONFIG_FOUND)
-    list(APPEND SUITESPARSE_INCLUDE_DIRS
-      ${UFCONFIG_INCLUDE_DIR})
-  endif (UFCONFIG_FOUND)
-  # As SuiteSparse includes are often all in the same directory, remove any
-  # repetitions.
-  list(REMOVE_DUPLICATES SUITESPARSE_INCLUDE_DIRS)
+  foreach (component IN ITEMS AMD CAMD CCOLAMD COLAMD)
+    if (TARGET SuiteSparse::${component})
+      set_property (TARGET SuiteSparse::CHOLMOD APPEND PROPERTY
+        INTERFACE_LINK_LIBRARIES SuiteSparse::${component})
+    else (TARGET SuiteSparse::${component})
+      # Consider CHOLMOD not found if COLAMD cannot be found
+      set (SuiteSparse_CHOLMOD_FOUND FALSE)
+    endif (TARGET SuiteSparse::${component})
+  endforeach (component IN ITEMS AMD CAMD CCOLAMD COLAMD)
+endif (TARGET SuiteSparse::CHOLMOD)
 
-  # Important: The ordering of these libraries is *NOT* arbitrary, as these
-  # could potentially be static libraries their link ordering is important.
-  list(APPEND SUITESPARSE_LIBRARIES
-    ${SUITESPARSEQR_LIBRARY}
-    ${CHOLMOD_LIBRARY}
-    ${CCOLAMD_LIBRARY}
-    ${CAMD_LIBRARY}
-    ${COLAMD_LIBRARY}
-    ${AMD_LIBRARY}
-    ${LAPACK_LIBRARIES}
-    ${BLAS_LIBRARIES})
-  if (SUITESPARSE_CONFIG_FOUND)
-    list(APPEND SUITESPARSE_LIBRARIES
-      ${SUITESPARSE_CONFIG_LIBRARY})
-  endif (SUITESPARSE_CONFIG_FOUND)
-  if (METIS_FOUND)
-    list(APPEND SUITESPARSE_LIBRARIES
-      ${METIS_LIBRARY})
-  endif (METIS_FOUND)
-endif()
+# SPQR requires CHOLMOD
+if (TARGET SuiteSparse::SPQR)
+  if (TARGET SuiteSparse::CHOLMOD)
+    set_property (TARGET SuiteSparse::SPQR APPEND PROPERTY
+      INTERFACE_LINK_LIBRARIES SuiteSparse::CHOLMOD)
+  else (TARGET SuiteSparse::CHOLMOD)
+    # Consider SPQR not found if CHOLMOD cannot be found
+    set (SuiteSparse_SQPR_FOUND FALSE)
+  endif (TARGET SuiteSparse::CHOLMOD)
+endif (TARGET SuiteSparse::SPQR)
 
-# Determine if we are running on Ubuntu with the package install of SuiteSparse
-# which is broken and does not support linking a shared library.
-set(SUITESPARSE_IS_BROKEN_SHARED_LINKING_UBUNTU_SYSTEM_VERSION FALSE)
-if (CMAKE_SYSTEM_NAME MATCHES "Linux" AND
-    SUITESPARSE_VERSION VERSION_EQUAL 3.4.0)
-  find_program(LSB_RELEASE_EXECUTABLE lsb_release)
-  if (LSB_RELEASE_EXECUTABLE)
-    # Any even moderately recent Ubuntu release (likely to be affected by
-    # this bug) should have lsb_release, if it isn't present we are likely
-    # on a different Linux distribution (should be fine).
-    execute_process(COMMAND ${LSB_RELEASE_EXECUTABLE} -si
-      OUTPUT_VARIABLE LSB_DISTRIBUTOR_ID
-      OUTPUT_STRIP_TRAILING_WHITESPACE)
+# Add SuiteSparse::Config as dependency to all components
+if (TARGET SuiteSparse::Config)
+  foreach (component IN LISTS SuiteSparse_FIND_COMPONENTS)
+    if (component STREQUAL Config)
+      continue ()
+    endif (component STREQUAL Config)
 
-    if (LSB_DISTRIBUTOR_ID MATCHES "Ubuntu" AND
-        SUITESPARSE_LIBRARIES MATCHES "/usr/lib/libamd")
-      # We are on Ubuntu, and the SuiteSparse version matches the broken
-      # system install version and is a system install.
-      set(SUITESPARSE_IS_BROKEN_SHARED_LINKING_UBUNTU_SYSTEM_VERSION TRUE)
-      message(STATUS "Found system install of SuiteSparse "
-        "${SUITESPARSE_VERSION} running on Ubuntu, which has a known bug "
-        "preventing linking of shared libraries (static linking unaffected).")
-    endif (LSB_DISTRIBUTOR_ID MATCHES "Ubuntu" AND
-      SUITESPARSE_LIBRARIES MATCHES "/usr/lib/libamd")
-  endif (LSB_RELEASE_EXECUTABLE)
-endif (CMAKE_SYSTEM_NAME MATCHES "Linux" AND
-  SUITESPARSE_VERSION VERSION_EQUAL 3.4.0)
+    if (TARGET SuiteSparse::${component})
+      set_property (TARGET SuiteSparse::${component} APPEND PROPERTY
+        INTERFACE_LINK_LIBRARIES SuiteSparse::Config)
+    endif (TARGET SuiteSparse::${component})
+  endforeach (component IN LISTS SuiteSparse_FIND_COMPONENTS)
+endif (TARGET SuiteSparse::Config)
 
 suitesparse_reset_find_library_prefix()
 
 # Handle REQUIRED and QUIET arguments to FIND_PACKAGE
 include(FindPackageHandleStandardArgs)
-if (SUITESPARSE_FOUND)
+if (SuiteSparse_FOUND)
   find_package_handle_standard_args(SuiteSparse
-    REQUIRED_VARS ${SUITESPARSE_FOUND_REQUIRED_VARS}
-    VERSION_VAR SUITESPARSE_VERSION
-    FAIL_MESSAGE "Failed to find some/all required components of SuiteSparse.")
-else (SUITESPARSE_FOUND)
+    REQUIRED_VARS ${SuiteSparse_FOUND_REQUIRED_VARS}
+    VERSION_VAR SuiteSparse_VERSION
+    FAIL_MESSAGE "Failed to find some/all required components of SuiteSparse."
+    HANDLE_COMPONENTS)
+else (SuiteSparse_FOUND)
   # Do not pass VERSION_VAR to FindPackageHandleStandardArgs() if we failed to
   # find SuiteSparse to avoid a confusing autogenerated failure message
   # that states 'not found (missing: FOO) (found version: x.y.z)'.
   find_package_handle_standard_args(SuiteSparse
-    REQUIRED_VARS ${SUITESPARSE_FOUND_REQUIRED_VARS}
-    FAIL_MESSAGE "Failed to find some/all required components of SuiteSparse.")
-endif (SUITESPARSE_FOUND)
+    REQUIRED_VARS ${SuiteSparse_FOUND_REQUIRED_VARS}
+    FAIL_MESSAGE "Failed to find some/all required components of SuiteSparse."
+    HANDLE_COMPONENTS)
+endif (SuiteSparse_FOUND)
diff --git a/docs/source/installation.rst b/docs/source/installation.rst
index 3591901..86c6040 100644
--- a/docs/source/installation.rst
+++ b/docs/source/installation.rst
@@ -78,9 +78,9 @@
   examples and tests and usually a dependency for glog.
 
 - `SuiteSparse
-  <http://faculty.cse.tamu.edu/davis/suitesparse.html>`_. Needed for
-  solving large sparse linear systems. **Optional; strongly recomended
-  for large scale bundle adjustment**
+  <http://faculty.cse.tamu.edu/davis/suitesparse.html>`_ 4.0 or later. Needed
+  for solving large sparse linear systems. **Optional; strongly recomended for
+  large scale bundle adjustment**
 
   .. NOTE ::
 
@@ -90,11 +90,22 @@
      found TBB version. You can customize the searched TBB location
      with the ``TBB_ROOT`` variable.
 
+  A CMake native version of SuiteSparse that can be compiled on a variety of
+  platforms (e.g., using Visual Studio, Xcode, MinGW, etc.) is maintained by the
+  `CMake support for SuiteSparse <https://github.com/sergiud/SuiteSparse>`_
+  project.
+
 - `CXSparse <http://faculty.cse.tamu.edu/davis/suitesparse.html>`_.
   Similar to ``SuiteSparse`` but simpler and slower. CXSparse has
   no dependencies on ``LAPACK`` and ``BLAS``. This makes for a simpler
   build process and a smaller binary. **Optional**
 
+  A CMake native version of CXSparse that can be compiled on a variety of
+  platforms (e.g., using Visual Studio, Xcode, MinGW, etc.) is also maintained
+  by the `CMake support for SuiteSparse
+  <https://github.com/sergiud/SuiteSparse>`_ project and is part of the
+  SuiteSparse package.
+
 - `Apple's Accelerate sparse solvers <https://developer.apple.com/documentation/accelerate/sparse_solvers>`_.
   As of Xcode 9.0, Apple's Accelerate framework includes support for
   solving sparse linear systems across macOS, iOS et al. **Optional**
@@ -426,10 +437,6 @@
    #. ``GLOG_INCLUDE_DIR_HINTS``
    #. ``GLOG_LIBRARY_DIR_HINTS``
    #. (Optional) ``gflags_DIR`` (Set to directory containing ``gflags-config.cmake``)
-   #. (Optional) ``SUITESPARSE_INCLUDE_DIR_HINTS``
-   #. (Optional) ``SUITESPARSE_LIBRARY_DIR_HINTS``
-   #. (Optional) ``CXSPARSE_INCLUDE_DIR_HINTS``
-   #. (Optional) ``CXSPARSE_LIBRARY_DIR_HINTS``
 
    to the appropriate directories where you unpacked/built them. If
    any of the variables are not visible in the ``CMake`` GUI, create a
diff --git a/internal/ceres/CMakeLists.txt b/internal/ceres/CMakeLists.txt
index cc96af5..b18fc93 100644
--- a/internal/ceres/CMakeLists.txt
+++ b/internal/ceres/CMakeLists.txt
@@ -113,17 +113,18 @@
   endif()
 endif (NOT MINIGLOG AND GLOG_FOUND)
 
-if (SUITESPARSE AND SUITESPARSE_FOUND)
+if (SUITESPARSE AND SuiteSparse_FOUND)
   # Define version information for use in Solver::FullReport.
-  add_definitions(-DCERES_SUITESPARSE_VERSION="${SUITESPARSE_VERSION}")
-  list(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES ${SUITESPARSE_LIBRARIES})
-endif (SUITESPARSE AND SUITESPARSE_FOUND)
+  add_definitions(-DCERES_SUITESPARSE_VERSION="${SuiteSparse_VERSION}")
+  list(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES SuiteSparse::CHOLMOD
+    SuiteSparse::SPQR)
+endif (SUITESPARSE AND SuiteSparse_FOUND)
 
-if (CXSPARSE AND CXSPARSE_FOUND)
+if (CXSPARSE AND CXSparse_FOUND)
   # Define version information for use in Solver::FullReport.
-  add_definitions(-DCERES_CXSPARSE_VERSION="${CXSPARSE_VERSION}")
-  list(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES ${CXSPARSE_LIBRARIES})
-endif (CXSPARSE AND CXSPARSE_FOUND)
+  add_definitions(-DCERES_CXSPARSE_VERSION="${CXSparse_VERSION}")
+  list(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES CXSparse::CXSparse)
+endif (CXSPARSE AND CXSparse_FOUND)
 
 if (ACCELERATESPARSE AND AccelerateSparse_FOUND)
   list(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES ${AccelerateSparse_LIBRARIES})
@@ -372,14 +373,6 @@
   list(APPEND CERES_LIBRARY_PUBLIC_DEPENDENCIES_INCLUDE_DIRS
     ${GLOG_INCLUDE_DIRS})
 endif()
-if (SUITESPARSE)
-  list(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES_INCLUDE_DIRS
-    ${SUITESPARSE_INCLUDE_DIRS})
-endif()
-if (CXSPARSE)
-  list(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES_INCLUDE_DIRS
-    ${CXSPARSE_INCLUDE_DIRS})
-endif()
 if (ACCELERATESPARSE)
   list(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES_INCLUDE_DIRS
     ${AccelerateSparse_INCLUDE_DIRS})