From ca183990bd2ab9118f1b70c5cadd0821131fcd56 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 27 Oct 2026 04:42:57 +0000 Subject: [PATCH 1/6] Add openocean-messages and moos-ivp as submodules, and an init script external/openocean-messages and external/moos-ivp are pinned at their main branches; moos-ivp is shallow, since its full history is about 160 MB. init.sh checks out the submodules and installs the Ubuntu packages to build them and IvPico: openocean-messages' C++ dependencies (through its own init.sh --cxx), Protobuf, and the compiler and build tools for moos-ivp's libraries and non-GUI apps. The README describes the build. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01VLcYK4e29B5FiPbDDJy5fp --- .gitmodules | 7 +++++++ README.md | 19 +++++++++++++++++-- external/moos-ivp | 1 + external/openocean-messages | 1 + init.sh | 33 +++++++++++++++++++++++++++++++++ 5 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 .gitmodules create mode 160000 external/moos-ivp create mode 160000 external/openocean-messages create mode 100755 init.sh diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..82f6e36 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,7 @@ +[submodule "external/openocean-messages"] + path = external/openocean-messages + url = https://github.com/openocean-software/openocean-messages.git +[submodule "external/moos-ivp"] + path = external/moos-ivp + url = https://github.com/GobySoft/moos-ivp.git + shallow = true diff --git a/README.md b/README.md index 2f1ac14..1fa5e05 100644 --- a/README.md +++ b/README.md @@ -15,14 +15,29 @@ One way to think of this project is as a generator for the equivalent of the MOO - bin: Binary source - goby: Goby middleware app - ros: ROS middleware node +- external: Submodules + - openocean-messages: [openocean-messages](https://github.com/openocean-software/openocean-messages), for the `Navigation` and `ControlSetpoint` messages + - moos-ivp: [MOOS-IvP](https://github.com/GobySoft/moos-ivp), for the IvP solver and behaviors ## Building *This section was written by Claude.* -The interface messages use `Navigation` and `ControlSetpoint` from [openocean-messages](https://github.com/openocean-software/openocean-messages), found with `find_package(openocean_messages)`: install it, or point CMake at its build directory: +`init.sh` checks out the submodules and installs the Ubuntu packages needed to build them and IvPico. Then build openocean-messages and point IvPico at it: ``` -cmake -S . -B build -Dopenocean_messages_DIR=/path/to/openocean-messages/build +./init.sh +external/openocean-messages/build.sh +cmake -S . -B build -Dopenocean_messages_DIR=$PWD/external/openocean-messages/build cmake --build build ``` + +MOOS-IvP isn't built by IvPico yet. To build its libraries and non-GUI apps (MOOSGeodesy downloads PROJ while building): + +``` +cd external/moos-ivp +./build-moos.sh +./build-ivp.sh --nogui +``` + +To update a submodule, check out the commit you want in it and commit the new pointer, e.g. `git -C external/openocean-messages pull origin main && git add external/openocean-messages`. diff --git a/external/moos-ivp b/external/moos-ivp new file mode 160000 index 0000000..68d862f --- /dev/null +++ b/external/moos-ivp @@ -0,0 +1 @@ +Subproject commit 68d862fbd5fe4a3bb697af513cac0d60efd63259 diff --git a/external/openocean-messages b/external/openocean-messages new file mode 160000 index 0000000..11a1328 --- /dev/null +++ b/external/openocean-messages @@ -0,0 +1 @@ +Subproject commit 11a132839af11befb3d858f4a4b3570d9dc013e5 diff --git a/init.sh b/init.sh new file mode 100755 index 0000000..9c1c260 --- /dev/null +++ b/init.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +# Checks out the submodules and installs the Ubuntu packages needed to build them and IvPico. +# +# Usage: init.sh +set -euo pipefail + +cd "$(dirname "$0")" + +case "${1:-}" in + "") ;; + -h | --help) + sed -n '4p' "$0" | sed 's/^# //' + exit 0 + ;; + *) + sed -n '4p' "$0" | sed 's/^# //' >&2 + exit 1 + ;; +esac + +git submodule update --init --recommend-shallow + +SUDO="" +if [ "$(id -u)" -ne 0 ]; then + SUDO=sudo +fi + +# moos-ivp's libraries and non-GUI apps (build-ivp.sh --nogui), so not FLTK and the X libraries +packages=(cmake make g++ git ca-certificates protobuf-compiler libprotobuf-dev) +$SUDO apt-get update +$SUDO env DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends "${packages[@]}" + +external/openocean-messages/init.sh --cxx From 5946aec2878561286aab5d8da31c9b23f66dfefa Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 27 Oct 2026 04:45:24 +0000 Subject: [PATCH 2/6] Build MOOS without its GUI tools in the README's steps build-moos.sh builds MOOSToolsUI, which needs FLTK, unless given --minrobot; build-ivp.sh's equivalent is --nogui. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01VLcYK4e29B5FiPbDDJy5fp --- README.md | 4 ++-- init.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1fa5e05..b75f172 100644 --- a/README.md +++ b/README.md @@ -32,11 +32,11 @@ cmake -S . -B build -Dopenocean_messages_DIR=$PWD/external/openocean-messages/bu cmake --build build ``` -MOOS-IvP isn't built by IvPico yet. To build its libraries and non-GUI apps (MOOSGeodesy downloads PROJ while building): +MOOS-IvP isn't built by IvPico yet. To build its libraries and non-GUI apps (`build-moos.sh` calls skipping its GUI tools `--minrobot`, and MOOSGeodesy downloads PROJ while building): ``` cd external/moos-ivp -./build-moos.sh +./build-moos.sh --minrobot ./build-ivp.sh --nogui ``` diff --git a/init.sh b/init.sh index 9c1c260..23138b6 100755 --- a/init.sh +++ b/init.sh @@ -25,7 +25,7 @@ if [ "$(id -u)" -ne 0 ]; then SUDO=sudo fi -# moos-ivp's libraries and non-GUI apps (build-ivp.sh --nogui), so not FLTK and the X libraries +# moos-ivp without its GUI tools (build-moos.sh --minrobot, build-ivp.sh --nogui), so not FLTK or X packages=(cmake make g++ git ca-certificates protobuf-compiler libprotobuf-dev) $SUDO apt-get update $SUDO env DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends "${packages[@]}" From 5f6c8f36c40358804e0f17f34d07154a343e9439 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 27 Oct 2026 04:47:32 +0000 Subject: [PATCH 3/6] Install patch, which MOOSGeodesy needs to patch the PROJ it downloads Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01VLcYK4e29B5FiPbDDJy5fp --- init.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/init.sh b/init.sh index 23138b6..05a6258 100755 --- a/init.sh +++ b/init.sh @@ -25,8 +25,9 @@ if [ "$(id -u)" -ne 0 ]; then SUDO=sudo fi -# moos-ivp without its GUI tools (build-moos.sh --minrobot, build-ivp.sh --nogui), so not FLTK or X -packages=(cmake make g++ git ca-certificates protobuf-compiler libprotobuf-dev) +# moos-ivp without its GUI tools (build-moos.sh --minrobot, build-ivp.sh --nogui), so not FLTK or X. +# MOOSGeodesy downloads PROJ and patches it while building. +packages=(cmake make g++ patch git ca-certificates protobuf-compiler libprotobuf-dev) $SUDO apt-get update $SUDO env DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends "${packages[@]}" From 90fd647494a1ce8461f564efefaf0333d4c8c822 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 27 Oct 2026 04:54:07 +0000 Subject: [PATCH 4/6] Add build.sh, which builds openocean-messages and then IvPico into build/ openocean-messages builds from its submodule into build/external, so the checkout stays clean, and IvPico finds it there. init.sh now installs Ninja for it. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01VLcYK4e29B5FiPbDDJy5fp --- README.md | 8 ++++---- build.sh | 17 +++++++++++++++++ init.sh | 2 +- 3 files changed, 22 insertions(+), 5 deletions(-) create mode 100755 build.sh diff --git a/README.md b/README.md index b75f172..af7f262 100644 --- a/README.md +++ b/README.md @@ -23,15 +23,15 @@ One way to think of this project is as a generator for the equivalent of the MOO *This section was written by Claude.* -`init.sh` checks out the submodules and installs the Ubuntu packages needed to build them and IvPico. Then build openocean-messages and point IvPico at it: +`init.sh` checks out the submodules and installs the Ubuntu packages needed to build them and IvPico. `build.sh` then builds openocean-messages from its submodule (into `build/external/openocean-messages`) and IvPico against it (into `build/`): ``` ./init.sh -external/openocean-messages/build.sh -cmake -S . -B build -Dopenocean_messages_DIR=$PWD/external/openocean-messages/build -cmake --build build +./build.sh ``` +`build.sh` passes any arguments on to IvPico's CMake, and `BUILD_DIR` overrides the build directory. + MOOS-IvP isn't built by IvPico yet. To build its libraries and non-GUI apps (`build-moos.sh` calls skipping its GUI tools `--minrobot`, and MOOSGeodesy downloads PROJ while building): ``` diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..32243c6 --- /dev/null +++ b/build.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +# Builds openocean-messages from its submodule, then IvPico against it, all in BUILD_DIR (default +# build). Arguments are passed on to IvPico's cmake. +set -euo pipefail + +cd "$(dirname "$0")" +if [ ! -e external/openocean-messages/CMakeLists.txt ]; then + echo "external/openocean-messages is empty: run ./init.sh first" >&2 + exit 1 +fi +BUILD_DIR=$(realpath -m "${BUILD_DIR:-build}") +OPENOCEAN_BUILD_DIR=${BUILD_DIR}/external/openocean-messages + +BUILD_DIR=${OPENOCEAN_BUILD_DIR} external/openocean-messages/build.sh -DBUILD_TESTING=OFF + +cmake -S . -B "${BUILD_DIR}" -G Ninja -Dopenocean_messages_DIR="${OPENOCEAN_BUILD_DIR}" "$@" +ninja -C "${BUILD_DIR}" diff --git a/init.sh b/init.sh index 05a6258..3d5e86c 100755 --- a/init.sh +++ b/init.sh @@ -27,7 +27,7 @@ fi # moos-ivp without its GUI tools (build-moos.sh --minrobot, build-ivp.sh --nogui), so not FLTK or X. # MOOSGeodesy downloads PROJ and patches it while building. -packages=(cmake make g++ patch git ca-certificates protobuf-compiler libprotobuf-dev) +packages=(cmake ninja-build make g++ patch git ca-certificates protobuf-compiler libprotobuf-dev) $SUDO apt-get update $SUDO env DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends "${packages[@]}" From 93380b4d8097db3cb5bc8802dc584be5f33fd825 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 27 Oct 2026 05:12:43 +0000 Subject: [PATCH 5/6] Build MOOS-IvP's helm libraries in build.sh and find them with find_package(IVP) external/moos-ivp moves to GobySoft/moos-ivp's helm-libraries branch, which adds IVP_BUILD_HELM_LIBS_ONLY: lib_helmivp and the libraries it links, without MOOS or its apps, optionally as shared libraries. build.sh builds them shared into build/external/moos-ivp and installs them into build/external/install, since find_package(IVP) only works from an installation; nothing is built in the submodule. CMake finds them with find_package(IVP CONFIG), and the helm_libs test creates waypoint and COLREGS behaviors and solves a course with them. init.sh no longer installs make and patch, which only the full MOOS build needed. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01VLcYK4e29B5FiPbDDJy5fp --- CMakeLists.txt | 5 +++ README.md | 15 ++++----- build.sh | 31 ++++++++++++++----- external/moos-ivp | 2 +- init.sh | 5 ++- src/CMakeLists.txt | 4 +++ src/test/CMakeLists.txt | 3 ++ src/test/check_helm_libs.cpp | 59 ++++++++++++++++++++++++++++++++++++ 8 files changed, 104 insertions(+), 20 deletions(-) create mode 100644 src/test/CMakeLists.txt create mode 100644 src/test/check_helm_libs.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b847828..78324dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,4 +9,9 @@ endif() set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") +# MOOS-IvP's helm libraries (IVP_BUILD_HELM_LIBS_ONLY) +find_package(IVP CONFIG REQUIRED) + +include(CTest) + add_subdirectory(src) diff --git a/README.md b/README.md index af7f262..9421a49 100644 --- a/README.md +++ b/README.md @@ -23,21 +23,18 @@ One way to think of this project is as a generator for the equivalent of the MOO *This section was written by Claude.* -`init.sh` checks out the submodules and installs the Ubuntu packages needed to build them and IvPico. `build.sh` then builds openocean-messages from its submodule (into `build/external/openocean-messages`) and IvPico against it (into `build/`): +`init.sh` checks out the submodules and installs the Ubuntu packages needed to build them and IvPico. `build.sh` then builds, all in `build/`: + +- openocean-messages, into `build/external/openocean-messages`; +- MOOS-IvP's helm libraries (`IVP_BUILD_HELM_LIBS_ONLY`, as shared libraries, without MOOS or its apps), into `build/external/moos-ivp`, installed into `build/external/install` for `find_package(IVP)`; +- IvPico, against both. ``` ./init.sh ./build.sh +ctest --test-dir build ``` `build.sh` passes any arguments on to IvPico's CMake, and `BUILD_DIR` overrides the build directory. -MOOS-IvP isn't built by IvPico yet. To build its libraries and non-GUI apps (`build-moos.sh` calls skipping its GUI tools `--minrobot`, and MOOSGeodesy downloads PROJ while building): - -``` -cd external/moos-ivp -./build-moos.sh --minrobot -./build-ivp.sh --nogui -``` - To update a submodule, check out the commit you want in it and commit the new pointer, e.g. `git -C external/openocean-messages pull origin main && git add external/openocean-messages`. diff --git a/build.sh b/build.sh index 32243c6..bfbe048 100755 --- a/build.sh +++ b/build.sh @@ -1,17 +1,34 @@ #!/usr/bin/env bash -# Builds openocean-messages from its submodule, then IvPico against it, all in BUILD_DIR (default -# build). Arguments are passed on to IvPico's cmake. +# Builds the dependencies from their submodules (openocean-messages, and MOOS-IvP's helm libraries), +# then IvPico against them, all in BUILD_DIR (default build). Arguments are passed on to IvPico's +# cmake. set -euo pipefail cd "$(dirname "$0")" -if [ ! -e external/openocean-messages/CMakeLists.txt ]; then - echo "external/openocean-messages is empty: run ./init.sh first" >&2 - exit 1 -fi +for submodule in openocean-messages moos-ivp; do + if [ -z "$(ls -A "external/${submodule}")" ]; then + echo "external/${submodule} is empty: run ./init.sh first" >&2 + exit 1 + fi +done BUILD_DIR=$(realpath -m "${BUILD_DIR:-build}") OPENOCEAN_BUILD_DIR=${BUILD_DIR}/external/openocean-messages +IVP_BUILD_DIR=${BUILD_DIR}/external/moos-ivp +# find_package(IVP) only works from an installation +IVP_INSTALL_DIR=${BUILD_DIR}/external/install BUILD_DIR=${OPENOCEAN_BUILD_DIR} external/openocean-messages/build.sh -DBUILD_TESTING=OFF -cmake -S . -B "${BUILD_DIR}" -G Ninja -Dopenocean_messages_DIR="${OPENOCEAN_BUILD_DIR}" "$@" +cmake -S external/moos-ivp/ivp/src -B "${IVP_BUILD_DIR}" -G Ninja \ + -DIVP_BUILD_HELM_LIBS_ONLY=ON -DBUILD_SHARED_LIBS=ON \ + -DIVP_LIB_DIRECTORY="${IVP_BUILD_DIR}/lib" \ + -DIVP_INC_DIRECTORY="${IVP_BUILD_DIR}/include" \ + -DIVP_BIN_DIRECTORY="${IVP_BUILD_DIR}/bin" +ninja -C "${IVP_BUILD_DIR}" +cmake --install "${IVP_BUILD_DIR}" --prefix "${IVP_INSTALL_DIR}" > /dev/null + +cmake -S . -B "${BUILD_DIR}" -G Ninja \ + -Dopenocean_messages_DIR="${OPENOCEAN_BUILD_DIR}" \ + -DIVP_DIR="${IVP_INSTALL_DIR}/lib/cmake/IVP" \ + "$@" ninja -C "${BUILD_DIR}" diff --git a/external/moos-ivp b/external/moos-ivp index 68d862f..be40e2c 160000 --- a/external/moos-ivp +++ b/external/moos-ivp @@ -1 +1 @@ -Subproject commit 68d862fbd5fe4a3bb697af513cac0d60efd63259 +Subproject commit be40e2c7cef168be29f57a756df6a16a1c7882f1 diff --git a/init.sh b/init.sh index 3d5e86c..1821fc7 100755 --- a/init.sh +++ b/init.sh @@ -25,9 +25,8 @@ if [ "$(id -u)" -ne 0 ]; then SUDO=sudo fi -# moos-ivp without its GUI tools (build-moos.sh --minrobot, build-ivp.sh --nogui), so not FLTK or X. -# MOOSGeodesy downloads PROJ and patches it while building. -packages=(cmake ninja-build make g++ patch git ca-certificates protobuf-compiler libprotobuf-dev) +# moos-ivp's helm libraries (IVP_BUILD_HELM_LIBS_ONLY) need only CMake and a compiler +packages=(cmake ninja-build g++ git ca-certificates protobuf-compiler libprotobuf-dev) $SUDO apt-get update $SUDO env DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends "${packages[@]}" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1d235e1..9489610 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,2 +1,6 @@ add_subdirectory(lib) add_subdirectory(bin) + +if(BUILD_TESTING) + add_subdirectory(test) +endif() diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt new file mode 100644 index 0000000..6631915 --- /dev/null +++ b/src/test/CMakeLists.txt @@ -0,0 +1,3 @@ +add_executable(check_helm_libs check_helm_libs.cpp) +target_link_libraries(check_helm_libs PRIVATE IVP::helmivp IVP::ivpbuild IVP::ivpsolve IVP::ivpcore) +add_test(NAME helm_libs COMMAND check_helm_libs) diff --git a/src/test/check_helm_libs.cpp b/src/test/check_helm_libs.cpp new file mode 100644 index 0000000..0168326 --- /dev/null +++ b/src/test/check_helm_libs.cpp @@ -0,0 +1,59 @@ +// Checks that IvPico can use MOOS-IvP's helm libraries (external/moos-ivp, built by build.sh): +// +// 1. The static behavior factory creates behaviors from lib_behaviors-marine +// and lib_behaviors-colregs, which loads every helm library. +// 2. The IvP solver finds the peak of a one-function problem over course. +// +// Prints one line per problem and exits non-zero if there were any. + +#include +#include +#include + +#include "BFactoryStatic.h" +#include "IvPBehavior.h" +#include "IvPDomain.h" +#include "IvPProblem.h" +#include "ZAIC_PEAK.h" + +int main() +{ + int errors = 0; + + IvPDomain domain; + domain.addDomain("course", 0, 359, 360); + domain.addDomain("speed", 0, 4, 41); + + BFactoryStatic factory; + factory.setDomain(domain); + for (const std::string type : {"BHV_Waypoint", "BHV_AvdColregsV22"}) + { + IvPBehavior* behavior = factory.newBehavior(type); + if (!behavior) + { + std::cerr << "failed: no " << type << " from BFactoryStatic\n"; + ++errors; + } + delete behavior; + } + + IvPDomain course; + course.addDomain("course", 0, 359, 360); + ZAIC_PEAK zaic(course, "course"); + zaic.setSummit(90); + zaic.setBaseWidth(90); + zaic.setValueWrap(true); + + IvPProblem problem; + problem.setDomain(course); + problem.addOF(zaic.extractIvPFunction()); + problem.solve(); + const double result = problem.getResult("course"); + if (std::fabs(result - 90) > 1) + { + std::cerr << "failed: solved course " << result << ", not 90\n"; + ++errors; + } + + return errors == 0 ? 0 : 1; +} From 229a8e2e261fa991355a973091dbdef8b0836682 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 27 Oct 2026 05:26:18 +0000 Subject: [PATCH 6/6] Add CI: build the dependencies and IvPico on Ubuntu 24.04 and 26.04, amd64 and arm64 Each job runs init.sh, build.sh, and the tests in a clean Ubuntu container, so it catches any dependency init.sh doesn't install. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01VLcYK4e29B5FiPbDDJy5fp --- .github/workflows/ci.yml | 43 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..9282590 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,43 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + workflow_dispatch: + +defaults: + run: + shell: bash + +env: + DEBIAN_FRONTEND: noninteractive + +jobs: + build: + name: Ubuntu ${{ matrix.ubuntu }} (${{ matrix.arch }}) + runs-on: ${{ matrix.runner }} + container: ubuntu:${{ matrix.ubuntu }} + strategy: + fail-fast: false + matrix: + ubuntu: ["24.04", "26.04"] + arch: [amd64, arm64] + include: + - arch: amd64 + runner: ubuntu-24.04 + - arch: arm64 + runner: ubuntu-24.04-arm + steps: + # Without git, actions/checkout downloads an archive, and init.sh can't check out the submodules + - name: Install git + run: apt-get update && apt-get install -y --no-install-recommends ca-certificates git + - uses: actions/checkout@v5 + - name: Install dependencies + run: | + git config --global --add safe.directory '*' + ./init.sh + - name: Build + run: ./build.sh + - name: Test + run: ctest --test-dir build --output-on-failure --no-tests=error