At last!

int pid = fork();
if (pid) {
    printf("Yahoo!\n");
    drink();
}
else if (!pid) {
    execl("Boris", "");
}
else {
    // never executed
}

Перешел на Arch Linux

Fedora перестала меня удовлетворять, и главным образом по двум причинам.

Во-первых, мне было совершенно непонятно, что там у нее происходит под капотом. Я обращался с ней как с черным ящиком, и ровно как полагается черному ящику она себя и вела — иногда непредсказуемо, иногда излишне самостоятельно. И однажды я понял, что для человека из той группы, к которой я себя причисляю, непозволительно быть таким невежей в настройке и понимании рабочей ОС.

Во-вторых, концепция релизов меня окончательно разочаровала. Релизы хороши для корпоративного использования, когда развитие проекта должно двигаться вперед, но в то же время для распространяемых дистрибутивов должна гарантироваться поддержка и стабильность. Для домашнего использования в этом мало смысла: почему я должен ждать следующего релиза чтобы моя любимая программа обновилась до свежей версии? В принципе, учитывая мою консервативность, проблема свежего софта меня не очень напрягала, но сама мысль мешала спокойно спать.

В результате я пришел к непростому выбору из Gentoo, Arch и FreeBSD. Бесполезно меня спрашивать, почему именно эти три, и почему только они. Не знаю. Возможно, Gentoo просто на слуху, Arch мне советовал коллега (который сам при этом поклонник Gentoo), а FreeBSD — это просто старая платоническая любовь к неведомому миру, который «тоже опенсорс, но другой». Уважение к опыту коллеги перевесило все остальные доводы, и я поставил Arch Linux.

Как человек, развращенный автоматическими установщиками, графическими утилитами настройки и прочими bells and whistles, я готовился к худшему. Отчетливо представлялся процесс установки в виде загрузки с live-диска в голую консоль с приглашением «Вот вам консоль. Пожалуйста, установите Linux на свой вкус и цвет. Спасибо». После этого я должен был погрузиться в чтение мануалов, провести за этим занятием пару недель, отрастить бороду до груди и приобрести интенсивный красный цвет глаз. Эти атрибуты позволили бы мне достигнуть просветления, и я, пятнадцать раз пересобрав ядро и шестнадцать раз — все остальное, — получил бы, наконец, вожделенную системищу. Вот такую жуть напредставлял.

И конечно же, все оказалось совсем не так. Новичковый мануал написан в духе «делай раз, делай два», и точное следование указаниям позволяет уже через пару часов получить работающую систему с настроенным иксовым окружением. На самом деле, я уже где-то с середины мануала плюнул на их скучные инструкции, и стал все делать по-своему. Все оказалось настолько просто и логично, что я оказался даже немножко разочарован. Хотелось почувствовать себя суровым админом, но нет, не судьба.

Что сразу подкупает в установке «почти вручную», так это что после окончания процесса ты знаешь, где у тебя что лежит, как, откуда и в каком порядке запускается, и где хранятся все настройки. Этакое ощущение тотального контроля появляется, как будто вертолет из Лего собираешь. Перечислю вкратце ключевые достоинства:

  1. Философия «чем проще, тем лучше». Что характерно, «проще» здесь означает «оценишь простоту, когда научишься», а не «любой дурак поймет». Arch — однозначно не для новичков и сторонников подхода, чтобы все из коробки автоматически поставилось и подушечку подложило. Это как раз тот случай, когда «вы можете настроить все… и вы будете настраивать все».
  2. Простое и прозрачное конфигурирование загрузки (все практически в двух файлах — /etc/rc.conf и ~/.xinitrc). Скрипты из /etc/rc.d никуда не делись, но все демоны вызываются централизованно, а не исходя из первой буквы соответствующей символической ссылки.
  3. Менеджер пакетов pacman определенно хорош. В первую очередь тем, что про него сложно сказать что-то плохое.
  4. Arch Build System позволяет при желании превратить Arch в этакий Gentoo. Формат файлов PKGBUILD, управляющих сборкой пакетов, нормально пишется и читается.
  5. AUR — гигантская база пользовательских пакетов в исходных кодах на случай, если в арчевских репозитариях чего-то нет.
  6. Концепция rolling release: отсутствуют релизы. Система эволюционирует, нет нужды переустанавливать ее или делать «апгрейд». Кроме того, всегда доступны самые свежие версии пакетов.
  7. Обширная Wiki, в которой можно найти инструкции почти на все случаи жизни. В некоторой степени переведена на русский.

Короче говоря, друзья, категорически рекомендую Arch тем, для кого Ubuntu — это «для чайников», а Gentoo — «для красноглазых». Очень разумный компромисс.

УжасноПлохоНормальноХорошоОтлично (Еще не оценили)
Loading ... Loading ...

Shave: чистим вывод make при использовании Autotools

Не люблю, когда make выплевывает километры всякого мусора. Зачем мне для каждого файла полный вызов gcc со всеми флагами? Спасибо, я эти флаги сам задавал, знаю что к чему. Зато среди всей этой ерунды пропустить что-то важное — проще простого. Значит, надо как-то выделить важное, а неважное вовсе не показывать. Вот какой я мудрый!

В обычных Makefile’ах все просто:

chset.c: chset.lex
        @echo "  FLEX  $(@:.c=)"
        @$(LEX) --outfile=$@ $<

Символ ‘@’, указанный перед командой, подавляет вывод на stdout, оставляя возможность увидеть ошибки, выводимые в stderr. Строчка-подсказка выводится как раз для того, чтобы увидеть, на каком этапе сборки произошла ошибка, если таковая будет.

При использовании Autotools все становится сложнее, тут уже одними собачками не обойдешься. Интересное решение предлагает Shave: он подменяет вызовы компилятора и libtool на вызовы своих сценариев, которые молча выполняют все что нужно, а выводят только краткую диагностику, как в предыдущем примере. Вот так, например:

[nkalex@stables build]$ make
Making all in src
CC    main.o
CC    msg.o
CC    ctype.o
CC    collate.o
CC    charset.o
CC    ldefpars.o
CC    locopts.o
CC    chset.o
CC    ldeflex.o
LINK  localedef

Как настраивать Shave, написано в его кратком руководстве, но там есть пара граблей, на которые я не преминул наступить. Поэтому лучше уж я свою инструкцию напишу, чтоб люди не мучались.

  1. Делаем нормально собирающийся проект, использующий Automake и Autoconf.
  2. Скачиваем Shave по адресу http://download.lespiau.name/shave.
  3. Сценарии shave.in и shave-libtool.in кладем в корневой каталог проекта.
  4. Файл shave.m4 копируем в файл acinclude.m4 в корневом каталоге проекта.
  5. Вносим изменения в configure.ac:
    1. даже если не используем libtool, добавляем строку
      LT_INIT
    2. добавляем сценарии Shave в AC_CONFIG_FILES, чтобы получилось как-то так:
      AC_CONFIG_FILES([
      shave
      shave-libtool
      Makefile
      src/Makefile
      ])
    3. сразу перед AC_CONFIG_FILES добавляем строчку
      SHAVE_INIT(.,enable)
  6. Если не пользовались до этого libtool, в корневом каталоге нужно вызвать
    $ libtoolize
    $ automake --add-missing
  7. Profit!

Теперь по умолчанию Shave включен, и вывод при сборке будет кратким. Чтобы все-таки посмотреть подробный вывод, нужно добавить ключ в вызов configure:

$ configure --disable-shave

Грабли, на которые я наступил, заключались в необходимости включить поддержку libtool. Без этого вызов SHAVE_INIT выдает крайне невнятную диагностику в духе syntax error, и пришлось читать shave.m4, чтобы разобраться, в чем, собственно, дело.
УжасноПлохоНормальноХорошоОтлично (2 голосов, средний: 5,00 из 5)
Loading ... Loading ...

Получить полный путь к файлу/каталогу в bash

Иногда в аргументах сценария приходят пути к файлам и каталогам в разнообразных форматах, ну например:

./file1
~/cat1/cat2/
../../cat1/file2
justfile
cat1/file3

А хочется в каждом случае получить полный путь, скажем, «/home/user/cat1/file». И если второй вариант раскроется оболочкой в полный путь еще до передачи сценарию, то остальные так и останутся с точками и относительными путями.

Есть простое и изящное решение, подсмотренное на каких-то форумах:

absPath=$(readlink -f "$(dirname "$relPath")")/$(basename "$relPath")

Эта штука замечательно работает, но ровно до тех пор, пока мы не передадим ей путь «.», «./», «..» или «../». В таком случае basename "$relPath" выдаст «.» или «..», и мы в результате получим путь, который выглядит, соответственно, как-то вроде «/home/user/cat1/cat2/.» или «/home/user/cat1/cat2/..», который работать-то будет, но выглядит не очень.

Можно, конечно, почистить путь от стоящих в конце точек, но в случае с двумя точками придется еще и удалить предпоследнюю компоненту. Но зачем делать работу самому, если ее за тебя могут сделать другие? Вот такой получился окончательный вариант:

absPath=$(readlink -f $(readlink -f "$(dirname "$relPath")")/$(basename "$relPath"))
УжасноПлохоНормальноХорошоОтлично (1 голосов, средний: 5,00 из 5)
Loading ... Loading ...

Реализация cond на операторе ?:

Если кто будет спрашивать, cond — это из мира Лиспа.

Подобную же конструкцию можно сделать и в C:

var = (cond1 ? expression1 :
       cond2 ? expression2 :
       /* ... */
       else-expression);

Переменной var присваивается значение выражения expression1, если истинно значение выражения cond1, присваивается значение expression2, если истинно значение cond2, и т.д. Если ни один condX не истинен, присваивается значение else-expression.

По-моему, красиво. Для пущего сходства с Лиспом можно добавить скобочек.

УжасноПлохоНормальноХорошоОтлично (1 голосов, средний: 3,00 из 5)
Loading ... Loading ...

Исходники: текст или что-то другое?

Последние две недели мне приходилось разбираться в чужом коде с целью отловить и уничтожить неведомую ошибку. Не сказать, чтобы код был особенно сложен, но сам я настолько далек от звания гуру современного программирования, что несколько седых волос где-то в глубинах моей шевелюры наверняка за это время зародились. Задача усугублялось невозможностью выполнить код под отладчиком (это был планировщик ОС), так что в моем распоряжении были только

  • заботливо раскиданная по коду отладочная печать на терминал и
  • пресловутый «долгий пристальный взгляд».

Были еще встроенные в ОС средства протоколирования, но они именно в эти две недели не работали. Удивительное совпадение. Хотя нет, скорее, все дело в кривизне рук. Неважно.

Так вот, отладочная печать прекрасно себя зарекомендовала. Изучение длинных простыней протоколов из строк вроде «(kernDispatchThread) pre-switch ct=174380000 diff=55489 nn=4», «test 4»и даже просто «hahaha!!!» позволяют получить истинное удовольствие от расследования а-ля Хаус. Ну-ка, кто у нас тут вытеснил этот поток? Но вот аномальная последовательность строк найдена, и теперь никуда не денешься — придется разглядывать код, который эту аномалию продемонстрировал.

Казалось бы, самое время сказать: «Трепещите, о презренные байты! Склонитесь перед интеллектом Человека!». Но нет, байты трепетать отказываются, функции плодятся прямо на глазах, макросы-сволочи делают вид, что они функции, или даже того хуже — оперируют именами локальных переменных (ужас-ужас!). Вся эта компания разбегается по двум десяткам файлов, откуда, ехидно посмеиваясь, гадит в глобальные переменные, норовя смешать физическую и виртуальную адресацию.

Вот как-то так я и провел две недели.

И не переставало мне думаться, что текст в качестве носителья исходного кода всем хорош: и редактировать его легко, и всякие diff’ы со слияниями делать, и от платформы не зависит (ну, почти), да и сколько уже проверенных временем алгоритмов на строках есть. Вот только читать чужие исходники неудобно. Хорошая IDE позволяет от вызова функции перейти к ее определению, но серебряной пулей тут и не пахнет. Пока читаешь код вызванной функции, забываешь, что делала вызывающая. И хорошо еще когда в когнитивном процессе участвует две функции. А что если 10? Или 50?

В таком случае поможет только абстрагирование: надо поделить 50 функций на 5 групп, рассмотреть взаимодействие этих групп, а потом — внутри каждой в отдельности. Да, модульное программирование явно неглупые люди придумали. Вот только выделение абстракций — отдельная большая работа. Если мы читаем свой код, то эта работа уже сделана еще при его написании. А вот выделение абстракций на уже существующем коде… Вот тут-то его текстовая природа и подкладывает нам козу: чтобы выделить абстракции, нужно сначала код прочитать и понять.

Короче, умные люди решили, что неплохо бы дать возможность людям видеть сразу весь интересующий их код. А чтобы удобнее было выделять абстракции, дать возможность еще и как-то помечать фрагменты. Ну и редактировать, само собой. Примерно так и работает Code Bubbles. Обязательно посмотрите демонстрационное видео.

В таком подходе есть ряд очевидных недостатков. Например, нужен гигантский монитор. И отсутствие аллергии на работу мышкой. И ширина строк кода должна быть вменяемой (обратили внимание, какие они короткие в демке?). Но в целом идея здравая: кто сказал, что код — это обязательно плоский текст? (Я не говорил.) При анализе чужого кода такая штука уж точно будет полезной.

P.S. Я давно уже дочитал «Организацию ЭВМ» и с пяток книжек сверху. Просто под линуксом не работает мой антикварный сканер. Постараюсь что-нибудь придумать.

УжасноПлохоНормальноХорошоОтлично (Еще не оценили)
Loading ... Loading ...