Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

--
- Bumped vendored Eigen to version 5.0.1 (from 3.4.0)
- Patched vendored Ceres Solver 2.2.0 for Eigen 5.x compatibility

### Deprecated

Expand Down
2 changes: 1 addition & 1 deletion ceres-solver-src/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ceres-solver-src"
version = "0.5.0+ceres2.2.0-eigen3.4.0-glog0.7.1"
version = "0.5.0+ceres2.2.0-eigen5.0.1-glog0.7.1"
edition = "2024"
links = "ceres"
readme = "README.md"
Expand Down
76 changes: 71 additions & 5 deletions ceres-solver-src/build.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;

#[derive(Debug)]
struct DstDirs {
Expand Down Expand Up @@ -63,12 +65,77 @@ fn install_glog(vendor_dir: &Path) -> DstDirs {
}
}

fn install_ceres(vendor_dir: &Path) -> DstDirs {
fn apply_patches(src_dir: &Path, patches_dir: &Path) {
if !patches_dir.exists() {
return;
}

let mut patches: Vec<_> = fs::read_dir(patches_dir)
.expect("Failed to read patches directory")
.filter_map(|entry| entry.ok())
.filter(|entry| {
entry
.path()
.extension()
.map(|ext| ext == "patch")
.unwrap_or(false)
})
.map(|entry| entry.path())
.collect();

patches.sort();

for patch_path in patches {
println!("cargo:warning=Applying patch: {}", patch_path.display());

// Try to apply the patch with --forward, which skips already applied patches
let output = Command::new("patch")
.arg("-p1")
.arg("-d")
.arg(src_dir)
.arg("-i")
.arg(&patch_path)
.arg("--forward")
.arg("--reject-file=-")
.output()
.expect("Failed to execute patch command");

// Check if patch failed (exit code != 0) and it's not because patch was already applied
if !output.status.success() {
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
let combined = format!("{}{}", stdout, stderr);

// If the error is NOT "Reversed (or previously applied) patch detected", then panic
if !combined.contains("Reversed (or previously applied) patch detected") {
eprintln!("Patch stdout: {}", stdout);
eprintln!("Patch stderr: {}", stderr);
panic!("Failed to apply patch: {}", patch_path.display());
}
// Otherwise, the patch was already applied, which is fine
println!(
"cargo:warning=Patch already applied: {}",
patch_path.display()
);
}
}
}

fn install_ceres(vendor_dir: &Path, manifest_dir: &Path) -> DstDirs {
let src_dir = {
let mut dir = vendor_dir.to_owned();
dir.push("ceres-solver");
dir
};

let patches_dir = {
let mut dir = manifest_dir.to_owned();
dir.push("patches");
dir
};

apply_patches(&src_dir, &patches_dir);

let dst = cmake::Config::new(src_dir)
.profile("Release")
.pic(true)
Expand Down Expand Up @@ -106,13 +173,12 @@ fn install_ceres(vendor_dir: &Path) -> DstDirs {
}

fn main() {
let vendor_dir: PathBuf = [env::var("CARGO_MANIFEST_DIR").unwrap(), "vendor".into()]
.into_iter()
.collect();
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
let vendor_dir = manifest_dir.join("vendor");

let eigen_dirs = install_eigen(&vendor_dir);
let glog_dirs = install_glog(&vendor_dir);
let ceres_dirs = install_ceres(&vendor_dir);
let ceres_dirs = install_ceres(&vendor_dir, &manifest_dir);

println!(
"cargo:rustc-link-search=native={}",
Expand Down
74 changes: 74 additions & 0 deletions ceres-solver-src/patches/0001-support-eigen-5.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8e49c19e..44d98d53 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -180,9 +180,34 @@ endif (IOS)

unset(CERES_COMPILE_OPTIONS)

+# We call find_package multiple time with different versioning scheme to support
+# both Eigen3 3.x and 5.x. If the first invocation fails and Eigen3_DIR was set
+# to a possible location, e.g., during cross-compilation, failure to locate the
+# package will unset the variable. To avoid losing the path hint, we save it and
+# reuse it in the second find_package call.
+set (_Ceres_Eigen3_DIR)
+
+if (Eigen3_DIR)
+ set (_Ceres_Eigen3_DIR "${Eigen3_DIR}")
+endif (Eigen3_DIR)
+
# Eigen.
# Eigen delivers Eigen3Config.cmake since v3.3.3
-find_package(Eigen3 3.3 REQUIRED)
+find_package(Eigen3 3.3...5 NO_MODULE)
+
+if (NOT Eigen3_FOUND)
+ if (_Ceres_Eigen3_DIR)
+ set (Eigen3_DIR "${_Ceres_Eigen3_DIR}")
+ endif (_Ceres_Eigen3_DIR)
+ # Eigen3's CMake package config prior to 5.0.0 does not support version ranges
+ # with different major version components. To ensure backward compatibility,
+ # we locate the package using the previous version scheme as a fallback
+ # mechanism.
+ find_package(Eigen3 3.3 REQUIRED NO_MODULE)
+endif (NOT Eigen3_FOUND)
+
+unset (_Ceres_Eigen3_DIR)
+
if (Eigen3_FOUND)
message("-- Found Eigen version ${Eigen3_VERSION}: ${Eigen3_DIR}")
if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64.*|AARCH64.*)" AND
diff --git a/internal/ceres/covariance_impl.cc b/internal/ceres/covariance_impl.cc
index 6e8362da..deb0ce12 100644
--- a/internal/ceres/covariance_impl.cc
+++ b/internal/ceres/covariance_impl.cc
@@ -723,8 +723,13 @@ bool CovarianceImpl::ComputeCovarianceValuesUsingDenseSVD() {
}
event_logger.AddEvent("ConvertToDenseMatrix");

+#if EIGEN_VERSION_AT_LEAST(5, 0, 0)
+ Eigen::BDCSVD<Matrix, Eigen::ComputeThinU | Eigen::ComputeThinV> svd(
+ dense_jacobian);
+#else // !EIGEN_VERSION_AT_LEAST(5, 0, 0)
Eigen::BDCSVD<Matrix> svd(dense_jacobian,
Eigen::ComputeThinU | Eigen::ComputeThinV);
+#endif // EIGEN_VERSION_AT_LEAST(5, 0, 0)

event_logger.AddEvent("SingularValueDecomposition");

diff --git a/internal/ceres/invert_psd_matrix.h b/internal/ceres/invert_psd_matrix.h
index bc749009..34a46982 100644
--- a/internal/ceres/invert_psd_matrix.h
+++ b/internal/ceres/invert_psd_matrix.h
@@ -68,7 +68,11 @@ typename EigenTypes<kSize, kSize>::Matrix InvertPSDMatrix(

// For a thin SVD the number of columns of the matrix need to be dynamic.
using SVDMType = typename EigenTypes<kSize, Eigen::Dynamic>::Matrix;
+#if EIGEN_VERSION_AT_LEAST(5, 0, 0)
+ Eigen::JacobiSVD<SVDMType, Eigen::ComputeThinU | Eigen::ComputeThinV> svd(m);
+#else // !EIGEN_VERSION_AT_LEAST(5, 0, 0)
Eigen::JacobiSVD<SVDMType> svd(m, Eigen::ComputeThinU | Eigen::ComputeThinV);
+#endif // EIGEN_VERSION_AT_LEAST(5, 0, 0)
return svd.solve(MType::Identity(size, size));
}

2 changes: 1 addition & 1 deletion ceres-solver-src/vendor/eigen
Submodule eigen updated from 314739 to bc3b39