15 мая 2013 г.

Аннотации в PyBindGen

 Ссылки


PyBindGen

PyBindGen - это генератор биндингов к коду на C/C++ для Python. Он позволяет сгенерировать код на C или C++, компилирующийся в динамическую библиотеку. Эта библиотека будет модулем Python с интерфейсом для всех классов и функций C/C++.

Есть два основных варианта его использования:
  1. Использовать модуль pybindgen и вручную описать на Python все классы, методы и функции, для которых нужно сгенерировать биндинги.
  2. Использовать модуль pybindgen.gccxmlparser, который позволяет распарсить заголовочные файлы C/C++ с помощью pygccxml и автоматически сгенерировать скрипт Python, аналогичный написанному вручную в пункте (1). Этот скрипт будет в свою очередь генерировать биндинги.

Атрибуты

При возникновении неоднозначных ситуаций, их нужно устранять, указывая для классов, функций и их параметров дополнительные атрибуты, в частности политику передачи владения объектами.
  1. Если используется вариант (1), атрибуты указываются при добавлении методов в скрипте на Python.
  2. Если используется вариант (2), атрибуты указываются в коде на C/C++ в комментариях специального формата (аннотациях).

Аннотации

Аннотация - это комментарий вида:

// -#- АННОТАЦИЯ -#-

Между // и -#- должен быть пробел. Комментарий должен быть строго на предыдущей строке от объявления.

Для функции, метода или поля:

// -#- АННОТАЦИЯ -#-
void foo();

Для класса или структуры:

class bar
// -#- АННОТАЦИЯ -#-
{
...
};

Игнорирование

Аннотация ignore отключает генерацию биндингов для объявления.

// -#- ignore -#-
void foo()

Наследование

Аннотация allow_subclassing включает возможность наследования классов Python от классов C++.

class foo
// -#- allow_subclassing=true -#-
{
...
};

Если наследник в питоне имеет конструктор, нужно не забыть вызвать в нем конструктор базового класса, иначе сгенерированный биндинг будет проинициализирован неправильно.

class bar(foo):
    def __init__(self):
        foo.__init__(self)
        # do something

Подсчет ссылок

Если указать методы объекта, реализующие подсчет ссылок, они будут автоматически использоваться в Python. Это может значительно упростить соглашения о передачи владения объектов, см. раздел "Владение".

class foo
// -#- incref_method=IncRef; decref_method=DecRef; peekref_method=PeekRef -#-
{
  void IncRef();
  void DecRef();
  int PeekRef();
};

Владение

Эти атрибуты устраняют неоднозначности поведения сгенерированного кода при передаче и возвращении указателей. Набор атрибутов аналогичен политикам в Boost.Python.

Использовать объекты с подсчетом ссылок проще:
  • политики владения для объектов без подсчета ссылок зависят от поведения каждого конкретного метода и способов создания и удаления объектов;
  • политики для объектов с подсчетом ссылок зависят только от соглашения, вызывает ли incref() и decref() вызывающая сторона или вызываемая, в остальном владение автоматически разруливается подсчетом ссылок.

Аннотации имеют вид:

// -#- @параметр(атрибут=значение, атрибут=значение); @параметр(...); ... -#-

Специальный параметр @return обозначает возвращаемое значение.

Атрибуты для объектов без подсчета ссылок


Параметры

Атрибут transfer_ownership определяет, передает ли Python владение переданным объектом коду C++:
  • Если равен true:
    • Python теряет владение объектом.
    • Python больше не отвечает за удаление объекта.
    • Python обнулит все свои ссылки на этот объект.
    • Конструктор копирования не вызывается.
  • Если равен false:
    •  Python сохраняет владение объектом.
    • Для объекта будет вызван конструктор копирования и в C++ будет передана копия. Если у объекта запрещен конструктор копирования, биндинги не скомпилируются. Если объект полиморфный, могут возникнуть проблемы в рантайме.

// -#- @p1(transfer_ownership=false) -#-
void myfunc(myclass *p1);

Возвращаемое значение

Атрибут caller_owns_return определяет, получает ли Python владение объектом, возвращенным из C++:
  • Если равен true:
    • Python получает владение объектом.
    • Python отвечает за удаление объекта.
    • C++-код больше не имеет права использовать этот объект.
    • Конструктор копирования не вызывается.
  • Если равен false:
    • Python не владеет объектом.
    • Python не отвечает за удаление объекта.
    • C++-код по-прежнему может использовать объект и отвечает за его удаление.
    • Для возвращенного объекта будет вызван конструктор копирования, и в в Python будет использоваться созданная копия. Если у объекта запрещен конструктор копирования, биндинги не скомпилируются. Если объект полиморфный, могут возникнуть проблемы в рантайме.

// -#- @return(caller_owns_return=true) -#-
myclass * myfunc();


Атрибут reference_existing_object может модифицировать поведение caller_owns_return:
  • Если равен true:
    • Python получает владение объектом.
    • Python отвечает за удаление объекта.
    • C++-код по-прежнему может использовать объект.
    • C++-код при этом больше не отвечает за удаление объекта. Программист ответственен за то, чтобы Python не удалил объект раньше, чем C++-код перестал его использовать.
    • Конструктор копирования не вызывается.

// -#- @return(reference_existing_object=true) -#-
myclass * myfunc();

 

Атрибут return_internal_reference указывает, что метод вернул указатель на объект, являющийся составной частью вызываемого объекта.

struct foo
{
  bar b;

  // -#- @return(return_internal_reference=true) -#-
  bar * get_bar()
  {
    return &b;
  }
};

Атрибуты объектов с подсчетом ссылок


Параметры

Атрибут transfer_ownership определяет, кто отвечает за увеличения счетчика ссылок.
  • Если равен true, Python должен увеличить счетчик ссылок перед вызовом, если хочет продолжать использовать объект.
  • Если равен false, Python не должен ничего делать. Если C++-код хочет пользоваться объектом, он сам увеличит счетчик ссылок.

Возвращаемое значение

Атрибут caller_owns_return определяет, кто отвечает за увеличения счетчика ссылок.
  • Если равен true, C++-код уже увеличил счетчик ссылок перед тем, как вернуть объект.
  • Если равен false, Python должен сам увеличить счетчик ссылок, если хочет пользоваться объектом.

Выходные аргументы

Если атрибут direction равен out, C++-код будет модифицировать переданный объект.

// -#- @p1(direction=out) -#-
void foo(int *p1);


Массивы

Если параметр является массивом, его длину можно указать с помощью атрибута array_length.

// -#- @a1(direction=out, array_length=100) -#-
void bar(int *a1);

4 мая 2013 г.

Убрать прозрачность и поменять DPI в pic2graph




$ cat > hello.pic 
ellipse "hello";
arrow;
ellipse "world!";
^D
$ DPI=150
$ pic2graph -alpha Remove -density ${DPI}x${DPI} < hello.pic > hello.png



13 мар. 2013 г.

/bin/sh: no: command not found

Ошибка

$ ./configure
...
/bin/sh: line 1: no: command not found


Возможное решение

# apt-get install gettext

10 мар. 2013 г.

Пьесы Шекспира в две колонки с переводом

Если Вы хотите почитать Шекспира на английском, но ничего не понимаете, можно отформатировать оригинал и перевод на русский в две колонки: слева реплика на английском, справа ее перевод.

Удобные для парсинга английские варианты есть на shakespeare.mit.edu. В HTML текст уже разделен на акты, сцены и пронумерованные реплики. Русские переводы есть на lib.ru/SHAKESPEARE. HTML для парсинга неудобен, но plain text можно разбить на реплики регулярными выражениями.

Здесь находятся 3 скрипта, которые делают следующее:
  1. mit2xml: преобразует пьесу с mit.edu в XML.
  2. libru2xml: преобразует пьесу с lib.ru в XML.
  3. concat-en-ru: склеивает два XML по репликам и генерирует один HTML-файл.
Скрипты проверялись только на пьесе "Буря" (The Tempest): en, ru (и на других её переводах с lib.ru). URL исходных HTML  прописываются в Makefile. Собрать выходной HTML с двумя колонками для "Бури" можно так:

$ make tempest

Необходимые перловые модули можно установить с помощью пакетного менеджера или так:

$ sudo make cpan

Результат можно посмотреть здесь.

Для форматирования других пьес потребуется создать файл с переводом имен героев, по аналогии с tempest_names.cfg. Он используется для нахождения соответствия между английскими и русскими репликами, которые не всегда идут один-в-один.

Список имен героев можно получить так:

$ perl mit2xml ... | grep '<actor>'
$ perl libru2xml ... | grep '<actor>'

Кроме этого, возможно, придется поколдовать в регулярными выражениями в libru2xml, они могут не подходить для других пьес.

16 февр. 2013 г.

Gentoo: Сборка GCC 3.2 в современном окружении

В Gentoo есть ebuild-ы для GCC старых версий, однако GCC 3.2 не собирается последними версиями GCC, в том числе текущим стабильным 4.6. Возможное решение следующее: с помощью GCC 4.6 собрать GCC 3.4, а с помощью GCC 3.4 уже собрать GCC 3.2.

Шаг 1: версия bison


GCC 3.2 не собирается текущим стабильным bison 2.x. Для bison слотов нет, так что для сборки GCC можно просто замаскировать новые версии. У меня работает bison-1.875d.

/etc/portage/package.mask

>=sys-devel/bison-2.0

# emerge -u sys-devel/bison

Шаг 2: настройка окружения


См. /etc/portage/env.
  1. Во-первых, GCC версии 3.x могут не поддерживать ваши CFLAGS (в частности -march=native), поэтому отключим их для этих пакетов.
  2. Во-вторых, мы должны указать, что для сборки GCC 3.2 будет использоваться GCC 3.4.
/etc/portage/package.env

# Отключаем CFLAGS для GCC 3.x
=sys-devel/gcc-3* use-simple-cflags.conf

# Включаем использование GCC 3.4 для GCC 3.2
=sys-devel/gcc-3.2* use-gcc-3.4.conf

 /etc/portage/env/use-simple-cflags.conf 

CFLAGS="-O2"
CXXFLAGS="-O2"

/etc/portage/env/use-gcc-3.4.conf 

CC="gcc-3.4.6"


Шаг 3: сборка GCC 3.4


# emerge sys-devel/gcc:3.4


Шаг 4: сборка GCC 3.2


# emerge sys-devel/gcc:3.2
# /usr/i686-pc-linux-gnu/gcc-bin/3.2/gcc --version

13 февр. 2013 г.

Emacs, tramp: File ... is read-only on disk. Change buffer mode?


Это сообщение может появиться, если соединение разорвалось и tramp не может установить повторное соединение самостоятельно.

Решение:

M-x tramp-cleanup-all-connections

Затем можно обновить буфер в dired или повторно сохранить файл.

2 февр. 2013 г.

Emacs: тормоза, плавная прокрутка


Ссылки

  1. Возможные причины медленной работы
  2. Плавная прокрутка

Возможные симптомы и их причины


1. Задержки при наборе текста


Это возможно при использовании модуля tabbar, старый баг. AFAIK, его мало кто использует.

2. Задержки при прокрутке и построчном перемещении курсора

Возможные причины:
  1. Самое главное, из-за linum-mode (нумерация строк).
  2. Из-за font-lock-mode (применение цветов и шрифтов к тексту), когда в буфере слишком много разноцветных жирных шрифтов.
  3. Из-за hl-line-mode (подсветка текущей строки).

Плавная прокрутка без тормозов и без отключения перечисленных режимов возможна, но, как и положено, опциональна и отключена по-дефолту.

Настройки прокрутки

;; При прокрутке применять font-lock не сразу, а после небольшой задежки.
(setq jit-lock-defer-time 0.01)

;; Эту опцию часто советуют выставлять в t, но я не заметил разницы с nil.
;(setq redisplay-dont-pause t)

;; Опционально: медленная плавная прокрутка колесиком.
(setq mouse-wheel-scroll-amount '(2 ((shift) . 2)))   ; Прокручивать по 2 строки.
(setq mouse-wheel-progressive-speed nil)
(setq mouse-wheel-follow-mouse 't)

;; Опционально: никогда не прокручивать более, чем на 1 строку при перемещении курсора за
;; нижнюю или верхнюю границу экрана.
(setq scroll-conservatively 10000)

;; Опционально: отступ от верха и низа экрана в 1 строку, при попадании курсора за отступ
;; происходит прокрутка.
(setq scroll-margin 1)

См. также Bug #12936.

Настройки нумерации строк

Дело в том, что linum-mode перерисовывает номера строк во время прокрутки, из-за чего она и тормозит. Мне известны 2 альтенативы:

  1. nlinum-mode: успешно решает в точности описанную проблему. Доступен на github.
  2. setnu-mode: предшественник linum-mode, работает почти без задержек, но есть баги, в том числе при использовании совместно с модулем auto-complete.
Стандартный linum позволяет установить hook на генерацию формата номеров строк и face для них, причем они могут быть свои для каждой строки. В nlinum это на данный момент не поддерживается, но такую возможность легко добавить, см. nlinum--region.

Справедливости ради замечу, что на 8-ядерном компьютере прокрутка у меня все же немного плавнее, чем на 2-х ядерном.