Процессор J1 — куда уж проще

Осторожно — эта статья не содержит и теоретической, ни практической пользы, и была написана просто, как подведение черты под одним из увлечений.

Я давний фанат этого процессора. Я писал о нем на хабре, дважды, и хочется написать еще.

Для тех, кто не слышал никогда о J1 — это простенький процессор,
ориентированный на язык Форт. Для любителей подробностей — официальный сайт J1 CPU.

Так вот, я с гордостью могу сказать, что я маялся бездельем и тем временем написал эмулятор + компилятор почти-Форта для J1. Здесь я расскажу что это и зачем. Читать далее

Реклама

tip-топ. Или не тип-топ?

Недавно узнал, что у сайта http://golang.org есть особенная версия — http://tip.golang.org

Там находится всякая документация относительно последней версии (tip, по-старинке — head: последний коммит) языка из репозитория.

Вот, например, когда я последний раз его обновлял, я удивился, что там больше нет Makefile (помните — еще недавно мы их учились писать). Теперь все возложили на утилиту go. И сборку, и установку, и тестирование, и форматирование кода. Читать далее

Go 1

Слышали, да? Это стучат клавиатуры и щелкают мыши. Там пишут Go 1.

Это будет первая стабильная база языка Go. API зачерствеет и не будет меняться каждый месяц. Язык станет совсем взрослым и серьезным.

Появятся нумерация версий языка — напр., в Go 1.x будут включаться багфиксы для Go 1.

Итак, что же нового принесет язык? Читать далее

codesearch is dead, long live the codesearch!

Это произошло. codesearch.google.com или google.com/codesearch больше нет.
Я пользовался этим сервисом часто, и теперь я даже не знаю что делать.
Но, спасибо Робу Пайку и Россу Коксу, которые тоже тяжело переживают эту утрату.
Они начали новый проект — codesearch.

Проект позволяет очень быстро искать по исходникам, правда только на локальной машине, а не на серверах гугла.

Для неленивых

Проект написан на Go. Поэтому все кто собирать его вручную — сначала установите Go.

Затем:

cd $GOROOT/src/pkg
# Возможно go install может установить все автоматически прямо с сайта,
# но у меня не получилось.
mkdir -p code.google.com/p/codesearch
hg clone https://code.google.com/p/codesearch code.google.com/p/codesearch
cd code.google.com/p/codesearch/lib
# buildall перебирает все архитектуры и собирает под все что можно, 
# изучите его, закомментируйте то что вам не надо (напр. упаковку результатов
# сборки в *.zip), и тогда запускайте.
./buildall

После этого у вас в $GOBIN появятся три утилиты: cindex, csearch, cgrep.

Для ленивых

Качаем утилиты с сайта проекта и распаковываем куда удобно.

Начало работы

Проиндексируем какую-нибудь папку, напр. наш /usr/include:

$ cindex /usr/include

В результате получим «базу» для поиска в файле ~/.csearchindex

UPD: Описанный ниже баг уже оперативно исправили.
У меня в 64-битной Gentoo произошла ошибка, cindex не смог смержить пустую базу в .csearchindex и временную базу по /usr/include (.csearchindex~ — с тильдой в конце). Проблема была в том, что делали mmap для размера в 0 байт (файл-то пустой), получали ошибку, и завершали программу. Не знаю, это баг Go или codesearch, но уже сообщил о нем. Временный фикс:
$ cp ~/.csearchindex\~ ~/.csearchindex
Так ведь у нас мержат пустой файл с непустым? 🙂
Это надо делать только для 1-го запуска cindex. Дальше все как по маслу.

Войдя в азарт я проиндексировал /usr/src/linux и еще пару мелких проектов.
Размер ~/.csearchindex составил около 50 Мб, что в целом неплохо для всех include и ядра линукса.

Поиск

Для поиска я использовал csearch. В результатах отображается файл и (опционально) номер строки. Конечно, не так красиво как было у codesearch, но пользоваться можно. Глядишь — web-интерфейс сделают когда-нибудь.

$ csearch hcd_bus_
/usr/src/linux/drivers/usb/core/generic.c:		rc = hcd_bus_suspend(udev, msg);
/usr/src/linux/drivers/usb/core/generic.c:		rc = hcd_bus_resume(udev, msg);
/usr/src/linux/drivers/usb/core/hcd.c:int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg)
/usr/src/linux/drivers/usb/core/hcd.c:int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg)
/usr/src/linux/include/linux/usb/hcd.h:extern int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg);
/usr/src/linux/include/linux/usb/hcd.h:extern int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg);

time вернул: csearch hcd_bus_ 0.02s user 0.01s system 74% cpu 0.031 total. Неплохой показатель, и глазом не моргнул. Старикашка grep тут бы трудился около минуты.

# Смотрим где объявлены функции для работы с интерфейсами в libusb (поиск по regex)
$ csearch -n "libusb_.+_interface"
2012/01/19 22:46:58 56591902 56594432
/usr/include/libusb-1.0/libusb.h:803:int libusb_claim_interface(libusb_device_handle *dev, int iface);
/usr/include/libusb-1.0/libusb.h:804:int libusb_release_interface(libusb_device_handle *dev, int iface);
/usr/include/libusb-1.0/libusb.h:809:int libusb_set_interface_alt_setting(libusb_device_handle *dev,

А вот бы еще…

Проект свою функцию выполняет — ищет, и ищет очень быстро. Но аппетит разыгрался. Хочу инверсный поиск (все что не regex), хочу текст до и после совпадающей строки, хочу цепочки фильтров, хочу упрощенный синтаксис наряду с regex, хочу красивый интерфейс (ох как непривычно от самого себя такое слышать). Другие пожелания думаю тоже можно в Issue ребятам писать, так что не скромничайте.

А может взять да и форкнуть? И сделать круто? Робу Пайку думаю не до интерфейсов, а вот самому сделать бы да покрасивше.. Или может взять дерево исходников, скажем, ядра или андроида, да сделать проект на Google App Engine для быстрого поиска по этому дереву прям онлайн, чтобы себе репозитории огромные не качать. Круто, да? Ау, есть желающие? У кого какие еще есть идеи?

Без паники

Короткая заметка про panic() в языке Go.

Часто можно услышать критику языка Go за отказ от исключений (Exceptions). Ведь это же такой хороший способ обработки ошибок. Да, способ хороший, особенно для ООП.

Итак, как же обрабатывают ошибки в Go.

os.Error

Этот тип используется почти во всех библиотечных вызовах. Благодаря возможности возвращать несколько значений в функциях теперь можно возвращать не только значение, но и саму ошибку (nil в случае успеха). Это своеобразный аналог errno в C, только локальный, а не глобальный. Удобно ли это?

// C
fd = open("myfile.txt")
if (fd < 0 && errno == ENOENT) {
  printf("No such file\n");
  return
}

// Go
fd, err := os.Open("myfile.txt")
if err == os.ENOENT {
  println("No such file")
  return
}

Т.е. использование C и Go мало чем отличается в таком случае. Однако, если мы вызываем подряд 5 функций, после вызова каждой будем проверять значение err, то это сильно запутает код. Зачем же нужно возвращать os.Error? Он нужен только для того, чтобы восстановить последствия отдельной конкретной ошибки. Если вы пишете библиотечную функцию, то возвращайте os.Error, потому что приложение может захотеть обрабатывать особые ошибки по-особому.

Кстати, еще в os.Error меня огорчает, что для этого типа необходимо импортировать модуль os. Так, кстати сложилось чисто исторически, и в Go 1 вместо os.Error будет built-in тип error. Но об этом будет совсем другая статья.

И все же, как быть, если приложению плевать на ошибку — ее никак не восстановить, и нужно просто прекратить работу функции? Тогда нам понадобится аналог исключений.

panic

`panic()` вызывает run-time ошибку и прекращает работу программы.

Фактически глобальный exit. Как правило.

Однако, в Go существуют отложенные функции (defer). Так вот, они будут вызваны даже если сработал panic(). Т.е. если вы открыли файл, указали defer f.Close(), то файл будет закрыт даже если в процессе работы будет критическая ошибка.

А значит, можно установить defer-функцию, которая будет реагировать на ошибки panic. Это функция recover(). Например:

func f() {
   ...
   if ... {
      panic("Failed to open file")
   }
   ...
}

func g() {
   ...
   if ... {
      panic("Failed to parse file")
   }
   ...
}

func h() {
   ...
}

func main() {
   // set panic handler
   defer func() {
      if err := recover(); err != nil {
         fmt.Println("Fatal error: ", err)
      }
   }

   // run functions that can fail, like:
   // try {
   //    f();
   //    g();
   //    h();
   // } catch(Exception e) {
   //    ...
   // }
   f()
   g()
   h()
}

Если в любой из функций f(), g() или h() случится, то выполнение main() прервется, и будет вызвана только отложенная функция. В этой отложенной функции будет выведено сообщение «Fatal error: » и текст ошибки. Аналог catch(). Только наоборот. Впрочем, как и многое в Go — наоборот.

Ловить panic-ошибки можно в любой функции на любом уровне вложенности. Единственное, что нужно помнить — panic() только для ошибок, которые невозможно (или не хотите) восстанавливать.

Выводы

По-моему достаточно удобный механизм. Идея не нова, сразу вспоминается старый сишный `atexit()`.

Учитывая, что с помощью panic() можно передавать произвольные типы, то это аналог исключений. При этом эти исключения не обязательно должны наследоваться от базового класса Exception. Весьма простое и гибкое решение.

Сборка Go-проекта

У новичка могут возникнуть проблемы со сборкой проектов, написанных на Go. Это потому, что вначале во всех учебниках говорят про 8g/8l (6g/6l), а потом вот так сразу переходят к дебрям языка, а про make и правила сборки упускают.

Так вот, не пугайтесь. В Go самые простые Makefile. Давайте разбираться.

Сборка проекта

Для сборки проекта можно использовать такой шаблон Makefile:

include $(GOROOT)/src/Make.inc

TARG=mycmd
GOFILES=mycmd.go

include $(GOROOT)/src/Make.cmd

В любом Makefile для Go вначале включают Make.inc. В этом файле лежат общие правила сборки, а именно:

  • Проверяется окружение ($GOROOT, $GOOS, …)
  • Устанавливаются компиляторы (?g, ?l, ?a)
  • Создается правило, которое показывает ваше окружение: make go-env

После включения Make.inc (который обеспечивает вам кросс-платформенность, потому что внутри сам определяет платформу и устанавливает соответствующие переменные) создаем переменную $TARG. Это — имя вашего бинарника, который должен получиться в результате сборки.

Затем указывает $GOFILES — список файлов, из которых состоит проект. Файлов может быть несколько, напр. GOFILES=main.go util.go conf.go

Последняя строчка — это включение Make.cmd, файла, в котором описаны правила сборки «команды» — обычного приложения. В нем определяются также правила для тестирования проекта с помощью gotest.

Сборка пакета

Если же вы хотите собрать не приложение, а библиотеку (пакет), то замените Make.cmd на Make.pkg.

Все. Теперь можете делать make, make clean и даже make install.