Add CMake feature and dependency summary

Use CMake's standard package discovery output and FeatureSummary instead
of custom status messages, so configuration reports package
availability, versions, and failure reasons consistently. Rename Ceres
feature controls to use the WITH_ prefix to group them consistently and
eliminate inconcistent naming. Remove retrospective cache updates so
package discovery preserves caller-provided values and avoids
unnecessary side effects.

Fixes #876

Change-Id: Ib6e40d56a0ea89b292fe34554777593ffda95f42
This commit is contained in:
Sergiu Deitsch
2023-09-10 17:46:26 +02:00
parent 2017abdf9e
commit 0b03102b09
14 changed files with 1018 additions and 931 deletions
+2 -1
View File
@@ -66,7 +66,8 @@ function(ADD_GERRIT_COMMIT_HOOK SOURCE_DIR BINARY_DIR)
if (EXISTS ${LOCAL_GIT_DIRECTORY})
if (NOT EXISTS ${LOCAL_GIT_DIRECTORY}/hooks/commit-msg)
message(STATUS "Detected Ceres being used as a git submodule, adding "
# Hook installation is an internal setup detail.
message(DEBUG "Detected Ceres being used as a git submodule, adding "
"commit hook for Gerrit to: ${LOCAL_GIT_DIRECTORY}")
# Download the hook only if it is not already present.
file(DOWNLOAD https://ceres-solver-review.googlesource.com/tools/hooks/commit-msg
+70 -141
View File
@@ -1,5 +1,5 @@
# Ceres Solver - A fast non-linear least squares minimizer
# Copyright 2025 Google Inc. All rights reserved.
# Copyright 2026 Google Inc. All rights reserved.
# http://ceres-solver.org/
#
# Redistribution and use in source and binary forms, with or without
@@ -60,12 +60,14 @@
# CMake target already includes the definition of its public
# include directories.
@PACKAGE_INIT@
include(CMakeFindDependencyMacro)
# Called if we failed to find Ceres or any of its required dependencies,
# unsets all public (designed to be used externally) variables and reports
# error message at priority depending upon [REQUIRED/QUIET/<NONE>] argument.
macro(CERES_REPORT_NOT_FOUND REASON_MSG)
# Called if Ceres or one of its required dependencies cannot be used. Clears
# the public result variables and provides the standard find_package failure
# reason. find_package controls whether and how the reason is reported.
macro(ceres_set_not_found REASON_MSG)
# FindPackage() only references Ceres_FOUND, and requires it to be
# explicitly set FALSE to denote not found (not merely undefined).
set(Ceres_FOUND FALSE)
@@ -76,102 +78,38 @@ macro(CERES_REPORT_NOT_FOUND REASON_MSG)
# Reset the CMake module path to its state when this script was called.
set(CMAKE_MODULE_PATH ${CALLERS_CMAKE_MODULE_PATH})
# Concatenate REASON_MSG and ARGN with each element separated by a space
string(JOIN " " ${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE "${REASON_MSG}" ${ARGN})
string(JOIN " " Ceres_NOT_FOUND_MESSAGE "${REASON_MSG}" ${ARGN})
return()
endmacro(CERES_REPORT_NOT_FOUND)
# ceres_message([mode] "message text")
#
# Wraps the standard cmake 'message' command, but suppresses output
# if the QUIET flag was passed to the find_package(Ceres ...) call.
function(ceres_message)
if (NOT Ceres_FIND_QUIETLY)
message(${ARGN})
endif()
endfunction()
# ceres_pretty_print_cmake_list( OUTPUT_VAR [item1 [item2 ... ]] )
#
# Sets ${OUTPUT_VAR} in the caller's scope to a human-readable string
# representation of the list passed as the remaining arguments formed
# as: "[item1, item2, ..., itemN]".
function(ceres_pretty_print_cmake_list OUTPUT_VAR)
string(REPLACE ";" ", " PRETTY_LIST_STRING "[${ARGN}]")
set(${OUTPUT_VAR} "${PRETTY_LIST_STRING}" PARENT_SCOPE)
endfunction()
endmacro(ceres_set_not_found)
# The list of (optional) components this version of Ceres was compiled with.
set(CERES_COMPILED_COMPONENTS "@CERES_COMPILED_COMPONENTS@")
# If Ceres was not installed, then by definition it was exported
# from a build directory.
set(CERES_WAS_INSTALLED @SETUP_CERES_CONFIG_FOR_INSTALLATION@)
# Record the state of the CMake module path when this script was
# called so that we can ensure that we leave it in the same state on
# exit as it was on entry, but modify it locally.
set(CALLERS_CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH})
# Get the (current, i.e. installed) directory containing this file.
# Get the directory containing this file.
get_filename_component(CERES_CURRENT_CONFIG_DIR
"${CMAKE_CURRENT_LIST_FILE}" PATH)
if (CERES_WAS_INSTALLED)
# Update the CMake module path to include the installation directory of this
# script, thus we will use the FindPackage() scripts shipped with Ceres to
# find Ceres' dependencies, even if the user has equivalently named
# FindPackage() scripts in their project.
list(PREPEND CMAKE_MODULE_PATH ${CERES_CURRENT_CONFIG_DIR})
# Build the absolute root install directory as a relative path
# (determined when Ceres was configured & built) from the current
# install directory for this this file. This allows for the install
# tree to be relocated, after Ceres was built, outside of CMake.
get_filename_component(CURRENT_ROOT_INSTALL_DIR
"${CERES_CURRENT_CONFIG_DIR}/@INSTALL_ROOT_REL_CONFIG_INSTALL_DIR@"
ABSOLUTE)
if (NOT EXISTS ${CURRENT_ROOT_INSTALL_DIR})
ceres_report_not_found(
"Ceres install root: ${CURRENT_ROOT_INSTALL_DIR}, "
"determined from relative path from CeresConfig.cmake install location: "
"${CERES_CURRENT_CONFIG_DIR}, does not exist. Either the install "
"directory was deleted, or the install tree was only partially relocated "
"outside of CMake after Ceres was built.")
endif (NOT EXISTS ${CURRENT_ROOT_INSTALL_DIR})
else(CERES_WAS_INSTALLED)
# Ceres was exported from the build tree.
set(CERES_EXPORTED_BUILD_DIR ${CERES_CURRENT_CONFIG_DIR})
get_filename_component(CERES_EXPORTED_SOURCE_DIR
"${CERES_EXPORTED_BUILD_DIR}/@INSTALL_ROOT_REL_CONFIG_INSTALL_DIR@"
ABSOLUTE)
if (NOT EXISTS ${CERES_EXPORTED_SOURCE_DIR})
ceres_report_not_found(
"Ceres exported source directory: ${CERES_EXPORTED_SOURCE_DIR}, "
"determined from relative path from CeresConfig.cmake exported build "
"directory: ${CERES_EXPORTED_BUILD_DIR} does not exist.")
endif()
# Update the CMake module path to include the cmake directory in the Ceres
# source tree which was exported, thus we will use the FindPackage() scripts
# shipped with Ceres to find Ceres' dependencies, even if the user has
# equivalently named FindPackage() scripts in their project.
list(PREPEND CMAKE_MODULE_PATH ${CERES_EXPORTED_SOURCE_DIR}/cmake)
endif(CERES_WAS_INSTALLED)
# Use dependency find modules available relative to this package config.
list(PREPEND CMAKE_MODULE_PATH
${CERES_CURRENT_CONFIG_DIR}/CeresFindModules
${CERES_CURRENT_CONFIG_DIR})
# Set the version.
set(CERES_VERSION @CERES_VERSION@)
include(CMakeFindDependencyMacro)
# Required dependencies
find_dependency(Threads)
# Optional dependencies
@METIS_DEPENDENCY@
@SuiteSparse_DEPENDENCY@
@CUDAToolkit_DEPENDENCY@
@cudss_DEPENDENCY@
@Threads_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
@@ -187,27 +125,25 @@ if (_CERES_USE_SYSTEM_ABSL)
find_dependency(absl ${_CERES_ABSL_VERSION})
if (NOT absl_VERSION)
if (NOT TARGET absl::absl_vlog_is_on)
ceres_report_not_found("The version of abseil installed on the system "
ceres_set_not_found("The version of abseil installed on the system "
"provides no version info and is missing TARGET 'absl::absl_vlog_is_on'")
endif ()
endif ()
else ()
# absl from submodule, configs installed with ceres-solver
get_filename_component(_ABSL_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH)
get_filename_component(_ABSL_IMPORT_PREFIX "${_ABSL_IMPORT_PREFIX}" PATH)
set(_ABSL_IMPORT_PREFIX "${_ABSL_IMPORT_PREFIX}/absl")
find_dependency(absl ${_CERES_ABSL_VERSION} HINTS "${_ABSL_IMPORT_PREFIX}")
set(_CERES_ABSL_HINTS
"${CERES_CURRENT_CONFIG_DIR}/third_party/abseil-cpp"
"${CERES_CURRENT_CONFIG_DIR}/../absl")
find_dependency(absl ${_CERES_ABSL_VERSION} HINTS ${_CERES_ABSL_HINTS})
unset(_CERES_ABSL_HINTS)
endif ()
ceres_message(STATUS "Found required Ceres dependency: "
"absl version ${_CERES_ABSL_VERSION} in ${absl_DIR}")
unset(_CERES_ABSL_VERSION)
unset(_CERES_USE_SYSTEM_ABSL)
# Eigen.
# Flag set during configuration and build of Ceres.
set(CERES_EIGEN_VERSION @Eigen3_VERSION@)
# Search quietly to control the timing of the error message if not found. The
# search should be for an exact match, but for usability reasons do a soft
# The search should be for an exact match, but for usability reasons do a soft
# match and reject with an explanation below.
find_package(Eigen3 ${CERES_EIGEN_VERSION} QUIET)
if (Eigen3_FOUND)
@@ -215,17 +151,15 @@ if (Eigen3_FOUND)
# CMake's VERSION check in FIND_PACKAGE() will accept any version >= the
# specified version. However, only version = is supported. Improve
# usability by explaining why we don't accept non-exact version matching.
ceres_report_not_found("Found Eigen dependency, but the version of Eigen "
ceres_set_not_found("Found Eigen dependency, but the version of Eigen "
"found (${Eigen3_VERSION}) does not exactly match the version of Eigen "
"Ceres was compiled with (${CERES_EIGEN_VERSION}). This can cause subtle "
"bugs by triggering violations of the One Definition Rule. See the "
"Wikipedia article http://en.wikipedia.org/wiki/One_Definition_Rule "
"for more details")
endif ()
ceres_message(STATUS "Found required Ceres dependency: "
"Eigen version ${CERES_EIGEN_VERSION} in ${Eigen3_DIR}")
else (Eigen3_FOUND)
ceres_report_not_found("Missing required Ceres "
ceres_set_not_found("Missing required Ceres "
"dependency: Eigen version ${CERES_EIGEN_VERSION}, please set "
"Eigen3_DIR.")
endif (Eigen3_FOUND)
@@ -240,59 +174,54 @@ set(CERES_LIBRARIES Ceres::ceres)
# Reset CMake module path to its state when this script was called.
set(CMAKE_MODULE_PATH ${CALLERS_CMAKE_MODULE_PATH})
# Build the detected Ceres version string to correctly capture whether it
# was installed, or exported.
ceres_pretty_print_cmake_list(CERES_COMPILED_COMPONENTS_STRING
${CERES_COMPILED_COMPONENTS})
if (CERES_WAS_INSTALLED)
set(CERES_DETECTED_VERSION_STRING "Ceres version: ${CERES_VERSION} "
"installed in: ${CURRENT_ROOT_INSTALL_DIR} with components: "
"${CERES_COMPILED_COMPONENTS_STRING}")
else (CERES_WAS_INSTALLED)
set(CERES_DETECTED_VERSION_STRING "Ceres version: ${CERES_VERSION} "
"exported from build directory: ${CERES_EXPORTED_BUILD_DIR} with "
"components: ${CERES_COMPILED_COMPONENTS_STRING}")
endif()
# Advertise compiled components and let CMake apply required and optional
# component semantics.
foreach(_Ceres_component IN LISTS Ceres_FIND_COMPONENTS)
set(Ceres_${_Ceres_component}_FOUND FALSE)
endforeach()
foreach(_Ceres_component IN LISTS CERES_COMPILED_COMPONENTS)
set(Ceres_${_Ceres_component}_FOUND TRUE)
endforeach()
# If the user called this script through find_package() whilst specifying
# particular Ceres components that should be found via:
# find_package(Ceres COMPONENTS XXX YYY), check the requested components against
# those with which Ceres was compiled. In this case, we should only report
# Ceres as found if all the requested components have been found.
if (Ceres_FIND_COMPONENTS)
foreach (REQUESTED_COMPONENT ${Ceres_FIND_COMPONENTS})
list(FIND CERES_COMPILED_COMPONENTS ${REQUESTED_COMPONENT} HAVE_REQUESTED_COMPONENT)
# list(FIND ..) returns -1 if the element was not in the list, but CMake
# interprets if (VAR) to be true if VAR is any non-zero number, even
# negative ones, hence we have to explicitly check for >= 0.
if (HAVE_REQUESTED_COMPONENT EQUAL -1)
# Check for the presence of all requested components before reporting
# not found, such that we report all of the missing components rather
# than just the first.
list(APPEND MISSING_CERES_COMPONENTS ${REQUESTED_COMPONENT})
endif()
endforeach()
if (MISSING_CERES_COMPONENTS)
ceres_pretty_print_cmake_list(REQUESTED_CERES_COMPONENTS_STRING
${Ceres_FIND_COMPONENTS})
ceres_pretty_print_cmake_list(MISSING_CERES_COMPONENTS_STRING
${MISSING_CERES_COMPONENTS})
ceres_report_not_found("Missing requested Ceres components: "
"${MISSING_CERES_COMPONENTS_STRING} (components requested: "
"${REQUESTED_CERES_COMPONENTS_STRING}). Detected "
"${CERES_DETECTED_VERSION_STRING}.")
set(_Ceres_missing_required_components)
foreach(_Ceres_component IN LISTS Ceres_FIND_COMPONENTS)
if (Ceres_FIND_REQUIRED_${_Ceres_component}
AND NOT Ceres_${_Ceres_component}_FOUND)
list(APPEND _Ceres_missing_required_components ${_Ceres_component})
endif()
endforeach()
unset(_Ceres_component)
set(Ceres_FOUND TRUE)
check_required_components(Ceres)
if (NOT Ceres_FOUND)
list(LENGTH _Ceres_missing_required_components
_Ceres_missing_required_component_count)
if (_Ceres_missing_required_component_count EQUAL 1)
set(_Ceres_component_noun "component")
else()
set(_Ceres_component_noun "components")
endif()
string(JOIN ", " _Ceres_missing_required_components_string
${_Ceres_missing_required_components})
string(CONCAT _Ceres_missing_required_components_reason
"Missing required Ceres ${_Ceres_component_noun}: "
"${_Ceres_missing_required_components_string}.")
if (CERES_COMPILED_COMPONENTS)
string(JOIN ", " CERES_COMPILED_COMPONENTS_STRING
${CERES_COMPILED_COMPONENTS})
ceres_set_not_found(
"${_Ceres_missing_required_components_reason}"
"Available components: ${CERES_COMPILED_COMPONENTS_STRING}.")
else()
ceres_set_not_found(
"${_Ceres_missing_required_components_reason}"
"No Ceres components are available.")
endif()
endif()
# As we use CERES_REPORT_NOT_FOUND() to abort, if we reach this point we have
# found Ceres and all required dependencies.
ceres_message(STATUS "Found " ${CERES_DETECTED_VERSION_STRING})
# Set CERES_FOUND to be equivalent to Ceres_FOUND, which is set to
# TRUE by FindPackage() if this file is found and run, and after which
# Ceres_FOUND is not (explicitly, i.e. undefined does not count) set
# to FALSE.
set(CERES_FOUND TRUE)
# Preserve the legacy uppercase result variable.
set(CERES_FOUND ${Ceres_FOUND})
if (NOT TARGET ceres)
# For backwards compatibility, create a local 'alias' target with the
+2 -3
View File
@@ -56,9 +56,9 @@ set(CERES_CONFIG_IN_FILE "${CMAKE_CURRENT_LIST_DIR}/config.h.in")
# will be <src>/include/ceres/internal.
function(CREATE_CERES_CONFIG CURRENT_CERES_COMPILE_OPTIONS CERES_CONFIG_OUTPUT_DIRECTORY)
# Create the specified output directory if it does not exist.
# Creating the generated directory is an internal setup detail.
if (NOT EXISTS "${CERES_CONFIG_OUTPUT_DIRECTORY}")
message(STATUS "Creating configured Ceres config.h output directory: "
message(DEBUG "Creating configured Ceres config.h output directory: "
"${CERES_CONFIG_OUTPUT_DIRECTORY}")
file(MAKE_DIRECTORY "${CERES_CONFIG_OUTPUT_DIRECTORY}")
endif()
@@ -89,7 +89,6 @@ function(CREATE_CERES_CONFIG CURRENT_CERES_COMPILE_OPTIONS CERES_CONFIG_OUTPUT_D
# interprets if (VAR) to be true if VAR is any non-zero number, even
# negative ones, hence we have to explicitly check for >= 0.
if (OPTION_ENABLED GREATER -1)
message(STATUS "Enabling ${CERES_OPTION} in Ceres config.h")
set(${CERES_OPTION} "#define ${CERES_OPTION}")
# Remove the item from the list of current options so that we can identify
+1 -1
View File
@@ -85,7 +85,7 @@ macro(enable_sanitizer)
message(FATAL_ERROR "Specified sanitizer: ${REQUESTED_SANITIZER} is not "
"supported by the compiler.")
endif()
message(STATUS "Enabling sanitizer: ${REQUESTED_SANITIZER}")
message(DEBUG "Enabling sanitizer: ${REQUESTED_SANITIZER}")
set(ADDED_SANITIZER TRUE)
# As per the Clang documentation, the sanitizer flags must be added to both
# the compiler and linker flags.
+29 -38
View File
@@ -1,5 +1,5 @@
# Ceres Solver - A fast non-linear least squares minimizer
# Copyright 2023 Google Inc. All rights reserved.
# Copyright 2026 Google Inc. All rights reserved.
# http://ceres-solver.org/
#
# Redistribution and use in source and binary forms, with or without
@@ -34,20 +34,20 @@
# Note that this is distinct from the Accelerate
# framework on its own, which existed in previous
# versions but without the sparse solvers.
# Apple does not provide a CMake package configuration for this API. This
# module verifies the headers, framework library, and sparse solver symbols.
#
# This module defines the following variables which should be referenced
# by the caller to use the library.
# This module defines the following variables.
#
# AccelerateSparse_FOUND: TRUE iff an Accelerate framework including the sparse
# solvers, and all dependencies, has been found.
# AccelerateSparse_INCLUDE_DIRS: Include directories for Accelerate framework.
# AccelerateSparse_LIBRARIES: Libraries for Accelerate framework and all
# dependencies.
#
# 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
# The following imported target is also defined when the package is found:
#
# AccelerateSparse::Accelerate: Accelerate framework with sparse solvers.
#
# The following variables affect the behavior 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,
@@ -62,31 +62,24 @@
# any dependencies.
# Called if we failed to find the Accelerate framework with the sparse solvers.
# Unsets all public (designed to be used externally) variables and reports
# error message at priority depending upon [REQUIRED/QUIET/<NONE>] argument.
# Lets the standard package helper report the failure.
macro(accelerate_sparse_report_not_found REASON_MSG)
unset(AccelerateSparse_FOUND)
unset(AccelerateSparse_INCLUDE_DIRS)
unset(AccelerateSparse_LIBRARIES)
# Make results of search visible in the CMake GUI if Accelerate has not
# been found so that user does not have to toggle to advanced view.
mark_as_advanced(CLEAR AccelerateSparse_INCLUDE_DIR
AccelerateSparse_LIBRARY)
# Note <package>_FIND_[REQUIRED/QUIETLY] variables defined by FindPackage()
# use the camelcase library name, not uppercase.
if (AccelerateSparse_FIND_QUIETLY)
message(STATUS "Failed to find Accelerate framework with sparse solvers - "
${REASON_MSG} ${ARGN})
elseif (AccelerateSparse_FIND_REQUIRED)
message(FATAL_ERROR "Failed to find Accelerate framework with sparse solvers - "
${REASON_MSG} ${ARGN})
if (ARGN)
string(JOIN " " ACCELERATE_SPARSE_FAILURE_REASON
"${REASON_MSG}" ${ARGN})
else()
# Neither QUIETLY nor REQUIRED, use no priority which emits a message
# but continues configuration and allows generation.
message("-- Failed to find Accelerate framework with sparse solvers - "
${REASON_MSG} ${ARGN})
set(ACCELERATE_SPARSE_FAILURE_REASON "${REASON_MSG}")
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(AccelerateSparse
REQUIRED_VARS AccelerateSparse_INCLUDE_DIR AccelerateSparse_LIBRARY
REASON_FAILURE_MESSAGE "${ACCELERATE_SPARSE_FAILURE_REASON}")
return()
endmacro()
@@ -96,16 +89,14 @@ find_path(AccelerateSparse_INCLUDE_DIR NAMES Accelerate.h)
if (NOT AccelerateSparse_INCLUDE_DIR OR
NOT EXISTS ${AccelerateSparse_INCLUDE_DIR})
accelerate_sparse_report_not_found(
"Could not find Accelerate framework headers. Set "
"AccelerateSparse_INCLUDE_DIR to the directory containing Accelerate.h")
"Could not find AccelerateSparse because the Accelerate framework headers were not found")
endif()
find_library(AccelerateSparse_LIBRARY NAMES Accelerate)
if (NOT AccelerateSparse_LIBRARY OR
NOT EXISTS ${AccelerateSparse_LIBRARY})
accelerate_sparse_report_not_found(
"Could not find Accelerate framework. Set AccelerateSparse_LIBRARY "
"to the Accelerate.framework directory")
"Could not find AccelerateSparse because the Accelerate framework was not found. Set AccelerateSparse_LIBRARY to the Accelerate.framework directory")
endif()
set(AccelerateSparse_FOUND TRUE)
@@ -126,20 +117,20 @@ unset(CMAKE_REQUIRED_INCLUDES)
unset(CMAKE_REQUIRED_LIBRARIES)
if (NOT ACCELERATE_FRAMEWORK_HAS_SPARSE_SOLVER)
accelerate_sparse_report_not_found(
"Detected Accelerate framework: ${AccelerateSparse_LIBRARY} does not "
"include the sparse solvers.")
endif()
if (AccelerateSparse_FOUND)
set(AccelerateSparse_INCLUDE_DIRS ${AccelerateSparse_INCLUDE_DIR})
set(AccelerateSparse_LIBRARIES ${AccelerateSparse_LIBRARY})
"Could not find AccelerateSparse because the Accelerate framework ${AccelerateSparse_LIBRARY} does not include the sparse solvers")
endif()
# Handle REQUIRED / QUIET optional arguments and version.
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(AccelerateSparse
REQUIRED_VARS AccelerateSparse_INCLUDE_DIRS AccelerateSparse_LIBRARIES)
REQUIRED_VARS AccelerateSparse_INCLUDE_DIR AccelerateSparse_LIBRARY)
if (AccelerateSparse_FOUND)
if (NOT TARGET AccelerateSparse::Accelerate)
add_library(AccelerateSparse::Accelerate UNKNOWN IMPORTED)
set_target_properties(AccelerateSparse::Accelerate PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${AccelerateSparse_INCLUDE_DIR}"
IMPORTED_LOCATION "${AccelerateSparse_LIBRARY}")
endif()
mark_as_advanced(FORCE AccelerateSparse_INCLUDE_DIR
AccelerateSparse_LIBRARY)
endif()
+245 -122
View File
@@ -1,5 +1,5 @@
# Ceres Solver - A fast non-linear least squares minimizer
# Copyright 2023 Google Inc. All rights reserved.
# Copyright 2026 Google Inc. All rights reserved.
# http://ceres-solver.org/
#
# Redistribution and use in source and binary forms, with or without
@@ -35,6 +35,10 @@ FindSuiteSparse
Module for locating SuiteSparse libraries and its dependencies.
SuiteSparse 7 and later provide a unified CMake package configuration. This
module retains a component-based fallback for older supported releases such as
SuiteSparse 5.10.1 in Ubuntu 22.04.
This module defines the following variables:
``SuiteSparse_FOUND``
@@ -93,14 +97,30 @@ Optional SuiteSparse dependencies:
Serial Graph Partitioning and Fill-reducing Matrix Ordering (METIS)
]=======================================================================]
# Keep native package-config diagnostics deterministic.
if (SuiteSparse_FIND_COMPONENTS)
list(SORT SuiteSparse_FIND_COMPONENTS COMPARE STRING CASE INSENSITIVE)
endif ()
if (NOT SuiteSparse_NO_CMAKE)
find_package (SuiteSparse NO_MODULE QUIET)
if (SuiteSparse_FOUND)
# Report the main include directory instead of the package configuration
# file path in FindPackageHandleStandardArgs' standard success message.
get_target_property(SuiteSparse_INCLUDE_DIR SuiteSparse::Config
INTERFACE_INCLUDE_DIRECTORIES)
if (SuiteSparse_INCLUDE_DIR)
list(GET SuiteSparse_INCLUDE_DIR -1 SuiteSparse_INCLUDE_DIR)
endif ()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(SuiteSparse
REQUIRED_VARS SuiteSparse_INCLUDE_DIR
VERSION_VAR SuiteSparse_VERSION
HANDLE_COMPONENTS)
return ()
endif (SuiteSparse_FOUND)
endif (NOT SuiteSparse_NO_CMAKE)
if (SuiteSparse_FOUND)
return ()
endif (SuiteSparse_FOUND)
# Push CMP0057 to enable support for IN_LIST, when cmake_minimum_required is
# set to <3.3.
cmake_policy (PUSH)
@@ -121,10 +141,28 @@ if (NOT SuiteSparse_FIND_COMPONENTS)
endforeach (component IN LISTS SuiteSparse_FIND_COMPONENTS)
endif (NOT SuiteSparse_FIND_COMPONENTS)
# Assume SuiteSparse was found and set it to false only if third-party
# dependencies could not be located. SuiteSparse components are handled by
# FindPackageHandleStandardArgs HANDLE_COMPONENTS option.
# Assume SuiteSparse was found and set it to false when a component or a
# third-party dependency could not be located. SuiteSparse component failures
# are reported by FindPackageHandleStandardArgs HANDLE_COMPONENTS.
set (SuiteSparse_FOUND TRUE)
set (CMAKE_FIND_PACKAGE_REASON)
# Keep nested dependency failures available for SuiteSparse's final reason.
macro (suitesparse_find_dependency DEPENDENCY)
find_package(${DEPENDENCY} ${ARGN} QUIET)
if (NOT ${DEPENDENCY}_FOUND)
set (SuiteSparse_${DEPENDENCY}_REASON
"${DEPENDENCY}: Could not find ${DEPENDENCY}.")
if (${DEPENDENCY}_NOT_FOUND_MESSAGE)
set (SuiteSparse_${DEPENDENCY}_REASON
"${DEPENDENCY}: ${${DEPENDENCY}_NOT_FOUND_MESSAGE}")
endif ()
endif ()
endmacro (suitesparse_find_dependency)
# SuiteSparseQR optionally depends on TBB. Find it here so that it is treated
# as a SuiteSparse dependency rather than as a Ceres dependency.
suitesparse_find_dependency(TBB NO_MODULE)
include (CheckLibraryExists)
include (CheckSymbolExists)
@@ -152,6 +190,7 @@ list (APPEND SuiteSparse_FIND_COMPONENTS ${SuiteSparse_IMPLICIT_COMPONENTS})
# Do not list components multiple times.
list (REMOVE_DUPLICATES SuiteSparse_FIND_COMPONENTS)
list (SORT SuiteSparse_FIND_COMPONENTS COMPARE STRING CASE INSENSITIVE)
# Reset CALLERS_CMAKE_FIND_LIBRARY_PREFIXES to its value when
# FindSuiteSparse was invoked.
@@ -161,12 +200,12 @@ macro(SuiteSparse_RESET_FIND_LIBRARY_PREFIX)
endif (MSVC)
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.
# Called if we failed to find SuiteSparse or any of its required dependencies.
# The standard package helper reports the failure after all components have
# been checked.
macro(SuiteSparse_REPORT_NOT_FOUND REASON_MSG)
# Will be set to FALSE by find_package_handle_standard_args
unset (SuiteSparse_FOUND)
set (SuiteSparse_FOUND FALSE)
list (APPEND CMAKE_FIND_PACKAGE_REASON "${REASON_MSG}")
# Do NOT unset SuiteSparse_REQUIRED_VARS here, as it is used by
# FindPackageHandleStandardArgs() to generate the automatic error message on
@@ -174,21 +213,7 @@ macro(SuiteSparse_REPORT_NOT_FOUND REASON_MSG)
suitesparse_reset_find_library_prefix()
# Note <package>_FIND_[REQUIRED/QUIETLY] variables defined by FindPackage()
# use the camelcase library name, not uppercase.
if (SuiteSparse_FIND_QUIETLY)
message(STATUS "Failed to find SuiteSparse - " ${REASON_MSG} ${ARGN})
elseif (SuiteSparse_FIND_REQUIRED)
message(FATAL_ERROR "Failed to find SuiteSparse - " ${REASON_MSG} ${ARGN})
else()
# Neither QUIETLY nor REQUIRED, use no priority which emits a message
# but continues configuration and allows generation.
message("-- Failed to find SuiteSparse - " ${REASON_MSG} ${ARGN})
endif (SuiteSparse_FIND_QUIETLY)
# 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.
# Do not return so all components can be checked before standard reporting.
endmacro(SuiteSparse_REPORT_NOT_FOUND)
# Handle possible presence of lib prefix for libraries on MSVC, see
@@ -222,18 +247,13 @@ macro(suitesparse_find_component COMPONENT)
NAMES ${SuiteSparse_FIND_COMPONENT_${COMPONENT}_FILES}
PATH_SUFFIXES ${SuiteSparse_CHECK_PATH_SUFFIXES})
if (SuiteSparse_${COMPONENT}_INCLUDE_DIR)
message(STATUS "Found ${COMPONENT} headers in: "
"${SuiteSparse_${COMPONENT}_INCLUDE_DIR}")
mark_as_advanced(SuiteSparse_${COMPONENT}_INCLUDE_DIR)
else()
# Specified headers not found.
set(SuiteSparse_${COMPONENT}_FOUND FALSE)
if (SuiteSparse_FIND_REQUIRED_${COMPONENT})
suitesparse_report_not_found(
"Did not find ${COMPONENT} header (required SuiteSparse component).")
set(SuiteSparse_FOUND FALSE)
else()
message(STATUS "Did not find ${COMPONENT} header (optional "
"SuiteSparse component).")
# Hide optional vars from CMake GUI even if not found.
mark_as_advanced(SuiteSparse_${COMPONENT}_INCLUDE_DIR)
endif()
@@ -245,17 +265,13 @@ macro(suitesparse_find_component COMPONENT)
NAMES ${SuiteSparse_FIND_COMPONENT_${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)
else ()
# Specified libraries not found.
set(SuiteSparse_${COMPONENT}_FOUND FALSE)
if (SuiteSparse_FIND_REQUIRED_${COMPONENT})
suitesparse_report_not_found(
"Did not find ${COMPONENT} library (required SuiteSparse component).")
set(SuiteSparse_FOUND FALSE)
else()
message(STATUS "Did not find ${COMPONENT} library (optional SuiteSparse "
"dependency)")
# Hide optional vars from CMake GUI even if not found.
mark_as_advanced(SuiteSparse_${COMPONENT}_LIBRARY)
endif()
@@ -290,18 +306,14 @@ endmacro()
unset(SuiteSparse_REQUIRED_VARS)
# BLAS.
find_package(BLAS QUIET)
if (NOT BLAS_FOUND)
suitesparse_report_not_found(
"Did not find BLAS library (required for SuiteSparse).")
endif (NOT BLAS_FOUND)
if (NOT DEFINED BLAS_FOUND)
suitesparse_find_dependency(BLAS)
endif()
# LAPACK.
find_package(LAPACK QUIET)
if (NOT LAPACK_FOUND)
suitesparse_report_not_found(
"Did not find LAPACK library (required for SuiteSparse).")
endif (NOT LAPACK_FOUND)
if (NOT DEFINED LAPACK_FOUND)
suitesparse_find_dependency(LAPACK)
endif()
foreach (component IN LISTS SuiteSparse_FIND_COMPONENTS)
if (component STREQUAL Partition)
@@ -325,68 +337,14 @@ foreach (component IN LISTS SuiteSparse_FIND_COMPONENTS)
LIBRARIES ${component_library})
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.
find_package(TBB QUIET NO_MODULE)
if (TBB_FOUND)
message(STATUS "Found Intel Thread Building Blocks (TBB) library "
"(${TBB_VERSION}). "
"Assuming SuiteSparseQR was compiled with TBB.")
# Add the TBB libraries to the SuiteSparseQR libraries (the only
# libraries to optionally depend on TBB).
set_property (TARGET SuiteSparse::SPQR APPEND PROPERTY
INTERFACE_LINK_LIBRARIES TBB::tbb)
else (TBB_FOUND)
message(STATUS "Did not find Intel TBB library, assuming SuiteSparseQR was "
"not compiled with TBB.")
endif (TBB_FOUND)
endif (TARGET SuiteSparse::SPQR)
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 (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)
# 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)
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)
# SuiteSparse version >= 4.
set(SuiteSparse_VERSION_FILE
${SuiteSparse_Config_INCLUDE_DIR}/SuiteSparse_config.h)
if (NOT EXISTS ${SuiteSparse_VERSION_FILE})
list(APPEND SuiteSparse_REQUIRED_VARS SuiteSparse_VERSION)
suitesparse_report_not_found(
"Could not find file: ${SuiteSparse_VERSION_FILE} containing version "
"information for >= v4 SuiteSparse installs, but SuiteSparse_config was "
@@ -423,6 +381,7 @@ if (TARGET SuiteSparse::Config)
unset (SuiteSparse_VERSION_MAJOR)
unset (SuiteSparse_VERSION_MINOR)
unset (SuiteSparse_VERSION_PATCH)
list(APPEND SuiteSparse_REQUIRED_VARS SuiteSparse_VERSION)
endif (SuiteSparse_VERSION MATCHES "[0-9]+\\.[0-9]+\\.[0-9]+")
endif (NOT EXISTS ${SuiteSparse_VERSION_FILE})
endif (TARGET SuiteSparse::Config)
@@ -436,6 +395,7 @@ if (TARGET SuiteSparse::CHOLMOD)
else (TARGET SuiteSparse::${component})
# Consider CHOLMOD not found if COLAMD cannot be found
set (SuiteSparse_CHOLMOD_FOUND FALSE)
set (SuiteSparse_FOUND FALSE)
endif (TARGET SuiteSparse::${component})
endforeach (component IN ITEMS AMD CAMD CCOLAMD COLAMD)
endif (TARGET SuiteSparse::CHOLMOD)
@@ -447,7 +407,8 @@ if (TARGET SuiteSparse::SPQR)
INTERFACE_LINK_LIBRARIES SuiteSparse::CHOLMOD)
else (TARGET SuiteSparse::CHOLMOD)
# Consider SPQR not found if CHOLMOD cannot be found
set (SuiteSparse_SQPR_FOUND FALSE)
set (SuiteSparse_SPQR_FOUND FALSE)
set (SuiteSparse_FOUND FALSE)
endif (TARGET SuiteSparse::CHOLMOD)
endif (TARGET SuiteSparse::SPQR)
@@ -465,13 +426,180 @@ if (TARGET SuiteSparse::Config)
endforeach (component IN LISTS SuiteSparse_FIND_COMPONENTS)
endif (TARGET SuiteSparse::Config)
# Check whether the SuiteSparse libraries need their optional dependencies.
# This avoids adding libraries that are available but are not required by the
# installed SuiteSparse build.
function (suitesparse_check_link RESULT SYMBOL)
set (SuiteSparse_LINK_CHECK_SOURCE
"${CMAKE_BINARY_DIR}/CMakeFiles/SuiteSparseLinkCheck.cxx")
file (WRITE "${SuiteSparse_LINK_CHECK_SOURCE}"
"extern \"C\" void ${SYMBOL}(void);\n"
"int main(void) { ${SYMBOL}(); return 0; }\n")
unset (SuiteSparse_LINK_CHECK_RESULT CACHE)
unset (SuiteSparse_LINK_CHECK_RESULT)
try_compile (SuiteSparse_LINK_CHECK_RESULT
"${CMAKE_BINARY_DIR}/CMakeFiles/SuiteSparseLinkCheck"
"${SuiteSparse_LINK_CHECK_SOURCE}"
LINK_LIBRARIES ${ARGN}
OUTPUT_VARIABLE SuiteSparse_LINK_CHECK_OUTPUT)
set (${RESULT} ${SuiteSparse_LINK_CHECK_RESULT} PARENT_SCOPE)
unset (SuiteSparse_LINK_CHECK_RESULT CACHE)
unset (SuiteSparse_LINK_CHECK_RESULT)
endfunction (suitesparse_check_link)
set (SuiteSparse_LINK_TARGET)
set (SuiteSparse_LINK_SYMBOL)
if (TARGET SuiteSparse::SPQR)
set (SuiteSparse_LINK_TARGET SuiteSparse::SPQR)
set (SuiteSparse_LINK_SYMBOL SuiteSparseQR_C_symbolic)
elseif (TARGET SuiteSparse::CHOLMOD)
set (SuiteSparse_LINK_TARGET SuiteSparse::CHOLMOD)
set (SuiteSparse_LINK_SYMBOL cholmod_start)
endif ()
set (SuiteSparse_BLAS_LINK)
if (TARGET BLAS::BLAS)
set (SuiteSparse_BLAS_LINK BLAS::BLAS)
elseif (BLAS_LIBRARIES)
set (SuiteSparse_BLAS_LINK ${BLAS_LIBRARIES})
endif ()
set (SuiteSparse_LAPACK_LINK)
if (TARGET LAPACK::LAPACK)
set (SuiteSparse_LAPACK_LINK LAPACK::LAPACK)
elseif (LAPACK_LIBRARIES)
set (SuiteSparse_LAPACK_LINK ${LAPACK_LIBRARIES})
endif ()
set (SuiteSparse_TBB_LINK)
if (TARGET TBB::tbb)
set (SuiteSparse_TBB_LINK TBB::tbb)
elseif (TBB_LIBRARIES)
set (SuiteSparse_TBB_LINK ${TBB_LIBRARIES})
endif ()
set (SuiteSparse_RT_LINK)
if (HAVE_LIBRT)
set (SuiteSparse_RT_LINK rt)
endif ()
set (SuiteSparse_OPTIONAL_DEPENDENCIES)
if (SuiteSparse_BLAS_LINK)
list (APPEND SuiteSparse_OPTIONAL_DEPENDENCIES BLAS)
endif ()
if (SuiteSparse_LAPACK_LINK)
list (APPEND SuiteSparse_OPTIONAL_DEPENDENCIES LAPACK)
endif ()
if (TARGET SuiteSparse::SPQR AND SuiteSparse_TBB_LINK)
list (APPEND SuiteSparse_OPTIONAL_DEPENDENCIES TBB)
endif ()
if (SuiteSparse_RT_LINK)
list (APPEND SuiteSparse_OPTIONAL_DEPENDENCIES RT)
endif ()
if (SuiteSparse_FOUND AND SuiteSparse_LINK_TARGET)
get_target_property(SuiteSparse_ORIGINAL_CONFIG_LINK
SuiteSparse::Config INTERFACE_LINK_LIBRARIES)
if (SuiteSparse_ORIGINAL_CONFIG_LINK MATCHES "-NOTFOUND$")
set (SuiteSparse_ORIGINAL_CONFIG_LINK)
endif ()
if (TARGET SuiteSparse::SPQR)
get_target_property(SuiteSparse_ORIGINAL_SPQR_LINK
SuiteSparse::SPQR INTERFACE_LINK_LIBRARIES)
if (SuiteSparse_ORIGINAL_SPQR_LINK MATCHES "-NOTFOUND$")
set (SuiteSparse_ORIGINAL_SPQR_LINK)
endif ()
endif ()
function (suitesparse_set_link_dependencies)
set (SuiteSparse_CONFIG_LINK ${SuiteSparse_ORIGINAL_CONFIG_LINK})
if (BLAS IN_LIST ARGN)
list (APPEND SuiteSparse_CONFIG_LINK ${SuiteSparse_BLAS_LINK})
endif ()
if (LAPACK IN_LIST ARGN)
list (APPEND SuiteSparse_CONFIG_LINK ${SuiteSparse_LAPACK_LINK})
endif ()
if (RT IN_LIST ARGN)
list (APPEND SuiteSparse_CONFIG_LINK ${SuiteSparse_RT_LINK})
endif ()
set_property (TARGET SuiteSparse::Config PROPERTY
INTERFACE_LINK_LIBRARIES "${SuiteSparse_CONFIG_LINK}")
if (TARGET SuiteSparse::SPQR)
set (SuiteSparse_SPQR_LINK ${SuiteSparse_ORIGINAL_SPQR_LINK})
if (TBB IN_LIST ARGN)
list (APPEND SuiteSparse_SPQR_LINK ${SuiteSparse_TBB_LINK})
endif ()
set_property (TARGET SuiteSparse::SPQR PROPERTY
INTERFACE_LINK_LIBRARIES "${SuiteSparse_SPQR_LINK}")
endif ()
endfunction (suitesparse_set_link_dependencies)
suitesparse_set_link_dependencies(${SuiteSparse_OPTIONAL_DEPENDENCIES})
suitesparse_check_link(SuiteSparse_LINKS
${SuiteSparse_LINK_SYMBOL} ${SuiteSparse_LINK_TARGET})
if (SuiteSparse_LINKS)
set (SuiteSparse_REQUIRED_DEPENDENCIES)
foreach (dependency IN LISTS SuiteSparse_OPTIONAL_DEPENDENCIES)
set (SuiteSparse_DEPENDENCIES_WITHOUT
${SuiteSparse_OPTIONAL_DEPENDENCIES})
list (REMOVE_ITEM SuiteSparse_DEPENDENCIES_WITHOUT ${dependency})
suitesparse_set_link_dependencies(${SuiteSparse_DEPENDENCIES_WITHOUT})
suitesparse_check_link(SuiteSparse_LINKS_WITHOUT_DEPENDENCY
${SuiteSparse_LINK_SYMBOL} ${SuiteSparse_LINK_TARGET})
if (NOT SuiteSparse_LINKS_WITHOUT_DEPENDENCY)
list (APPEND SuiteSparse_REQUIRED_DEPENDENCIES ${dependency})
endif ()
endforeach ()
suitesparse_set_link_dependencies(${SuiteSparse_REQUIRED_DEPENDENCIES})
else ()
suitesparse_set_link_dependencies()
list (APPEND SuiteSparse_REQUIRED_VARS SuiteSparse_LINKS)
set (SuiteSparse_MISSING_DEPENDENCIES)
if (NOT SuiteSparse_BLAS_LINK)
list (APPEND SuiteSparse_MISSING_DEPENDENCIES BLAS)
endif ()
if (NOT SuiteSparse_LAPACK_LINK)
list (APPEND SuiteSparse_MISSING_DEPENDENCIES LAPACK)
endif ()
if (TARGET SuiteSparse::SPQR AND NOT SuiteSparse_TBB_LINK)
list (APPEND SuiteSparse_MISSING_DEPENDENCIES TBB)
endif ()
if (NOT SuiteSparse_RT_LINK)
list (APPEND SuiteSparse_MISSING_DEPENDENCIES RT)
endif ()
if (SuiteSparse_MISSING_DEPENDENCIES)
foreach (dependency IN LISTS SuiteSparse_MISSING_DEPENDENCIES)
if (SuiteSparse_${dependency}_REASON)
list (APPEND CMAKE_FIND_PACKAGE_REASON
"${SuiteSparse_${dependency}_REASON}")
endif ()
endforeach ()
set (SuiteSparse_LINK_FAILURE_REASON
"SuiteSparse libraries could not be linked with the detected "
"dependencies. The following dependencies were not found, so their "
"necessity could not be determined: ${SuiteSparse_MISSING_DEPENDENCIES}.")
suitesparse_report_not_found("${SuiteSparse_LINK_FAILURE_REASON}")
else ()
set (SuiteSparse_LINK_FAILURE_REASON
"SuiteSparse libraries could not be linked with the detected "
"dependencies.")
suitesparse_report_not_found("${SuiteSparse_LINK_FAILURE_REASON}")
endif ()
endif ()
endif ()
# Check whether CHOLMOD was compiled with METIS support. The check can be
# performed only after the main components have been set up.
if (TARGET SuiteSparse::CHOLMOD)
# NOTE If SuiteSparse was compiled as a static library we'll need to link
# against METIS already during the check. Otherwise, the check can fail due to
# undefined references even though SuiteSparse was compiled with METIS.
find_package (METIS)
if (NOT DEFINED METIS_FOUND)
find_package (METIS)
endif()
if (TARGET METIS::METIS)
cmake_push_check_state (RESET)
@@ -505,23 +633,18 @@ endif (TARGET SuiteSparse::Partition)
suitesparse_reset_find_library_prefix()
# Handle REQUIRED and QUIET arguments to FIND_PACKAGE
list(REMOVE_DUPLICATES SuiteSparse_REQUIRED_VARS)
# Handle REQUIRED and QUIET arguments to FIND_PACKAGE.
include(FindPackageHandleStandardArgs)
if (SuiteSparse_FOUND)
find_package_handle_standard_args(SuiteSparse
REQUIRED_VARS ${SuiteSparse_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_REQUIRED_VARS}
FAIL_MESSAGE "Failed to find some/all required components of SuiteSparse."
HANDLE_COMPONENTS)
endif (SuiteSparse_FOUND)
list(REMOVE_DUPLICATES CMAKE_FIND_PACKAGE_REASON)
string(JOIN "\n " CMAKE_FIND_PACKAGE_REASON
${CMAKE_FIND_PACKAGE_REASON})
find_package_handle_standard_args(SuiteSparse
REQUIRED_VARS ${SuiteSparse_REQUIRED_VARS}
VERSION_VAR SuiteSparse_VERSION
REASON_FAILURE_MESSAGE "${CMAKE_FIND_PACKAGE_REASON}"
HANDLE_COMPONENTS)
# Pop CMP0057.
cmake_policy (POP)
-3
View File
@@ -75,7 +75,4 @@ macro(read_ceres_version_from_source CERES_SOURCE_ROOT)
# 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.;2.;0 nonsense.
set(CERES_VERSION "${CERES_VERSION_MAJOR}.${CERES_VERSION_MINOR}.${CERES_VERSION_PATCH}")
message(STATUS "Detected Ceres version: ${CERES_VERSION} from "
"${CERES_VERSION_FILE}")
endmacro()
-48
View File
@@ -1,48 +0,0 @@
# Ceres Solver - A fast non-linear least squares minimizer
# Copyright 2023 Google Inc. All rights reserved.
# http://ceres-solver.org/
#
# 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 name of Google Inc. nor the names of its 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 OWNER 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.
#
# Author: alexs.mac@gmail.com (Alex Stewart)
# By default, there is no easy way in CMake to set the value of a cache
# variable without reinitialising it, which involves resetting its
# associated help string. This is particularly annoying for CMake options
# where they need to programmatically updated.
#
# This function automates this process by getting the current help string
# for the cache variable to update, then reinitialising it with the new
# value, but with the original help string.
function(UPDATE_CACHE_VARIABLE VAR_NAME VALUE)
get_property(IS_DEFINED_IN_CACHE CACHE ${VAR_NAME} PROPERTY VALUE SET)
if (NOT IS_DEFINED_IN_CACHE)
message(FATAL_ERROR "Specified variable to update in cache: "
"${VAR_NAME} has not been set in the cache.")
endif()
get_property(HELP_STRING CACHE ${VAR_NAME} PROPERTY HELPSTRING)
get_property(VAR_TYPE CACHE ${VAR_NAME} PROPERTY TYPE)
set(${VAR_NAME} ${VALUE} CACHE ${VAR_TYPE} "${HELP_STRING}" FORCE)
endfunction()
+9 -8
View File
@@ -82,7 +82,7 @@ execute_process(COMMAND xcodebuild -version
OUTPUT_STRIP_TRAILING_WHITESPACE)
string(REGEX MATCH "Xcode [0-9\\.]+" XCODE_VERSION "${XCODE_VERSION}")
string(REGEX REPLACE "Xcode ([0-9\\.]+)" "\\1" XCODE_VERSION "${XCODE_VERSION}")
message(STATUS "Building with Xcode version: ${XCODE_VERSION}")
message(VERBOSE "Building with Xcode version: ${XCODE_VERSION}")
# Default to building for iPhoneOS if not specified otherwise, and we cannot
# determine the platform from the CMAKE_OSX_ARCHITECTURES variable. The use
@@ -127,7 +127,7 @@ if (NOT CMAKE_OSX_SYSROOT)
OUTPUT_VARIABLE CMAKE_OSX_SYSROOT
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
message(STATUS "Using SDK: ${CMAKE_OSX_SYSROOT} for platform: ${IOS_PLATFORM}")
message(VERBOSE "Using SDK: ${CMAKE_OSX_SYSROOT} for platform: ${IOS_PLATFORM}")
endif()
if (NOT EXISTS ${CMAKE_OSX_SYSROOT})
message(FATAL_ERROR "Invalid CMAKE_OSX_SYSROOT: ${CMAKE_OSX_SYSROOT} "
@@ -158,14 +158,14 @@ if (NOT CMAKE_C_COMPILER)
OUTPUT_VARIABLE CMAKE_C_COMPILER
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
message(STATUS "Using C compiler: ${CMAKE_C_COMPILER}")
message(VERBOSE "Using C compiler: ${CMAKE_C_COMPILER}")
endif()
if (NOT CMAKE_CXX_COMPILER)
execute_process(COMMAND xcrun -sdk ${CMAKE_OSX_SYSROOT} -find clang++
OUTPUT_VARIABLE CMAKE_CXX_COMPILER
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
message(STATUS "Using CXX compiler: ${CMAKE_CXX_COMPILER}")
message(VERBOSE "Using CXX compiler: ${CMAKE_CXX_COMPILER}")
endif()
# Find (Apple's) libtool.
@@ -173,7 +173,7 @@ execute_process(COMMAND xcrun -sdk ${CMAKE_OSX_SYSROOT} -find libtool
OUTPUT_VARIABLE IOS_LIBTOOL
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
message(STATUS "Using libtool: ${IOS_LIBTOOL}")
message(VERBOSE "Using libtool: ${IOS_LIBTOOL}")
# Configure libtool to be used instead of ar + ranlib to build static libraries.
# This is required on Xcode 7+, but should also work on previous versions of
# Xcode.
@@ -192,13 +192,14 @@ execute_process(COMMAND uname -r
# Unless specified, the latest SDK version is used by default.
set(IOS_DEPLOYMENT_TARGET "${IOS_SDK_VERSION}"
CACHE STRING "Minimum iOS version to build for." )
message(STATUS "Building for minimum iOS version: ${IOS_DEPLOYMENT_TARGET}"
# Toolchain selections are detailed user-facing diagnostics.
message(VERBOSE "Building for minimum iOS version: ${IOS_DEPLOYMENT_TARGET}"
" (SDK version: ${IOS_SDK_VERSION})")
if (NOT IOS_DEPLOYMENT_TARGET VERSION_LESS 11.0)
# iOS 11+ does not support 32-bit architectures (armv7).
foreach(ARCH ${IOS_ARCH})
if (ARCH MATCHES "armv7*")
message(STATUS "Removing iOS architecture: ${ARCH} from build as it is "
message(VERBOSE "Removing iOS architecture: ${ARCH} from build as it is "
"not supported by the minimum iOS version to build for: "
"${IOS_DEPLOYMENT_TARGET} (iOS >= 11 requires 64-bit).")
else()
@@ -208,7 +209,7 @@ if (NOT IOS_DEPLOYMENT_TARGET VERSION_LESS 11.0)
set(IOS_ARCH ${VALID_IOS_ARCH_FOR_SDK_VERSION})
endif()
message(STATUS "Configuring iOS build for platform: ${IOS_PLATFORM}, "
message(VERBOSE "Configuring iOS build for platform: ${IOS_PLATFORM}, "
"architecture(s): ${IOS_ARCH}")
# Standard settings.