Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

g2o: new recipe #22337

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
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
8 changes: 8 additions & 0 deletions recipes/g2o/all/FindSuiteSparse.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Simplified replacement for https://github.com/RainerKuemmerle/g2o/blob/master/cmake_modules/FindSuiteSparse.cmake

if (G2O_USE_CHOLMOD)
find_package(CHOLMOD REQUIRED CONFIG)
add_library(SuiteSparse::Partition ALIAS SuiteSparse::CHOLMOD)
set(SuiteSparse_FOUND TRUE)
set(SuiteSparse_CHOLMOD_FOUND TRUE)
endif()
12 changes: 12 additions & 0 deletions recipes/g2o/all/conandata.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
sources:
"20230806":
url: "https://github.com/RainerKuemmerle/g2o/archive/refs/tags/20230806_git.tar.gz"
sha256: "e717d3b96cc6d00fcbbaf637aae648c9823599e6aa8fcf4546fc9ad4034dcde5"
patches:
"20230806":
- patch_file: "patches/001-unvendor-freeglut.patch"
patch_description: "Replace vendored FreeGLUT with a Conan version"
patch_type: "conan"
- patch_file: "patches/002-use-openmp-target.patch"
patch_description: "Require OpenMP if enabled, use a target instead of plain compiler flags"
patch_type: "portability"
300 changes: 300 additions & 0 deletions recipes/g2o/all/conanfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,300 @@
import os

from conan import ConanFile
from conan.errors import ConanInvalidConfiguration
from conan.tools.build import check_min_cppstd, check_max_cppstd
from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout
from conan.tools.files import copy, get, rm, rmdir, save, export_conandata_patches, apply_conandata_patches, replace_in_file
from conan.tools.microsoft import is_msvc
from conan.tools.scm import Version

required_conan_version = ">=1.53.0"


class G2oConan(ConanFile):
name = "g2o"
description = "g2o: A General Framework for Graph Optimization"
license = "BSD-2-Clause", "GPL-3.0-or-later", "LGPL-2.1-or-later"
url = "https://github.com/conan-io/conan-center-index"
homepage = "https://github.com/RainerKuemmerle/g2o"
topics = ("graph-optimization", "slam", "state-estimation", "computer-vision", "robotics")

package_type = "library"
settings = "os", "arch", "compiler", "build_type"
options = {
"shared": [True, False],
"fPIC": [True, False],
"build_slam2d_types": [True, False],
"build_slam2d_addon_types": [True, False],
"build_data_types": [True, False],
"build_sclam2d_types": [True, False],
"build_slam3d_types": [True, False],
"build_slam3d_addon_types": [True, False],
"build_sba_types": [True, False],
"build_icp_types": [True, False],
"build_sim3_types": [True, False],
"fast_math": [True, False],
"no_implicit_ownership_of_objects": [True, False],
"sse_autodetect": [True, False],
"sse2": [True, False],
"sse3": [True, False],
"sse4_1": [True, False],
"sse4_2": [True, False],
"sse4_a": [True, False],
"with_openmp": [True, False],
"with_cholmod": [True, False],
"with_csparse": [True, False],
"with_opengl": [True, False],
}
default_options = {
"shared": False,
"fPIC": True,
"build_slam2d_types": True,
"build_slam2d_addon_types": True,
"build_data_types": True,
"build_sclam2d_types": True,
"build_slam3d_types": True,
"build_slam3d_addon_types": True,
"build_sba_types": True,
"build_icp_types": True,
"build_sim3_types": True,
"fast_math": False,
"no_implicit_ownership_of_objects": False,
"sse_autodetect": False,
# All SSE extensions except for SSE4a (34%) have a 99%+ adoption rate
# as of 2024-01 in https://store.steampowered.com/hwsurvey
"sse2": True,
"sse3": True,
"sse4_1": True,
"sse4_2": True,
"sse4_a": False,
"with_openmp": True,
"with_cholmod": False,
"with_csparse": False,
"with_opengl": True,
}

@property
def _min_cppstd(self):
return 17

@property
def _max_cppstd(self):
return 17

@property
def _compilers_minimum_version(self):
return {
"Visual Studio": "16",
"msvc": "192",
"gcc": "8",
"clang": "7",
"apple-clang": "12",
}

def export_sources(self):
export_conandata_patches(self)
copy(self, "FindSuiteSparse.cmake", self.recipe_folder, self.export_sources_folder)

def config_options(self):
if self.settings.os == "Windows":
del self.options.fPIC

def configure(self):
if self.options.shared:
self.options.rm_safe("fPIC")

def layout(self):
cmake_layout(self, src_folder="src")

def package_id(self):
if self.info.options.sse_autodetect:
del self.info.options.sse2
del self.info.options.sse3
del self.info.options.sse4_1
del self.info.options.sse4_2
del self.info.options.sse4_a
if not self.info.options.build_slam2d_types:
del self.info.options.build_slam2d_addon_types
del self.info.options.build_sclam2d_types
del self.info.options.build_data_types
if not self.info.options.build_slam3d_types:
del self.info.options.build_slam3d_addon_types
del self.info.options.build_sba_types
del self.info.options.build_icp_types
del self.info.options.build_sim3_types

def requirements(self):
# Used in public core/eigen_types.h
self.requires("eigen/3.4.0", transitive_headers=True, transitive_libs=True)
# Used in stuff/logger.h
self.requires("spdlog/1.14.1", transitive_headers=True, transitive_libs=True)
if self.options.with_opengl:
# Used in stuff/opengl_wrapper.h
self.requires("opengl/system", transitive_headers=True, transitive_libs=True)
self.requires("freeglut/3.4.0", transitive_headers=True, transitive_libs=True)
if self.options.with_openmp and self.settings.compiler in ["clang", "apple-clang"]:
# Used in core/openmp_mutex.h, also '#pragma omp' is used in several core public headers
self.requires("llvm-openmp/18.1.8", transitive_headers=True, transitive_libs=True)
if self.options.with_cholmod:
self.requires("suitesparse-cholmod/5.3.0")
if self.options.with_csparse:
self.requires("suitesparse-cxsparse/4.4.1")

# TODO: optional dependencies
# self.requires("qt/[~5.15]")
# self.requires("libqglviewer/x.y.z")

def validate(self):
if self.settings.compiler.cppstd:
check_min_cppstd(self, self._min_cppstd)
# C++20 fails with
# error: call to non-‘constexpr’ function ‘void fmt::v10::detail::throw_format_error(const char*)’
check_max_cppstd(self, self._max_cppstd)
minimum_version = self._compilers_minimum_version.get(str(self.settings.compiler), False)
if minimum_version and Version(self.settings.compiler.version) < minimum_version:
raise ConanInvalidConfiguration(
f"{self.ref} requires C++{self._min_cppstd}, which your compiler does not support."
)

if self.settings.os == "Windows" and self.options.shared:
# Build fails with "unresolved external symbol "public: __cdecl g2o::internal::LoggerInterface::LoggerInterface(void)"
raise ConanInvalidConfiguration("g2o does not currently support shared libraries on Windows")

def source(self):
get(self, **self.conan_data["sources"][self.version], strip_root=True)

def generate(self):
tc = CMakeToolchain(self)
tc.variables["G2O_BUILD_EXAMPLES"] = False
tc.variables["G2O_BUILD_APPS"] = False
tc.variables["G2O_USE_OPENMP"] = self.options.with_openmp
tc.variables["G2O_USE_CHOLMOD"] = self.options.with_cholmod
tc.variables["G2O_USE_CSPARSE"] = self.options.with_csparse
tc.variables["G2O_USE_OPENGL"] = self.options.with_opengl
tc.variables["G2O_USE_LOGGING"] = True
tc.variables["G2O_BUILD_SLAM2D_TYPES"] = self.options.build_slam2d_types
tc.variables["G2O_BUILD_SLAM2D_ADDON_TYPES"] = self.options.build_slam2d_addon_types
tc.variables["G2O_BUILD_DATA_TYPES"] = self.options.build_data_types
tc.variables["G2O_BUILD_SCLAM2D_TYPES"] = self.options.build_sclam2d_types
tc.variables["G2O_BUILD_SLAM3D_TYPES"] = self.options.build_slam3d_types
tc.variables["G2O_BUILD_SLAM3D_ADDON_TYPES"] = self.options.build_slam3d_addon_types
tc.variables["G2O_BUILD_SBA_TYPES"] = self.options.build_sba_types
tc.variables["G2O_BUILD_ICP_TYPES"] = self.options.build_icp_types
tc.variables["G2O_BUILD_SIM3_TYPES"] = self.options.build_sim3_types
tc.variables["G2O_FAST_MATH"] = self.options.fast_math
tc.variables["G2O_NO_IMPLICIT_OWNERSHIP_OF_OBJECTS"] = self.options.no_implicit_ownership_of_objects
tc.variables["DO_SSE_AUTODETECT"] = self.options.sse_autodetect
tc.variables["DISABLE_SSE2"] = not self.options.sse2
tc.variables["DISABLE_SSE3"] = not self.options.sse3
tc.variables["DISABLE_SSE4_1"] = not self.options.sse4_1
tc.variables["DISABLE_SSE4_2"] = not self.options.sse4_2
tc.variables["DISABLE_SSE4_A"] = not self.options.sse4_a

tc.generate()

deps = CMakeDeps(self)
deps.set_property("freeglut", "cmake_target_name", "FreeGLUT::freeglut")
# CXSparse is a compatible extension of CSparse
deps.set_property("suitesparse-cxsparse", "cmake_file_name", "CSPARSE")
deps.generate()

def _patch_sources(self):
apply_conandata_patches(self)
copy(self, "FindSuiteSparse.cmake", self.export_sources_folder, os.path.join(self.source_folder, "cmake_modules"))
save(self, os.path.join(self.source_folder, "g2o", "EXTERNAL", "CMakeLists.txt"), "")
replace_in_file(self, os.path.join(self.source_folder, "CMakeLists.txt"),
"find_package(CSparse)", "find_package(CSPARSE)")
replace_in_file(self, os.path.join(self.source_folder, "g2o", "solvers", "csparse", "CMakeLists.txt"),
"$<BUILD_INTERFACE:${CSPARSE_INCLUDE_DIR}>",
'"$<BUILD_INTERFACE:${CSPARSE_INCLUDE_DIR}>"')
replace_in_file(self, os.path.join(self.source_folder, "g2o", "solvers", "csparse", "CMakeLists.txt"),
"${CSPARSE_LIBRARY}", "${CSPARSE_LIBRARIES}")

def build(self):
self._patch_sources()
cmake = CMake(self)
cmake.configure()
cmake.build()

def package(self):
copy(self, "license-*.txt", os.path.join(self.source_folder, "doc"), os.path.join(self.package_folder, "licenses"))
cmake = CMake(self)
cmake.install()
rmdir(self, os.path.join(self.package_folder, "lib", "pkgconfig"))
rmdir(self, os.path.join(self.package_folder, "lib", "cmake"))
rm(self, "*.pdb", self.package_folder, recursive=True)

def package_info(self):
self.cpp_info.set_property("cmake_find_mode", "both")
# https://github.com/RainerKuemmerle/g2o/blob/20230806_git/cmake_modules/FindG2O.cmake
self.cpp_info.set_property("cmake_module_file_name", "G2O")
# https://github.com/RainerKuemmerle/g2o/blob/20230806_git/CMakeLists.txt#L495
self.cpp_info.set_property("cmake_file_name", "g2o")

def _add_component(name, requires=None):
if not self.options.with_opengl and "opengl_helper" in requires:
requires.remove("opengl_helper")
self.cpp_info.components[name].set_property("cmake_target_name", f"g2o::{name}")
self.cpp_info.components[name].libs = [f"g2o_{name}"]
self.cpp_info.components[name].requires = requires or []

# Core libraries
self.cpp_info.components["g2o_ceres_ad"].set_property("cmake_target_name", "g2o::g2o_ceres_ad")
_add_component("stuff", requires=["spdlog::spdlog", "eigen::eigen"])
_add_component("core", requires=["stuff", "eigen::eigen", "g2o_ceres_ad"])
if self.options.with_opengl:
_add_component("opengl_helper", requires=["opengl::opengl", "freeglut::freeglut", "eigen::eigen"])

# Solvers
_add_component("solver_dense", requires=["core"])
_add_component("solver_eigen", requires=["core"])
_add_component("solver_pcg", requires=["core"])
_add_component("solver_structure_only", requires=["core"])
if self.options.build_slam2d_types:
_add_component("solver_slam2d_linear", requires=["core", "solver_eigen", "types_slam2d"])
if self.options.with_cholmod:
_add_component("solver_cholmod", requires=["core", "suitesparse-cholmod::suitesparse-cholmod"])
if self.options.with_csparse:
_add_component("csparse_extension", requires=["stuff", "suitesparse-cxsparse::suitesparse-cxsparse", "eigen::eigen"])
_add_component("solver_csparse", requires=["core", "csparse_extension"])

# Types
if self.options.build_slam2d_types:
_add_component("types_slam2d", requires=["core", "opengl_helper"])
if self.options.build_slam2d_addon_types:
_add_component("types_slam2d_addons", requires=["core", "types_slam2d", "opengl_helper"])
if self.options.build_sclam2d_types:
_add_component("types_sclam2d", requires=["core", "opengl_helper", "types_slam2d"])
if self.options.build_data_types:
_add_component("types_data", requires=["core", "types_slam2d", "opengl_helper"])
if self.options.build_slam3d_types:
_add_component("types_slam3d", requires=["core", "opengl_helper"])
if self.options.build_slam3d_addon_types:
_add_component("types_slam3d_addons", requires=["core", "types_slam3d", "opengl_helper"])
if self.options.build_sba_types:
_add_component("types_sba", requires=["core", "types_slam3d"])
if self.options.build_icp_types:
_add_component("types_icp", requires=["core", "types_sba", "types_slam3d"])
if self.options.build_sim3_types:
_add_component("types_sim3", requires=["core", "types_sba"])

if self.options.with_openmp:
openmp_flags = []
if self.settings.compiler in ["clang", "apple-clang"]:
self.cpp_info.components["core"].requires.append("llvm-openmp::llvm-openmp")
openmp_flags = ["-Xpreprocessor", "-fopenmp"]
elif self.settings.compiler == "gcc":
openmp_flags = ["-fopenmp"]
elif self.settings.compiler == "intel-cc":
openmp_flags = ["/Qopenmp"] if self.settings.os == "Windows" else ["-Qopenmp"]
elif is_msvc(self):
openmp_flags = ["-openmp"]
# '#pragma omp parallel for' is used in multiple public headers in core
self.cpp_info.components["core"].cxxflags = openmp_flags
self.cpp_info.components["core"].sharedlinkflags = openmp_flags
self.cpp_info.components["core"].exelinkflags = openmp_flags

if self.settings.os in ["Linux", "FreeBSD"]:
self.cpp_info.components["stuff"].system_libs.append("m")
self.cpp_info.components["stuff"].system_libs.append("rt")
44 changes: 44 additions & 0 deletions recipes/g2o/all/patches/001-unvendor-freeglut.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
--- g2o/types/data/CMakeLists.txt
+++ g2o/types/data/CMakeLists.txt
@@ -22,7 +22,8 @@
target_compile_features(types_data PUBLIC cxx_std_17)
target_link_libraries(types_data core types_slam2d)
if(G2O_HAVE_OPENGL)
+ find_package(FreeGLUT REQUIRED CONFIG)
- target_link_libraries(types_data freeglut_minimal opengl_helper)
+ target_link_libraries(types_data FreeGLUT::freeglut opengl_helper)
endif()

target_include_directories(types_data PUBLIC
--- g2o/types/data/vertex_ellipse.cpp
+++ g2o/types/data/vertex_ellipse.cpp
@@ -30,7 +30,7 @@
#include "g2o/stuff/misc.h"

#ifdef G2O_HAVE_OPENGL
-#include "g2o/EXTERNAL/freeglut/freeglut_minimal.h"
+#include <GL/freeglut.h>
#include "g2o/stuff/opengl_primitives.h"
#include "g2o/stuff/opengl_wrapper.h"
#endif
--- g2o/types/data/vertex_tag.cpp
+++ g2o/types/data/vertex_tag.cpp
@@ -29,7 +29,7 @@
#include "g2o/stuff/macros.h"

#ifdef G2O_HAVE_OPENGL
-#include "g2o/EXTERNAL/freeglut/freeglut_minimal.h"
+#include <GL/freeglut.h>
#include "g2o/stuff/opengl_primitives.h"
#include "g2o/stuff/opengl_wrapper.h"
#endif
@@ -99,8 +99,7 @@
opengl::drawBox(0.1f * textSize, 0.1f * textSize, 0.1f * textSize);
glTranslatef(0.2f * textSize, 0.f, 0.f);
glScalef(0.003f * textSize, 0.003f * textSize, 1.f);
- freeglut_minimal::glutStrokeString(freeglut_minimal::GLUT_STROKE_ROMAN,
- that->name().c_str());
+ glutStrokeString(GLUT_STROKE_ROMAN, (const unsigned char*)that->name().c_str());
glPopMatrix();
return this;
}
20 changes: 20 additions & 0 deletions recipes/g2o/all/patches/002-use-openmp-target.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -138,13 +138,10 @@
# OPENMP is experimental. We experienced some slowdown with it
option(G2O_USE_OPENMP "Build g2o with OpenMP support (EXPERIMENTAL)" OFF)
if(G2O_USE_OPENMP)
- find_package(OpenMP)
- if(OPENMP_FOUND)
- set (G2O_OPENMP 1)
- set(g2o_C_FLAGS "${g2o_C_FLAGS} ${OpenMP_C_FLAGS}")
- set(g2o_CXX_FLAGS "${g2o_CXX_FLAGS} -DEIGEN_DONT_PARALLELIZE ${OpenMP_CXX_FLAGS}")
- message(STATUS "Compiling with OpenMP support")
- endif(OPENMP_FOUND)
+ find_package(OpenMP REQUIRED)
+ set(G2O_OPENMP 1)
+ set(g2o_CXX_FLAGS "${g2o_CXX_FLAGS} -DEIGEN_DONT_PARALLELIZE")
+ link_libraries(OpenMP::OpenMP_CXX)
endif(G2O_USE_OPENMP)

# OpenGL is used in the draw actions for the different types, as well
8 changes: 8 additions & 0 deletions recipes/g2o/all/test_package/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
cmake_minimum_required(VERSION 3.15)
project(test_package LANGUAGES CXX)

find_package(g2o REQUIRED CONFIG)

add_executable(${PROJECT_NAME} test_package.cpp)
target_link_libraries(${PROJECT_NAME} PRIVATE g2o::g2o)
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_17)
Loading