Показаны сообщения с ярлыком Fedora 20. Показать все сообщения
Показаны сообщения с ярлыком Fedora 20. Показать все сообщения

вторник, 14 октября 2014 г.

Как я обновлял ghc до версии 7.8 в Fedora 20

Официально в Fedora до сих пор старые ghc-7.6.3 и haskell-platform-2013.2.0.0. И по всей видимости они останутся в следующей Fedora 21 (см. здесь). Однако, выход есть, и для этого не нужно собирать ghc с нуля. Достаточно установить репозитории ghc-7.8 и cabal-install от Йенса Петерсена — мэйнтейнера haskell в Fedora (кстати, у него есть и другие интересные репозитории, связанные с haskell: статическая сборка pandoc, функциональный язык idris, vim-подобный редактор yi — все это можно найти по этой ссылке). Поскольку у меня уже стояли ghc и haskell-platform, то первое, что я сделал — это удалил их из системы.
yum remove ghc* haskell-platform
Затем настроил репозитории Йенса и установил ghc и cabal-install.
yum install ghc cabal-install
Заметьте — пакета-коллекции haskell-platform в репозитории ghc-7.8 нет, да он и не нужен, поскольку все пакеты можно установить с помощью cabal. Естественно, я и раньше использовал cabal для установки пакетов haskell и делал это с опцией --global, соответственно в директории /usr/local/lib/ скопилось множество директорий типа conduit-1.1.6/, содержащих в себе единственную поддиректорию ghc-7.6.3/ с данными пакетов. Новый ghc, как выяснилось позже, устанавливает все пакеты в единую директорию /usr/local/lib/x86_64-linux-ghc-7.8.3/ (имя последней поддиректории, очевидно, зависит от системы), поэтому старые пакетные директории следовало удалить. Вот команда, которая позволяет перечислить все пакетные директории:
find /usr/local/lib -mindepth 2 -maxdepth 2 -type d -name 'ghc-7*' | xargs dirname
Теперь требуется убедиться, что список не содержит неожиданных верхнеуровневых директорий типа /usr/local/lib, потому что сейчас мы будем их удалять! Я постарался максимально обезопасить команду find с помощью опций -mindepth и -maxdepth, поэтому появление неожиданных директорий в списке очень маловероятно. Итак, удаляем пакетные директории.
find /usr/local/lib -mindepth 2 -maxdepth 2 -type d -name 'ghc-7*' | xargs dirname | xargs rm -rf
Также удаляем директории .ghc/ и .cabal/ в домашних директориях пользователя и суперпользователя (так как я устанавливал пакеты от имени суперпользователя с опцией --global), но делаем это осторожно, вспоминая, нет ли там каких-нибудь персональных настроек. У меня все персональные настройки находятся в файле .ghci в домашней директории, поэтому удаление этих директорий не могло привести к потере настроек. На этом этапе мы еще не закончили с удалениями. Данные о пакетах все еще хранятся в директории /usr/lib64/ghc-7.6.3/package.conf.d/, в этом можно убедиться, выполнив команду
ghc --info | grep "Global Package DB"
Хотя после установки нового ghc эта команда покажет новую поддиректорию ghc-7.8.3/, старая директория будет по-прежнему находиться в системе. Удаляем проблемные пакеты из реестра (хотя сейчас я не уверен, что этот шаг вообще был нужен, поскольку Global Package DB указывает на новую директорию):
for p in `ghc-pkg check 2>&1 | grep problems | awk '{print $6}' | sed -e 's/:$//'` ; do ghc-pkg unregister $p --force ; done
(этот скрипт я позаимствовал отсюда) и физически удаляем директорию /usr/lib64/ghc-7.6.3/:
rm -rf /usr/lib64/ghc-7.6.3
Вот теперь все готово для установки новых пакетов. Лично я устанавливал пакеты pandoc, happy, alex, hlint, MissingH, ghc-vis и lens с опцией --global.
cabal update
...
cabal install pandoc --global
...
cabal install happy --global
...
cabal install alex --global
...
cabal install hlint --global
...
cabal install MissingH --global
...
cabal install gtk2hs-buildtools --global
...
yum install librsvg2-devel
...
cabal install ghc-vis --global
...
cabal install -ftransformer3 transformers-compat --global
...
cabal install --constraint="transformers==0.3.0.0" lens --global
...
Я заменил выводы команд многоточиями, поскольку они многословны и малоинтересны. Порядок установки пакетов может иметь значение! Для установки ghc-vis потребовалось установить пакет gtk2hs-buildtools и системный пакет librsvg2-devel. После установки ghc-vis имеет смысл скопировать содержимое файла /usr/local/share/ghc-vis-0.7.2.3/ghci в домашний .ghci. Установка пакета lens выглядит необычно, но без этих опций его не установить, собственно решение я нашел здесь. Во время установки пакетов вы возможно заметите такие предупреждения:
<no location info>:
    Warning: Couldn't figure out linker information!
             Make sure you're using GNU gcc, or clang
Точно такие же сообщения вы увидите при компиляции любой программы новым ghc. Но это только в том случае, если ваша локаль не является английской (моя локаль русская). Я долго искал в чем здесь проблема и таки нашел, вот этот баг на трекере ghc. В общем-то ничего опасного: ghc запускает команду gcc -v, ищет в выводе строку gcc version ... и просто выводит предупреждение, если ее не находит. В русской локали gcc выводит строку gcc версия .... Лично меня раздражают эти бессмысленные предупреждения, обновление ghc с исправлением выйдет не скоро, поэтому я просто добавил в .bashrc новый алиас ghc-make.
alias ghc-make='LANG=C ghc --make'
Да, кстати. В ghc 7.8 появилась возможность настроить prompt2 — приглашение командной строки ghci для многострочных команд. Лично я выделяю приглашения разными цветами, вот мои настройки в .ghci:
:set prompt "\ESC[38;5;208m%s> \ESC[m"
:set prompt2 "\ESC[38;5;221m%s| \ESC[m"

вторник, 24 декабря 2013 г.

Что делать, если у вас маленький /, а обновить Федору очень хочется

В общем-то, не обязательно /, в общем случае это точка монтирования файловой системы, в которой находятся директории /var/lib/ и /var/tmp/. На моем рабочем компьютере эти директории находятся в корневой файловой системе, размер которой составляет всего 20 Гб. Это приводит к проблемам при штатном обновлении ядра через yum, что уж тогда говорить об обновлении всей системы.

Итак, обновляться я решил вчера, 23 декабря 2013 года, с Fedora 19 до Fedora 20, то есть уже после официального выхода Fedora 20. Инструмент для обновления - fedup-0.8.0-3, совсем недавно заменивший версию 0.7. Он запускается из командной строки и в процессе загрузки пакетов использует директории /var/lib/system-upgrade/ и /var/tmp/system-upgrade/. Опций для настройки других директорий нет (хотя в файле TODO.asciidoc, входящем в состав пакета fedup, такая возможность анонсируется в будущем). То есть, если запускать fedup без всяких предварительных настроек следующим образом:
fedup --network 20 --nogpgcheck
, то мой корневой раздел будет заполнен до отказа еще до начала реального обновления системы. Кстати, обратите внимание на опцию --nogpgcheck. Как я понял, она появилась в версии fedup 0.8, и без нее мой fedup не захотел работать.

Итак, что же делать? Самое очевидное решение - снести директории /var/lib/system-upgrade/ и /var/tmp/system-upgrade/ вместе с их содержимым, найти диск, на котором достаточно места для пары-тройки гигабайт обновлений, и создать символические ссылки на эти директории из /var/lib/system-upgrade и /var/tmp/system-upgrade. У меня нашлось достаточно места на диске, который монтируется в корневую файловую систему как /home. Поэтому, от имени суперпользователя я создал на нем две директории /home/fedup/cache/ и /home/fedup/packages/, а затем и упомянутые символические ссылки:
ln -s ../../home/fedup/cache /var/tmp/system-upgrade
ln -s ../../home/fedup/packages /var/lib/system-upgrade
Обратите внимание на то, что ссылки задаются не через абсолютные пути, а через относительные, это очень важно! Дело в том, что после перезагрузки системы для ее обновления все файловые системы, в том числе /home, будут смонтированы в /sysroot, а не в /, и загрузчик просто не сможет найти пакеты для обновления (см. об этом здесь).

В общем-то, на этом историю про обновление Fedora с небольшим дисковым пространством можно было бы и закончить. Но не тут-то было! Обновление Федоры - это почти всегда приключение, сопряженное с риском и опасностью, в которых не место домохозяйкам! После перезагрузки системы для дальнейшего обновления и загрузки нескольких сервисов systemd, запустился релэйблинг SELinux, как я понял на загруженные новые пакеты (хотя SELinux в системе у меня отключен). Помурыжив минут 15, компьютер перезагрузился, оставив опцию с апгрейдом системы в верхней строке загрузчика GRUB2. Я попробовал загрузить апгрейд снова: в итоге обычная загрузка GDM как ни в чем не бывало. То есть система не обновилась! Я перезагрузился в старое ядро от Fedora 19, снес Upgrade опцию из загрузчика:
fedup --resetbootloader
и запустил fedup--network 20 --nogpgcheck сначала. После серии таких попыток обновления я понял, что проблема не в новых пакетах, установленных неожиданным для fedup образом, а в чем-то другом. На правильный путь меня натолкнуло описание этого бага. В одном из комментариев было сказано про аргумент ядра systemd.unit=system-upgrade.target, который устанавливал старый fedup 0.7 для старта процесса обновления после перезагрузки системы. Я открыл /boot/grub2/grub.cfg, нашел секцию, соответствующую апгрейду системы, и вставил туда этот параметр, на авось, поскольку так и не понял, нужен ли он новому fedup 0.8 и установочному образу ядра. Кроме того, добавил туда же опцию selinux=0, чтобы не ждать релэйблинга новых пакетов (или чего-то там еще, не суть важно). Более того, новый fedup был так добр, что не установил в аргументы загрузки ядра опцию plymouth.splash=fedup: это в дальнейшем позволило наблюдать за реальным процессом установки пакетов в консоли, а не бестолковый графический прогрессбар. Если вы тоже захотите удалить эту опцию, то не пугайтесь, когда в процессе установки консоль заснет и дисплей погаснет: просто нажмите на клавиатуре Shift - это разбудит консоль.

Итак, как вы уже поняли, после добавления в аргументы загрузки ядра опции с systemd.unit, процесс пошел. Система обновилась, и после перезагрузки опция с апгрейдом системы ушла из меню GRUB2, что и должно было произойти. Однако, в момент загрузки новой Fedora 20 вернулась проблема с SELinux, с одной стороны неудивительно - я ведь устанавливал ее только для ядра, загружаемого для обновления системы. С другой стороны непонятно, почему fedup не вычистил эти пакеты сразу после обновления. После загрузки Fedora 20 и запуска fedup --clean все стало понятно: fedup сообщил, что он не в состоянии выполнить rmtree на символических ссылках. Пришлось вручную удалять все содержимое из директорий /home/fedup/cache/ и /home/fedup/packages/.

Осталось сказать, что проблему с нехваткой дискового пространства при обновлении ядра через yum решить просто - намного проще, чем с fedup. Создаем директорию /home/yum/cache/, открываем файл /etc/yum.conf и заменяем строку
cachedir=/var/cache/yum/$basearch/$releasever
на
cachedir=/home/yum/cache/$basearch/$releasever