diff --git a/distros/humble/ci.yaml b/distros/humble/ci.yaml index 63d3a18eb..035f1fcb2 100644 --- a/distros/humble/ci.yaml +++ b/distros/humble/ci.yaml @@ -23,4 +23,6 @@ full_rebuild: false # # Remember that dependents are not rebuilt automatically: evict them as well if # they must pick up the change. -evict_cache: [] +evict_cache: + - mola_kernel # new Windows patch; reset before merging + - mola_yaml # new Windows patch; reset before merging diff --git a/distros/humble/patch/dependencies.yaml b/distros/humble/patch/dependencies.yaml index 7213a431f..8fc8153b2 100644 --- a/distros/humble/patch/dependencies.yaml +++ b/distros/humble/patch/dependencies.yaml @@ -62,6 +62,11 @@ mimick_vendor: add_build: ["vcstool"] moveit_visual_tools: add_host: ["${{ 'libgl-devel' if linux }}", "${{ 'libopengl-devel' if linux }}"] +mrpt_gui: + # Overrides shared/: this distribution maps Qt to qt-main 5.15, whose builds need + # gstreamer <1.27, while the pinned wxwidgets (3.3.3) needs gstreamer 1.28. A version + # spec bypasses that pin, so the solver picks a wxwidgets that coexists with qt-main. + add_host: ["wxwidgets >=3.2"] nav2_constrained_smoother: add_host: ["${{ 'openblas' if win }}"] nav2_util: diff --git a/distros/jazzy/ci.yaml b/distros/jazzy/ci.yaml index 63d3a18eb..035f1fcb2 100644 --- a/distros/jazzy/ci.yaml +++ b/distros/jazzy/ci.yaml @@ -23,4 +23,6 @@ full_rebuild: false # # Remember that dependents are not rebuilt automatically: evict them as well if # they must pick up the change. -evict_cache: [] +evict_cache: + - mola_kernel # new Windows patch; reset before merging + - mola_yaml # new Windows patch; reset before merging diff --git a/distros/jazzy/patch/dependencies.yaml b/distros/jazzy/patch/dependencies.yaml index 17870a563..4c517e12d 100644 --- a/distros/jazzy/patch/dependencies.yaml +++ b/distros/jazzy/patch/dependencies.yaml @@ -101,6 +101,11 @@ mimick_vendor: add_host: ["setuptools <81"] moveit_visual_tools: add_host: ["${{ 'libgl-devel' if linux }}", "${{ 'libopengl-devel' if linux }}"] +mrpt_gui: + # Overrides shared/: this distribution maps Qt to qt-main 5.15, whose builds need + # gstreamer <1.27, while the pinned wxwidgets (3.3.3) needs gstreamer 1.28. A version + # spec bypasses that pin, so the solver picks a wxwidgets that coexists with qt-main. + add_host: ["wxwidgets >=3.2"] nav2_constrained_smoother: add_host: ["${{ 'openblas' if win }}"] nav2_mppi_controller: diff --git a/distros/lyrical/ci.yaml b/distros/lyrical/ci.yaml index 63d3a18eb..035f1fcb2 100644 --- a/distros/lyrical/ci.yaml +++ b/distros/lyrical/ci.yaml @@ -23,4 +23,6 @@ full_rebuild: false # # Remember that dependents are not rebuilt automatically: evict them as well if # they must pick up the change. -evict_cache: [] +evict_cache: + - mola_kernel # new Windows patch; reset before merging + - mola_yaml # new Windows patch; reset before merging diff --git a/shared/patch/dependencies.yaml b/shared/patch/dependencies.yaml index 06fe3b647..5f96ebd5d 100644 --- a/shared/patch/dependencies.yaml +++ b/shared/patch/dependencies.yaml @@ -78,6 +78,18 @@ moveit_setup_framework: add_host: ["${{ 'libgl-devel' if linux }}", "${{ 'libopengl-devel' if linux }}"] moveit_setup_srdf_plugins: add_host: ["${{ 'libgl-devel' if linux }}", "${{ 'libopengl-devel' if linux }}"] +mrpt_common: + # CMakeLists.txt calls find_package(ament_cmake) when ROS_VERSION=2 (set by ros_environment), + # but package.xml (build_type cmake) does not declare it + add_host: ["ros2-ament-cmake"] +mrpt_gui: + # links libwx_*; the wxwidgets/wx-common keys map to wxpython, so wxwidgets is only a + # transitive host dep and its (weak) run_exports never reach the run requirements + add_host: ["wxwidgets"] +mrpt_math: + # its exported CMake targets (and mrpt_poses') carry /Library/include/eigen3 on + # Windows, so dependents without their own eigen host dep failed to configure + add_run: ["${{ 'eigen' if win }}"] mujoco_ros2_control_plugins: add_host: - if: linux diff --git a/shared/patch/ros2-mola-bridge-ros2.win.patch b/shared/patch/ros2-mola-bridge-ros2.win.patch new file mode 100644 index 000000000..45dcfb2b8 --- /dev/null +++ b/shared/patch/ros2-mola-bridge-ros2.win.patch @@ -0,0 +1,15 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 1002ccf..fc37b9a 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -85,6 +85,10 @@ mola_add_library( + # Same for mrpt_libros_bridge + mola_version_to_hexadecimal(mrpt_libros_bridge_VERSION_HEX ${mrpt_libros_bridge_VERSION}) + target_compile_definitions(${PROJECT_NAME} PRIVATE MRPT_ROS2_BRIDGE_VERSION=${mrpt_libros_bridge_VERSION_HEX}) ++if(MSVC) ++ # error C1128: number of sections exceeded object file format limit ++ target_compile_options(${PROJECT_NAME} PRIVATE /bigobj) ++endif() + message(STATUS "Found: mrpt_libros_bridge_VERSION: ${mrpt_libros_bridge_VERSION} (${mrpt_libros_bridge_VERSION_HEX})") + + if (gps_msgs_FOUND) diff --git a/shared/patch/ros2-mola-kernel.win.patch b/shared/patch/ros2-mola-kernel.win.patch new file mode 100644 index 000000000..03f5155d4 --- /dev/null +++ b/shared/patch/ros2-mola-kernel.win.patch @@ -0,0 +1,17 @@ +diff --git a/include/mola_kernel/interfaces/DiagnosticsProvider.h b/include/mola_kernel/interfaces/DiagnosticsProvider.h +index 9ee9be8..fb7423d 100644 +--- a/include/mola_kernel/interfaces/DiagnosticsProvider.h ++++ b/include/mola_kernel/interfaces/DiagnosticsProvider.h +@@ -22,6 +22,12 @@ + #include + #include + ++// windows.h (wingdi.h) defines ERROR, which breaks DiagnosticLevel::ERROR below ++// (the generated diagnostic_msgs headers do the same) ++#if defined(_WIN32) && defined(ERROR) ++#undef ERROR ++#endif ++ + namespace mola + { + /** \addtogroup mola_kernel_interfaces_grp diff --git a/shared/patch/ros2-mola-launcher.patch b/shared/patch/ros2-mola-launcher.patch new file mode 100644 index 000000000..644565f5a --- /dev/null +++ b/shared/patch/ros2-mola-launcher.patch @@ -0,0 +1,70 @@ +diff --git a/src/MolaDLL_Loader.cpp b/src/MolaDLL_Loader.cpp +--- a/src/MolaDLL_Loader.cpp ++++ b/src/MolaDLL_Loader.cpp +@@ -24,7 +24,7 @@ + + #include + +-#if defined(__unix__) ++#if defined(__unix__) || defined(__APPLE__) + #include + #endif + +@@ -39,7 +39,9 @@ + { + MRPT_TRY_START + +-#if defined(__unix__) ++#if defined(__APPLE__) ++#define DLL_EXT "dylib" ++#elif defined(__unix__) + #define DLL_EXT "so" + #else + #define DLL_EXT "dll" +@@ -59,11 +61,14 @@ + for (const auto& lib : lst) + { + if (lib.name.find("mola") == std::string::npos) continue; // skip ++ // ROS interface libraries (e.g. mola_msgs) are never MOLA modules, and the ++ // Python ones cannot be dlopen()ed from a non-Python process: ++ if (lib.name.find("__rosidl_") != std::string::npos) continue; // skip + + // Already loaded? + if (loaded_lib_handled.count(lib.name) != 0) continue; // skip + +-#if defined(__unix__) ++#if defined(__unix__) || defined(__APPLE__) + // Check if already loaded? + { + void* handle = dlopen(lib.wholePath.c_str(), RTLD_NOLOAD); +@@ -109,7 +114,7 @@ + { + // printf("[mola-launcher] Unloading: %s\n", + // lib.second.lib_path.c_str()); +-#if defined(__unix__) ++#if defined(__unix__) || defined(__APPLE__) + dlclose(lib.second.handle); + #else + FreeLibrary(lib.second.handle); +diff --git a/src/MolaLauncherApp.cpp b/src/MolaLauncherApp.cpp +--- a/src/MolaLauncherApp.cpp ++++ b/src/MolaLauncherApp.cpp +@@ -119,6 +119,18 @@ + // do not filter these ones by *directory* name, since *filenames* will be + // filtered later on: + from_env_var_to_list("LD_LIBRARY_PATH", lib_search_paths_); ++ ++ // conda/RoboStack environments do not set LD_LIBRARY_PATH: also search ++ // /lib (/bin for Windows DLLs) for every prefix in AMENT_PREFIX_PATH. ++ { ++ std::vector prefixes; ++ from_env_var_to_list("AMENT_PREFIX_PATH", prefixes); ++#if defined(_WIN32) ++ for (const auto& prefix : prefixes) safe_add_to_list(prefix + "/bin", lib_search_paths_); ++#else ++ for (const auto& prefix : prefixes) safe_add_to_list(prefix + "/lib", lib_search_paths_); ++#endif ++ } + } + + MolaLauncherApp::~MolaLauncherApp() diff --git a/shared/patch/ros2-mola-launcher.win.patch b/shared/patch/ros2-mola-launcher.win.patch new file mode 100644 index 000000000..d368fcf72 --- /dev/null +++ b/shared/patch/ros2-mola-launcher.win.patch @@ -0,0 +1,105 @@ +diff --git a/apps/mola-cli.cpp b/apps/mola-cli.cpp +index 2bd97ff..d77ceda 100644 +--- a/apps/mola-cli.cpp ++++ b/apps/mola-cli.cpp +@@ -23,7 +23,11 @@ + #include + #include + #include ++#if defined(_WIN32) ++#include // _write() ++#else + #include // write() ++#endif + + #include + #include +@@ -48,7 +52,11 @@ void mola_signal_handler([[maybe_unused]] int s) + // raw write() to stderr. The actual shutdown (which logs, sleeps and joins + // threads) is done by the main thread as soon as spin() returns. + static const char msg[] = "\nTermination signal caught. Shutting down...\n"; ++#if defined(_WIN32) ++ [[maybe_unused]] const auto n = ::_write(2, msg, sizeof(msg) - 1); ++#else + [[maybe_unused]] const auto n = ::write(STDERR_FILENO, msg, sizeof(msg) - 1); ++#endif + + if (auto* app = theApp.load()) + { +@@ -58,6 +66,11 @@ void mola_signal_handler([[maybe_unused]] int s) + + void mola_install_signal_handler() + { ++#if defined(_WIN32) ++ // No sigaction() on Windows: ++ std::signal(SIGINT, &mola_signal_handler); ++ std::signal(SIGTERM, &mola_signal_handler); ++#else + struct sigaction sigIntHandler; + + sigIntHandler.sa_handler = &mola_signal_handler; +@@ -71,6 +84,7 @@ void mola_install_signal_handler() + // the main MOLA loop keeps running, so the process never exits and lingers + // with its ROS 2 endpoints still advertised but no longer served. + sigaction(SIGTERM, &sigIntHandler, nullptr); ++#endif + } + + // Default task for mola-cli: launching a SLAM system +diff --git a/src/MolaDLL_Loader.cpp b/src/MolaDLL_Loader.cpp +index ec376eb..6dcee68 100644 +--- a/src/MolaDLL_Loader.cpp ++++ b/src/MolaDLL_Loader.cpp +@@ -26,6 +26,11 @@ + + #if defined(__unix__) || defined(__APPLE__) + #include ++#elif defined(_WIN32) ++#ifndef NOMINMAX ++#define NOMINMAX ++#endif ++#include // LoadLibraryA(), FreeLibrary() + #endif + + /** From internal_load_lib_modules() */ +@@ -81,11 +86,17 @@ void internal_load_lib_modules( + + void* handle = dlopen(lib.wholePath.c_str(), RTLD_LAZY); + #else +- HMODULE handle = LoadLibrary(lib.wholePath.c_str()); ++ void* handle = LoadLibraryA(lib.wholePath.c_str()); + #endif + if (handle == nullptr) + { ++#if defined(_WIN32) ++ const std::string err_str = ++ mrpt::format("LoadLibrary() error code %lu", static_cast(GetLastError())); ++ const char* err = err_str.c_str(); ++#else + const char* err = dlerror(); ++#endif + if (!err) err = "(error calling dlerror())"; + THROW_EXCEPTION(mrpt::format( + "Error loading module: `%s`\ndlerror(): `%s`", lib.wholePath.c_str(), err)); +@@ -117,7 +128,7 @@ void internal_unload_lib_modules() + #if defined(__unix__) || defined(__APPLE__) + dlclose(lib.second.handle); + #else +- FreeLibrary(lib.second.handle); ++ FreeLibrary(static_cast(lib.second.handle)); + #endif + } + loaded_lib_handled.clear(); +diff --git a/src/MolaLauncherApp.cpp b/src/MolaLauncherApp.cpp +index d939bfe..37be9fc 100644 +--- a/src/MolaLauncherApp.cpp ++++ b/src/MolaLauncherApp.cpp +@@ -99,7 +99,7 @@ std::string relative_to_abs_path( + if (f.is_relative()) + { + f = fs::path(*basePath) / f; +- return f; ++ return f.string(); // no implicit conversion on Windows (wchar_t paths) + } + else + return path; diff --git a/shared/patch/ros2-mola-yaml.win.patch b/shared/patch/ros2-mola-yaml.win.patch new file mode 100644 index 000000000..7ef3e5962 --- /dev/null +++ b/shared/patch/ros2-mola-yaml.win.patch @@ -0,0 +1,22 @@ +diff --git a/include/mola_yaml/macro_helpers.h b/include/mola_yaml/macro_helpers.h +index 0f76953..cb7c4a4 100644 +--- a/include/mola_yaml/macro_helpers.h ++++ b/include/mola_yaml/macro_helpers.h +@@ -48,7 +48,10 @@ + // which corresponds to the actual argument count (up to 10 args supported). + // --------------------------------------------------------------------------- + #define MOLA_NARG(...) MOLA_NARG_I_(__VA_ARGS__, MOLA_RSEQ_N()) +-#define MOLA_NARG_I_(...) MOLA_ARG_N(__VA_ARGS__) ++// MSVC's traditional preprocessor passes __VA_ARGS__ on as one argument unless ++// it is rescanned through another macro: ++#define MOLA_EXPAND_(x) x ++#define MOLA_NARG_I_(...) MOLA_EXPAND_(MOLA_ARG_N(__VA_ARGS__)) + + /** Picks the 11th argument - used internally by MOLA_NARG. */ + #define MOLA_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N +@@ -80,4 +83,4 @@ + * @param func Base name of the macro family (without trailing digit). + * @param ... Arguments forwarded verbatim to the selected overload. + */ +-#define VFUNC(func, ...) MOLA_VFUNC(func, MOLA_NARG(__VA_ARGS__))(__VA_ARGS__) ++#define VFUNC(func, ...) MOLA_EXPAND_(MOLA_VFUNC(func, MOLA_NARG(__VA_ARGS__))(__VA_ARGS__)) diff --git a/shared/patch/ros2-mp2p-icp-core.patch b/shared/patch/ros2-mp2p-icp-core.patch new file mode 100644 index 000000000..42c17e283 --- /dev/null +++ b/shared/patch/ros2-mp2p-icp-core.patch @@ -0,0 +1,108 @@ +diff --git a/mp2p_icp/include/mp2p_icp/LogRecord.h b/mp2p_icp/include/mp2p_icp/LogRecord.h +--- a/mp2p_icp/include/mp2p_icp/LogRecord.h ++++ b/mp2p_icp/include/mp2p_icp/LogRecord.h +@@ -80,7 +80,7 @@ class LogRecord : public mrpt::serialization::CSerializable + + DECLARE_TTYPENAME_CLASSNAME(mp2p_icp::LogRecord::DebugInfoPerIteration) + }; +- using iteration_idx_t = std::size_t; ++ using iteration_idx_t = std::uint64_t; + using IterationsDetails = std::map; + + std::optional iterationsDetails; +diff --git a/mp2p_icp/src/Pairings.cpp b/mp2p_icp/src/Pairings.cpp +--- a/mp2p_icp/src/Pairings.cpp ++++ b/mp2p_icp/src/Pairings.cpp +@@ -57,7 +57,7 @@ void Pairings::serializeFrom(mrpt::serialization::CArchive& in) + { + // Removed in v3: per-point weights. Read and discard, for backward + // compatibility with older serialized icplog files. +- std::vector> unusedPointWeights; ++ std::vector> unusedPointWeights; + in >> unusedPointWeights; + } + if (readVersion >= 1) +diff --git a/mp2p_icp/src/Results.cpp b/mp2p_icp/src/Results.cpp +--- a/mp2p_icp/src/Results.cpp ++++ b/mp2p_icp/src/Results.cpp +@@ -25,7 +25,7 @@ static const uint8_t SERIALIZATION_VERSION = 1; + void Results::serializeTo(mrpt::serialization::CArchive& out) const + { + out.WriteAs(SERIALIZATION_VERSION); +- out << optimal_tf << optimalScale << nIterations; ++ out << optimal_tf << optimalScale << static_cast(nIterations); + out << static_cast(terminationReason); + out << quality; + finalPairings.serializeTo(out); +@@ -37,7 +37,8 @@ void Results::serializeFrom(mrpt::serialization::CArchive& in) + + ASSERT_LE_(readVersion, SERIALIZATION_VERSION); + +- in >> optimal_tf >> optimalScale >> nIterations; ++ in >> optimal_tf >> optimalScale; ++ nIterations = static_cast(in.ReadAs()); + terminationReason = static_cast(in.ReadAs()); + in >> quality; + finalPairings.serializeFrom(in); +diff --git a/mp2p_icp_common/src/load_plugin.cpp b/mp2p_icp_common/src/load_plugin.cpp +--- a/mp2p_icp_common/src/load_plugin.cpp ++++ b/mp2p_icp_common/src/load_plugin.cpp +@@ -27,7 +27,7 @@ + #include + namespace fs = std::filesystem; + +-#if defined(__unix__) ++#if defined(__unix__) || defined(__APPLE__) + #include + #endif + +@@ -72,6 +72,14 @@ void mp2p_icp::load_plugin( + { + std::string absPath; + ++#if defined(__APPLE__) ++ // Plugin names are usually given as "lib.so": use the macOS suffix. ++ if (fs::path(moduleToLoad).extension() == ".so") ++ { ++ return load_plugin(fs::path(moduleToLoad).replace_extension(".dylib").string(), logger); ++ } ++#endif ++ + if (!fs::path(moduleToLoad).is_relative()) + { + // already absolute: +@@ -83,6 +91,13 @@ void mp2p_icp::load_plugin( + // search for it: + std::vector lstPath; + from_env_var_to_list("LD_LIBRARY_PATH", lstPath); ++ // conda/RoboStack environments do not set LD_LIBRARY_PATH: also search ++ // /lib for every prefix in AMENT_PREFIX_PATH. ++ { ++ std::vector prefixes; ++ from_env_var_to_list("AMENT_PREFIX_PATH", prefixes); ++ for (const auto& prefix : prefixes) safe_add_to_list(prefix + "/lib", lstPath); ++ } + + for (const auto& p : lstPath) + { +@@ -101,7 +116,7 @@ void mp2p_icp::load_plugin( + } + } + +-#if defined(__unix__) ++#if defined(__unix__) || defined(__APPLE__) + // Check if already loaded? + { + void* handle = dlopen(absPath.c_str(), RTLD_NOLOAD); +diff --git a/tests/test-mp2p_Pairings.cpp b/tests/test-mp2p_Pairings.cpp +--- a/tests/test-mp2p_Pairings.cpp ++++ b/tests/test-mp2p_Pairings.cpp +@@ -149,7 +149,7 @@ void test_Pairings_BackwardCompatDeserialization() + MatchedLineList ln2ln; + MatchedPlaneList pl2pl; + // Old-format per-point weights block, no longer used by current code: +- std::vector> point_weights; ++ std::vector> point_weights; + point_weights.emplace_back(1, 2.5); + const uint64_t potential_pairings = 42; + MatchedPointWithCovList cov2cov; diff --git a/shared/patch/ros2-mp2p-icp-core.win.patch b/shared/patch/ros2-mp2p-icp-core.win.patch new file mode 100644 index 000000000..baa7458be --- /dev/null +++ b/shared/patch/ros2-mp2p-icp-core.win.patch @@ -0,0 +1,64 @@ +diff --git a/mp2p_icp_common/src/load_plugin.cpp b/mp2p_icp_common/src/load_plugin.cpp +index c3cf7d7..48d26eb 100644 +--- a/mp2p_icp_common/src/load_plugin.cpp ++++ b/mp2p_icp_common/src/load_plugin.cpp +@@ -29,6 +29,11 @@ namespace fs = std::filesystem; + + #if defined(__unix__) || defined(__APPLE__) + #include ++#elif defined(_WIN32) ++#ifndef NOMINMAX ++#define NOMINMAX ++#endif ++#include // LoadLibraryA() + #endif + + namespace +@@ -79,6 +84,16 @@ void mp2p_icp::load_plugin( + return load_plugin(fs::path(moduleToLoad).replace_extension(".dylib").string(), logger); + } + #endif ++#if defined(_WIN32) ++ // Plugin names are usually given as "lib.so": MSVC builds ".dll". ++ if (fs::path(moduleToLoad).extension() == ".so") ++ { ++ auto p = fs::path(moduleToLoad).replace_extension(".dll"); ++ auto name = p.filename().string(); ++ if (name.rfind("lib", 0) == 0) p.replace_filename(name.substr(3)); ++ return load_plugin(p.string(), logger); ++ } ++#endif + + if (!fs::path(moduleToLoad).is_relative()) + { +@@ -96,7 +111,11 @@ void mp2p_icp::load_plugin( + { + std::vector prefixes; + from_env_var_to_list("AMENT_PREFIX_PATH", prefixes); ++#if defined(_WIN32) ++ for (const auto& prefix : prefixes) safe_add_to_list(prefix + "/bin", lstPath); ++#else + for (const auto& prefix : prefixes) safe_add_to_list(prefix + "/lib", lstPath); ++#endif + } + + for (const auto& p : lstPath) +@@ -128,11 +147,17 @@ void mp2p_icp::load_plugin( + void* handle = dlopen(absPath.c_str(), RTLD_LAZY); + + #else +- HMODULE handle = LoadLibrary(absPath.c_str()); ++ void* handle = LoadLibraryA(absPath.c_str()); + #endif + if (handle == nullptr) + { ++#if defined(_WIN32) ++ const std::string err_str = ++ mrpt::format("LoadLibrary() error code %lu", static_cast(GetLastError())); ++ const char* err = err_str.c_str(); ++#else + const char* err = dlerror(); ++#endif + if (!err) + { + err = "(error calling dlerror())"; diff --git a/shared/patch/ros2-mp2p-icp-viz.patch b/shared/patch/ros2-mp2p-icp-viz.patch new file mode 100644 index 000000000..f7a6c7b61 --- /dev/null +++ b/shared/patch/ros2-mp2p-icp-viz.patch @@ -0,0 +1,13 @@ +diff --git a/apps/imgui_app_common/CMakeLists.txt b/apps/imgui_app_common/CMakeLists.txt +--- a/apps/imgui_app_common/CMakeLists.txt ++++ b/apps/imgui_app_common/CMakeLists.txt +@@ -20,4 +20,9 @@ find_package(Threads REQUIRED) + + target_link_libraries(${PROJECT_NAME} PUBLIC imgui::imgui Threads::Threads) + ++# libcfgpath (used here and by the apps) calls FSFindFolder() on macOS: ++if(APPLE) ++ target_link_libraries(${PROJECT_NAME} PUBLIC "-framework CoreServices") ++endif() ++ + target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_17) diff --git a/shared/patch/ros2-mrpt-gui.patch b/shared/patch/ros2-mrpt-gui.patch new file mode 100644 index 000000000..42b22cb5d --- /dev/null +++ b/shared/patch/ros2-mrpt-gui.patch @@ -0,0 +1,48 @@ +diff --git a/3rdparty/nanogui/CMakeLists.txt b/3rdparty/nanogui/CMakeLists.txt +--- a/3rdparty/nanogui/CMakeLists.txt ++++ b/3rdparty/nanogui/CMakeLists.txt +@@ -64,9 +64,9 @@ endif() + # ------------------------------------------------------------------------- + # Resource / Font Compilation + # ------------------------------------------------------------------------- +-find_file(ENTYPO_TTF_FILE entypo.ttf PATHS "${CMAKE_CURRENT_SOURCE_DIR}/resources" REQUIRED) +-find_file(ROBOTO_BOLD_TTF_FILE Roboto-Bold.ttf PATHS /usr/share/fonts/truetype/roboto-fontface/roboto/ "${CMAKE_CURRENT_SOURCE_DIR}/resources" REQUIRED) +-find_file(ROBOTO_REGULAR_TTF_FILE Roboto-Regular.ttf PATHS /usr/share/fonts/truetype/roboto-fontface/roboto/ "${CMAKE_CURRENT_SOURCE_DIR}/resources" REQUIRED) ++find_file(ENTYPO_TTF_FILE entypo.ttf PATHS "${CMAKE_CURRENT_SOURCE_DIR}/resources" NO_CMAKE_FIND_ROOT_PATH REQUIRED) ++find_file(ROBOTO_BOLD_TTF_FILE Roboto-Bold.ttf PATHS /usr/share/fonts/truetype/roboto-fontface/roboto/ "${CMAKE_CURRENT_SOURCE_DIR}/resources" NO_CMAKE_FIND_ROOT_PATH REQUIRED) ++find_file(ROBOTO_REGULAR_TTF_FILE Roboto-Regular.ttf PATHS /usr/share/fonts/truetype/roboto-fontface/roboto/ "${CMAKE_CURRENT_SOURCE_DIR}/resources" NO_CMAKE_FIND_ROOT_PATH REQUIRED) + + set(resources ${ENTYPO_TTF_FILE} ${ROBOTO_BOLD_TTF_FILE} ${ROBOTO_REGULAR_TTF_FILE}) + message(STATUS "Font resources: ${resources}") +diff --git a/cmake/script_nanogui.cmake b/cmake/script_nanogui.cmake +--- a/cmake/script_nanogui.cmake ++++ b/cmake/script_nanogui.cmake +@@ -4,11 +4,9 @@ + set(CMAKE_MRPT_HAS_NANOGUI 0) + set(CMAKE_MRPT_HAS_NANOGUI_SYSTEM 0) + +-if (APPLE) +- set(def_ OFF) +-else() +- set(def_ ON) +-endif() ++# RoboStack: also build nanogui on macOS (needed by mola_viz); it builds with GLFW and ++# OpenGL.framework. ++set(def_ ON) + set(MRPT_WITH_NANOGUI ${def_} CACHE BOOL "Build an embedded version of nanogui (OpenGL GUIs)") + unset(def_) + +diff --git a/src/error_box.cpp b/src/error_box.cpp +--- a/src/error_box.cpp ++++ b/src/error_box.cpp +@@ -22,7 +22,9 @@ + #else + #include + #endif // MRPT_HAS_Qt5 +-#if MRPT_HAS_WXWIDGETS ++// Only needed without Qt (see showErrorMessage()); on macOS the wx and Qt 5 headers ++// clash (NSData/NSString forward declarations). ++#if MRPT_HAS_WXWIDGETS && !MRPT_HAS_Qt5 + #include + #endif + diff --git a/shared/patch/ros2-mrpt-imgui-vendor.patch b/shared/patch/ros2-mrpt-imgui-vendor.patch new file mode 100644 index 000000000..10614efb9 --- /dev/null +++ b/shared/patch/ros2-mrpt-imgui-vendor.patch @@ -0,0 +1,13 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -141,6 +141,9 @@ + # Always PIC: a static vendor library gets linked into MRPT shared libraries. + set_target_properties(${PROJECT_NAME} PROPERTIES POSITION_INDEPENDENT_CODE TRUE) + ++# The GLFW/OpenGL3 backends call dlopen()/dlsym(), which live in libdl on glibc < 2.34. ++target_link_libraries(${PROJECT_NAME} PUBLIC ${CMAKE_DL_LIBS}) ++ + # Upstream headers are included unqualified (`#include "imgui.h"`), so the + # directory holding them must itself be on the interface include path. SYSTEM + # keeps third-party warnings out of consumers' builds. diff --git a/shared/patch/ros2-mrpt-maps.patch b/shared/patch/ros2-mrpt-maps.patch new file mode 100644 index 000000000..a1a92f6a7 --- /dev/null +++ b/shared/patch/ros2-mrpt-maps.patch @@ -0,0 +1,15 @@ +diff --git a/include/mrpt/maps/bonxai/bonxai.hpp b/include/mrpt/maps/bonxai/bonxai.hpp +--- a/include/mrpt/maps/bonxai/bonxai.hpp ++++ b/include/mrpt/maps/bonxai/bonxai.hpp +@@ -538,7 +538,10 @@ + { + dim_ = other.dim_; + size_ = other.size_; +- mask_ = std::move(other.mask_); ++ // Mask has const members, so it is not assignable (clang rejects this even if ++ // the operator is never instantiated): re-construct it in place instead. ++ mask_.~Mask(); ++ new (&mask_) Bonxai::Mask(std::move(other.mask_)); + std::swap(data_, other.data_); + return *this; + } diff --git a/shared/pkg_additional_info.yaml b/shared/pkg_additional_info.yaml index 4db4b4fd2..a4294d623 100644 --- a/shared/pkg_additional_info.yaml +++ b/shared/pkg_additional_info.yaml @@ -106,6 +106,8 @@ libpointmatcher: then: "-DINSTALL_CMAKE_DIR=share/libpointmatcher/cmake" moveit_ros_visualization: additional_cmake_args: "-DCMAKE_WINDOWS_EXPORT_ALL_SYMBOLS=ON" +mrpt_libros_bridge: # exports no symbols on Windows: no import library for its tests + additional_cmake_args: "-DCMAKE_WINDOWS_EXPORT_ALL_SYMBOLS=ON" mujoco_vendor: additional_cmake_args: "-DAMENT_VENDOR_POLICY=NEVER_VENDOR_IGNORE_SATISFIED_CHECK" octomap_ros: diff --git a/shared/robostack.yaml b/shared/robostack.yaml index c2880a076..d286b3971 100644 --- a/shared/robostack.yaml +++ b/shared/robostack.yaml @@ -56,6 +56,8 @@ clang-format: robostack: [clang-format] clang-tidy: robostack: [clang-tools] +cli11: + robostack: [cli11] cmake: robostack: [cmake] coinor-libcbc-dev: diff --git a/shared/tests/ros2-mola.yaml b/shared/tests/ros2-mola.yaml new file mode 100644 index 000000000..a08e566e9 --- /dev/null +++ b/shared/tests/ros2-mola.yaml @@ -0,0 +1,5 @@ +tests: + # mola-cli must find the module libraries of a conda environment without any environment + # variable (shared/patch/ros2-mola-launcher.patch) and register their classes. + - script: + - python -c "import subprocess; out = subprocess.run(['mola-cli', '--rtti-list-all'], capture_output=True, text=True).stdout; missing = [c for c in ('mola::MolaViz', 'mola::BridgeROS2', 'mola::Rosbag2Dataset', 'mola::KeyframePointCloudMap') if c not in out]; assert not missing, missing" diff --git a/shared/vinca.yaml b/shared/vinca.yaml index 16ad91a96..fe1eae88d 100644 --- a/shared/vinca.yaml +++ b/shared/vinca.yaml @@ -186,6 +186,7 @@ packages_select_by_deps: - mocap4r2_msgs - mocap4r2_robot_gt - mocap4r2_robot_gt_msgs + - mola # requested in https://github.com/RoboStack/robostack/issues/106 - motion_capture_tracking - mouse_teleop - moveit