├── .gitignore ├── CMakeLists.txt ├── README.md ├── module ├── FindCXSparse.cmake ├── FindGflags.cmake └── FindSuiteSparse.cmake ├── sample ├── city.g2o ├── drifted_circle.g2o ├── intel.g2o └── manhattan.g2o ├── script ├── create_sample.py └── plot_results.py └── src ├── CMakeLists.txt └── se2 ├── CMakeLists.txt ├── error_function.h ├── normalize_angle.h ├── optimize.cc ├── problem.h ├── read_g2o.h └── types.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | # Build files 35 | *build*/* 36 | 37 | # CLion files 38 | .idea/* 39 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.0) 2 | cmake_policy(VERSION 2.8) 3 | 4 | cmake_policy(SET CMP0003 NEW) 5 | if (POLICY CMP0042) 6 | cmake_policy(SET CMP0042 NEW) 7 | endif() 8 | 9 | ################## 10 | # Build Settings # 11 | ################## 12 | 13 | # Set project name 14 | project(pose-graph-optimization C CXX) 15 | 16 | # Set cmake module path 17 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/module) 18 | 19 | # Disable in-source build 20 | set(CMAKE_DISABLE_IN_SOURCE_BUILD ON) 21 | set(CMAKE_DISABLE_SOURCE_CHANGES ON) 22 | 23 | # Set Runtime output path 24 | set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) 25 | 26 | # Set default build type 27 | if(NOT CMAKE_BUILD_TYPE) 28 | set(CMAKE_BUILD_TYPE Release) 29 | endif() 30 | message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") 31 | 32 | # Check if the compiler supports C++11 33 | include(CheckCXXCompilerFlag) 34 | check_cxx_compiler_flag(-std=c++11 COMPILER_SUPPORTS_CXX11) 35 | if(NOT COMPILER_SUPPORTS_CXX11) 36 | message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support!") 37 | endif() 38 | 39 | # Set compiler flags 40 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Wextra -pedantic") 41 | set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g3 -march=native -DDEBUG") 42 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -march=native -DNDEBUG") 43 | 44 | ######################################### 45 | # Set include directories and libraries # 46 | ######################################### 47 | 48 | # core module 49 | include_directories(${PROJECT_SOURCE_DIR}/src) 50 | 51 | # Eigen 52 | find_package(Eigen3 3.3 REQUIRED) 53 | include_directories(${EIGEN3_INCLUDE_DIRS}) 54 | 55 | # Ceres Solver 56 | find_package(Ceres REQUIRED) 57 | include_directories(${Ceres_INCLUDE_DIR}) 58 | 59 | # Lapack for Ceres Solver 60 | find_package(LAPACK) 61 | if (LAPACK_FOUND) 62 | include_directories(${LAPACK_INCLUDE_DIRS}) 63 | endif() 64 | 65 | # CXSparse for Ceres Solver 66 | find_package(CXSparse) 67 | if (CXSPARSE_FOUND) 68 | include_directories(${CXSPARSE_INCLUDE_DIRS}) 69 | endif() 70 | 71 | # SuiteSparse for Ceres Solver 72 | find_package(SuiteSparse) 73 | if (SUITESPARSE_FOUND) 74 | include_directories(${SUITESPARSE_INCLUDE_DIRS}) 75 | endif() 76 | 77 | # Gflags 78 | find_package(Gflags REQUIRED) 79 | include_directories(${GFLAGS_INCLUDE_DIR}) 80 | message("-- Found Google Flags header in: ${GFLAGS_INCLUDE_DIRS}, in namespace: ${GFLAGS_NAMESPACE}") 81 | add_definitions(-DCERES_GFLAGS_NAMESPACE=${GFLAGS_NAMESPACE}) 82 | 83 | # OpenMP 84 | find_package(OpenMP) 85 | if(OPENMP_FOUND) 86 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") 87 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") 88 | endif() 89 | 90 | add_subdirectory(src) 91 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pose-graph-optimizaion 2 | 3 | Sample codes to conduct 2D pose graph optimization with Ceres Solver. 4 | 5 | ## Dependences 6 | 7 | - Eigen 3.3 or later 8 | - Ceres Solver 1.12.0 or later 9 | - Gflags 2.2.0 or later 10 | - Python with matplotlib 11 | 12 | ## Build 13 | 14 | ```bash 15 | $ git clone https://github.com/shinsumicco/pose-graph-optimization.git 16 | $ cd pose-graph-optimization 17 | $ mkdir build 18 | $ cd build 19 | $ cmake .. 20 | $ make -j4 21 | ``` 22 | 23 | ## Optimize 24 | 25 | ```bash 26 | $ cd pose-graph-optimization/build 27 | $ bin/se2_optimize --filename ../sample/manhattan.g2o 28 | Number of poses: 3500 29 | Number of constraints: 5598 30 | 31 | Solver Summary (v 1.13.0-eigen-(3.3.4)-lapack-suitesparse-(4.5.5)-cxsparse-(3.1.9)-no_openmp) 32 | 33 | Original Reduced 34 | Parameter blocks 10500 10497 35 | Parameters 10500 10497 36 | Residual blocks 5598 5598 37 | Residual 16794 16794 38 | 39 | Minimizer TRUST_REGION 40 | 41 | Sparse linear algebra library SUITE_SPARSE 42 | Trust region strategy LEVENBERG_MARQUARDT 43 | 44 | Given Used 45 | Linear solver SPARSE_NORMAL_CHOLESKY SPARSE_NORMAL_CHOLESKY 46 | Threads 1 1 47 | Linear solver threads 1 1 48 | Linear solver ordering AUTOMATIC 10497 49 | 50 | Cost: 51 | Initial 3.457147e+04 52 | Final 7.303833e+01 53 | Change 3.449843e+04 54 | 55 | Minimizer iterations 17 56 | Successful steps 17 57 | Unsuccessful steps 0 58 | 59 | Time (in seconds): 60 | Preprocessor 0.0215 61 | 62 | Residual evaluation 0.0096 63 | Jacobian evaluation 0.0282 64 | Linear solver 0.1898 65 | Minimizer 0.2525 66 | 67 | Postprocessor 0.0005 68 | Total 0.2745 69 | 70 | Termination: CONVERGENCE (Function tolerance reached. |cost_change|/cost: 2.743214e-07 <= 1.000000e-06) 71 | 72 | ``` 73 | 74 | ## Visualize 75 | 76 | ```bash 77 | $ cd pose-graph-optimization 78 | $ python script/plot_results.py build/poses_original.txt build/poses_optimized.txt 79 | ``` 80 | -------------------------------------------------------------------------------- /module/FindCXSparse.cmake: -------------------------------------------------------------------------------- 1 | # Ceres Solver - A fast non-linear least squares minimizer 2 | # Copyright 2015 Google Inc. All rights reserved. 3 | # http://ceres-solver.org/ 4 | # 5 | # Redistribution and use in source and binary forms, with or without 6 | # modification, are permitted provided that the following conditions are met: 7 | # 8 | # * Redistributions of source code must retain the above copyright notice, 9 | # this list of conditions and the following disclaimer. 10 | # * Redistributions in binary form must reproduce the above copyright notice, 11 | # this list of conditions and the following disclaimer in the documentation 12 | # and/or other materials provided with the distribution. 13 | # * Neither the name of Google Inc. nor the names of its contributors may be 14 | # used to endorse or promote products derived from this software without 15 | # specific prior written permission. 16 | # 17 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 | # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | # POSSIBILITY OF SUCH DAMAGE. 28 | # 29 | # Author: alexs.mac@gmail.com (Alex Stewart) 30 | # 31 | 32 | # FindCXSparse.cmake - Find CXSparse libraries & dependencies. 33 | # 34 | # This module defines the following variables which should be referenced 35 | # by the caller to use the library. 36 | # 37 | # CXSPARSE_FOUND: TRUE iff CXSparse and all dependencies have been found. 38 | # CXSPARSE_INCLUDE_DIRS: Include directories for CXSparse. 39 | # CXSPARSE_LIBRARIES: Libraries for CXSparse and all dependencies. 40 | # 41 | # CXSPARSE_VERSION: Extracted from cs.h. 42 | # CXSPARSE_MAIN_VERSION: Equal to 3 if CXSPARSE_VERSION = 3.1.2 43 | # CXSPARSE_SUB_VERSION: Equal to 1 if CXSPARSE_VERSION = 3.1.2 44 | # CXSPARSE_SUBSUB_VERSION: Equal to 2 if CXSPARSE_VERSION = 3.1.2 45 | # 46 | # The following variables control the behaviour of this module: 47 | # 48 | # CXSPARSE_INCLUDE_DIR_HINTS: List of additional directories in which to 49 | # search for CXSparse includes, 50 | # e.g: /timbuktu/include. 51 | # CXSPARSE_LIBRARY_DIR_HINTS: List of additional directories in which to 52 | # search for CXSparse libraries, e.g: /timbuktu/lib. 53 | # 54 | # The following variables are also defined by this module, but in line with 55 | # CMake recommended FindPackage() module style should NOT be referenced directly 56 | # by callers (use the plural variables detailed above instead). These variables 57 | # do however affect the behaviour of the module via FIND_[PATH/LIBRARY]() which 58 | # are NOT re-called (i.e. search for library is not repeated) if these variables 59 | # are set with valid values _in the CMake cache_. This means that if these 60 | # variables are set directly in the cache, either by the user in the CMake GUI, 61 | # or by the user passing -DVAR=VALUE directives to CMake when called (which 62 | # explicitly defines a cache variable), then they will be used verbatim, 63 | # bypassing the HINTS variables and other hard-coded search locations. 64 | # 65 | # CXSPARSE_INCLUDE_DIR: Include directory for CXSparse, not including the 66 | # include directory of any dependencies. 67 | # CXSPARSE_LIBRARY: CXSparse library, not including the libraries of any 68 | # dependencies. 69 | 70 | # Reset CALLERS_CMAKE_FIND_LIBRARY_PREFIXES to its value when 71 | # FindCXSparse was invoked. 72 | macro(CXSPARSE_RESET_FIND_LIBRARY_PREFIX) 73 | if (MSVC) 74 | set(CMAKE_FIND_LIBRARY_PREFIXES "${CALLERS_CMAKE_FIND_LIBRARY_PREFIXES}") 75 | endif (MSVC) 76 | endmacro(CXSPARSE_RESET_FIND_LIBRARY_PREFIX) 77 | 78 | # Called if we failed to find CXSparse or any of it's required dependencies, 79 | # unsets all public (designed to be used externally) variables and reports 80 | # error message at priority depending upon [REQUIRED/QUIET/] argument. 81 | macro(CXSPARSE_REPORT_NOT_FOUND REASON_MSG) 82 | unset(CXSPARSE_FOUND) 83 | unset(CXSPARSE_INCLUDE_DIRS) 84 | unset(CXSPARSE_LIBRARIES) 85 | # Make results of search visible in the CMake GUI if CXSparse has not 86 | # been found so that user does not have to toggle to advanced view. 87 | mark_as_advanced(CLEAR CXSPARSE_INCLUDE_DIR 88 | CXSPARSE_LIBRARY) 89 | 90 | cxsparse_reset_find_library_prefix() 91 | 92 | # Note _FIND_[REQUIRED/QUIETLY] variables defined by FindPackage() 93 | # use the camelcase library name, not uppercase. 94 | if (CXSparse_FIND_QUIETLY) 95 | message(STATUS "Failed to find CXSparse - " ${REASON_MSG} ${ARGN}) 96 | elseif (CXSparse_FIND_REQUIRED) 97 | message(FATAL_ERROR "Failed to find CXSparse - " ${REASON_MSG} ${ARGN}) 98 | else() 99 | # Neither QUIETLY nor REQUIRED, use no priority which emits a message 100 | # but continues configuration and allows generation. 101 | message("-- Failed to find CXSparse - " ${REASON_MSG} ${ARGN}) 102 | endif () 103 | return() 104 | endmacro(CXSPARSE_REPORT_NOT_FOUND) 105 | 106 | # Protect against any alternative find_package scripts for this library having 107 | # been called previously (in a client project) which set CXSPARSE_FOUND, but not 108 | # the other variables we require / set here which could cause the search logic 109 | # here to fail. 110 | unset(CXSPARSE_FOUND) 111 | 112 | # Handle possible presence of lib prefix for libraries on MSVC, see 113 | # also CXSPARSE_RESET_FIND_LIBRARY_PREFIX(). 114 | if (MSVC) 115 | # Preserve the caller's original values for CMAKE_FIND_LIBRARY_PREFIXES 116 | # s/t we can set it back before returning. 117 | set(CALLERS_CMAKE_FIND_LIBRARY_PREFIXES "${CMAKE_FIND_LIBRARY_PREFIXES}") 118 | # The empty string in this list is important, it represents the case when 119 | # the libraries have no prefix (shared libraries / DLLs). 120 | set(CMAKE_FIND_LIBRARY_PREFIXES "lib" "" "${CMAKE_FIND_LIBRARY_PREFIXES}") 121 | endif (MSVC) 122 | 123 | # Search user-installed locations first, so that we prefer user installs 124 | # to system installs where both exist. 125 | # 126 | # TODO: Add standard Windows search locations for CXSparse. 127 | list(APPEND CXSPARSE_CHECK_INCLUDE_DIRS 128 | /usr/local/include 129 | /usr/local/homebrew/include # Mac OS X 130 | /opt/local/var/macports/software # Mac OS X. 131 | /opt/local/include 132 | /usr/include) 133 | list(APPEND CXSPARSE_CHECK_LIBRARY_DIRS 134 | /usr/local/lib 135 | /usr/local/homebrew/lib # Mac OS X. 136 | /opt/local/lib 137 | /usr/lib) 138 | 139 | # Search supplied hint directories first if supplied. 140 | find_path(CXSPARSE_INCLUDE_DIR 141 | NAMES cs.h 142 | PATHS ${CXSPARSE_INCLUDE_DIR_HINTS} 143 | ${CXSPARSE_CHECK_INCLUDE_DIRS}) 144 | if (NOT CXSPARSE_INCLUDE_DIR OR 145 | NOT EXISTS ${CXSPARSE_INCLUDE_DIR}) 146 | cxsparse_report_not_found( 147 | "Could not find CXSparse include directory, set CXSPARSE_INCLUDE_DIR " 148 | "to directory containing cs.h") 149 | endif (NOT CXSPARSE_INCLUDE_DIR OR 150 | NOT EXISTS ${CXSPARSE_INCLUDE_DIR}) 151 | 152 | find_library(CXSPARSE_LIBRARY NAMES cxsparse 153 | PATHS ${CXSPARSE_LIBRARY_DIR_HINTS} 154 | ${CXSPARSE_CHECK_LIBRARY_DIRS}) 155 | if (NOT CXSPARSE_LIBRARY OR 156 | NOT EXISTS ${CXSPARSE_LIBRARY}) 157 | cxsparse_report_not_found( 158 | "Could not find CXSparse library, set CXSPARSE_LIBRARY " 159 | "to full path to libcxsparse.") 160 | endif (NOT CXSPARSE_LIBRARY OR 161 | NOT EXISTS ${CXSPARSE_LIBRARY}) 162 | 163 | # Mark internally as found, then verify. CXSPARSE_REPORT_NOT_FOUND() unsets 164 | # if called. 165 | set(CXSPARSE_FOUND TRUE) 166 | 167 | # Extract CXSparse version from cs.h 168 | if (CXSPARSE_INCLUDE_DIR) 169 | set(CXSPARSE_VERSION_FILE ${CXSPARSE_INCLUDE_DIR}/cs.h) 170 | if (NOT EXISTS ${CXSPARSE_VERSION_FILE}) 171 | cxsparse_report_not_found( 172 | "Could not find file: ${CXSPARSE_VERSION_FILE} " 173 | "containing version information in CXSparse install located at: " 174 | "${CXSPARSE_INCLUDE_DIR}.") 175 | else (NOT EXISTS ${CXSPARSE_VERSION_FILE}) 176 | file(READ ${CXSPARSE_INCLUDE_DIR}/cs.h CXSPARSE_VERSION_FILE_CONTENTS) 177 | 178 | string(REGEX MATCH "#define CS_VER [0-9]+" 179 | CXSPARSE_MAIN_VERSION "${CXSPARSE_VERSION_FILE_CONTENTS}") 180 | string(REGEX REPLACE "#define CS_VER ([0-9]+)" "\\1" 181 | CXSPARSE_MAIN_VERSION "${CXSPARSE_MAIN_VERSION}") 182 | 183 | string(REGEX MATCH "#define CS_SUBVER [0-9]+" 184 | CXSPARSE_SUB_VERSION "${CXSPARSE_VERSION_FILE_CONTENTS}") 185 | string(REGEX REPLACE "#define CS_SUBVER ([0-9]+)" "\\1" 186 | CXSPARSE_SUB_VERSION "${CXSPARSE_SUB_VERSION}") 187 | 188 | string(REGEX MATCH "#define CS_SUBSUB [0-9]+" 189 | CXSPARSE_SUBSUB_VERSION "${CXSPARSE_VERSION_FILE_CONTENTS}") 190 | string(REGEX REPLACE "#define CS_SUBSUB ([0-9]+)" "\\1" 191 | CXSPARSE_SUBSUB_VERSION "${CXSPARSE_SUBSUB_VERSION}") 192 | 193 | # This is on a single line s/t CMake does not interpret it as a list of 194 | # elements and insert ';' separators which would result in 3.;1.;2 nonsense. 195 | set(CXSPARSE_VERSION "${CXSPARSE_MAIN_VERSION}.${CXSPARSE_SUB_VERSION}.${CXSPARSE_SUBSUB_VERSION}") 196 | endif (NOT EXISTS ${CXSPARSE_VERSION_FILE}) 197 | endif (CXSPARSE_INCLUDE_DIR) 198 | 199 | # Catch the case when the caller has set CXSPARSE_LIBRARY in the cache / GUI and 200 | # thus FIND_LIBRARY was not called, but specified library is invalid, otherwise 201 | # we would report CXSparse as found. 202 | # TODO: This regex for CXSparse library is pretty primitive, we use lowercase 203 | # for comparison to handle Windows using CamelCase library names, could 204 | # this check be better? 205 | string(TOLOWER "${CXSPARSE_LIBRARY}" LOWERCASE_CXSPARSE_LIBRARY) 206 | if (CXSPARSE_LIBRARY AND 207 | EXISTS ${CXSPARSE_LIBRARY} AND 208 | NOT "${LOWERCASE_CXSPARSE_LIBRARY}" MATCHES ".*cxsparse[^/]*") 209 | cxsparse_report_not_found( 210 | "Caller defined CXSPARSE_LIBRARY: " 211 | "${CXSPARSE_LIBRARY} does not match CXSparse.") 212 | endif (CXSPARSE_LIBRARY AND 213 | EXISTS ${CXSPARSE_LIBRARY} AND 214 | NOT "${LOWERCASE_CXSPARSE_LIBRARY}" MATCHES ".*cxsparse[^/]*") 215 | 216 | # Set standard CMake FindPackage variables if found. 217 | if (CXSPARSE_FOUND) 218 | set(CXSPARSE_INCLUDE_DIRS ${CXSPARSE_INCLUDE_DIR}) 219 | set(CXSPARSE_LIBRARIES ${CXSPARSE_LIBRARY}) 220 | endif (CXSPARSE_FOUND) 221 | 222 | cxsparse_reset_find_library_prefix() 223 | 224 | # Handle REQUIRED / QUIET optional arguments and version. 225 | include(FindPackageHandleStandardArgs) 226 | find_package_handle_standard_args(CXSparse 227 | REQUIRED_VARS CXSPARSE_INCLUDE_DIRS CXSPARSE_LIBRARIES 228 | VERSION_VAR CXSPARSE_VERSION) 229 | 230 | # Only mark internal variables as advanced if we found CXSparse, otherwise 231 | # leave them visible in the standard GUI for the user to set manually. 232 | if (CXSPARSE_FOUND) 233 | mark_as_advanced(FORCE CXSPARSE_INCLUDE_DIR 234 | CXSPARSE_LIBRARY) 235 | endif (CXSPARSE_FOUND) 236 | -------------------------------------------------------------------------------- /module/FindGflags.cmake: -------------------------------------------------------------------------------- 1 | # Ceres Solver - A fast non-linear least squares minimizer 2 | # Copyright 2015 Google Inc. All rights reserved. 3 | # http://ceres-solver.org/ 4 | # 5 | # Redistribution and use in source and binary forms, with or without 6 | # modification, are permitted provided that the following conditions are met: 7 | # 8 | # * Redistributions of source code must retain the above copyright notice, 9 | # this list of conditions and the following disclaimer. 10 | # * Redistributions in binary form must reproduce the above copyright notice, 11 | # this list of conditions and the following disclaimer in the documentation 12 | # and/or other materials provided with the distribution. 13 | # * Neither the name of Google Inc. nor the names of its contributors may be 14 | # used to endorse or promote products derived from this software without 15 | # specific prior written permission. 16 | # 17 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 | # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | # POSSIBILITY OF SUCH DAMAGE. 28 | # 29 | # Author: alexs.mac@gmail.com (Alex Stewart) 30 | # 31 | 32 | # FindGflags.cmake - Find Google gflags logging library. 33 | # 34 | # This module will attempt to find gflags, either via an exported CMake 35 | # configuration (generated by gflags >= 2.1 which are built with CMake), or 36 | # by performing a standard search for all gflags components. The order of 37 | # precedence for these two methods of finding gflags is controlled by: 38 | # GFLAGS_PREFER_EXPORTED_GFLAGS_CMAKE_CONFIGURATION. 39 | # 40 | # This module defines the following variables: 41 | # 42 | # GFLAGS_FOUND: TRUE iff gflags is found. 43 | # GFLAGS_INCLUDE_DIRS: Include directories for gflags. 44 | # GFLAGS_LIBRARIES: Libraries required to link gflags. 45 | # GFLAGS_NAMESPACE: The namespace in which gflags is defined. In versions of 46 | # gflags < 2.1, this was google, for versions >= 2.1 it is 47 | # by default gflags, although can be configured when building 48 | # gflags to be something else (i.e. google for legacy 49 | # compatibility). 50 | # FOUND_INSTALLED_GFLAGS_CMAKE_CONFIGURATION: True iff the version of gflags 51 | # found was built & installed / 52 | # exported as a CMake package. 53 | # 54 | # The following variables control the behaviour of this module when an exported 55 | # gflags CMake configuration is not found. 56 | # 57 | # GFLAGS_PREFER_EXPORTED_GFLAGS_CMAKE_CONFIGURATION: TRUE/FALSE, iff TRUE then 58 | # then prefer using an exported CMake configuration 59 | # generated by gflags >= 2.1 over searching for the 60 | # gflags components manually. Otherwise (FALSE) 61 | # ignore any exported gflags CMake configurations and 62 | # always perform a manual search for the components. 63 | # Default: TRUE iff user does not define this variable 64 | # before we are called, and does NOT specify either 65 | # GFLAGS_INCLUDE_DIR_HINTS or GFLAGS_LIBRARY_DIR_HINTS 66 | # otherwise FALSE. 67 | # GFLAGS_INCLUDE_DIR_HINTS: List of additional directories in which to 68 | # search for gflags includes, e.g: /timbuktu/include. 69 | # GFLAGS_LIBRARY_DIR_HINTS: List of additional directories in which to 70 | # search for gflags libraries, e.g: /timbuktu/lib. 71 | # 72 | # The following variables are also defined by this module, but in line with 73 | # CMake recommended FindPackage() module style should NOT be referenced directly 74 | # by callers (use the plural variables detailed above instead). These variables 75 | # do however affect the behaviour of the module via FIND_[PATH/LIBRARY]() which 76 | # are NOT re-called (i.e. search for library is not repeated) if these variables 77 | # are set with valid values _in the CMake cache_. This means that if these 78 | # variables are set directly in the cache, either by the user in the CMake GUI, 79 | # or by the user passing -DVAR=VALUE directives to CMake when called (which 80 | # explicitly defines a cache variable), then they will be used verbatim, 81 | # bypassing the HINTS variables and other hard-coded search locations. 82 | # 83 | # GFLAGS_INCLUDE_DIR: Include directory for gflags, not including the 84 | # include directory of any dependencies. 85 | # GFLAGS_LIBRARY: gflags library, not including the libraries of any 86 | # dependencies. 87 | 88 | # Reset CALLERS_CMAKE_FIND_LIBRARY_PREFIXES to its value when FindGflags was 89 | # invoked, necessary for MSVC. 90 | macro(GFLAGS_RESET_FIND_LIBRARY_PREFIX) 91 | if (MSVC AND CALLERS_CMAKE_FIND_LIBRARY_PREFIXES) 92 | set(CMAKE_FIND_LIBRARY_PREFIXES "${CALLERS_CMAKE_FIND_LIBRARY_PREFIXES}") 93 | endif() 94 | endmacro(GFLAGS_RESET_FIND_LIBRARY_PREFIX) 95 | 96 | # Called if we failed to find gflags or any of it's required dependencies, 97 | # unsets all public (designed to be used externally) variables and reports 98 | # error message at priority depending upon [REQUIRED/QUIET/] argument. 99 | macro(GFLAGS_REPORT_NOT_FOUND REASON_MSG) 100 | unset(GFLAGS_FOUND) 101 | unset(GFLAGS_INCLUDE_DIRS) 102 | unset(GFLAGS_LIBRARIES) 103 | # Do not use unset, as we want to keep GFLAGS_NAMESPACE in the cache, 104 | # but simply clear its value. 105 | set(GFLAGS_NAMESPACE "" CACHE STRING 106 | "gflags namespace (google or gflags)" FORCE) 107 | 108 | # Make results of search visible in the CMake GUI if gflags has not 109 | # been found so that user does not have to toggle to advanced view. 110 | mark_as_advanced(CLEAR GFLAGS_INCLUDE_DIR 111 | GFLAGS_LIBRARY 112 | GFLAGS_NAMESPACE) 113 | 114 | gflags_reset_find_library_prefix() 115 | 116 | # Note _FIND_[REQUIRED/QUIETLY] variables defined by FindPackage() 117 | # use the camelcase library name, not uppercase. 118 | if (Gflags_FIND_QUIETLY) 119 | message(STATUS "Failed to find gflags - " ${REASON_MSG} ${ARGN}) 120 | elseif (Gflags_FIND_REQUIRED) 121 | message(FATAL_ERROR "Failed to find gflags - " ${REASON_MSG} ${ARGN}) 122 | else() 123 | # Neither QUIETLY nor REQUIRED, use no priority which emits a message 124 | # but continues configuration and allows generation. 125 | message("-- Failed to find gflags - " ${REASON_MSG} ${ARGN}) 126 | endif () 127 | return() 128 | endmacro(GFLAGS_REPORT_NOT_FOUND) 129 | 130 | # Verify that all variable names passed as arguments are defined (can be empty 131 | # but must be defined) or raise a fatal error. 132 | macro(GFLAGS_CHECK_VARS_DEFINED) 133 | foreach(CHECK_VAR ${ARGN}) 134 | if (NOT DEFINED ${CHECK_VAR}) 135 | message(FATAL_ERROR "Ceres Bug: ${CHECK_VAR} is not defined.") 136 | endif() 137 | endforeach() 138 | endmacro(GFLAGS_CHECK_VARS_DEFINED) 139 | 140 | # Use check_cxx_source_compiles() to compile trivial test programs to determine 141 | # the gflags namespace. This works on all OSs except Windows. If using Visual 142 | # Studio, it fails because msbuild forces check_cxx_source_compiles() to use 143 | # CMAKE_BUILD_TYPE=Debug for the test project, which usually breaks detection 144 | # because MSVC requires that the test project use the same build type as gflags, 145 | # which would normally be built in Release. 146 | # 147 | # Defines: GFLAGS_NAMESPACE in the caller's scope with the detected namespace, 148 | # which is blank (empty string, will test FALSE is CMake conditionals) 149 | # if detection failed. 150 | function(GFLAGS_CHECK_GFLAGS_NAMESPACE_USING_TRY_COMPILE) 151 | # Verify that all required variables are defined. 152 | gflags_check_vars_defined( 153 | GFLAGS_INCLUDE_DIR GFLAGS_LIBRARY) 154 | # Ensure that GFLAGS_NAMESPACE is always unset on completion unless 155 | # we explicitly set if after having the correct namespace. 156 | set(GFLAGS_NAMESPACE "" PARENT_SCOPE) 157 | 158 | include(CheckCXXSourceCompiles) 159 | # Setup include path & link library for gflags for CHECK_CXX_SOURCE_COMPILES. 160 | set(CMAKE_REQUIRED_INCLUDES ${GFLAGS_INCLUDE_DIR}) 161 | set(CMAKE_REQUIRED_LIBRARIES ${GFLAGS_LIBRARY} ${GFLAGS_LINK_LIBRARIES}) 162 | # First try the (older) google namespace. Note that the output variable 163 | # MUST be unique to the build type as otherwise the test is not repeated as 164 | # it is assumed to have already been performed. 165 | check_cxx_source_compiles( 166 | "#include 167 | int main(int argc, char * argv[]) { 168 | google::ParseCommandLineFlags(&argc, &argv, true); 169 | return 0; 170 | }" 171 | GFLAGS_IN_GOOGLE_NAMESPACE) 172 | if (GFLAGS_IN_GOOGLE_NAMESPACE) 173 | set(GFLAGS_NAMESPACE google PARENT_SCOPE) 174 | return() 175 | endif() 176 | 177 | # Try (newer) gflags namespace instead. Note that the output variable 178 | # MUST be unique to the build type as otherwise the test is not repeated as 179 | # it is assumed to have already been performed. 180 | set(CMAKE_REQUIRED_INCLUDES ${GFLAGS_INCLUDE_DIR}) 181 | set(CMAKE_REQUIRED_LIBRARIES ${GFLAGS_LIBRARY} ${GFLAGS_LINK_LIBRARIES}) 182 | check_cxx_source_compiles( 183 | "#include 184 | int main(int argc, char * argv[]) { 185 | gflags::ParseCommandLineFlags(&argc, &argv, true); 186 | return 0; 187 | }" 188 | GFLAGS_IN_GFLAGS_NAMESPACE) 189 | if (GFLAGS_IN_GFLAGS_NAMESPACE) 190 | set(GFLAGS_NAMESPACE gflags PARENT_SCOPE) 191 | return() 192 | endif (GFLAGS_IN_GFLAGS_NAMESPACE) 193 | endfunction(GFLAGS_CHECK_GFLAGS_NAMESPACE_USING_TRY_COMPILE) 194 | 195 | # Use regex on the gflags headers to attempt to determine the gflags namespace. 196 | # Checks both gflags.h (contained namespace on versions < 2.1.2) and 197 | # gflags_declare.h, which contains the namespace on versions >= 2.1.2. 198 | # In general, this method should only be used when 199 | # GFLAGS_CHECK_GFLAGS_NAMESPACE_USING_TRY_COMPILE() cannot be used, or has 200 | # failed. 201 | # 202 | # Defines: GFLAGS_NAMESPACE in the caller's scope with the detected namespace, 203 | # which is blank (empty string, will test FALSE is CMake conditionals) 204 | # if detection failed. 205 | function(GFLAGS_CHECK_GFLAGS_NAMESPACE_USING_REGEX) 206 | # Verify that all required variables are defined. 207 | gflags_check_vars_defined(GFLAGS_INCLUDE_DIR) 208 | # Ensure that GFLAGS_NAMESPACE is always undefined on completion unless 209 | # we explicitly set if after having the correct namespace. 210 | set(GFLAGS_NAMESPACE "" PARENT_SCOPE) 211 | 212 | # Scan gflags.h to identify what namespace gflags was built with. On 213 | # versions of gflags < 2.1.2, gflags.h was configured with the namespace 214 | # directly, on >= 2.1.2, gflags.h uses the GFLAGS_NAMESPACE #define which 215 | # is defined in gflags_declare.h, we try each location in turn. 216 | set(GFLAGS_HEADER_FILE ${GFLAGS_INCLUDE_DIR}/gflags/gflags.h) 217 | if (NOT EXISTS ${GFLAGS_HEADER_FILE}) 218 | gflags_report_not_found( 219 | "Could not find file: ${GFLAGS_HEADER_FILE} " 220 | "containing namespace information in gflags install located at: " 221 | "${GFLAGS_INCLUDE_DIR}.") 222 | endif() 223 | file(READ ${GFLAGS_HEADER_FILE} GFLAGS_HEADER_FILE_CONTENTS) 224 | 225 | string(REGEX MATCH "namespace [A-Za-z]+" 226 | GFLAGS_NAMESPACE "${GFLAGS_HEADER_FILE_CONTENTS}") 227 | string(REGEX REPLACE "namespace ([A-Za-z]+)" "\\1" 228 | GFLAGS_NAMESPACE "${GFLAGS_NAMESPACE}") 229 | 230 | if (NOT GFLAGS_NAMESPACE) 231 | gflags_report_not_found( 232 | "Failed to extract gflags namespace from header file: " 233 | "${GFLAGS_HEADER_FILE}.") 234 | endif (NOT GFLAGS_NAMESPACE) 235 | 236 | if (GFLAGS_NAMESPACE STREQUAL "google" OR 237 | GFLAGS_NAMESPACE STREQUAL "gflags") 238 | # Found valid gflags namespace from gflags.h. 239 | set(GFLAGS_NAMESPACE "${GFLAGS_NAMESPACE}" PARENT_SCOPE) 240 | return() 241 | endif() 242 | 243 | # Failed to find gflags namespace from gflags.h, gflags is likely a new 244 | # version, check gflags_declare.h, which in newer versions (>= 2.1.2) contains 245 | # the GFLAGS_NAMESPACE #define, which is then referenced in gflags.h. 246 | set(GFLAGS_DECLARE_FILE ${GFLAGS_INCLUDE_DIR}/gflags/gflags_declare.h) 247 | if (NOT EXISTS ${GFLAGS_DECLARE_FILE}) 248 | gflags_report_not_found( 249 | "Could not find file: ${GFLAGS_DECLARE_FILE} " 250 | "containing namespace information in gflags install located at: " 251 | "${GFLAGS_INCLUDE_DIR}.") 252 | endif() 253 | file(READ ${GFLAGS_DECLARE_FILE} GFLAGS_DECLARE_FILE_CONTENTS) 254 | 255 | string(REGEX MATCH "#define GFLAGS_NAMESPACE [A-Za-z]+" 256 | GFLAGS_NAMESPACE "${GFLAGS_DECLARE_FILE_CONTENTS}") 257 | string(REGEX REPLACE "#define GFLAGS_NAMESPACE ([A-Za-z]+)" "\\1" 258 | GFLAGS_NAMESPACE "${GFLAGS_NAMESPACE}") 259 | 260 | if (NOT GFLAGS_NAMESPACE) 261 | gflags_report_not_found( 262 | "Failed to extract gflags namespace from declare file: " 263 | "${GFLAGS_DECLARE_FILE}.") 264 | endif (NOT GFLAGS_NAMESPACE) 265 | 266 | if (GFLAGS_NAMESPACE STREQUAL "google" OR 267 | GFLAGS_NAMESPACE STREQUAL "gflags") 268 | # Found valid gflags namespace from gflags.h. 269 | set(GFLAGS_NAMESPACE "${GFLAGS_NAMESPACE}" PARENT_SCOPE) 270 | return() 271 | endif() 272 | endfunction(GFLAGS_CHECK_GFLAGS_NAMESPACE_USING_REGEX) 273 | 274 | # Protect against any alternative find_package scripts for this library having 275 | # been called previously (in a client project) which set GFLAGS_FOUND, but not 276 | # the other variables we require / set here which could cause the search logic 277 | # here to fail. 278 | unset(GFLAGS_FOUND) 279 | 280 | # ----------------------------------------------------------------- 281 | # By default, if the user has expressed no preference for using an exported 282 | # gflags CMake configuration over performing a search for the installed 283 | # components, and has not specified any hints for the search locations, then 284 | # prefer a gflags exported configuration if available. 285 | if (NOT DEFINED GFLAGS_PREFER_EXPORTED_GFLAGS_CMAKE_CONFIGURATION 286 | AND NOT GFLAGS_INCLUDE_DIR_HINTS 287 | AND NOT GFLAGS_LIBRARY_DIR_HINTS) 288 | message(STATUS "No preference for use of exported gflags CMake configuration " 289 | "set, and no hints for include/library directories provided. " 290 | "Defaulting to preferring an installed/exported gflags CMake configuration " 291 | "if available.") 292 | set(GFLAGS_PREFER_EXPORTED_GFLAGS_CMAKE_CONFIGURATION TRUE) 293 | endif() 294 | 295 | if (GFLAGS_PREFER_EXPORTED_GFLAGS_CMAKE_CONFIGURATION) 296 | # Try to find an exported CMake configuration for gflags, as generated by 297 | # gflags versions >= 2.1. 298 | # 299 | # We search twice, s/t we can invert the ordering of precedence used by 300 | # find_package() for exported package build directories, and installed 301 | # packages (found via CMAKE_SYSTEM_PREFIX_PATH), listed as items 6) and 7) 302 | # respectively in [1]. 303 | # 304 | # By default, exported build directories are (in theory) detected first, and 305 | # this is usually the case on Windows. However, on OS X & Linux, the install 306 | # path (/usr/local) is typically present in the PATH environment variable 307 | # which is checked in item 4) in [1] (i.e. before both of the above, unless 308 | # NO_SYSTEM_ENVIRONMENT_PATH is passed). As such on those OSs installed 309 | # packages are usually detected in preference to exported package build 310 | # directories. 311 | # 312 | # To ensure a more consistent response across all OSs, and as users usually 313 | # want to prefer an installed version of a package over a locally built one 314 | # where both exist (esp. as the exported build directory might be removed 315 | # after installation), we first search with NO_CMAKE_PACKAGE_REGISTRY which 316 | # means any build directories exported by the user are ignored, and thus 317 | # installed directories are preferred. If this fails to find the package 318 | # we then research again, but without NO_CMAKE_PACKAGE_REGISTRY, so any 319 | # exported build directories will now be detected. 320 | # 321 | # To prevent confusion on Windows, we also pass NO_CMAKE_BUILDS_PATH (which 322 | # is item 5) in [1]), to not preferentially use projects that were built 323 | # recently with the CMake GUI to ensure that we always prefer an installed 324 | # version if available. 325 | # 326 | # [1] http://www.cmake.org/cmake/help/v2.8.11/cmake.html#command:find_package 327 | find_package(gflags QUIET 328 | NO_MODULE 329 | NO_CMAKE_PACKAGE_REGISTRY 330 | NO_CMAKE_BUILDS_PATH) 331 | if (gflags_FOUND) 332 | message(STATUS "Found installed version of gflags: ${gflags_DIR}") 333 | else(gflags_FOUND) 334 | # Failed to find an installed version of gflags, repeat search allowing 335 | # exported build directories. 336 | message(STATUS "Failed to find installed gflags CMake configuration, " 337 | "searching for gflags build directories exported with CMake.") 338 | # Again pass NO_CMAKE_BUILDS_PATH, as we know that gflags is exported and 339 | # do not want to treat projects built with the CMake GUI preferentially. 340 | find_package(gflags QUIET 341 | NO_MODULE 342 | NO_CMAKE_BUILDS_PATH) 343 | if (gflags_FOUND) 344 | message(STATUS "Found exported gflags build directory: ${gflags_DIR}") 345 | endif(gflags_FOUND) 346 | endif(gflags_FOUND) 347 | 348 | set(FOUND_INSTALLED_GFLAGS_CMAKE_CONFIGURATION ${gflags_FOUND}) 349 | 350 | # gflags v2.1 - 2.1.2 shipped with a bug in their gflags-config.cmake [1] 351 | # whereby gflags_LIBRARIES = "gflags", but there was no imported target 352 | # called "gflags", they were called: gflags[_nothreads]-[static/shared]. 353 | # As this causes linker errors when gflags is not installed in a location 354 | # on the current library paths, detect if this problem is present and 355 | # fix it. 356 | # 357 | # [1] https://github.com/gflags/gflags/issues/110 358 | if (gflags_FOUND) 359 | # NOTE: This is not written as additional conditions in the outer 360 | # if (gflags_FOUND) as the NOT TARGET "${gflags_LIBRARIES}" 361 | # condition causes problems if gflags is not found. 362 | if (${gflags_VERSION} VERSION_LESS 2.1.3 AND 363 | NOT TARGET "${gflags_LIBRARIES}") 364 | message(STATUS "Detected broken gflags install in: ${gflags_DIR}, " 365 | "version: ${gflags_VERSION} <= 2.1.2 which defines gflags_LIBRARIES = " 366 | "${gflags_LIBRARIES} which is not an imported CMake target, see: " 367 | "https://github.com/gflags/gflags/issues/110. Attempting to fix by " 368 | "detecting correct gflags target.") 369 | # Ordering here expresses preference for detection, specifically we do not 370 | # want to use the _nothreads variants if the full library is available. 371 | list(APPEND CHECK_GFLAGS_IMPORTED_TARGET_NAMES 372 | gflags-shared gflags-static 373 | gflags_nothreads-shared gflags_nothreads-static) 374 | foreach(CHECK_GFLAGS_TARGET ${CHECK_GFLAGS_IMPORTED_TARGET_NAMES}) 375 | if (TARGET ${CHECK_GFLAGS_TARGET}) 376 | message(STATUS "Found valid gflags target: ${CHECK_GFLAGS_TARGET}, " 377 | "updating gflags_LIBRARIES.") 378 | set(gflags_LIBRARIES ${CHECK_GFLAGS_TARGET}) 379 | break() 380 | endif() 381 | endforeach() 382 | if (NOT TARGET ${gflags_LIBRARIES}) 383 | message(STATUS "Failed to fix detected broken gflags install in: " 384 | "${gflags_DIR}, version: ${gflags_VERSION} <= 2.1.2, none of the " 385 | "imported targets for gflags: ${CHECK_GFLAGS_IMPORTED_TARGET_NAMES} " 386 | "are defined. Will continue with a manual search for gflags " 387 | "components. We recommend you build/install a version of gflags > " 388 | "2.1.2 (or master).") 389 | set(FOUND_INSTALLED_GFLAGS_CMAKE_CONFIGURATION FALSE) 390 | endif() 391 | endif() 392 | endif() 393 | 394 | if (FOUND_INSTALLED_GFLAGS_CMAKE_CONFIGURATION) 395 | message(STATUS "Detected gflags version: ${gflags_VERSION}") 396 | set(GFLAGS_FOUND ${gflags_FOUND}) 397 | set(GFLAGS_INCLUDE_DIR ${gflags_INCLUDE_DIR}) 398 | set(GFLAGS_LIBRARY ${gflags_LIBRARIES}) 399 | 400 | # gflags does not export the namespace in their CMake configuration, so 401 | # use our function to determine what it should be, as it can be either 402 | # gflags or google dependent upon version & configuration. 403 | # 404 | # NOTE: We use the regex method to determine the namespace here, as 405 | # check_cxx_source_compiles() will not use imported targets, which 406 | # is what gflags will be in this case. 407 | gflags_check_gflags_namespace_using_regex() 408 | 409 | if (NOT GFLAGS_NAMESPACE) 410 | gflags_report_not_found( 411 | "Failed to determine gflags namespace using regex for gflags " 412 | "version: ${gflags_VERSION} exported here: ${gflags_DIR} using CMake.") 413 | endif (NOT GFLAGS_NAMESPACE) 414 | else (FOUND_INSTALLED_GFLAGS_CMAKE_CONFIGURATION) 415 | message(STATUS "Failed to find an installed/exported CMake configuration " 416 | "for gflags, will perform search for installed gflags components.") 417 | endif (FOUND_INSTALLED_GFLAGS_CMAKE_CONFIGURATION) 418 | endif(GFLAGS_PREFER_EXPORTED_GFLAGS_CMAKE_CONFIGURATION) 419 | 420 | if (NOT GFLAGS_FOUND) 421 | # Either failed to find an exported gflags CMake configuration, or user 422 | # told us not to use one. Perform a manual search for all gflags components. 423 | 424 | # Handle possible presence of lib prefix for libraries on MSVC, see 425 | # also GFLAGS_RESET_FIND_LIBRARY_PREFIX(). 426 | if (MSVC) 427 | # Preserve the caller's original values for CMAKE_FIND_LIBRARY_PREFIXES 428 | # s/t we can set it back before returning. 429 | set(CALLERS_CMAKE_FIND_LIBRARY_PREFIXES "${CMAKE_FIND_LIBRARY_PREFIXES}") 430 | # The empty string in this list is important, it represents the case when 431 | # the libraries have no prefix (shared libraries / DLLs). 432 | set(CMAKE_FIND_LIBRARY_PREFIXES "lib" "" "${CMAKE_FIND_LIBRARY_PREFIXES}") 433 | endif (MSVC) 434 | 435 | # Search user-installed locations first, so that we prefer user installs 436 | # to system installs where both exist. 437 | list(APPEND GFLAGS_CHECK_INCLUDE_DIRS 438 | /usr/local/include 439 | /usr/local/homebrew/include # Mac OS X 440 | /opt/local/var/macports/software # Mac OS X. 441 | /opt/local/include 442 | /usr/include) 443 | list(APPEND GFLAGS_CHECK_PATH_SUFFIXES 444 | gflags/include # Windows (for C:/Program Files prefix). 445 | gflags/Include ) # Windows (for C:/Program Files prefix). 446 | 447 | list(APPEND GFLAGS_CHECK_LIBRARY_DIRS 448 | /usr/local/lib 449 | /usr/local/homebrew/lib # Mac OS X. 450 | /opt/local/lib 451 | /usr/lib) 452 | list(APPEND GFLAGS_CHECK_LIBRARY_SUFFIXES 453 | gflags/lib # Windows (for C:/Program Files prefix). 454 | gflags/Lib ) # Windows (for C:/Program Files prefix). 455 | 456 | # Search supplied hint directories first if supplied. 457 | find_path(GFLAGS_INCLUDE_DIR 458 | NAMES gflags/gflags.h 459 | PATHS ${GFLAGS_INCLUDE_DIR_HINTS} 460 | ${GFLAGS_CHECK_INCLUDE_DIRS} 461 | PATH_SUFFIXES ${GFLAGS_CHECK_PATH_SUFFIXES}) 462 | if (NOT GFLAGS_INCLUDE_DIR OR 463 | NOT EXISTS ${GFLAGS_INCLUDE_DIR}) 464 | gflags_report_not_found( 465 | "Could not find gflags include directory, set GFLAGS_INCLUDE_DIR " 466 | "to directory containing gflags/gflags.h") 467 | endif (NOT GFLAGS_INCLUDE_DIR OR 468 | NOT EXISTS ${GFLAGS_INCLUDE_DIR}) 469 | 470 | find_library(GFLAGS_LIBRARY NAMES gflags 471 | PATHS ${GFLAGS_LIBRARY_DIR_HINTS} 472 | ${GFLAGS_CHECK_LIBRARY_DIRS} 473 | PATH_SUFFIXES ${GFLAGS_CHECK_LIBRARY_SUFFIXES}) 474 | if (NOT GFLAGS_LIBRARY OR 475 | NOT EXISTS ${GFLAGS_LIBRARY}) 476 | gflags_report_not_found( 477 | "Could not find gflags library, set GFLAGS_LIBRARY " 478 | "to full path to libgflags.") 479 | endif (NOT GFLAGS_LIBRARY OR 480 | NOT EXISTS ${GFLAGS_LIBRARY}) 481 | 482 | # gflags typically requires a threading library (which is OS dependent), note 483 | # that this defines the CMAKE_THREAD_LIBS_INIT variable. If we are able to 484 | # detect threads, we assume that gflags requires it. 485 | find_package(Threads QUIET) 486 | set(GFLAGS_LINK_LIBRARIES ${CMAKE_THREAD_LIBS_INIT}) 487 | # On Windows (including MinGW), the Shlwapi library is used by gflags if 488 | # available. 489 | if (WIN32) 490 | include(CheckIncludeFileCXX) 491 | check_include_file_cxx("shlwapi.h" HAVE_SHLWAPI) 492 | if (HAVE_SHLWAPI) 493 | list(APPEND GFLAGS_LINK_LIBRARIES shlwapi.lib) 494 | endif(HAVE_SHLWAPI) 495 | endif (WIN32) 496 | 497 | # Mark internally as found, then verify. GFLAGS_REPORT_NOT_FOUND() unsets 498 | # if called. 499 | set(GFLAGS_FOUND TRUE) 500 | 501 | # Identify what namespace gflags was built with. 502 | if (GFLAGS_INCLUDE_DIR AND NOT GFLAGS_NAMESPACE) 503 | # To handle Windows peculiarities / CMake bugs on MSVC we try two approaches 504 | # to detect the gflags namespace: 505 | # 506 | # 1) Try to use check_cxx_source_compiles() to compile a trivial program 507 | # with the two choices for the gflags namespace. 508 | # 509 | # 2) [In the event 1) fails] Use regex on the gflags headers to try to 510 | # determine the gflags namespace. Whilst this is less robust than 1), 511 | # it does avoid any interaction with msbuild. 512 | gflags_check_gflags_namespace_using_try_compile() 513 | 514 | if (NOT GFLAGS_NAMESPACE) 515 | # Failed to determine gflags namespace using check_cxx_source_compiles() 516 | # method, try and obtain it using regex on the gflags headers instead. 517 | message(STATUS "Failed to find gflags namespace using using " 518 | "check_cxx_source_compiles(), trying namespace regex instead, " 519 | "this is expected on Windows.") 520 | gflags_check_gflags_namespace_using_regex() 521 | 522 | if (NOT GFLAGS_NAMESPACE) 523 | gflags_report_not_found( 524 | "Failed to determine gflags namespace either by " 525 | "check_cxx_source_compiles(), or namespace regex.") 526 | endif (NOT GFLAGS_NAMESPACE) 527 | endif (NOT GFLAGS_NAMESPACE) 528 | endif (GFLAGS_INCLUDE_DIR AND NOT GFLAGS_NAMESPACE) 529 | 530 | # Make the GFLAGS_NAMESPACE a cache variable s/t the user can view it, and could 531 | # overwrite it in the CMake GUI. 532 | set(GFLAGS_NAMESPACE "${GFLAGS_NAMESPACE}" CACHE STRING 533 | "gflags namespace (google or gflags)" FORCE) 534 | 535 | # gflags does not seem to provide any record of the version in its 536 | # source tree, thus cannot extract version. 537 | 538 | # Catch case when caller has set GFLAGS_NAMESPACE in the cache / GUI 539 | # with an invalid value. 540 | if (GFLAGS_NAMESPACE AND 541 | NOT GFLAGS_NAMESPACE STREQUAL "google" AND 542 | NOT GFLAGS_NAMESPACE STREQUAL "gflags") 543 | gflags_report_not_found( 544 | "Caller defined GFLAGS_NAMESPACE:" 545 | " ${GFLAGS_NAMESPACE} is not valid, not google or gflags.") 546 | endif () 547 | # Catch case when caller has set GFLAGS_INCLUDE_DIR in the cache / GUI and 548 | # thus FIND_[PATH/LIBRARY] are not called, but specified locations are 549 | # invalid, otherwise we would report the library as found. 550 | if (GFLAGS_INCLUDE_DIR AND 551 | NOT EXISTS ${GFLAGS_INCLUDE_DIR}/gflags/gflags.h) 552 | gflags_report_not_found( 553 | "Caller defined GFLAGS_INCLUDE_DIR:" 554 | " ${GFLAGS_INCLUDE_DIR} does not contain gflags/gflags.h header.") 555 | endif (GFLAGS_INCLUDE_DIR AND 556 | NOT EXISTS ${GFLAGS_INCLUDE_DIR}/gflags/gflags.h) 557 | # TODO: This regex for gflags library is pretty primitive, we use lowercase 558 | # for comparison to handle Windows using CamelCase library names, could 559 | # this check be better? 560 | string(TOLOWER "${GFLAGS_LIBRARY}" LOWERCASE_GFLAGS_LIBRARY) 561 | if (GFLAGS_LIBRARY AND 562 | NOT "${LOWERCASE_GFLAGS_LIBRARY}" MATCHES ".*gflags[^/]*") 563 | gflags_report_not_found( 564 | "Caller defined GFLAGS_LIBRARY: " 565 | "${GFLAGS_LIBRARY} does not match gflags.") 566 | endif (GFLAGS_LIBRARY AND 567 | NOT "${LOWERCASE_GFLAGS_LIBRARY}" MATCHES ".*gflags[^/]*") 568 | 569 | gflags_reset_find_library_prefix() 570 | 571 | endif(NOT GFLAGS_FOUND) 572 | 573 | # Set standard CMake FindPackage variables if found. 574 | if (GFLAGS_FOUND) 575 | set(GFLAGS_INCLUDE_DIRS ${GFLAGS_INCLUDE_DIR}) 576 | set(GFLAGS_LIBRARIES ${GFLAGS_LIBRARY} ${GFLAGS_LINK_LIBRARIES}) 577 | endif (GFLAGS_FOUND) 578 | 579 | # Handle REQUIRED / QUIET optional arguments. 580 | include(FindPackageHandleStandardArgs) 581 | find_package_handle_standard_args(Gflags DEFAULT_MSG 582 | GFLAGS_INCLUDE_DIRS GFLAGS_LIBRARIES GFLAGS_NAMESPACE) 583 | 584 | # Only mark internal variables as advanced if we found gflags, otherwise 585 | # leave them visible in the standard GUI for the user to set manually. 586 | if (GFLAGS_FOUND) 587 | mark_as_advanced(FORCE GFLAGS_INCLUDE_DIR 588 | GFLAGS_LIBRARY 589 | GFLAGS_NAMESPACE 590 | gflags_DIR) # Autogenerated by find_package(gflags) 591 | endif (GFLAGS_FOUND) 592 | -------------------------------------------------------------------------------- /module/FindSuiteSparse.cmake: -------------------------------------------------------------------------------- 1 | # Ceres Solver - A fast non-linear least squares minimizer 2 | # Copyright 2015 Google Inc. All rights reserved. 3 | # http://ceres-solver.org/ 4 | # 5 | # Redistribution and use in source and binary forms, with or without 6 | # modification, are permitted provided that the following conditions are met: 7 | # 8 | # * Redistributions of source code must retain the above copyright notice, 9 | # this list of conditions and the following disclaimer. 10 | # * Redistributions in binary form must reproduce the above copyright notice, 11 | # this list of conditions and the following disclaimer in the documentation 12 | # and/or other materials provided with the distribution. 13 | # * Neither the name of Google Inc. nor the names of its contributors may be 14 | # used to endorse or promote products derived from this software without 15 | # specific prior written permission. 16 | # 17 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 | # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | # POSSIBILITY OF SUCH DAMAGE. 28 | # 29 | # Author: alexs.mac@gmail.com (Alex Stewart) 30 | # 31 | 32 | # FindSuiteSparse.cmake - Find SuiteSparse libraries & dependencies. 33 | # 34 | # This module defines the following variables: 35 | # 36 | # SUITESPARSE_FOUND: TRUE iff SuiteSparse and all dependencies have been found. 37 | # SUITESPARSE_INCLUDE_DIRS: Include directories for all SuiteSparse components. 38 | # SUITESPARSE_LIBRARIES: Libraries for all SuiteSparse component libraries and 39 | # dependencies. 40 | # SUITESPARSE_VERSION: Extracted from UFconfig.h (<= v3) or 41 | # SuiteSparse_config.h (>= v4). 42 | # SUITESPARSE_MAIN_VERSION: Equal to 4 if SUITESPARSE_VERSION = 4.2.1 43 | # SUITESPARSE_SUB_VERSION: Equal to 2 if SUITESPARSE_VERSION = 4.2.1 44 | # SUITESPARSE_SUBSUB_VERSION: Equal to 1 if SUITESPARSE_VERSION = 4.2.1 45 | # 46 | # SUITESPARSE_IS_BROKEN_SHARED_LINKING_UBUNTU_SYSTEM_VERSION: TRUE iff running 47 | # on Ubuntu, SUITESPARSE_VERSION is 3.4.0 and found SuiteSparse is a system 48 | # install, in which case found version of SuiteSparse cannot be used to link 49 | # a shared library due to a bug (static linking is unaffected). 50 | # 51 | # The following variables control the behaviour of this module: 52 | # 53 | # SUITESPARSE_INCLUDE_DIR_HINTS: List of additional directories in which to 54 | # search for SuiteSparse includes, 55 | # e.g: /timbuktu/include. 56 | # SUITESPARSE_LIBRARY_DIR_HINTS: List of additional directories in which to 57 | # search for SuiteSparse libraries, 58 | # e.g: /timbuktu/lib. 59 | # 60 | # The following variables define the presence / includes & libraries for the 61 | # SuiteSparse components searched for, the SUITESPARSE_XX variables are the 62 | # union of the variables for all components. 63 | # 64 | # == Symmetric Approximate Minimum Degree (AMD) 65 | # AMD_FOUND 66 | # AMD_INCLUDE_DIR 67 | # AMD_LIBRARY 68 | # 69 | # == Constrained Approximate Minimum Degree (CAMD) 70 | # CAMD_FOUND 71 | # CAMD_INCLUDE_DIR 72 | # CAMD_LIBRARY 73 | # 74 | # == Column Approximate Minimum Degree (COLAMD) 75 | # COLAMD_FOUND 76 | # COLAMD_INCLUDE_DIR 77 | # COLAMD_LIBRARY 78 | # 79 | # Constrained Column Approximate Minimum Degree (CCOLAMD) 80 | # CCOLAMD_FOUND 81 | # CCOLAMD_INCLUDE_DIR 82 | # CCOLAMD_LIBRARY 83 | # 84 | # == Sparse Supernodal Cholesky Factorization and Update/Downdate (CHOLMOD) 85 | # CHOLMOD_FOUND 86 | # CHOLMOD_INCLUDE_DIR 87 | # CHOLMOD_LIBRARY 88 | # 89 | # == Multifrontal Sparse QR (SuiteSparseQR) 90 | # SUITESPARSEQR_FOUND 91 | # SUITESPARSEQR_INCLUDE_DIR 92 | # SUITESPARSEQR_LIBRARY 93 | # 94 | # == Common configuration for all but CSparse (SuiteSparse version >= 4). 95 | # SUITESPARSE_CONFIG_FOUND 96 | # SUITESPARSE_CONFIG_INCLUDE_DIR 97 | # SUITESPARSE_CONFIG_LIBRARY 98 | # 99 | # == Common configuration for all but CSparse (SuiteSparse version < 4). 100 | # UFCONFIG_FOUND 101 | # UFCONFIG_INCLUDE_DIR 102 | # 103 | # Optional SuiteSparse Dependencies: 104 | # 105 | # == Serial Graph Partitioning and Fill-reducing Matrix Ordering (METIS) 106 | # METIS_FOUND 107 | # METIS_LIBRARY 108 | # 109 | # == Intel Thread Building Blocks (TBB) 110 | # TBB_FOUND 111 | # TBB_LIBRARIES 112 | 113 | # Reset CALLERS_CMAKE_FIND_LIBRARY_PREFIXES to its value when 114 | # FindSuiteSparse was invoked. 115 | macro(SUITESPARSE_RESET_FIND_LIBRARY_PREFIX) 116 | if (MSVC) 117 | set(CMAKE_FIND_LIBRARY_PREFIXES "${CALLERS_CMAKE_FIND_LIBRARY_PREFIXES}") 118 | endif (MSVC) 119 | endmacro(SUITESPARSE_RESET_FIND_LIBRARY_PREFIX) 120 | 121 | # Called if we failed to find SuiteSparse or any of it's required dependencies, 122 | # unsets all public (designed to be used externally) variables and reports 123 | # error message at priority depending upon [REQUIRED/QUIET/] argument. 124 | macro(SUITESPARSE_REPORT_NOT_FOUND REASON_MSG) 125 | unset(SUITESPARSE_FOUND) 126 | unset(SUITESPARSE_INCLUDE_DIRS) 127 | unset(SUITESPARSE_LIBRARIES) 128 | unset(SUITESPARSE_VERSION) 129 | unset(SUITESPARSE_MAIN_VERSION) 130 | unset(SUITESPARSE_SUB_VERSION) 131 | unset(SUITESPARSE_SUBSUB_VERSION) 132 | # Do NOT unset SUITESPARSE_FOUND_REQUIRED_VARS here, as it is used by 133 | # FindPackageHandleStandardArgs() to generate the automatic error message on 134 | # failure which highlights which components are missing. 135 | 136 | suitesparse_reset_find_library_prefix() 137 | 138 | # Note _FIND_[REQUIRED/QUIETLY] variables defined by FindPackage() 139 | # use the camelcase library name, not uppercase. 140 | if (SuiteSparse_FIND_QUIETLY) 141 | message(STATUS "Failed to find SuiteSparse - " ${REASON_MSG} ${ARGN}) 142 | elseif (SuiteSparse_FIND_REQUIRED) 143 | message(FATAL_ERROR "Failed to find SuiteSparse - " ${REASON_MSG} ${ARGN}) 144 | else() 145 | # Neither QUIETLY nor REQUIRED, use no priority which emits a message 146 | # but continues configuration and allows generation. 147 | message("-- Failed to find SuiteSparse - " ${REASON_MSG} ${ARGN}) 148 | endif (SuiteSparse_FIND_QUIETLY) 149 | 150 | # Do not call return(), s/t we keep processing if not called with REQUIRED 151 | # and report all missing components, rather than bailing after failing to find 152 | # the first. 153 | endmacro(SUITESPARSE_REPORT_NOT_FOUND) 154 | 155 | # Protect against any alternative find_package scripts for this library having 156 | # been called previously (in a client project) which set SUITESPARSE_FOUND, but 157 | # not the other variables we require / set here which could cause the search 158 | # logic here to fail. 159 | unset(SUITESPARSE_FOUND) 160 | 161 | # Handle possible presence of lib prefix for libraries on MSVC, see 162 | # also SUITESPARSE_RESET_FIND_LIBRARY_PREFIX(). 163 | if (MSVC) 164 | # Preserve the caller's original values for CMAKE_FIND_LIBRARY_PREFIXES 165 | # s/t we can set it back before returning. 166 | set(CALLERS_CMAKE_FIND_LIBRARY_PREFIXES "${CMAKE_FIND_LIBRARY_PREFIXES}") 167 | # The empty string in this list is important, it represents the case when 168 | # the libraries have no prefix (shared libraries / DLLs). 169 | set(CMAKE_FIND_LIBRARY_PREFIXES "lib" "" "${CMAKE_FIND_LIBRARY_PREFIXES}") 170 | endif (MSVC) 171 | 172 | # Specify search directories for include files and libraries (this is the union 173 | # of the search directories for all OSs). Search user-specified hint 174 | # directories first if supplied, and search user-installed locations first 175 | # so that we prefer user installs to system installs where both exist. 176 | list(APPEND SUITESPARSE_CHECK_INCLUDE_DIRS 177 | ${SUITESPARSE_INCLUDE_DIR_HINTS} 178 | /opt/local/include 179 | /opt/local/include/ufsparse # Mac OS X 180 | /usr/local/homebrew/include # Mac OS X 181 | /usr/local/include 182 | /usr/local/include/suitesparse 183 | /usr/include/suitesparse # Ubuntu 184 | /usr/include) 185 | list(APPEND SUITESPARSE_CHECK_LIBRARY_DIRS 186 | ${SUITESPARSE_LIBRARY_DIR_HINTS} 187 | /opt/local/lib 188 | /opt/local/lib/ufsparse # Mac OS X 189 | /usr/local/homebrew/lib # Mac OS X 190 | /usr/local/lib 191 | /usr/local/lib/suitesparse 192 | /usr/lib/suitesparse # Ubuntu 193 | /usr/lib) 194 | 195 | # Given the number of components of SuiteSparse, and to ensure that the 196 | # automatic failure message generated by FindPackageHandleStandardArgs() 197 | # when not all required components are found is helpful, we maintain a list 198 | # of all variables that must be defined for SuiteSparse to be considered found. 199 | unset(SUITESPARSE_FOUND_REQUIRED_VARS) 200 | 201 | # BLAS. 202 | find_package(BLAS QUIET) 203 | if (NOT BLAS_FOUND) 204 | suitesparse_report_not_found( 205 | "Did not find BLAS library (required for SuiteSparse).") 206 | endif (NOT BLAS_FOUND) 207 | list(APPEND SUITESPARSE_FOUND_REQUIRED_VARS BLAS_FOUND) 208 | 209 | # LAPACK. 210 | find_package(LAPACK QUIET) 211 | if (NOT LAPACK_FOUND) 212 | suitesparse_report_not_found( 213 | "Did not find LAPACK library (required for SuiteSparse).") 214 | endif (NOT LAPACK_FOUND) 215 | list(APPEND SUITESPARSE_FOUND_REQUIRED_VARS LAPACK_FOUND) 216 | 217 | # AMD. 218 | set(AMD_FOUND TRUE) 219 | list(APPEND SUITESPARSE_FOUND_REQUIRED_VARS AMD_FOUND) 220 | find_library(AMD_LIBRARY NAMES amd 221 | PATHS ${SUITESPARSE_CHECK_LIBRARY_DIRS}) 222 | if (EXISTS ${AMD_LIBRARY}) 223 | message(STATUS "Found AMD library: ${AMD_LIBRARY}") 224 | else (EXISTS ${AMD_LIBRARY}) 225 | suitesparse_report_not_found( 226 | "Did not find AMD library (required SuiteSparse component).") 227 | set(AMD_FOUND FALSE) 228 | endif (EXISTS ${AMD_LIBRARY}) 229 | mark_as_advanced(AMD_LIBRARY) 230 | 231 | find_path(AMD_INCLUDE_DIR NAMES amd.h 232 | PATHS ${SUITESPARSE_CHECK_INCLUDE_DIRS}) 233 | if (EXISTS ${AMD_INCLUDE_DIR}) 234 | message(STATUS "Found AMD header in: ${AMD_INCLUDE_DIR}") 235 | else (EXISTS ${AMD_INCLUDE_DIR}) 236 | suitesparse_report_not_found( 237 | "Did not find AMD header (required SuiteSparse component).") 238 | set(AMD_FOUND FALSE) 239 | endif (EXISTS ${AMD_INCLUDE_DIR}) 240 | mark_as_advanced(AMD_INCLUDE_DIR) 241 | 242 | # CAMD. 243 | set(CAMD_FOUND TRUE) 244 | list(APPEND SUITESPARSE_FOUND_REQUIRED_VARS CAMD_FOUND) 245 | find_library(CAMD_LIBRARY NAMES camd 246 | PATHS ${SUITESPARSE_CHECK_LIBRARY_DIRS}) 247 | if (EXISTS ${CAMD_LIBRARY}) 248 | message(STATUS "Found CAMD library: ${CAMD_LIBRARY}") 249 | else (EXISTS ${CAMD_LIBRARY}) 250 | suitesparse_report_not_found( 251 | "Did not find CAMD library (required SuiteSparse component).") 252 | set(CAMD_FOUND FALSE) 253 | endif (EXISTS ${CAMD_LIBRARY}) 254 | mark_as_advanced(CAMD_LIBRARY) 255 | 256 | find_path(CAMD_INCLUDE_DIR NAMES camd.h 257 | PATHS ${SUITESPARSE_CHECK_INCLUDE_DIRS}) 258 | if (EXISTS ${CAMD_INCLUDE_DIR}) 259 | message(STATUS "Found CAMD header in: ${CAMD_INCLUDE_DIR}") 260 | else (EXISTS ${CAMD_INCLUDE_DIR}) 261 | suitesparse_report_not_found( 262 | "Did not find CAMD header (required SuiteSparse component).") 263 | set(CAMD_FOUND FALSE) 264 | endif (EXISTS ${CAMD_INCLUDE_DIR}) 265 | mark_as_advanced(CAMD_INCLUDE_DIR) 266 | 267 | # COLAMD. 268 | set(COLAMD_FOUND TRUE) 269 | list(APPEND SUITESPARSE_FOUND_REQUIRED_VARS COLAMD_FOUND) 270 | find_library(COLAMD_LIBRARY NAMES colamd 271 | PATHS ${SUITESPARSE_CHECK_LIBRARY_DIRS}) 272 | if (EXISTS ${COLAMD_LIBRARY}) 273 | message(STATUS "Found COLAMD library: ${COLAMD_LIBRARY}") 274 | else (EXISTS ${COLAMD_LIBRARY}) 275 | suitesparse_report_not_found( 276 | "Did not find COLAMD library (required SuiteSparse component).") 277 | set(COLAMD_FOUND FALSE) 278 | endif (EXISTS ${COLAMD_LIBRARY}) 279 | mark_as_advanced(COLAMD_LIBRARY) 280 | 281 | find_path(COLAMD_INCLUDE_DIR NAMES colamd.h 282 | PATHS ${SUITESPARSE_CHECK_INCLUDE_DIRS}) 283 | if (EXISTS ${COLAMD_INCLUDE_DIR}) 284 | message(STATUS "Found COLAMD header in: ${COLAMD_INCLUDE_DIR}") 285 | else (EXISTS ${COLAMD_INCLUDE_DIR}) 286 | suitesparse_report_not_found( 287 | "Did not find COLAMD header (required SuiteSparse component).") 288 | set(COLAMD_FOUND FALSE) 289 | endif (EXISTS ${COLAMD_INCLUDE_DIR}) 290 | mark_as_advanced(COLAMD_INCLUDE_DIR) 291 | 292 | # CCOLAMD. 293 | set(CCOLAMD_FOUND TRUE) 294 | list(APPEND SUITESPARSE_FOUND_REQUIRED_VARS CCOLAMD_FOUND) 295 | find_library(CCOLAMD_LIBRARY NAMES ccolamd 296 | PATHS ${SUITESPARSE_CHECK_LIBRARY_DIRS}) 297 | if (EXISTS ${CCOLAMD_LIBRARY}) 298 | message(STATUS "Found CCOLAMD library: ${CCOLAMD_LIBRARY}") 299 | else (EXISTS ${CCOLAMD_LIBRARY}) 300 | suitesparse_report_not_found( 301 | "Did not find CCOLAMD library (required SuiteSparse component).") 302 | set(CCOLAMD_FOUND FALSE) 303 | endif (EXISTS ${CCOLAMD_LIBRARY}) 304 | mark_as_advanced(CCOLAMD_LIBRARY) 305 | 306 | find_path(CCOLAMD_INCLUDE_DIR NAMES ccolamd.h 307 | PATHS ${SUITESPARSE_CHECK_INCLUDE_DIRS}) 308 | if (EXISTS ${CCOLAMD_INCLUDE_DIR}) 309 | message(STATUS "Found CCOLAMD header in: ${CCOLAMD_INCLUDE_DIR}") 310 | else (EXISTS ${CCOLAMD_INCLUDE_DIR}) 311 | suitesparse_report_not_found( 312 | "Did not find CCOLAMD header (required SuiteSparse component).") 313 | set(CCOLAMD_FOUND FALSE) 314 | endif (EXISTS ${CCOLAMD_INCLUDE_DIR}) 315 | mark_as_advanced(CCOLAMD_INCLUDE_DIR) 316 | 317 | # CHOLMOD. 318 | set(CHOLMOD_FOUND TRUE) 319 | list(APPEND SUITESPARSE_FOUND_REQUIRED_VARS CHOLMOD_FOUND) 320 | find_library(CHOLMOD_LIBRARY NAMES cholmod 321 | PATHS ${SUITESPARSE_CHECK_LIBRARY_DIRS}) 322 | if (EXISTS ${CHOLMOD_LIBRARY}) 323 | message(STATUS "Found CHOLMOD library: ${CHOLMOD_LIBRARY}") 324 | else (EXISTS ${CHOLMOD_LIBRARY}) 325 | suitesparse_report_not_found( 326 | "Did not find CHOLMOD library (required SuiteSparse component).") 327 | set(CHOLMOD_FOUND FALSE) 328 | endif (EXISTS ${CHOLMOD_LIBRARY}) 329 | mark_as_advanced(CHOLMOD_LIBRARY) 330 | 331 | find_path(CHOLMOD_INCLUDE_DIR NAMES cholmod.h 332 | PATHS ${SUITESPARSE_CHECK_INCLUDE_DIRS}) 333 | if (EXISTS ${CHOLMOD_INCLUDE_DIR}) 334 | message(STATUS "Found CHOLMOD header in: ${CHOLMOD_INCLUDE_DIR}") 335 | else (EXISTS ${CHOLMOD_INCLUDE_DIR}) 336 | suitesparse_report_not_found( 337 | "Did not find CHOLMOD header (required SuiteSparse component).") 338 | set(CHOLMOD_FOUND FALSE) 339 | endif (EXISTS ${CHOLMOD_INCLUDE_DIR}) 340 | mark_as_advanced(CHOLMOD_INCLUDE_DIR) 341 | 342 | # SuiteSparseQR. 343 | set(SUITESPARSEQR_FOUND TRUE) 344 | list(APPEND SUITESPARSE_FOUND_REQUIRED_VARS SUITESPARSEQR_FOUND) 345 | find_library(SUITESPARSEQR_LIBRARY NAMES spqr 346 | PATHS ${SUITESPARSE_CHECK_LIBRARY_DIRS}) 347 | if (EXISTS ${SUITESPARSEQR_LIBRARY}) 348 | message(STATUS "Found SuiteSparseQR library: ${SUITESPARSEQR_LIBRARY}") 349 | else (EXISTS ${SUITESPARSEQR_LIBRARY}) 350 | suitesparse_report_not_found( 351 | "Did not find SuiteSparseQR library (required SuiteSparse component).") 352 | set(SUITESPARSEQR_FOUND FALSE) 353 | endif (EXISTS ${SUITESPARSEQR_LIBRARY}) 354 | mark_as_advanced(SUITESPARSEQR_LIBRARY) 355 | 356 | find_path(SUITESPARSEQR_INCLUDE_DIR NAMES SuiteSparseQR.hpp 357 | PATHS ${SUITESPARSE_CHECK_INCLUDE_DIRS}) 358 | if (EXISTS ${SUITESPARSEQR_INCLUDE_DIR}) 359 | message(STATUS "Found SuiteSparseQR header in: ${SUITESPARSEQR_INCLUDE_DIR}") 360 | else (EXISTS ${SUITESPARSEQR_INCLUDE_DIR}) 361 | suitesparse_report_not_found( 362 | "Did not find SUITESPARSEQR header (required SuiteSparse component).") 363 | set(SUITESPARSEQR_FOUND FALSE) 364 | endif (EXISTS ${SUITESPARSEQR_INCLUDE_DIR}) 365 | mark_as_advanced(SUITESPARSEQR_INCLUDE_DIR) 366 | 367 | if (SUITESPARSEQR_FOUND) 368 | # SuiteSparseQR may be compiled with Intel Threading Building Blocks, 369 | # we assume that if TBB is installed, SuiteSparseQR was compiled with 370 | # support for it, this will do no harm if it wasn't. 371 | set(TBB_FOUND TRUE) 372 | find_library(TBB_LIBRARIES NAMES tbb 373 | PATHS ${SUITESPARSE_CHECK_LIBRARY_DIRS}) 374 | if (EXISTS ${TBB_LIBRARIES}) 375 | message(STATUS "Found Intel Thread Building Blocks (TBB) library: " 376 | "${TBB_LIBRARIES}, assuming SuiteSparseQR was compiled with TBB.") 377 | else (EXISTS ${TBB_LIBRARIES}) 378 | message(STATUS "Did not find Intel TBB library, assuming SuiteSparseQR was " 379 | "not compiled with TBB.") 380 | set(TBB_FOUND FALSE) 381 | endif (EXISTS ${TBB_LIBRARIES}) 382 | mark_as_advanced(TBB_LIBRARIES) 383 | 384 | if (TBB_FOUND) 385 | find_library(TBB_MALLOC_LIB NAMES tbbmalloc 386 | PATHS ${SUITESPARSE_CHECK_LIBRARY_DIRS}) 387 | if (EXISTS ${TBB_MALLOC_LIB}) 388 | message(STATUS "Found Intel Thread Building Blocks (TBB) Malloc library: " 389 | "${TBB_MALLOC_LIB}") 390 | # Append TBB malloc library to TBB libraries list whilst retaining 391 | # any CMake generated help string (cache variable). 392 | list(APPEND TBB_LIBRARIES ${TBB_MALLOC_LIB}) 393 | get_property(HELP_STRING CACHE TBB_LIBRARIES PROPERTY HELPSTRING) 394 | set(TBB_LIBRARIES "${TBB_LIBRARIES}" CACHE STRING "${HELP_STRING}") 395 | 396 | # Add the TBB libraries to the SuiteSparseQR libraries (the only 397 | # libraries to optionally depend on TBB). 398 | list(APPEND SUITESPARSEQR_LIBRARY ${TBB_LIBRARIES}) 399 | 400 | else (EXISTS ${TBB_MALLOC_LIB}) 401 | # If we cannot find all required TBB components do not include it as 402 | # a dependency. 403 | message(STATUS "Did not find Intel Thread Building Blocks (TBB) Malloc " 404 | "Library, discarding TBB as a dependency.") 405 | set(TBB_FOUND FALSE) 406 | endif (EXISTS ${TBB_MALLOC_LIB}) 407 | mark_as_advanced(TBB_MALLOC_LIB) 408 | endif (TBB_FOUND) 409 | endif(SUITESPARSEQR_FOUND) 410 | 411 | # UFconfig / SuiteSparse_config. 412 | # 413 | # If SuiteSparse version is >= 4 then SuiteSparse_config is required. 414 | # For SuiteSparse 3, UFconfig.h is required. 415 | find_library(SUITESPARSE_CONFIG_LIBRARY NAMES suitesparseconfig 416 | PATHS ${SUITESPARSE_CHECK_LIBRARY_DIRS}) 417 | if (EXISTS ${SUITESPARSE_CONFIG_LIBRARY}) 418 | message(STATUS "Found SuiteSparse_config library: " 419 | "${SUITESPARSE_CONFIG_LIBRARY}") 420 | endif (EXISTS ${SUITESPARSE_CONFIG_LIBRARY}) 421 | mark_as_advanced(SUITESPARSE_CONFIG_LIBRARY) 422 | 423 | find_path(SUITESPARSE_CONFIG_INCLUDE_DIR NAMES SuiteSparse_config.h 424 | PATHS ${SUITESPARSE_CHECK_INCLUDE_DIRS}) 425 | if (EXISTS ${SUITESPARSE_CONFIG_INCLUDE_DIR}) 426 | message(STATUS "Found SuiteSparse_config header in: " 427 | "${SUITESPARSE_CONFIG_INCLUDE_DIR}") 428 | endif (EXISTS ${SUITESPARSE_CONFIG_INCLUDE_DIR}) 429 | mark_as_advanced(SUITESPARSE_CONFIG_INCLUDE_DIR) 430 | 431 | set(SUITESPARSE_CONFIG_FOUND FALSE) 432 | set(UFCONFIG_FOUND FALSE) 433 | 434 | if (EXISTS ${SUITESPARSE_CONFIG_LIBRARY} AND 435 | EXISTS ${SUITESPARSE_CONFIG_INCLUDE_DIR}) 436 | set(SUITESPARSE_CONFIG_FOUND TRUE) 437 | # SuiteSparse_config (SuiteSparse version >= 4) requires librt library for 438 | # timing by default when compiled on Linux or Unix, but not on OSX (which 439 | # does not have librt). 440 | if (CMAKE_SYSTEM_NAME MATCHES "Linux" OR UNIX AND NOT APPLE) 441 | find_library(LIBRT_LIBRARY NAMES rt 442 | PATHS ${SUITESPARSE_CHECK_LIBRARY_DIRS}) 443 | if (LIBRT_LIBRARY) 444 | message(STATUS "Adding librt: ${LIBRT_LIBRARY} to " 445 | "SuiteSparse_config libraries (required on Linux & Unix [not OSX] if " 446 | "SuiteSparse is compiled with timing).") 447 | else (LIBRT_LIBRARY) 448 | message(STATUS "Could not find librt, but found SuiteSparse_config, " 449 | "assuming that SuiteSparse was compiled without timing.") 450 | endif (LIBRT_LIBRARY) 451 | mark_as_advanced(LIBRT_LIBRARY) 452 | list(APPEND SUITESPARSE_CONFIG_LIBRARY ${LIBRT_LIBRARY}) 453 | endif (CMAKE_SYSTEM_NAME MATCHES "Linux" OR UNIX AND NOT APPLE) 454 | 455 | else (EXISTS ${SUITESPARSE_CONFIG_LIBRARY} AND 456 | EXISTS ${SUITESPARSE_CONFIG_INCLUDE_DIR}) 457 | # Failed to find SuiteSparse_config (>= v4 installs), instead look for 458 | # UFconfig header which should be present in < v4 installs. 459 | set(SUITESPARSE_CONFIG_FOUND FALSE) 460 | find_path(UFCONFIG_INCLUDE_DIR NAMES UFconfig.h 461 | PATHS ${SUITESPARSE_CHECK_INCLUDE_DIRS}) 462 | if (EXISTS ${UFCONFIG_INCLUDE_DIR}) 463 | message(STATUS "Found UFconfig header in: ${UFCONFIG_INCLUDE_DIR}") 464 | set(UFCONFIG_FOUND TRUE) 465 | endif (EXISTS ${UFCONFIG_INCLUDE_DIR}) 466 | mark_as_advanced(UFCONFIG_INCLUDE_DIR) 467 | endif (EXISTS ${SUITESPARSE_CONFIG_LIBRARY} AND 468 | EXISTS ${SUITESPARSE_CONFIG_INCLUDE_DIR}) 469 | 470 | if (NOT SUITESPARSE_CONFIG_FOUND AND 471 | NOT UFCONFIG_FOUND) 472 | suitesparse_report_not_found( 473 | "Failed to find either: SuiteSparse_config header & library (should be " 474 | "present in all SuiteSparse >= v4 installs), or UFconfig header (should " 475 | "be present in all SuiteSparse < v4 installs).") 476 | endif (NOT SUITESPARSE_CONFIG_FOUND AND 477 | NOT UFCONFIG_FOUND) 478 | 479 | # Extract the SuiteSparse version from the appropriate header (UFconfig.h for 480 | # <= v3, SuiteSparse_config.h for >= v4). 481 | list(APPEND SUITESPARSE_FOUND_REQUIRED_VARS SUITESPARSE_VERSION) 482 | 483 | if (UFCONFIG_FOUND) 484 | # SuiteSparse version <= 3. 485 | set(SUITESPARSE_VERSION_FILE ${UFCONFIG_INCLUDE_DIR}/UFconfig.h) 486 | if (NOT EXISTS ${SUITESPARSE_VERSION_FILE}) 487 | suitesparse_report_not_found( 488 | "Could not find file: ${SUITESPARSE_VERSION_FILE} containing version " 489 | "information for <= v3 SuiteSparse installs, but UFconfig was found " 490 | "(only present in <= v3 installs).") 491 | else (NOT EXISTS ${SUITESPARSE_VERSION_FILE}) 492 | file(READ ${SUITESPARSE_VERSION_FILE} UFCONFIG_CONTENTS) 493 | 494 | string(REGEX MATCH "#define SUITESPARSE_MAIN_VERSION [0-9]+" 495 | SUITESPARSE_MAIN_VERSION "${UFCONFIG_CONTENTS}") 496 | string(REGEX REPLACE "#define SUITESPARSE_MAIN_VERSION ([0-9]+)" "\\1" 497 | SUITESPARSE_MAIN_VERSION "${SUITESPARSE_MAIN_VERSION}") 498 | 499 | string(REGEX MATCH "#define SUITESPARSE_SUB_VERSION [0-9]+" 500 | SUITESPARSE_SUB_VERSION "${UFCONFIG_CONTENTS}") 501 | string(REGEX REPLACE "#define SUITESPARSE_SUB_VERSION ([0-9]+)" "\\1" 502 | SUITESPARSE_SUB_VERSION "${SUITESPARSE_SUB_VERSION}") 503 | 504 | string(REGEX MATCH "#define SUITESPARSE_SUBSUB_VERSION [0-9]+" 505 | SUITESPARSE_SUBSUB_VERSION "${UFCONFIG_CONTENTS}") 506 | string(REGEX REPLACE "#define SUITESPARSE_SUBSUB_VERSION ([0-9]+)" "\\1" 507 | SUITESPARSE_SUBSUB_VERSION "${SUITESPARSE_SUBSUB_VERSION}") 508 | 509 | # This is on a single line s/t CMake does not interpret it as a list of 510 | # elements and insert ';' separators which would result in 4.;2.;1 nonsense. 511 | set(SUITESPARSE_VERSION 512 | "${SUITESPARSE_MAIN_VERSION}.${SUITESPARSE_SUB_VERSION}.${SUITESPARSE_SUBSUB_VERSION}") 513 | endif (NOT EXISTS ${SUITESPARSE_VERSION_FILE}) 514 | endif (UFCONFIG_FOUND) 515 | 516 | if (SUITESPARSE_CONFIG_FOUND) 517 | # SuiteSparse version >= 4. 518 | set(SUITESPARSE_VERSION_FILE 519 | ${SUITESPARSE_CONFIG_INCLUDE_DIR}/SuiteSparse_config.h) 520 | if (NOT EXISTS ${SUITESPARSE_VERSION_FILE}) 521 | suitesparse_report_not_found( 522 | "Could not find file: ${SUITESPARSE_VERSION_FILE} containing version " 523 | "information for >= v4 SuiteSparse installs, but SuiteSparse_config was " 524 | "found (only present in >= v4 installs).") 525 | else (NOT EXISTS ${SUITESPARSE_VERSION_FILE}) 526 | file(READ ${SUITESPARSE_VERSION_FILE} SUITESPARSE_CONFIG_CONTENTS) 527 | 528 | string(REGEX MATCH "#define SUITESPARSE_MAIN_VERSION [0-9]+" 529 | SUITESPARSE_MAIN_VERSION "${SUITESPARSE_CONFIG_CONTENTS}") 530 | string(REGEX REPLACE "#define SUITESPARSE_MAIN_VERSION ([0-9]+)" "\\1" 531 | SUITESPARSE_MAIN_VERSION "${SUITESPARSE_MAIN_VERSION}") 532 | 533 | string(REGEX MATCH "#define SUITESPARSE_SUB_VERSION [0-9]+" 534 | SUITESPARSE_SUB_VERSION "${SUITESPARSE_CONFIG_CONTENTS}") 535 | string(REGEX REPLACE "#define SUITESPARSE_SUB_VERSION ([0-9]+)" "\\1" 536 | SUITESPARSE_SUB_VERSION "${SUITESPARSE_SUB_VERSION}") 537 | 538 | string(REGEX MATCH "#define SUITESPARSE_SUBSUB_VERSION [0-9]+" 539 | SUITESPARSE_SUBSUB_VERSION "${SUITESPARSE_CONFIG_CONTENTS}") 540 | string(REGEX REPLACE "#define SUITESPARSE_SUBSUB_VERSION ([0-9]+)" "\\1" 541 | SUITESPARSE_SUBSUB_VERSION "${SUITESPARSE_SUBSUB_VERSION}") 542 | 543 | # This is on a single line s/t CMake does not interpret it as a list of 544 | # elements and insert ';' separators which would result in 4.;2.;1 nonsense. 545 | set(SUITESPARSE_VERSION 546 | "${SUITESPARSE_MAIN_VERSION}.${SUITESPARSE_SUB_VERSION}.${SUITESPARSE_SUBSUB_VERSION}") 547 | endif (NOT EXISTS ${SUITESPARSE_VERSION_FILE}) 548 | endif (SUITESPARSE_CONFIG_FOUND) 549 | 550 | # METIS (Optional dependency). 551 | find_library(METIS_LIBRARY NAMES metis 552 | PATHS ${SUITESPARSE_CHECK_LIBRARY_DIRS}) 553 | if (EXISTS ${METIS_LIBRARY}) 554 | message(STATUS "Found METIS library: ${METIS_LIBRARY}.") 555 | set(METIS_FOUND TRUE) 556 | else (EXISTS ${METIS_LIBRARY}) 557 | message(STATUS "Did not find METIS library (optional SuiteSparse dependency)") 558 | set(METIS_FOUND FALSE) 559 | endif (EXISTS ${METIS_LIBRARY}) 560 | mark_as_advanced(METIS_LIBRARY) 561 | 562 | # Only mark SuiteSparse as found if all required components and dependencies 563 | # have been found. 564 | set(SUITESPARSE_FOUND TRUE) 565 | foreach(REQUIRED_VAR ${SUITESPARSE_FOUND_REQUIRED_VARS}) 566 | if (NOT ${REQUIRED_VAR}) 567 | set(SUITESPARSE_FOUND FALSE) 568 | endif (NOT ${REQUIRED_VAR}) 569 | endforeach(REQUIRED_VAR ${SUITESPARSE_FOUND_REQUIRED_VARS}) 570 | 571 | if (SUITESPARSE_FOUND) 572 | list(APPEND SUITESPARSE_INCLUDE_DIRS 573 | ${AMD_INCLUDE_DIR} 574 | ${CAMD_INCLUDE_DIR} 575 | ${COLAMD_INCLUDE_DIR} 576 | ${CCOLAMD_INCLUDE_DIR} 577 | ${CHOLMOD_INCLUDE_DIR} 578 | ${SUITESPARSEQR_INCLUDE_DIR}) 579 | # Handle config separately, as otherwise at least one of them will be set 580 | # to NOTFOUND which would cause any check on SUITESPARSE_INCLUDE_DIRS to fail. 581 | if (SUITESPARSE_CONFIG_FOUND) 582 | list(APPEND SUITESPARSE_INCLUDE_DIRS 583 | ${SUITESPARSE_CONFIG_INCLUDE_DIR}) 584 | endif (SUITESPARSE_CONFIG_FOUND) 585 | if (UFCONFIG_FOUND) 586 | list(APPEND SUITESPARSE_INCLUDE_DIRS 587 | ${UFCONFIG_INCLUDE_DIR}) 588 | endif (UFCONFIG_FOUND) 589 | # As SuiteSparse includes are often all in the same directory, remove any 590 | # repetitions. 591 | list(REMOVE_DUPLICATES SUITESPARSE_INCLUDE_DIRS) 592 | 593 | # Important: The ordering of these libraries is *NOT* arbitrary, as these 594 | # could potentially be static libraries their link ordering is important. 595 | list(APPEND SUITESPARSE_LIBRARIES 596 | ${SUITESPARSEQR_LIBRARY} 597 | ${CHOLMOD_LIBRARY} 598 | ${CCOLAMD_LIBRARY} 599 | ${CAMD_LIBRARY} 600 | ${COLAMD_LIBRARY} 601 | ${AMD_LIBRARY} 602 | ${LAPACK_LIBRARIES} 603 | ${BLAS_LIBRARIES}) 604 | if (SUITESPARSE_CONFIG_FOUND) 605 | list(APPEND SUITESPARSE_LIBRARIES 606 | ${SUITESPARSE_CONFIG_LIBRARY}) 607 | endif (SUITESPARSE_CONFIG_FOUND) 608 | if (METIS_FOUND) 609 | list(APPEND SUITESPARSE_LIBRARIES 610 | ${METIS_LIBRARY}) 611 | endif (METIS_FOUND) 612 | endif() 613 | 614 | # Determine if we are running on Ubuntu with the package install of SuiteSparse 615 | # which is broken and does not support linking a shared library. 616 | set(SUITESPARSE_IS_BROKEN_SHARED_LINKING_UBUNTU_SYSTEM_VERSION FALSE) 617 | if (CMAKE_SYSTEM_NAME MATCHES "Linux" AND 618 | SUITESPARSE_VERSION VERSION_EQUAL 3.4.0) 619 | find_program(LSB_RELEASE_EXECUTABLE lsb_release) 620 | if (LSB_RELEASE_EXECUTABLE) 621 | # Any even moderately recent Ubuntu release (likely to be affected by 622 | # this bug) should have lsb_release, if it isn't present we are likely 623 | # on a different Linux distribution (should be fine). 624 | 625 | execute_process(COMMAND ${LSB_RELEASE_EXECUTABLE} -si 626 | OUTPUT_VARIABLE LSB_DISTRIBUTOR_ID 627 | OUTPUT_STRIP_TRAILING_WHITESPACE) 628 | 629 | if (LSB_DISTRIBUTOR_ID MATCHES "Ubuntu" AND 630 | SUITESPARSE_LIBRARIES MATCHES "/usr/lib/libamd") 631 | # We are on Ubuntu, and the SuiteSparse version matches the broken 632 | # system install version and is a system install. 633 | set(SUITESPARSE_IS_BROKEN_SHARED_LINKING_UBUNTU_SYSTEM_VERSION TRUE) 634 | message(STATUS "Found system install of SuiteSparse " 635 | "${SUITESPARSE_VERSION} running on Ubuntu, which has a known bug " 636 | "preventing linking of shared libraries (static linking unaffected).") 637 | endif (LSB_DISTRIBUTOR_ID MATCHES "Ubuntu" AND 638 | SUITESPARSE_LIBRARIES MATCHES "/usr/lib/libamd") 639 | endif (LSB_RELEASE_EXECUTABLE) 640 | endif (CMAKE_SYSTEM_NAME MATCHES "Linux" AND 641 | SUITESPARSE_VERSION VERSION_EQUAL 3.4.0) 642 | 643 | suitesparse_reset_find_library_prefix() 644 | 645 | # Handle REQUIRED and QUIET arguments to FIND_PACKAGE 646 | include(FindPackageHandleStandardArgs) 647 | if (SUITESPARSE_FOUND) 648 | find_package_handle_standard_args(SuiteSparse 649 | REQUIRED_VARS ${SUITESPARSE_FOUND_REQUIRED_VARS} 650 | VERSION_VAR SUITESPARSE_VERSION 651 | FAIL_MESSAGE "Failed to find some/all required components of SuiteSparse.") 652 | else (SUITESPARSE_FOUND) 653 | # Do not pass VERSION_VAR to FindPackageHandleStandardArgs() if we failed to 654 | # find SuiteSparse to avoid a confusing autogenerated failure message 655 | # that states 'not found (missing: FOO) (found version: x.y.z)'. 656 | find_package_handle_standard_args(SuiteSparse 657 | REQUIRED_VARS ${SUITESPARSE_FOUND_REQUIRED_VARS} 658 | FAIL_MESSAGE "Failed to find some/all required components of SuiteSparse.") 659 | endif (SUITESPARSE_FOUND) 660 | -------------------------------------------------------------------------------- /sample/drifted_circle.g2o: -------------------------------------------------------------------------------- 1 | VERTEX_SE2 0 49.98729508425216 -0.34751186766536984 0.008213526102867059 2 | VERTEX_SE2 1 50.07124615022407 2.958954777701467 0.0688448451012131 3 | VERTEX_SE2 2 49.68764080379982 5.975375101154801 0.13173866850989613 4 | VERTEX_SE2 3 49.43180576862195 11.227910369013843 0.17592439404685803 5 | VERTEX_SE2 4 48.77097293160463 11.733252523624909 0.22898967720993385 6 | VERTEX_SE2 5 47.668778188835994 15.307157979996948 0.32055611218722835 7 | VERTEX_SE2 6 47.14797192573042 17.957476913994654 0.3759612751094482 8 | VERTEX_SE2 7 45.601584137391455 20.838328676087315 0.4515751702670187 9 | VERTEX_SE2 8 45.2737506773949 26.385064802038368 0.5048958934115781 10 | VERTEX_SE2 9 43.655853423593314 28.18396514374539 0.5499554550169525 11 | VERTEX_SE2 10 41.04764540220912 29.127702538020174 0.6430539957843701 12 | VERTEX_SE2 11 39.277710696308226 33.00491124389505 0.7025218772821127 13 | VERTEX_SE2 12 36.986569632542505 34.464878304497596 0.7643829838789953 14 | VERTEX_SE2 13 35.17014089034383 37.2636543867336 0.8154526130875877 15 | VERTEX_SE2 14 33.41020551362904 38.93969402403609 0.8819756802882407 16 | VERTEX_SE2 15 30.964932190172107 42.111683730622154 0.946621263050814 17 | VERTEX_SE2 16 28.114914701226922 43.63343681864374 1.0210666442727465 18 | VERTEX_SE2 17 25.583522974573114 45.30121003288437 1.0523168812735337 19 | VERTEX_SE2 18 21.739670153108186 47.19199608404816 1.1300121165562895 20 | VERTEX_SE2 19 18.440158654434793 47.98583099218441 1.1842378239361266 21 | VERTEX_SE2 20 15.362873044526006 49.64575079469867 1.2664357388590184 22 | VERTEX_SE2 21 12.233175587063423 50.91709645006419 1.3272665701129351 23 | VERTEX_SE2 22 9.037708509500288 51.490303181693534 1.3768183576986943 24 | VERTEX_SE2 23 7.8348729679803215 51.77121909724414 1.445257274497025 25 | VERTEX_SE2 24 4.380514833221431 52.27012370178206 1.5031338560598537 26 | VERTEX_SE2 25 -0.5388435064072052 52.49983996756695 1.575770620577142 27 | VERTEX_SE2 26 -3.190320143044719 52.45098684567786 1.645328322456859 28 | VERTEX_SE2 27 -7.389754652189604 52.419946497514324 1.7128976993489826 29 | VERTEX_SE2 28 -8.1982173931156 51.665840450945765 1.7446173920964416 30 | VERTEX_SE2 29 -13.006331380858235 51.12717993293927 1.8010814547228722 31 | VERTEX_SE2 30 -15.895256009385703 50.8062171131363 1.8689109672996098 32 | VERTEX_SE2 31 -20.322820264453764 48.8896096182224 1.989244808406802 33 | VERTEX_SE2 32 -20.948697872476718 48.4394513145115 2.0236102606089146 34 | VERTEX_SE2 33 -25.64302338870251 47.07985109286192 2.097527869884424 35 | VERTEX_SE2 34 -28.519147041019345 45.9736313361906 2.1195708081269022 36 | VERTEX_SE2 35 -31.074738486367377 43.24043777215642 2.221275599694981 37 | VERTEX_SE2 36 -34.33411418047835 40.64833193255133 2.2461135170797317 38 | VERTEX_SE2 37 -37.06699145597901 38.6345704280628 2.3249799049989526 39 | VERTEX_SE2 38 -39.49841930860099 36.822808204155024 2.372680417382497 40 | VERTEX_SE2 39 -40.887540846427434 33.74904608334437 2.428943389471483 41 | VERTEX_SE2 40 -44.256236890321986 30.14398961159206 2.5115913103130305 42 | VERTEX_SE2 41 -45.62611588048821 29.52855241689407 2.5535868314737504 43 | VERTEX_SE2 42 -47.53553242280383 26.3725646201593 2.628093449452313 44 | VERTEX_SE2 43 -48.453037203276985 24.424094392422468 2.701165162482076 45 | VERTEX_SE2 44 -50.77617377859165 18.905896554996552 2.7682945342357965 46 | VERTEX_SE2 45 -51.55825240132836 18.417351740693334 2.830873829628538 47 | VERTEX_SE2 46 -52.70234370117479 13.048135038154317 2.896965588471066 48 | VERTEX_SE2 47 -53.74290037398103 10.669961630453773 2.924170057852226 49 | VERTEX_SE2 48 -54.36030041400626 7.440331036286062 3.011595475029585 50 | VERTEX_SE2 49 -54.85000442216017 3.5648883803465594 3.092237607568306 51 | VERTEX_SE2 50 -54.995706207673635 0.3596594632336311 3.119241444741488 52 | VERTEX_SE2 51 -55.06491357570874 -4.8917219241695085 3.1904120601284496 53 | VERTEX_SE2 52 -54.77365421516734 -8.818018933860948 3.2620406970039504 54 | VERTEX_SE2 53 -54.220156062742355 -12.064087996990045 3.326910443329639 55 | VERTEX_SE2 54 -53.96367387564894 -13.81523916052545 3.3998400897109486 56 | VERTEX_SE2 55 -53.01048523685696 -16.369836699513012 3.4435024294380336 57 | VERTEX_SE2 56 -52.088994376001686 -19.053291687468306 3.521317544252485 58 | VERTEX_SE2 57 -50.16791323014509 -22.941878901047552 3.5779343746561185 59 | VERTEX_SE2 58 -48.76412316340788 -27.41588646394899 3.6536375330722715 60 | VERTEX_SE2 59 -46.988071447414434 -29.76064364274968 3.710006963023602 61 | VERTEX_SE2 60 -45.16793674525977 -33.344959041191615 3.778364886380865 62 | VERTEX_SE2 61 -44.84269602264909 -36.728897112843924 3.826062023941249 63 | VERTEX_SE2 62 -40.78254629166248 -38.47663538521526 3.890490977283577 64 | VERTEX_SE2 63 -37.60163028231018 -41.214449186113626 3.967139348689667 65 | VERTEX_SE2 64 -36.66801679644714 -42.515135342596 4.0463485558574295 66 | VERTEX_SE2 65 -32.00024700030723 -45.9406701809562 4.092992799214865 67 | VERTEX_SE2 66 -28.919775168898312 -48.195327458109944 4.145603570448142 68 | VERTEX_SE2 67 -27.314068104672668 -49.86019770016304 4.222318791640588 69 | VERTEX_SE2 68 -25.39494185342376 -51.71229496957377 4.296907223666337 70 | VERTEX_SE2 69 -21.87259488029871 -52.236900541720516 4.352343559435541 71 | VERTEX_SE2 70 -18.168033707661337 -54.27229314421158 4.379382248897199 72 | VERTEX_SE2 71 -12.503168143407564 -55.49377919493862 4.447625796446634 73 | VERTEX_SE2 72 -9.959565808163541 -55.9753938685739 4.492600146770704 74 | VERTEX_SE2 73 -7.626328544761396 -56.930556568483766 4.581970837794327 75 | VERTEX_SE2 74 -6.0968435434496255 -57.310869757602156 4.633931635104347 76 | VERTEX_SE2 75 -0.9443640800943186 -57.49384101670345 4.729976349757393 77 | VERTEX_SE2 76 5.198989941480967 -57.52803163171627 4.79370295606659 78 | VERTEX_SE2 77 7.6775561720281775 -57.30700542745429 4.85695976536565 79 | VERTEX_SE2 78 11.99038972203175 -56.97268622982198 4.890113142496745 80 | VERTEX_SE2 79 13.241804902515042 -56.283932442982305 4.92464713643794 81 | VERTEX_SE2 80 18.882265782499537 -55.08337360098716 4.991334588806141 82 | VERTEX_SE2 81 21.654443159231867 -54.042562127021796 5.084397279542162 83 | VERTEX_SE2 82 24.201904031859 -52.44141297938038 5.1724387815720485 84 | VERTEX_SE2 83 28.16423209219658 -52.125986133835916 5.200867940178215 85 | VERTEX_SE2 84 33.26318447276302 -49.70720570394062 5.258618080258319 86 | VERTEX_SE2 85 33.20172860019519 -47.41645417145579 5.318069618612641 87 | VERTEX_SE2 86 36.89430696562502 -46.21853852756659 5.390727228759084 88 | VERTEX_SE2 87 38.30405810093761 -42.99053756571932 5.484244462048359 89 | VERTEX_SE2 88 44.282219073011575 -40.08493823116172 5.53376855895363 90 | VERTEX_SE2 89 44.64756300814931 -36.77219655537851 5.609016626676473 91 | VERTEX_SE2 90 48.367565051764004 -34.74896829330436 5.654598271060534 92 | VERTEX_SE2 91 50.510970062372515 -31.804081889418633 5.718644280683572 93 | VERTEX_SE2 92 51.96439173113677 -28.44145947158543 5.766991363239864 94 | VERTEX_SE2 93 53.25055579863139 -25.443848089141817 5.832774992702796 95 | VERTEX_SE2 94 54.783745597659035 -22.63841514607206 5.89313392430114 96 | VERTEX_SE2 95 56.6791620448279 -17.479782134778322 5.960414203423536 97 | VERTEX_SE2 96 57.64540250940932 -12.70553495918134 6.001862213109291 98 | VERTEX_SE2 97 58.48396469466767 -12.04567658492249 6.0942524621304885 99 | VERTEX_SE2 98 59.60044397069822 -7.15085954111562 6.156957560685211 100 | VERTEX_SE2 99 59.82583307540092 -3.4170291408539897 6.210111721982427 101 | EDGE_SE2 0 1 0.2533654802394525 3.1258230042946087 0.05477086813764118 1.0 0 0 1.0 0 1.0 102 | EDGE_SE2 1 2 0.21211050041914656 3.1410028904851357 0.07537787987976943 1.0 0 0 1.0 0 1.0 103 | EDGE_SE2 2 3 0.16940471040974414 3.1376974812346208 0.04987413617537464 1.0 0 0 1.0 0 1.0 104 | EDGE_SE2 3 4 0.19559311849573302 3.136531082556102 0.03583378336114229 1.0 0 0 1.0 0 1.0 105 | EDGE_SE2 4 5 0.13054376392760386 3.1326397348965886 0.0570774427055871 1.0 0 0 1.0 0 1.0 106 | EDGE_SE2 5 6 0.21889840382851208 3.1305675125034806 0.0732909254685693 1.0 0 0 1.0 0 1.0 107 | EDGE_SE2 6 7 0.2834118921178917 3.12950481496896 0.05750474212830238 1.0 0 0 1.0 0 1.0 108 | EDGE_SE2 7 8 0.2659614612289913 3.1346576248491216 0.025188753034307926 1.0 0 0 1.0 0 1.0 109 | EDGE_SE2 8 9 0.19912783902052633 3.1361486737903888 0.08788771778302396 1.0 0 0 1.0 0 1.0 110 | EDGE_SE2 9 10 0.18076190155489086 3.1346557317336816 0.05676491586377862 1.0 0 0 1.0 0 1.0 111 | EDGE_SE2 10 11 0.1874674118445149 3.136580572303911 0.07606683037288119 1.0 0 0 1.0 0 1.0 112 | EDGE_SE2 11 12 0.18107879417194586 3.138228294494778 0.06397279048530155 1.0 0 0 1.0 0 1.0 113 | EDGE_SE2 12 13 0.21140237783009186 3.1383152526373417 0.06798781303821017 1.0 0 0 1.0 0 1.0 114 | EDGE_SE2 13 14 0.1680455829527728 3.130198784056502 0.0454821487799686 1.0 0 0 1.0 0 1.0 115 | EDGE_SE2 14 15 0.2640588369614791 3.1272422001460676 0.03745861547943073 1.0 0 0 1.0 0 1.0 116 | EDGE_SE2 15 16 0.28426538558983316 3.139364156315956 0.04945258003554234 1.0 0 0 1.0 0 1.0 117 | EDGE_SE2 16 17 0.20383702079530208 3.137398945147838 0.07445459887355871 1.0 0 0 1.0 0 1.0 118 | EDGE_SE2 17 18 0.21390508172571723 3.1268347720277223 0.0744228333749698 1.0 0 0 1.0 0 1.0 119 | EDGE_SE2 18 19 0.16725054618937504 3.1336718465753037 0.05680448846726291 1.0 0 0 1.0 0 1.0 120 | EDGE_SE2 19 20 0.1702295955237566 3.1380212183651937 0.04601191062515825 1.0 0 0 1.0 0 1.0 121 | EDGE_SE2 20 21 0.2175781161947345 3.138249062403272 0.06151472883884203 1.0 0 0 1.0 0 1.0 122 | EDGE_SE2 21 22 0.17597266651716592 3.141077098190153 0.025969038123861928 1.0 0 0 1.0 0 1.0 123 | EDGE_SE2 22 23 0.2287913616580595 3.1379204567432266 0.0652549116112142 1.0 0 0 1.0 0 1.0 124 | EDGE_SE2 23 24 0.24792639569879452 3.1396439355611365 0.06724811421928473 1.0 0 0 1.0 0 1.0 125 | EDGE_SE2 24 25 0.19321206798607687 3.1254406829058405 0.06690454785212381 1.0 0 0 1.0 0 1.0 126 | EDGE_SE2 25 26 0.23535127073262824 3.1322925680593254 0.05787172702260407 1.0 0 0 1.0 0 1.0 127 | EDGE_SE2 26 27 0.1436359618926592 3.13479862153205 0.054071781936998395 1.0 0 0 1.0 0 1.0 128 | EDGE_SE2 27 28 0.2032975276589874 3.13448664026563 0.023909017051359727 1.0 0 0 1.0 0 1.0 129 | EDGE_SE2 28 29 0.1639901062454464 3.1277968970507826 0.0760460794502178 1.0 0 0 1.0 0 1.0 130 | EDGE_SE2 29 30 0.17445284757306692 3.138828846273472 0.05993391467246157 1.0 0 0 1.0 0 1.0 131 | EDGE_SE2 30 31 0.1914590426222688 3.131776049276394 0.06390661739119116 1.0 0 0 1.0 0 1.0 132 | EDGE_SE2 31 32 0.16424942801742948 3.1361971360769916 0.054559364502336755 1.0 0 0 1.0 0 1.0 133 | EDGE_SE2 32 33 0.31133093798234956 3.1371687533434116 0.05086275319101854 1.0 0 0 1.0 0 1.0 134 | EDGE_SE2 33 34 0.20284634988535555 3.134563400368695 0.05681284715891464 1.0 0 0 1.0 0 1.0 135 | EDGE_SE2 34 35 0.11637350401188759 3.1356726855649426 0.07832079247685031 1.0 0 0 1.0 0 1.0 136 | EDGE_SE2 35 36 0.15654074616333957 3.1349964168414615 0.06695404144829373 1.0 0 0 1.0 0 1.0 137 | EDGE_SE2 36 37 0.18130278838822644 3.134022970795696 0.07861115234934041 1.0 0 0 1.0 0 1.0 138 | EDGE_SE2 37 38 0.19330072998566672 3.137892587223238 0.0802071443812235 1.0 0 0 1.0 0 1.0 139 | EDGE_SE2 38 39 0.17607915778298927 3.136381101859138 0.07129457663704263 1.0 0 0 1.0 0 1.0 140 | EDGE_SE2 39 40 0.24273727909566262 3.1307225310916436 0.05510125202022741 1.0 0 0 1.0 0 1.0 141 | EDGE_SE2 40 41 0.23831476459171833 3.129693972062866 0.0823431573964449 1.0 0 0 1.0 0 1.0 142 | EDGE_SE2 41 42 0.1378881824288387 3.1374204291390853 0.06333748737760342 1.0 0 0 1.0 0 1.0 143 | EDGE_SE2 42 43 0.16878349989047617 3.133794670813047 0.07892274468309418 1.0 0 0 1.0 0 1.0 144 | EDGE_SE2 43 44 0.11507989849526784 3.1377054443841024 0.060221621409038584 1.0 0 0 1.0 0 1.0 145 | EDGE_SE2 44 45 0.1377911799211583 3.138888245710287 0.08878021314716478 1.0 0 0 1.0 0 1.0 146 | EDGE_SE2 45 46 0.20112159885235906 3.137140175723759 0.03388644224237709 1.0 0 0 1.0 0 1.0 147 | EDGE_SE2 46 47 0.159211917853197 3.1386838285833467 0.07264971796199352 1.0 0 0 1.0 0 1.0 148 | EDGE_SE2 47 48 0.11892551627076067 3.135712894404206 0.040784477009154496 1.0 0 0 1.0 0 1.0 149 | EDGE_SE2 48 49 0.2324252347967436 3.1358589835421307 0.044628085284386186 1.0 0 0 1.0 0 1.0 150 | EDGE_SE2 49 50 0.1755870566650283 3.1334084905229256 0.05212202079031153 1.0 0 0 1.0 0 1.0 151 | EDGE_SE2 50 51 0.17360535038595296 3.134194983393382 0.05916876929377862 1.0 0 0 1.0 0 1.0 152 | EDGE_SE2 51 52 0.21693413532186942 3.137508938771395 0.029079009764466243 1.0 0 0 1.0 0 1.0 153 | EDGE_SE2 52 53 0.3126092932504096 3.137926699339732 0.07318907238148807 1.0 0 0 1.0 0 1.0 154 | EDGE_SE2 53 54 0.18641947080969404 3.137801869675026 0.05452889519585046 1.0 0 0 1.0 0 1.0 155 | EDGE_SE2 54 55 0.1872772069020562 3.1302907646472846 0.0641201887188669 1.0 0 0 1.0 0 1.0 156 | EDGE_SE2 55 56 0.1855716600082799 3.1295078104157383 0.07773707876000178 1.0 0 0 1.0 0 1.0 157 | EDGE_SE2 56 57 0.1840591929290657 3.1362857601708343 0.020836171925651868 1.0 0 0 1.0 0 1.0 158 | EDGE_SE2 57 58 0.1796657753139188 3.134962144749277 0.08304381569637487 1.0 0 0 1.0 0 1.0 159 | EDGE_SE2 58 59 0.12382600899994954 3.138490291393196 0.06007132559055279 1.0 0 0 1.0 0 1.0 160 | EDGE_SE2 59 60 0.22281731812233857 3.140191044256806 0.07853900047672777 1.0 0 0 1.0 0 1.0 161 | EDGE_SE2 60 61 0.09210021951579811 3.1306880272818405 0.07460694116515007 1.0 0 0 1.0 0 1.0 162 | EDGE_SE2 61 62 0.2211895971600212 3.1324439787340115 0.060508129856288846 1.0 0 0 1.0 0 1.0 163 | EDGE_SE2 62 63 0.19360981027166485 3.136281287665512 0.05587963336235308 1.0 0 0 1.0 0 1.0 164 | EDGE_SE2 63 64 0.20028047817168643 3.1385941724662882 0.07021607802269639 1.0 0 0 1.0 0 1.0 165 | EDGE_SE2 64 65 0.10050861688599814 3.13530199595035 0.09092702169815373 1.0 0 0 1.0 0 1.0 166 | EDGE_SE2 65 66 0.2597887441762077 3.13589533012746 0.07685561205695406 1.0 0 0 1.0 0 1.0 167 | EDGE_SE2 66 67 0.22042294549005267 3.1386244668962204 0.05466469863227044 1.0 0 0 1.0 0 1.0 168 | EDGE_SE2 67 68 0.2457704105402786 3.1404921357008915 0.05213813693614489 1.0 0 0 1.0 0 1.0 169 | EDGE_SE2 68 69 0.17021433373991893 3.1369011157198763 0.054649421754094325 1.0 0 0 1.0 0 1.0 170 | EDGE_SE2 69 70 0.20743691471273656 3.1369592346577715 0.04948308978703325 1.0 0 0 1.0 0 1.0 171 | EDGE_SE2 70 71 0.12152804594280753 3.134676012260026 0.026197602338376078 1.0 0 0 1.0 0 1.0 172 | EDGE_SE2 71 72 0.2472622884302708 3.1337250127059857 0.07648835785160989 1.0 0 0 1.0 0 1.0 173 | EDGE_SE2 72 73 0.1552511417728305 3.131985483460907 0.06761985468703421 1.0 0 0 1.0 0 1.0 174 | EDGE_SE2 73 74 0.21143070084456966 3.13943808590413 0.057207605562713815 1.0 0 0 1.0 0 1.0 175 | EDGE_SE2 74 75 0.15211285440225172 3.13015363158262 0.08913185444521529 1.0 0 0 1.0 0 1.0 176 | EDGE_SE2 75 76 0.18870498843039954 3.1390463898783194 0.07360814581417442 1.0 0 0 1.0 0 1.0 177 | EDGE_SE2 76 77 0.2919414403838344 3.134567828403214 0.06063796436577557 1.0 0 0 1.0 0 1.0 178 | EDGE_SE2 77 78 0.1378685487661468 3.1389094513314455 0.08698673116932233 1.0 0 0 1.0 0 1.0 179 | EDGE_SE2 78 79 0.09420179760869629 3.1381785366549853 0.10906343449235062 1.0 0 0 1.0 0 1.0 180 | EDGE_SE2 79 80 0.14194420408706743 3.1394039260639035 0.07721000448837037 1.0 0 0 1.0 0 1.0 181 | EDGE_SE2 80 81 0.16260831394436548 3.1407621603041607 0.08556286083630558 1.0 0 0 1.0 0 1.0 182 | EDGE_SE2 81 82 0.240830527430482 3.1340773738495598 0.06617949017016904 1.0 0 0 1.0 0 1.0 183 | EDGE_SE2 82 83 0.23054624399468238 3.13876368402496 0.09458872979849625 1.0 0 0 1.0 0 1.0 184 | EDGE_SE2 83 84 0.1976098444639304 3.1313158347581487 0.0524683123231257 1.0 0 0 1.0 0 1.0 185 | EDGE_SE2 84 85 0.13358387048126066 3.137341466425239 0.058997882917596896 1.0 0 0 1.0 0 1.0 186 | EDGE_SE2 85 86 0.23190596239425207 3.139223459371972 0.06555186209860814 1.0 0 0 1.0 0 1.0 187 | EDGE_SE2 86 87 0.08296793532968047 3.1353967216595207 0.06644392813169529 1.0 0 0 1.0 0 1.0 188 | EDGE_SE2 87 88 0.16691956553632498 3.1296956998925234 0.0756551649965553 1.0 0 0 1.0 0 1.0 189 | EDGE_SE2 88 89 0.2654285902186303 3.1380644749984246 0.02323048952231102 1.0 0 0 1.0 0 1.0 190 | EDGE_SE2 89 90 0.26498046271672143 3.1325372226586636 0.071777148097296 1.0 0 0 1.0 0 1.0 191 | EDGE_SE2 90 91 0.21027256630730323 3.1325883531310925 0.06681478061811535 1.0 0 0 1.0 0 1.0 192 | EDGE_SE2 91 92 0.17571955207808343 3.139453588034856 0.041607667990114144 1.0 0 0 1.0 0 1.0 193 | EDGE_SE2 92 93 0.21746770958224076 3.136837208955735 0.038584279379408865 1.0 0 0 1.0 0 1.0 194 | EDGE_SE2 93 94 0.2454361036752024 3.1289405560183923 0.03917782277490611 1.0 0 0 1.0 0 1.0 195 | EDGE_SE2 94 95 0.12301263558231978 3.136774423878195 0.06872011740349353 1.0 0 0 1.0 0 1.0 196 | EDGE_SE2 95 96 0.23128949150385564 3.1347981812112304 0.058220008750225066 1.0 0 0 1.0 0 1.0 197 | EDGE_SE2 96 97 0.23029647221120786 3.139091756730795 0.04910169276504994 1.0 0 0 1.0 0 1.0 198 | EDGE_SE2 97 98 0.20562012374398708 3.1334407791562233 0.0639916042027847 1.0 0 0 1.0 0 1.0 199 | EDGE_SE2 98 99 0.17995166015374328 3.137847407400361 0.07371767377851446 1.0 0 0 1.0 0 1.0 200 | EDGE_SE2 99 0 0.1999546665872812 3.129985331075849 0.05367176944977552 1.0 0 0 1.0 0 1.0 201 | -------------------------------------------------------------------------------- /script/create_sample.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import csv 5 | import math 6 | import numpy as np 7 | import argparse 8 | 9 | parser = argparse.ArgumentParser() 10 | parser.add_argument("--radius", type=float, default=50.0, 11 | help="radius of the circle") 12 | parser.add_argument("--nodes", type=int, default=100, 13 | help="the number of nodes") 14 | parser.add_argument("--drift", type=float, default=0.2, 15 | help="the coefficient of drift error") 16 | args = parser.parse_args() 17 | 18 | radius = args.radius 19 | num_nodes = args.nodes 20 | drift_coeff = args.drift 21 | 22 | vertices = [] 23 | delta_theta = 2 * math.pi / num_nodes 24 | delta_length = 2 * math.pi * radius / num_nodes 25 | 26 | for i in xrange(num_nodes): 27 | x = (radius + radius * i * drift_coeff / num_nodes) * math.cos(delta_theta * i + np.random.normal(0, 0)) 28 | y = (radius + radius * i * drift_coeff / num_nodes) * math.sin(delta_theta * i + np.random.normal(0, 0)) 29 | theta = delta_theta * i + np.random.normal(0, 0) 30 | vertices.append(["VERTEX_SE2", i, x, y, theta]) 31 | 32 | constraint = [] 33 | 34 | for i in xrange(num_nodes - 1): 35 | (_, i_a, x_a, y_a, theta_a) = vertices[i] 36 | (_, i_b, x_b, y_b, theta_b) = vertices[i + 1] 37 | constraint.append(["EDGE_SE2", i_a, i_b, 38 | delta_length * math.sin(delta_theta + np.random.normal(0, math.pi / 180.0)), 39 | delta_length * math.cos(delta_theta + np.random.normal(0, math.pi / 180.0)), 40 | delta_theta + np.random.normal(0, math.pi / 180.0), 41 | 1.0, 0, 0, 1.0, 0, 1.0]) 42 | 43 | constraint.append(["EDGE_SE2", num_nodes - 1, 0, 44 | delta_length * math.sin(delta_theta + np.random.normal(0, math.pi / 180.0)), 45 | delta_length * math.cos(delta_theta + np.random.normal(0, math.pi / 180.0)), 46 | delta_theta + np.random.normal(0, math.pi / 180.0), 47 | 1.0, 0, 0, 1.0, 0, 1.0]) 48 | 49 | with open("drifted_circle.g2o", "w") as fout: 50 | writer = csv.writer(fout, delimiter=" ", lineterminator="\n") 51 | writer.writerows(vertices) 52 | 53 | with open("drifted_circle.g2o", "a") as fout: 54 | writer = csv.writer(fout, delimiter=" ", lineterminator="\n") 55 | writer.writerows(constraint) 56 | -------------------------------------------------------------------------------- /script/plot_results.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import numpy 5 | import argparse 6 | import matplotlib.pyplot as plot 7 | 8 | 9 | parser = argparse.ArgumentParser() 10 | parser.add_argument(dest="initial_poses", default="", 11 | help="The filename that contains the original poses") 12 | parser.add_argument(dest="optimized_poses", default="", 13 | help="The filename that contains the optimized poses") 14 | args = parser.parse_args() 15 | 16 | poses_original = None 17 | if args.initial_poses != '': 18 | poses_original = numpy.genfromtxt(args.initial_poses, delimiter=",", usecols = (1, 2)) 19 | 20 | poses_optimized = None 21 | if args.optimized_poses != '': 22 | poses_optimized = numpy.genfromtxt(args.optimized_poses, delimiter=",", usecols = (1, 2)) 23 | 24 | plot.figure() 25 | if poses_original is not None: 26 | plot.plot(poses_original[:, 0], poses_original[:, 1], '-', label="Original", alpha=0.5, color="green") 27 | 28 | if poses_optimized is not None: 29 | plot.plot(poses_optimized[:, 0], poses_optimized[:, 1], '-', label="Optimized", alpha=0.5, color="blue") 30 | 31 | plot.axis('equal') 32 | plot.legend() 33 | plot.show() 34 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(se2) 2 | -------------------------------------------------------------------------------- /src/se2/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB_RECURSE SOURCES ./*.cc) 2 | file(GLOB_RECURSE HEADERS ./*.h) 3 | 4 | add_executable(se2_optimize 5 | ${SOURCES} 6 | ${HEADERS}) 7 | target_link_libraries(se2_optimize 8 | ${CERES_LIBRARIES} 9 | ${LAPACK_LIBRARIES} 10 | ${CXSPARSE_LIBRARIES} 11 | ${SUITESPARSE_LIBRARIES} 12 | ${GFLAGS_LIBRARY} 13 | ) 14 | -------------------------------------------------------------------------------- /src/se2/error_function.h: -------------------------------------------------------------------------------- 1 | #ifndef SE2_ERROR_FUNCTION_H 2 | #define SE2_ERROR_FUNCTION_H 3 | 4 | #include "types.h" 5 | 6 | namespace se2 { 7 | 8 | // 誤差関数(残差関数)の関数オブジェクト 9 | class error_function { 10 | public: 11 | error_function(const double x_ab, const double y_ab, const double theta_ab, 12 | std::array decomposed_information) 13 | : x_ab_(x_ab), y_ab_(y_ab), theta_ab_(theta_ab), 14 | decomposed_information_(std::move(decomposed_information)) {} 15 | 16 | template 17 | bool operator()(const T* const x_a, const T* const y_a, const T* const theta_a, 18 | const T* const x_b, const T* const y_b, const T* const theta_b, 19 | T* residuals_ptr) const { 20 | T residual_x = ceres::cos(*theta_a) * (*x_b - *x_a) + ceres::sin(*theta_a) * (*y_b - *y_a) - static_cast(x_ab_); 21 | T residual_y = -ceres::sin(*theta_a) * (*x_b - *x_a) + ceres::cos(*theta_a) * (*y_b - *y_a) - static_cast(y_ab_); 22 | T residual_theta = normalize_angle((*theta_b - *theta_a) - static_cast(theta_ab_)); 23 | 24 | residuals_ptr[0] = residual_x * static_cast(decomposed_information_.at(0)); 25 | residuals_ptr[1] = residual_y * static_cast(decomposed_information_.at(1)); 26 | residuals_ptr[2] = residual_theta * static_cast(decomposed_information_.at(2)); 27 | 28 | return true; 29 | } 30 | 31 | private: 32 | const double x_ab_; 33 | const double y_ab_; 34 | const double theta_ab_; 35 | const std::array decomposed_information_; 36 | }; 37 | 38 | } // namespace se2 39 | 40 | #endif // SE2_ERROR_FUNCTION_H 41 | -------------------------------------------------------------------------------- /src/se2/normalize_angle.h: -------------------------------------------------------------------------------- 1 | #ifndef SE2_NORMALIZE_ANGLE_H 2 | #define SE2_NORMALIZE_ANGLE_H 3 | 4 | #include 5 | 6 | #include "ceres/ceres.h" 7 | 8 | namespace se2 { 9 | 10 | template 11 | inline T normalize_angle(const T& angle_radians) { 12 | T two_pi(2.0 * M_PI); 13 | return angle_radians - two_pi * ceres::floor((angle_radians + T(M_PI)) / two_pi); 14 | } 15 | 16 | } // namespace se2 17 | 18 | #endif // SE2_NORMALIZE_ANGLE_H -------------------------------------------------------------------------------- /src/se2/optimize.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #include "problem.h" 7 | #include "read_g2o.h" 8 | 9 | DEFINE_string(filename, "", ".g2o file name to read"); 10 | 11 | int main(int argc, char* argv[]) { 12 | google::ParseCommandLineFlags(&argc, &argv, true); 13 | 14 | if (FLAGS_filename.empty()) { 15 | std::cerr << "Error: Use --filename flag to give a file name" << std::endl; 16 | return EXIT_FAILURE; 17 | } 18 | 19 | se2::poses_t poses; 20 | se2::constraints_t constraints; 21 | 22 | se2::read_g2o_file(FLAGS_filename, poses, constraints); 23 | 24 | std::cout << "Number of poses: " << poses.size() << std::endl; 25 | std::cout << "Number of constraints: " << constraints.size() << std::endl; 26 | 27 | se2::output_poses("poses_original.txt", poses); 28 | 29 | ceres::Problem problem; 30 | se2::build_problem(constraints, poses, problem); 31 | 32 | se2::solve_problem(problem); 33 | 34 | se2::output_poses("poses_optimized.txt", poses); 35 | 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /src/se2/problem.h: -------------------------------------------------------------------------------- 1 | #ifndef SE2_PROBLEM_H 2 | #define SE2_PROBLEM_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | #include "types.h" 12 | #include "error_function.h" 13 | 14 | namespace se2 { 15 | 16 | void build_problem(const constraints_t& constraints, poses_t& poses, ceres::Problem& problem) { 17 | ceres::LossFunction* loss_function = nullptr; 18 | 19 | for (const auto& constraint: constraints) { 20 | auto pose_start_itr = poses.find(constraint.id_start); 21 | if (pose_start_itr == poses.end()) { 22 | std::cerr << "Pose ID: " << constraint.id_start << " not found." << std::endl; 23 | continue; 24 | } 25 | auto pose_end_itr = poses.find(constraint.id_end); 26 | if (pose_end_itr == poses.end()) { 27 | std::cerr << "Pose ID: " << constraint.id_end << " not found." << std::endl; 28 | continue; 29 | } 30 | 31 | // 情報行列をコレスキー分解してマハラノビス距離の計算に用いる 32 | // (対角行列を想定しているので,情報行列の対角成分の平方根を格納する) 33 | // (マハラノビス距離の定義を参照) 34 | std::array decomposed_information; 35 | for (unsigned int i = 0; i < 3; ++i) { 36 | decomposed_information.at(i) = sqrt(constraint.information.at(i)); 37 | } 38 | 39 | // AutoDiffCostFunctionでコスト関数とヤコビアンを構築 40 | // テンプレート引数 41 | // 残差パラメータ: 3個 42 | // 第1引数: 1個 (絶対位置A x) 43 | // 第2引数: 1個 (絶対位置A y) 44 | // 第3引数: 1個 (絶対位置A theta) 45 | // 第4引数: 1個 (絶対位置B x) 46 | // 第5引数: 1個 (絶対位置B y) 47 | // 第6引数: 1個 (絶対位置B theta) 48 | // 49 | // 相対姿勢[x, y, theta]とコレスキー分解した情報行列の対角成分decomposed_informationを設定する 50 | // (相対姿勢は局所的には信頼できるものとする) 51 | ceres::CostFunction* cost_function = 52 | new ceres::AutoDiffCostFunction( 53 | new error_function(constraint.x, constraint.y, constraint.theta, decomposed_information)); 54 | 55 | // 残差項を設定 56 | // cost_function構築時に入れた相対姿勢に対して,その相対姿勢の両端のノードの絶対姿勢を入れて絶対姿勢の誤差を計算させる 57 | problem.AddResidualBlock(cost_function, loss_function, 58 | &(pose_start_itr->second.x), 59 | &(pose_start_itr->second.y), 60 | &(pose_start_itr->second.theta), 61 | &(pose_end_itr->second.x), 62 | &(pose_end_itr->second.y), 63 | &(pose_end_itr->second.theta)); 64 | } 65 | 66 | auto pose_start_itr = poses.begin(); 67 | if (pose_start_itr == poses.end()) { 68 | std::cerr << "There are no poses" << std::endl; 69 | exit(EXIT_FAILURE); 70 | } 71 | 72 | // 経路の始点を最適化時に定数とする 73 | problem.SetParameterBlockConstant(&(pose_start_itr->second.x)); 74 | problem.SetParameterBlockConstant(&(pose_start_itr->second.y)); 75 | problem.SetParameterBlockConstant(&(pose_start_itr->second.theta)); 76 | } 77 | 78 | bool solve_problem(ceres::Problem& problem) { 79 | ceres::Solver::Options options; 80 | options.max_num_iterations = 100; 81 | options.linear_solver_type = ceres::SPARSE_NORMAL_CHOLESKY; 82 | 83 | ceres::Solver::Summary summary; 84 | ceres::Solve(options, &problem, &summary); 85 | 86 | std::cout << summary.FullReport() << std::endl; 87 | 88 | return summary.IsSolutionUsable(); 89 | } 90 | 91 | void output_poses(const std::string& filename, const poses_t& poses) { 92 | std::fstream outfile; 93 | outfile.open(filename.c_str(), std::istream::out); 94 | if (!outfile) { 95 | std::cerr << "Couldn't open a file: " << filename << std::endl; 96 | exit(EXIT_FAILURE); 97 | } 98 | for (const auto& pair : poses) { 99 | outfile << pair.first << "," 100 | << pair.second.x << "," 101 | << pair.second.y << "," 102 | << pair.second.theta << std::endl; 103 | } 104 | } 105 | 106 | } // namespace se2 107 | 108 | #endif // SE2_PROBLEM_H 109 | -------------------------------------------------------------------------------- /src/se2/read_g2o.h: -------------------------------------------------------------------------------- 1 | #ifndef SE2_READ_G2O_H 2 | #define SE2_READ_G2O_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "types.h" 9 | 10 | namespace se2 { 11 | 12 | void read_vertex(std::ifstream& infile, poses_t& poses) { 13 | int id; 14 | pose_2d pose; 15 | infile >> id >> pose; 16 | 17 | if (poses.count(id) != 0) { 18 | std::cout << "Duplicate vertex with ID: " << id << std::endl; 19 | exit(EXIT_FAILURE); 20 | } 21 | 22 | poses[id] = pose; 23 | } 24 | 25 | void read_constraint(std::ifstream& infile, constraints_t& constraints) { 26 | constraint_3d constraint; 27 | infile >> constraint; 28 | 29 | constraints.push_back(constraint); 30 | } 31 | 32 | void read_g2o_file(const std::string& filename, poses_t& poses, constraints_t& constraints) { 33 | poses.clear(); 34 | constraints.clear(); 35 | 36 | std::ifstream infile(filename.c_str()); 37 | if (!infile) { 38 | std::cerr << "Invalid file name: " << filename << std::endl; 39 | exit(EXIT_FAILURE); 40 | } 41 | 42 | while (infile.good()) { 43 | std::string data_type; 44 | infile >> data_type; 45 | if (data_type == "VERTEX_SE2") { 46 | read_vertex(infile, poses); 47 | } 48 | else if (data_type == "EDGE_SE2") { 49 | read_constraint(infile, constraints); 50 | } 51 | else { 52 | std::cout << "Unknown data type: " << data_type << std::endl; 53 | exit(EXIT_FAILURE); 54 | } 55 | infile >> std::ws; 56 | } 57 | } 58 | 59 | } // namespace se2 60 | 61 | #endif // SE2_READ_G2O_H 62 | -------------------------------------------------------------------------------- /src/se2/types.h: -------------------------------------------------------------------------------- 1 | #ifndef SE2_TYPES_H 2 | #define SE2_TYPES_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #include "normalize_angle.h" 14 | 15 | namespace se2 { 16 | 17 | // 2次元空間中の姿勢を扱う構造体 18 | struct pose_2d { 19 | public: 20 | // 絶対位置 [x, y] 21 | double x; 22 | double y; 23 | // 絶対ヨー回転 (rad) 24 | double theta; 25 | }; 26 | 27 | // g2o形式のファイルからの入力に使うオーバーライド関数 28 | std::istream& operator>>(std::istream& input, pose_2d& pose) { 29 | input >> pose.x >> pose.y >> pose.theta; 30 | // 角度の正規化 31 | pose.theta = normalize_angle(pose.theta); 32 | return input; 33 | } 34 | 35 | // 3次元空間中の姿勢のデータベース (IDの昇順に並べる) 36 | typedef std::map> poses_t; 37 | 38 | // グラフの2頂点間の拘束条件(相対姿勢)を扱う構造体 39 | // 頂点id_startから頂点id_endへの相対姿勢を格納する 40 | struct constraint_3d { 41 | public: 42 | // 相対姿勢の基準となる頂点のID 43 | int id_start; 44 | // 相対姿勢の終点となる頂点のID 45 | int id_end; 46 | 47 | // 頂点id_startから頂点id_endへの相対姿勢 48 | // (頂点id_endを基準としたベクトルを頂点id_start基準に変換する) 49 | // 相対位置 [x, y] 50 | double x; 51 | double y; 52 | // 相対ヨー回転 (rad) 53 | double theta; 54 | 55 | // 情報行列(ガウス誤差を仮定している場合は,相対姿勢の分散共分散行列の逆行列) 56 | // 簡単化のため対角成分のみを格納する 57 | // 格納順は[x, y, theta] 58 | std::array information; 59 | }; 60 | 61 | // g2o形式のファイルからの入力に使うオーバーライド関数 62 | std::istream& operator>>(std::istream& input, constraint_3d& constraint) { 63 | input >> constraint.id_start >> constraint.id_end >> constraint.x >> constraint.y >> constraint.theta; 64 | // 角度の正規化 65 | constraint.theta = normalize_angle(constraint.theta); 66 | // 情報行列の入力 67 | for (int i = 0; i < 3 && input.good(); ++i) { 68 | for (int j = i; j < 3 && input.good(); ++j) { 69 | double information_i_j; 70 | input >> information_i_j; 71 | // 対角成分のみ格納する 72 | if (i == j) { 73 | constraint.information.at(static_cast(i)) = information_i_j; 74 | } 75 | } 76 | } 77 | return input; 78 | } 79 | 80 | // 拘束条件のデータベース 81 | typedef std::vector constraints_t; 82 | 83 | } // namespace se2 84 | 85 | #endif // SE2_TYPES_H 86 | --------------------------------------------------------------------------------