Skip to content

Instantly share code, notes, and snippets.

@okalachev
Forked from urpylka/README.md
Created August 27, 2019 21:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save okalachev/1fcc749e3432df1a0dbead04c1a39221 to your computer and use it in GitHub Desktop.
Save okalachev/1fcc749e3432df1a0dbead04c1a39221 to your computer and use it in GitHub Desktop.
Сборка .deb пакетов из ROS пакетов

Сборка debian пакетов из ROS пакетов

Заметка основана на материалах:

  1. https://answers.ros.org/question/173804/generate-deb-from-ros-package/ (кстати, здесь описывается проблема иногда возникающая make[1]: *** [override_dh_auto_configure] Error 2)
  2. https://gist.github.com/awesomebytes/196eab972a94dd8fcdd69adfe3bd1152 (исходная инструкция)
  3. https://github.com/ros-infrastructure/ros_buildfarm/blob/master/doc/custom_rosdistro.rst (статья про использование кастомных зависимостей rosdep в rosbuildfarm)
  4. https://answers.ros.org/question/230104/using-bloom-to-generate-binaries-for-multiple-packages/ (вопрос про билдинг нескольких пакетов)
  5. https://answers.ros.org/question/292024/how-to-use-bloom-generate-with-private-dependencies/ (статья про билдинг с кастомными зависимостями)
  6. https://answers.ros.org/question/280213/generate-deb-from-dependent-res-package-locally/#280235 (исходная статья для предыдущей)
  7. https://github.com/ros/rosdistro (репа где содержатся все rosdep зависимости)
  8. http://qaru.site/questions/169600/dpkg-shlibdeps-error-no-dependency-information-found-for (dpkg-shlibdeps: error: no dependency information found - ошибка которая была для mavros)
  9. https://github.com/mavlink/mavros-release/tree/debian/kinetic/jessie/mavros (релиз репа - собственно код который собирается в deb пакеты и портируется как source)
  10. https://answers.ros.org/question/241227/problem-building-deb-for-rosconsole-in-kinetic/ (еще одна ошибка при сборке пакета)

Install Rosdep

Установка зависимостей с помозью rosdep выполняется следующей командой.

cd catkin_ws
rosdep install -y --from-paths src --ignore-src --rosdistro kinetic -r --os=debian:stretch

Работает это так:

  1. rosdep проходит по всем пакетам находящимся в папке src (определяя пакет по файлу package.xml)
  2. затем смотрит в package.xml и берет все rosdep ключи depend_*
  3. затем для каждого ключа смотрит в своей базе сопоставление для текущего или указанного явно --rosdistro и --os значения
  4. каждое найденное сопоставление устанавливает используя apt-get install

Build deb-pack

Install toolchain

sudo apt-get install dh-make python-bloom fakeroot dpkg-dev debhelper

Для сборки некоторых пакетов может потребоваться swap

Build algorithm

bloom-generate rosdebian --ros-distro kinetic
sudo fakeroot debian/rules binary

Сборка debian пакета состоит из двух этапов:

  1. Создание папки debian содержащей конфигурационные файлы описывающие данный пакет (зависимости, описание, версию)
  2. Генерирование и добавление скопилированных файлов в папку debian/<PACKAGE_NAME> и архивация в файл .deb

Для первого этапа используется bloom-generator, эта ROS утилита которая берет информацию из CMakefile.txt, package.xml и других о зависимостях, версиях итд и генерирует папку debian. Одно из ключевых действий, что делает эта утилита - это переводит rosdep key указанные в package.xml в apt-get зависимости используя rosdep. Поэтому если мы собираем какой-нибудь пакет, то rosdep должен иметь соответствие для всех ключей этого пакета в apt-get ключи.

Проблема возникает, если мы собираем пакет, на новую архитектуру которой нет в https://github.com/ros/rosdistro, например RPi. Для разрешения таких зависимостей и генерации своего .yaml файла я написал скрипт rosolve_rosdep_keys.sh, который берет зависимости для ключей от других операционных систем, например ubuntu:xenial и копирует их для целевой архитектуры.

Данный файл нужно добавить в индексацию rosdep'а:

echo "yaml file:///home/pi/urpylka-rpi.yaml" | sudo tee /etc/ros/rosdep/sources.list.d/20-default.list
rosdep update

Также можно копировать не в существующий файл, а в отдельный (по аналогии с /etc/apt), подробнее по сслыке №6.

Содержимое /home/pi/urpylka-rpi.yaml

ROSDEP_KEY:
  debian:             
    stretch: [APT_NAME]

Второй шаг выполняется dh. По сгенерированному на первом шаге скрипту для сборки пакета debian/rules. Для того чтобы собрать и установить пакет нужен fakeroot либо все права с текущего пользователя поменять под рута (потому что атрибуты файлов в пакете сохраняются).

dh-инструкции содержащиеся в файле debian/rules работают с папкой obj-* находящейся в корне пакета, а также CMakeFile.txt и папкой obj-*/cmake.

Важно: иногда необходимо передать параметры в cmake, для этого нужно добавить аргументы в шаг override_dh_auto_configure debian/rules значение -DCATKIN_INSTALL_INTO_PREFIX_ROOT="1" \ (это необходимо для сборки catkin, иначе он ничего не положет в /opt/ros/kinetic (например setup.bash)).

Пару других утилит для сборки пакета:

dh build -s
sudo dpkg-buildpackage -rfakeroot -d -B

Другое

Видимость ROS библиотек

Использовал, чтобы библиотеки находящиеся в папке /opt/ros появились в системе. Посмотреть, кажется можно с помощью lddconfig

sudo echo "/opt/ros/kinetic/lib" > /etc/ld.so.conf.d/roslib.conf

Распараллелить сборку на разных x86 узлах

  • Должен совпадать tootlchain: obj-arm-linux-gnueabihf
  • Штука для параллели: distcc
  • Кеш obj-файлов: ccache
#!/usr/bin/env bash
#set -e
rosdep update
SOURCE_DIR=$(pwd)
deb="${SOURCE_DIR}/debuild_deb.log"
rm -f ${deb} ${req} ${bloom}
for file in `find . -name "package.xml" -not -path "*/debian/*"`; do
echo "===================================================="
echo ${file}
cd $(dirname ${file})
rm -rf debian
echo "===================================================="
# https://gist.github.com/awesomebytes/196eab972a94dd8fcdd69adfe3bd1152
bloom-generate rosdebian && fakeroot debian/rules binary &>> ${deb} && echo "Build finished" || (echo "Error of building. Use 'less ${deb}'"; exit 1)
cd ${SOURCE_DIR}
done
# less -R debuild_deb.log
#!/usr/bin/env bash
#set -e
OS_DISTRO="ubuntu"
OS_VERSION="bionic"
ROS_DISTRO="melodic"
OS_DISTRO_SEARCH="ubuntu"
OS_VERSION_SEARCH="xenial"
ROS_DISTRO_SEARCH="kinetic"
#
# Мб создавать папку с датой сборки, а нее уже все класть?
# А также общий вывод программы туда складывать.
# А сборку каждого пакета в отдельный лог.
#
SOURCE_DIR=$(pwd)
bloom="${SOURCE_DIR}/debuild_bloom.log"
result="${SOURCE_DIR}/debuild_result.log"
yaml="${SOURCE_DIR}/distribution.yaml"
rm -f ${result} ${bloom}
# ${yaml}
for file in `find . -name "package.xml" -not -path "*/debian/*"`; do
echo "===================================================="
echo ${file}
cd $(dirname ${file})
rm -rf debian
echo "===================================================="
# https://gist.github.com/awesomebytes/196eab972a94dd8fcdd69adfe3bd1152
bloom-generate rosdebian --ros-distro ${ROS_DISTRO_SEARCH} --os-name ${OS_DISTRO_SEARCH} --os-version ${OS_VERSION_SEARCH} | tee -a ${bloom} \
| gawk 'match($0, /^\s+\033\[36m([a-zA-Z0-9_-]+)\s+\033\[35m=>\s\033\[36m\[\x27([a-zA-Z0-9_-]+)\x27\]\033\[0m\033\[0m/, a) {print a[1] ":" a[2]}' >> ${result}
cd ${SOURCE_DIR}
done
temp=$(mktemp)
# Sort & remove duplicates
cat ${result} | sort | uniq >> ${temp}
mv ${temp} ${result}
temp=$(mktemp)
# Move ros-kinetic packages to the result file
cat ${result} | grep "ros-${ROS_DISTRO_SEARCH}-" | sed "s/ros-${ROS_DISTRO_SEARCH}-/ros-${ROS_DISTRO}-/" >> ${temp}
# Get correct names for non ros-kinetic & move that to the result file
cat ${result} | grep -v "ros-${ROS_DISTRO_SEARCH}-" | sed 's/:.*$//' | gawk '{printf $1 ":";system("rosdep resolve --os=${OS_DISTRO}:${OS_VERSION} "$1" | grep -v \"#apt\"") }' >> ${temp}
mv ${temp} ${result}
wrapper() {
ROSDEP_KEY=$1
APT_NAME=$2
echo "${ROSDEP_KEY}:
${OS_DISTRO}:
${OS_VERSION}: [${APT_NAME}]"
}
# Create distribution.yaml
cat ${result} | grep "" | sed 's/:/ /' | while read line; do wrapper $line >> ${yaml}; done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment