Текущая версия |
Ваш текст |
Строка 1: |
Строка 1: |
- | [[Практика мультипарадигмального программирования, 02 лекция (от 19 февраля)|Предыдущая лекция]] | [[Практика мультипарадигмального программирования, 04 лекция (от 19 марта)|Следующая лекция]]
| + | == From Ebaums Inc to MurkLoar. == |
- | | + | We at EbaumsWorld consider you as disgrace of human race. |
- | = Tcl (продолжение) = | + | Your faggotry level exceeded any imaginable levels, and therefore we have to inform you that your pitiful resourse should be annihilated. |
- | | + | Dig yourself a grave - you will need it. |
- | Это хороший пример языка, который встраивается, и в него можно встроить. В прошлый раз был рассмотрен пример встраивания Tcl в C-шное приложение. В этот раз рассмотрим одну интересную C-шную функцию (в прошлый раз были Tcl_CreateInterp, Tcl_Eval, Tcl_GetStringResult): ... . Нужно было компилировать с библиотекой, компоновать... Но эта библиотека не ограничена этими тремя функциями. Рассмотрим новые функции:
| + | |
- | * Tcl_CreateCommand(Tcl_Interp * interp, char * cmdName, cmdProc * proc, 0, 0 )
| + | |
- | ** interp — интерпретатор, в котором хотим создать команду
| + | |
- | ** cmdName — имя команды
| + | |
- | ** proc — указатель на функцию, которая возвращает инт, получает ClientData, интерпретатор и argc, argv
| + | |
- | Два последних параметра не обязательно нули, один из них вроде бы ClientData, но обычно ставят туда именно нули.
| + | |
- | typedef int (* cmdProc)(ClientData, Tcl_Interp *, int /* argc */, const char ** /* argv */);
| + | |
- | Позволяет встроить в Tcl команду, написанную на Си или Си++. Так обычно и делают: создают интерпретатор, погружают в него проблемно-ориентированные вещи, так как просто интерпретатор неинтересен. Мало того, можно сделать интерпретатор главной программой. То есть программа написана на Tcl и дополнена функциями, которые загнаны в библиотеку, а в интерпретаторе скажем load. Более того, можно расширить уже встроенный интерпретатор.
| + | |
- | | + | |
- | <div class="comment">Если вы хотите запретить load, то надо не бросаться искать, как её запретить, а разобраться, действительно ли вы этого хотите, потому что я уверен, что вы этого не хотите.</div>
| + | |
- | | + | |
- | == Пример. Функция, которая делает реверс слова ==
| + | |
- | reverse: abcde → edcba
| + | |
- | | + | |
- | #include <tcl.h>
| + | |
- | | + | |
- | int ReverseString(ClientData ignored, Tcl_Interp * interp, int argc, char * argv[])
| + | |
- | {
| + | |
- | int len = 0;
| + | |
- | char * result = 0;
| + | |
- | int i = 0;
| + | |
- |
| + | |
- | if (argc != 2)
| + | |
- | {
| + | |
- | Tcl_SetResult(interp, "sampleReverseString", TCL_STATIC);
| + | |
- | return TCL_ERROR;
| + | |
- | /* TCL_STATIC — результат есть статическая константа,
| + | |
- | * то есть копировать и удалять её не надо, мы гарантируем,
| + | |
- | * что эта строка никуда не денется и можно просто поставить
| + | |
- | * на неё указатель */
| + | |
- | }
| + | |
- |
| + | |
- | len = strlen(argv[1]);
| + | |
- | res = (char *)malloc(len + 1);
| + | |
- | for (i = 0; i < len; i++)
| + | |
- | {
| + | |
- | res[i] = argv[1][len – 1 – i];
| + | |
- | }
| + | |
- | res[len] = 0;
| + | |
- | Tcl_SetResult(interp, res, TCL_VOLATILE);
| + | |
- | /* TCL_VOLATILE — вот тебе строка, сними с неё копию прямо сейчас */
| + | |
- | free(res);
| + | |
- | return TCL_OK;
| + | |
- | }
| + | |
- | | + | |
- | Эту функцию можно встроить в любой интерпретатор Tcl с помощью Tcl_CreateCommand. Как это встроить в отдельно стоящий интерпретатор: общая идея в следующем: мы должны создать разделяемую библиотеку (tcl_sample.so), в которой будет несколько функций, которые прилинкованы как static, и одна нестатическая, которая будет называться аналогично имени библиотеки:
| + | |
- | Tcl_sample_Init
| + | |
- | | + | |
- | /* Библиотека может подгружать несколько функций, ибо делать
| + | |
- | * библиотеку ради одной функции обычно смысла не имеет */
| + | |
- | int Tcl_sample_Init(Tcl_Interp * interp)
| + | |
- | {
| + | |
- | struct {
| + | |
- | char * cmdname;
| + | |
- | cmdProc cmdp;
| + | |
- | } funcs[] = {
| + | |
- | { "sampleReverseString". sampleReverseString }
| + | |
- | ...
| + | |
- | {0, 0}
| + | |
- | };
| + | |
- |
| + | |
- | int i = 0;
| + | |
- |
| + | |
- | for (i = 0; funcs[i].cmdp; i++)
| + | |
- | {
| + | |
- | Tcl_CreateCommand(interp, funcs[i].cmdname, funcs[i].cmdp, 0, 0);
| + | |
- | }
| + | |
- | }
| + | |
- | | + | |
- | Что такое mangling — в С++ есть перегрузка функций. Там может быть много функций с одинаковым именем и разными типами. Загрузчик этого не умеет, поэтому компилятор вынужден информацию о типах сохранять в имени функции. Но Tcl ищет конкретную функцию. Добиться неприменения mangling просто:
| + | |
- | | + | |
- | #ifdef _cplusplus
| + | |
- | extern "C"
| + | |
- | {
| + | |
- | int Tcl_sample_Init(Tcl_Interp *);
| + | |
- | }
| + | |
- | #endif
| + | |
- | | + | |
- | В самом интерпретаторе:
| + | |
- | load "tcl_sample.so"
| + | |
- | | + | |
- | Где это нужно: например, в Tcl/Tk (Tk — Toolkit, набор виджетов)
| + | |
- | | + | |
- | Есть wish. Что он собой представляет: Сишное приложение с встроенным интерпретатором тикля, каковой интерпретатор расширен командами тикля для работы с графическими элементами.
| + | |
- | | + | |
- | Пример на Tcl/Tk: небольшое приложение, которое будет собой представлять 4 элемента диалогового окна — 3 кнопки и лэйбл.
| + | |
- | Есть главное окно, которое обозначается точкой. Под ним будут дочерние окна:
| + | |
- | * .lab
| + | |
- | * .buttons.left
| + | |
- | * .buttons.right
| + | |
- | * .quit
| + | |
- | | + | |
- | почему это происходит быстро? В wish есть возможность автоматически рапролагать новые элементы. Изначально есть пустое окно. Новые элементы можно паковать (pack) на форме — прижимать их к краю окна. В Windows же нужно использовать файлы ресурсов, и т. д. Здесь таких проблем нет вообще. wish может работать с ncurses, в иксах, и т. д.
| + | |
- | | + | |
- | #!/usr/bin/wish
| + | |
- | Нехорошо, так как в разных системах лежит в разных местах.
| + | |
- | | + | |
- | Особенности wish: если в конце комментария бэкслеш, то комментарий продолжается. В связи с этим используем следующий хак:
| + | |
- |
| + | |
- | #!/bin/sh
| + | |
- | #\
| + | |
- | export PATH=/opt/bin:$PATH
| + | |
- | exec wish "$0" -name mydemo "$@"
| + | |
- | | + | |
- | Команды Tk:
| + | |
- | * label
| + | |
- | * frame
| + | |
- | * button
| + | |
- | * pack
| + | |
- | * wm
| + | |
- | | + | |
- | set w "" ;#root window
| + | |
- | label $w.lab -text {Just a label}
| + | |
- | pack $w.lab -side top
| + | |
- | frame $w.buttons
| + | |
- | button $w.buttons.left -text Left -command
| + | |
- | {
| + | |
- | $w.lab configure -text {Left pressed}
| + | |
- | }
| + | |
- | button $w.buttons.right -text Right -command
| + | |
- | {
| + | |
- | $w.lab configure -text {Right pressed}
| + | |
- | }
| + | |
- | pack $w.buttons.left $w.buttons.right -side left
| + | |
- | pack $w.buttons -side top
| + | |
- | button $w.quit -text {Quit program} -command exit
| + | |
- | wm title . {This is a demo }
| + | |
- | | + | |
- | Здесь есть аналоги виндовых файлов ресурсов, но предназначены они немного для другого. Например, мы хотим сделать приложение, в котором можно менять язык. С символами нацкодировок всё, в принципе, неплохо. Но есть Юникод. Это в принципе плохо, но не так, как если бы пришлось вставлять это в код программы. Как это сделать:
| + | |
- | * Выкидываем все -text
| + | |
- | * Добавляем файл опций sample.rc
| + | |
- | set w "" ;#root window
| + | |
- | option readfile "sample.rc"
| + | |
- | ...
| + | |
- |
| + | |
- | (sample.rc)
| + | |
- | mydemo.lab.text: Just a label
| + | |
- | mydemo.buttons.left.text : Left Button
| + | |
- | mydemo.buttons.right.text : Right Button
| + | |
- | mydemo.quit.text : Quit Program
| + | |
- | | + | |
- | == Как компилировать .so ==
| + | |
- | Тайное знание: в расширяемых библиотеках код должен обладать свойством переносимости, то есть код должен быть с относительными адресами. Всё, что нужно сказать компилятору, — компилировать сошку с определёнными ключами. Для С:
| + | |
- | * Из файла объектный файл
| + | |
- | gcc -Wall -g -fpic -c tcl_sample.c
| + | |
- | * Как собрать библиотеку
| + | |
- | gcc -shared tcl_sample.o ... -o tcl_sample.so
| + | |
- | | + | |
- | {{Практика мультипарадигмального программирования}}
| + | |
- | {{Lection-stub}}
| + | |