Skip to content

Commit 173461f

Browse files
committed
use system fmt, spdlog and metis.
1 parent ca54a30 commit 173461f

17 files changed

Lines changed: 194 additions & 86 deletions

CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ cmake_minimum_required(VERSION 3.19...4.0)
99

1010
project(symforce)
1111

12-
set(CMAKE_CXX_STANDARD 17)
12+
set(CMAKE_CXX_STANDARD 20)
1313
set(CMAKE_CXX_STANDARD_REQUIRED ON)
14+
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
1415

1516
# ==============================================================================
1617
# User-Configurable Options

cmake/FindMETIS.cmake

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
#
2+
# Copyright (c) 2022 Sergiu Deitsch
3+
#
4+
# Permission is hereby granted, free of charge, to any person obtaining a copy
5+
# of this software and associated documentation files (the "Software"), to deal
6+
# in the Software without restriction, including without limitation the rights
7+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
# copies of the Software, and to permit persons to whom the Software is
9+
# furnished to do so, subject to the following conditions:
10+
#
11+
# The above copyright notice and this permission notice shall be included in all
12+
# copies or substantial portions of the Software.
13+
#
14+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
# FITNESS FOR A PARTMETISLAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20+
# SOFTWARE.
21+
#
22+
#[=======================================================================[.rst:
23+
Module for locating METIS
24+
=========================
25+
26+
Read-only variables:
27+
28+
``METIS_FOUND``
29+
Indicates whether the library has been found.
30+
31+
``METIS_VERSION``
32+
Indicates library version.
33+
34+
Targets
35+
-------
36+
37+
``METIS::METIS``
38+
Specifies targets that should be passed to target_link_libararies.
39+
]=======================================================================]
40+
41+
include (FindPackageHandleStandardArgs)
42+
43+
find_path (METIS_INCLUDE_DIR NAMES metis.h
44+
PATH_SUFFIXES include
45+
DOC "METIS include directory")
46+
find_library (METIS_LIBRARY_DEBUG NAMES metis
47+
PATH_SUFFIXES Debug
48+
DOC "METIS debug library")
49+
find_library (METIS_LIBRARY_RELEASE NAMES metis
50+
PATH_SUFFIXES Release
51+
DOC "METIS release library")
52+
53+
if (METIS_LIBRARY_RELEASE)
54+
if (METIS_LIBRARY_DEBUG)
55+
set (METIS_LIBRARY debug ${METIS_LIBRARY_DEBUG} optimized
56+
${METIS_LIBRARY_RELEASE} CACHE STRING "METIS library")
57+
else (METIS_LIBRARY_DEBUG)
58+
set (METIS_LIBRARY ${METIS_LIBRARY_RELEASE} CACHE FILEPATH "METIS library")
59+
endif (METIS_LIBRARY_DEBUG)
60+
elseif (METIS_LIBRARY_DEBUG)
61+
set (METIS_LIBRARY ${METIS_LIBRARY_DEBUG} CACHE FILEPATH "METIS library")
62+
endif (METIS_LIBRARY_RELEASE)
63+
64+
set (_METIS_VERSION_HEADER ${METIS_INCLUDE_DIR}/metis.h)
65+
66+
if (EXISTS ${_METIS_VERSION_HEADER})
67+
file (READ ${_METIS_VERSION_HEADER} _METIS_VERSION_CONTENTS)
68+
69+
string (REGEX REPLACE ".*#define METIS_VER_MAJOR[ \t]+([0-9]+).*" "\\1"
70+
METIS_VERSION_MAJOR "${_METIS_VERSION_CONTENTS}")
71+
string (REGEX REPLACE ".*#define METIS_VER_MINOR[ \t]+([0-9]+).*" "\\1"
72+
METIS_VERSION_MINOR "${_METIS_VERSION_CONTENTS}")
73+
string (REGEX REPLACE ".*#define METIS_VER_SUBMINOR[ \t]+([0-9]+).*" "\\1"
74+
METIS_VERSION_PATCH "${_METIS_VERSION_CONTENTS}")
75+
76+
set (METIS_VERSION
77+
${METIS_VERSION_MAJOR}.${METIS_VERSION_MINOR}.${METIS_VERSION_PATCH})
78+
set (METIS_VERSION_COMPONENTS 3)
79+
endif (EXISTS ${_METIS_VERSION_HEADER})
80+
81+
mark_as_advanced (METIS_INCLUDE_DIR METIS_LIBRARY_DEBUG METIS_LIBRARY_RELEASE
82+
METIS_LIBRARY)
83+
84+
if (NOT TARGET METIS::METIS)
85+
if (METIS_INCLUDE_DIR OR METIS_LIBRARY)
86+
add_library (METIS::METIS IMPORTED UNKNOWN)
87+
endif (METIS_INCLUDE_DIR OR METIS_LIBRARY)
88+
endif (NOT TARGET METIS::METIS)
89+
90+
if (METIS_INCLUDE_DIR)
91+
set_property (TARGET METIS::METIS PROPERTY INTERFACE_INCLUDE_DIRECTORIES
92+
${METIS_INCLUDE_DIR})
93+
endif (METIS_INCLUDE_DIR)
94+
95+
if (METIS_LIBRARY_RELEASE)
96+
set_property (TARGET METIS::METIS PROPERTY IMPORTED_LOCATION_RELEASE
97+
${METIS_LIBRARY_RELEASE})
98+
set_property (TARGET METIS::METIS APPEND PROPERTY IMPORTED_CONFIGURATIONS
99+
RELEASE)
100+
endif (METIS_LIBRARY_RELEASE)
101+
102+
if (METIS_LIBRARY_DEBUG)
103+
set_property (TARGET METIS::METIS PROPERTY IMPORTED_LOCATION_DEBUG
104+
${METIS_LIBRARY_DEBUG})
105+
set_property (TARGET METIS::METIS APPEND PROPERTY IMPORTED_CONFIGURATIONS
106+
DEBUG)
107+
endif (METIS_LIBRARY_DEBUG)
108+
109+
find_package_handle_standard_args (METIS REQUIRED_VARS
110+
METIS_INCLUDE_DIR METIS_LIBRARY VERSION_VAR METIS_VERSION)

symforce/opt/CMakeLists.txt

Lines changed: 4 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -10,86 +10,9 @@
1010
include(FetchContent)
1111

1212
# ------------------------------------------------------------------------------
13-
# fmtlib
14-
15-
find_package(fmt 8...<9 QUIET)
16-
if (NOT fmt_FOUND)
17-
message(STATUS "fmt not found, adding with FetchContent")
18-
function(add_fmt)
19-
set(FMT_INSTALL ON CACHE INTERNAL "fmt should create an install target")
20-
FetchContent_Declare(
21-
fmtlib
22-
URL https://github.com/fmtlib/fmt/archive/8.0.1.zip
23-
URL_HASH SHA256=6747442c189064b857336007dd7fa3aaf58512aa1a0b2ba76bf1182eefb01025
24-
)
25-
set(CMAKE_POSITION_INDEPENDENT_CODE True)
26-
FetchContent_MakeAvailable(fmtlib)
27-
endfunction()
28-
29-
add_fmt()
30-
else()
31-
message(STATUS "fmt found: ${fmt_VERSION}")
32-
endif()
33-
34-
# ------------------------------------------------------------------------------
35-
# spdlog
36-
37-
find_package(spdlog 1.9...<1.11 QUIET)
38-
if (NOT spdlog_FOUND)
39-
message(STATUS "spdlog not found, adding with FetchContent")
40-
function(add_spdlog)
41-
set(SPDLOG_INSTALL ON CACHE INTERNAL "spdlog should create an install target")
42-
set(SPDLOG_FMT_EXTERNAL ON CACHE INTERNAL "spdlog shouldn't use its bundled fmtlib")
43-
set(CMAKE_POSITION_INDEPENDENT_CODE True)
44-
FetchContent_Declare(
45-
spdlog
46-
URL https://github.com/gabime/spdlog/archive/v1.9.2.zip
47-
URL_HASH SHA256=130bd593c33e2e2abba095b551db6a05f5e4a5a19c03ab31256c38fa218aa0a6
48-
)
49-
FetchContent_MakeAvailable(spdlog)
50-
endfunction()
51-
52-
add_spdlog()
53-
else()
54-
message(STATUS "spdlog found: ${spdlog_VERSION}")
55-
endif()
56-
57-
# ------------------------------------------------------------------------------
58-
# METIS
59-
60-
function(add_metis)
61-
set(CMAKE_POSITION_INDEPENDENT_CODE True)
62-
# CMake 4.0 removed compatibility with CMake 3.5: https://cmake.org/cmake/help/v4.0/release/4.0.html#deprecated-and-removed-features
63-
# See the note below on METIS versioning; newest GKlib at https://github.com/KarypisLab/GKlib does
64-
# support newer CMake, but we'd need to make sure the memory bugs mentioned below are resolved to
65-
# upgrade. The current copy of GKlib only declares it supports CMake 2.8.
66-
set(CMAKE_POLICY_VERSION_MINIMUM 3.5)
67-
FetchContent_Declare(
68-
metis
69-
# METIS does not have releases recently. Previously were using nearly the initial commit on
70-
# github, which is newer than the release on the METIS website. All of the releases on github
71-
# seem to have memory bugs, which do not appear in this release:
72-
URL https://symforce-org.github.io/downloads/metis-5.1.0.tar.gz
73-
URL_HASH SHA256=76faebe03f6c963127dbb73c13eab58c9a3faeae48779f049066a21c087c5db2
74-
# GKlib builds some test executables we can't disable without patching
75-
PATCH_COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/patch_metis.sh" "${FETCHCONTENT_BASE_DIR}/metis-src"
76-
)
77-
78-
# Tell metis where to find GKlib
79-
set(GKLIB_PATH
80-
"${FETCHCONTENT_BASE_DIR}/metis-src/GKlib" CACHE PATH "Path to GKlib for METIS" FORCE
81-
)
82-
83-
set(METIS_LIBRARY_TYPE "SHARED" CACHE STRING "Always build METIS as a shared library" FORCE)
84-
85-
FetchContent_MakeAvailable(metis)
86-
87-
# Metis doesn't put its main header (metis.h) on the metis target
88-
FetchContent_GetProperties(metis SOURCE_DIR metis_SOURCE_DIR)
89-
target_include_directories(metis INTERFACE ${metis_SOURCE_DIR}/include)
90-
endfunction()
91-
92-
add_metis()
13+
find_package(fmt REQUIRED)
14+
find_package(spdlog REQUIRED)
15+
find_package(metis REQUIRED)
9316

9417
# ==============================================================================
9518
# SymForce Targets
@@ -109,7 +32,7 @@ add_library(
10932
target_compile_options(symforce_cholesky PRIVATE ${SYMFORCE_COMPILE_OPTIONS})
11033
target_link_libraries(symforce_cholesky
11134
fmt::fmt
112-
metis
35+
METIS::METIS
11336
${SYMFORCE_EIGEN_TARGET}
11437
)
11538
target_include_directories(symforce_cholesky PUBLIC ../..)

symforce/opt/assert.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
#include <fmt/format.h>
1111

12+
#include "./fmt_compat.h"
13+
1214
namespace sym {
1315

1416
/**

symforce/opt/dense_linearizer.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#include <tuple>
99

10+
#include "./fmt_compat.h"
1011
#include "./internal/linearizer_utils.h"
1112

1213
namespace sym {

symforce/opt/dump_graph.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <fmt/format.h>
1212

1313
#include "./factor.h"
14+
#include "./fmt_compat.h"
1415
#include "./key.h"
1516

1617
namespace sym {

symforce/opt/factor.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <fmt/ranges.h>
1111

1212
#include "./assert.h"
13+
#include "./fmt_compat.h"
1314
#include "./internal/factor_utils.h"
1415

1516
namespace sym {

symforce/opt/fmt_compat.h

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/* ----------------------------------------------------------------------------
2+
* fmt 11.x compatibility header for symforce
3+
*
4+
* fmt >= 11 no longer auto-discovers operator<< for formatting. This header
5+
* restores that behaviour for every class type that provides operator<< but
6+
* is not already handled by fmt (strings, arithmetic, …).
7+
*
8+
* Two C++20 concepts do all the work:
9+
*
10+
* 1. EigenDerived – disables fmt/ranges.h's range formatter for Eigen
11+
* expression types (Eigen 3.4+ exposes begin()/end()).
12+
*
13+
* 2. The formatter partial specialization – a single, universal catch-all
14+
* that delegates to fmt::ostream_formatter for any remaining class type
15+
* with operator<<.
16+
* ---------------------------------------------------------------------------- */
17+
18+
#pragma once
19+
20+
#include <concepts>
21+
#include <ostream>
22+
#include <type_traits>
23+
24+
#include <Eigen/Core>
25+
#include <Eigen/SparseCore>
26+
#include <fmt/ostream.h>
27+
#include <fmt/ranges.h>
28+
29+
// ---------------------------------------------------------------------------
30+
// 1. Disable fmt's range formatter for Eigen types.
31+
//
32+
// Eigen 3.4+ types expose begin()/end() which makes fmt/ranges.h treat
33+
// them as iterable ranges. We want the human-readable matrix output from
34+
// operator<< instead, so we mark them as range_format::disabled.
35+
// ---------------------------------------------------------------------------
36+
template <typename T>
37+
concept EigenDerived = requires(const T& t) { t.derived(); };
38+
39+
template <EigenDerived T>
40+
struct fmt::range_format_kind<T, char>
41+
: std::integral_constant<fmt::range_format, fmt::range_format::disabled> {};
42+
43+
// ---------------------------------------------------------------------------
44+
// 2. Universal ostream-based formatter for class types with operator<<.
45+
//
46+
// Guards:
47+
// • std::is_class_v – excludes arithmetic, pointers, enums
48+
// that fmt already handles natively.
49+
// • !convertible to string_view – excludes std::string / string_view
50+
// which have their own fmt formatter.
51+
// • requires { os << t; } – the type must actually support operator<<.
52+
// ---------------------------------------------------------------------------
53+
template <typename T>
54+
requires std::is_class_v<T>
55+
&& (!std::is_convertible_v<const T&, fmt::string_view>)
56+
&& requires(std::ostream& os, const T& t) { os << t; }
57+
struct fmt::formatter<T, char> : fmt::ostream_formatter {};

symforce/opt/internal/derivative_checker.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
#include <spdlog/spdlog.h>
77

8+
#include "../fmt_compat.h"
9+
810
#include "../util.h"
911
#include "../values.h"
1012

symforce/opt/internal/linearizer_utils.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#include <fmt/ranges.h>
1414
#include <spdlog/spdlog.h>
1515

16+
#include "../fmt_compat.h"
17+
1618
#include <lcmtypes/sym/linearization_dense_factor_helper_t.hpp>
1719
#include <lcmtypes/sym/linearization_sparse_factor_helper_t.hpp>
1820

0 commit comments

Comments
 (0)