|
| 1 | +# AGENTS.md |
| 2 | + |
| 3 | +Working notes for future coding agents in a RoboStack repo. Replace $DISTRO with e.g. noetic/humble/kilted and so forth; you can check the working directory. |
| 4 | + |
| 5 | +## Session defaults for this repo |
| 6 | + |
| 7 | +- Prefer fixing easy, low-risk build failures first (one-line CMake / include / standard-level fixes). |
| 8 | +- Do not stop to ask the maintainer to run commands; run build/debug loops directly. |
| 9 | +- Use checked-out sources in `.pixi` and `output/src_cache` when patching. |
| 10 | +- Use `./build_gap_report.py` to track build/recipe gaps across platforms: |
| 11 | + - `Built package artifacts without matching recipe directory`: packages built in `output/<platform>` that are not represented as recipe folders. |
| 12 | + - `Recipe directories without built artifact on this platform`: generated recipes that still need successful builds for that platform. |
| 13 | +- If a package is truly Linux-only, move it to Linux-only handling in `vinca.yaml` (or non-linux skip), instead of keeping ad-hoc macOS comments. Follow similar strategies for other platforms such as Windows. |
| 14 | +- For patch naming, keep one patch per package and use package-based naming (`patch/ros-$DISTRO-<pkg>.patch`) with no extra suffix variants. |
| 15 | + |
| 16 | +## Standard build loop |
| 17 | + |
| 18 | +```bash |
| 19 | +# single package (preferred for debugging) |
| 20 | +pixi run build-one --package ros-$DISTRO-<pkg> |
| 21 | + |
| 22 | +# broad pass when needed |
| 23 | +pixi run build_continue_on_failure |
| 24 | +``` |
| 25 | + |
| 26 | +## Common fix patterns seen in this repo |
| 27 | + |
| 28 | +- Boost 1.88 breakages often need C++14 (`-std=c++14`) instead of `-std=c++11`. |
| 29 | +- Avoid linking to `Python::Python` on Apple for module-style targets; use: |
| 30 | + |
| 31 | +```cmake |
| 32 | +if( APPLE ) |
| 33 | + set_target_properties( ${_name} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup" ) |
| 34 | +else() |
| 35 | + target_link_libraries( ${_name} ${PYTHON_LIBRARIES} ) |
| 36 | +endif() |
| 37 | +``` |
| 38 | + |
| 39 | +- For gtest-related failures, prefer dependency or test-disable fixes over custom shims: |
| 40 | + - add dependency via `patch/dependencies.yaml`, or |
| 41 | + - disable tests when safe. |
| 42 | +- For rtabmap RViz plugin issues, force/confirm Qt5 discovery in CMake where needed. |
| 43 | + |
| 44 | +## Debug a failed build |
| 45 | + |
| 46 | +### 1. Find the work directory |
| 47 | + |
| 48 | +```bash |
| 49 | +tail -1 output/rattler-build-log.txt |
| 50 | +``` |
| 51 | + |
| 52 | +### 2. Inspect full log |
| 53 | + |
| 54 | +Read `conda_build.log` in the work dir. Focus on: |
| 55 | +- compile errors |
| 56 | +- link errors |
| 57 | +- configure failures |
| 58 | +- patch failures |
| 59 | +- missing files |
| 60 | + |
| 61 | +### 3. Inspect build env |
| 62 | + |
| 63 | +Read `build_env.sh` in the work dir: |
| 64 | +- `PREFIX` |
| 65 | +- `BUILD_PREFIX` |
| 66 | +- `SRC_DIR` |
| 67 | +- `RECIPE_DIR` |
| 68 | + |
| 69 | +### 4. Check fetched source metadata |
| 70 | + |
| 71 | +```bash |
| 72 | +cat .source_info.json | jq . |
| 73 | +``` |
| 74 | + |
| 75 | +### 5. Investigate by failure class |
| 76 | + |
| 77 | +- Missing headers: check `requirements.host`; verify under `$PREFIX/include`. |
| 78 | +- Undefined symbols: check host deps, `$PREFIX/lib`, linker flags. |
| 79 | +- Configure failures: inspect flags in `conda_build.sh`; rerun manually with verbosity. |
| 80 | +- Patch failures: refresh patch against current source revision. |
| 81 | +- Relocatability issues: inspect hardcoded prefixes/rpaths. |
| 82 | + |
| 83 | +### 6. Reproduce interactively |
| 84 | + |
| 85 | +```bash |
| 86 | +cd <work-directory> |
| 87 | +source build_env.sh |
| 88 | +bash -x conda_build.sh 2>&1 | less |
| 89 | +``` |
| 90 | + |
| 91 | +### 7. Rebuild package |
| 92 | + |
| 93 | +```bash |
| 94 | +pixi run build-one --package ros-$DISTRO-<pkg> |
| 95 | +``` |
| 96 | + |
| 97 | +## Create a patch from build-directory edits |
| 98 | + |
| 99 | +```bash |
| 100 | +WORK_DIR=$(tail -1 output/rattler-build-log.txt) |
| 101 | +cd "$WORK_DIR" |
| 102 | + |
| 103 | +# preview first |
| 104 | +rattler-build create-patch --directory . --name <patch-name> --dry-run |
| 105 | + |
| 106 | +# with excludes if needed |
| 107 | +rattler-build create-patch \ |
| 108 | + --directory . \ |
| 109 | + --name <patch-name> \ |
| 110 | + --exclude "*.o,*.so,*.dylib,*.a,*.pyc,__pycache__,build/" \ |
| 111 | + --dry-run |
| 112 | + |
| 113 | +# generate |
| 114 | +rattler-build create-patch \ |
| 115 | + --directory . \ |
| 116 | + --name <patch-name> \ |
| 117 | + --exclude "*.o,*.so,*.dylib,*.a,*.pyc,__pycache__,build/" |
| 118 | +``` |
| 119 | + |
| 120 | +Then move/merge patch into repo package patch file and ensure recipe uses it. |
| 121 | + |
| 122 | +## Validate that patches still apply |
| 123 | + |
| 124 | +Use the patch checker before/after large patch edits: |
| 125 | + |
| 126 | +```bash |
| 127 | +pixi run check-patches |
| 128 | +``` |
| 129 | + |
| 130 | +For faster iteration on one package patch, run the script directly with a recipe filter: |
| 131 | + |
| 132 | +```bash |
| 133 | +# prepare + check only one recipe |
| 134 | +python check_patches_clean_apply.py --recipe ros-$DISTRO-<pkg> |
| 135 | + |
| 136 | +# prepare only (no build), useful while editing |
| 137 | +python check_patches_clean_apply.py --dry --recipe ros-$DISTRO-<pkg> |
| 138 | + |
| 139 | +# multiple focused recipes |
| 140 | +python check_patches_clean_apply.py --recipe ros-$DISTRO-<pkg1> --recipe ros-$DISTRO-<pkg2> |
| 141 | +``` |
| 142 | + |
| 143 | +What it does: |
| 144 | +- scans all `recipes/**/recipe.yaml` |
| 145 | +- keeps only recipes that declare `source.patches` |
| 146 | +- creates `recipes_only_patch/` with minimal patch-check recipes |
| 147 | +- runs patch application checks recipe-by-recipe and prints a pass/fail summary |
| 148 | + |
| 149 | +## Patch placement and recipe wiring |
| 150 | + |
| 151 | +- Canonical patch location: `patch/ros-$DISTRO-<pkg>.patch` |
| 152 | +- Keep recipe copy in `recipes/ros-$DISTRO-<pkg>/patch/` if this repo flow expects it. |
| 153 | +- Ensure `recipes/ros-$DISTRO-<pkg>/recipe.yaml` has: |
| 154 | + |
| 155 | +```yaml |
| 156 | +source: |
| 157 | + patches: |
| 158 | + - patch/ros-$DISTRO-<pkg>.patch |
| 159 | +``` |
| 160 | +
|
| 161 | +## Parallelization and dependency-aware scheduling |
| 162 | +
|
| 163 | +It is worth splitting work across multiple agents, but only for independent packages. |
| 164 | +
|
| 165 | +Rules: |
| 166 | +- Do not build dependent packages in parallel. |
| 167 | +- Infer dependency relationships from `recipes/ros-$DISTRO-<pkg>/recipe.yaml` (`requirements.host` and `requirements.run`). |
| 168 | +- If package A depends on package B (for example `rosmon` -> `rosmon-core`), build/fix B first. |
| 169 | +- Run parallel lanes only for packages that do not depend on each other. |
| 170 | +- If unsure, serialize the builds. |
| 171 | + |
| 172 | +## Inspect a built conda package |
| 173 | + |
| 174 | +```bash |
| 175 | +find output/ -name "*<package-name>*" -type f \( -name "*.conda" -o -name "*.tar.bz2" \) |
| 176 | +``` |
| 177 | + |
| 178 | +For `.conda` artifacts: |
| 179 | + |
| 180 | +```bash |
| 181 | +TMPDIR=$(mktemp -d) |
| 182 | +cd "$TMPDIR" |
| 183 | +unzip -q <package.conda> |
| 184 | +zstd -d < pkg-*.tar.zst | tar -xvf - |
| 185 | +zstd -d < info-*.tar.zst | tar -xvf - |
| 186 | +``` |
| 187 | + |
| 188 | +Check: |
| 189 | +- `info/index.json` (deps/build string) |
| 190 | +- `info/paths.json` (installed files) |
| 191 | +- binaries/libs/rpaths (`otool -L` on macOS) |
| 192 | +- hardcoded prefixes in text metadata |
| 193 | + |
| 194 | +## `vinca.yaml` maintenance guidelines |
| 195 | + |
| 196 | +- Add package seeds under `packages_select_by_deps` using ROS package names (dash/underscore accepted). |
| 197 | +- Use platform conditions for Linux-only packages; avoid temporary macOS comment blocks. |
| 198 | +- Keep `packages_skip_by_deps` and `packages_remove_from_deps` coherent with platform constraints. |
| 199 | +- When `build_gap_report.py` shows built artifacts without recipe directories, add those package seeds to `vinca.yaml`. |
| 200 | +- After `vinca.yaml` edits, regenerate recipes before expecting `build_gap_report.py` results to change. |
| 201 | + |
| 202 | +## Local contribution workflow (RoboStack) |
| 203 | + |
| 204 | +```bash |
| 205 | +pixi run build |
| 206 | +``` |
| 207 | + |
| 208 | +## Full rebuilds |
| 209 | +For full rebuilds also remember: |
| 210 | +- refresh snapshot: `pixi run create_snapshot` |
| 211 | +- update `conda_build_config.yaml` for active migrations. You can use https://github.com/conda-forge/conda-forge-pinning-feedstock/blob/main/recipe/conda_build_config.yaml as a base, and then also apply migrations that are mostly done; you can check the status at https://conda-forge.org/status/. |
| 212 | +- bump `build_number` |
| 213 | +- bump mutex minor and update hardcoded mutex refs where needed |
| 214 | +- clear stale `pkg_additional_info.yaml` build-number overrides unless intentional |
| 215 | +- remember that in CI there is a build cache, if you fix a problem in an already built package you need to delete the cache for this package in the .github/workflows/testpr.yml under "Delete specific outdated cache entries" |
| 216 | + |
| 217 | +## Practical triage order |
| 218 | + |
| 219 | +1. Build a failing package directly. |
| 220 | +2. Apply smallest viable source or recipe fix. |
| 221 | +3. Update package patch file (package-named). |
| 222 | +4. Rebuild same package. |
| 223 | +5. Move on immediately if it becomes complex; prioritize easy wins. |
| 224 | +6. Revisit hard failures after reducing the failure queue. |
0 commit comments