Harbour для начинающих: различия между версиями

Содержимое удалено Содержимое добавлено
Новая страница: «Описывается «курс молодого бойца» для освоения языка програмирования '''Harbour''' — соврем…»
 
дополнение
Строка 3:
Основной материал — с [http://kresin.belgorod.su/rus/hrbfaq.html сайта Александра Кресина].
 
(''за основу содержания«Содержания» взял — пока — структуру из английского учебника [[:en:Application Development with Harbour|Application Development with Harbour]]'' — А. Густов)
 
== Введение ==
Строка 50:
 
=== Устанавливаем бинарники Harbour ===
Бинарные пакеты распростаняются в форматах, специфичных для соответствующей платформы. Для Windows это exe’шник — запускаете его и следуете инструкциям установщика; для Ubuntu это deb файл — пользователи Ubuntu знают, что с ним делать; ну и т. д.
 
=== Устанавливаем Harbour из исходников ===
Чтобы построить Харбор — компилятор и библиотеки, нам необходимо иметь C компилятор, об этом мы уже говорили [[#Выбираем C компилятор|ранее]].
 
В корне вашего дистрибутива Harbour есть файл ''README.txt'' (до 14.11.2012 он назывался ''INSTALL''), там содержатся подробные инструкции по сборке Харбора из исходников. Правда, этот файл — на английском языке. Ниже я расскажу об этом очень кратко, для большинства случаев этого будет достаточно.
 
Если у вас Windows, укажите путь к каталогу bin вашего C компилятора и запускайте win-make.exe — этот файл есть в вашем дистрибутиве Harbour. Я обычно делаю bat’ник с этими строками и запускаю его на исполнение.
 
Так, если у вас Borland C 5.5, то это будет выглядеть примерно так:
 
<pre>set path=c:\borland\bcc55\bin
win-make.exe</pre>
 
Для mingw может быть вот так:
 
<pre>set path=c:\mingw\bin
win-make.exe</pre>
 
Для Open Watcom:
 
<pre>set watcom=C:\watcom
set path=%WATCOM%\BINNT;%WATCOM%\BINW;%PATH%
set edpath=%WATCOM%\EDDAT
set include=%WATCOM%\H;%WATCOM%\H\NT
win-make.exe</pre>
 
Если у вас Линукс/Юникс, то достаточно запустить команду ''make''.
 
Примеры для других платформ и компиляторов смотрите в ''README.txt'' (до 14.11.2012 он назывался ''INSTALL''), раздел ''8.EXAMPLES'', там их множество.
 
Для начала этого хватит, но впоследствии вам, возможно, потребуется установить дополнительные переменные окружения для управления процессом сборки. Полный их список смотрите, опять-таки, в ''README.txt'', а здесь я приведу лишь несколько примеров, чтобы было ясно, о чем идет речь.
 
Некоторые модули Харбора (в основном, это дополнительные — те, что в contribs) зависят от так-называемых ''3rd party'' компонентов, то есть от установленных у вас в системе сторонних программ. Например, для сборки библиотеки hbmysql из Harbour/contrib требуются файлы заголовков (.h) от MySql клиента, который у вас установлен. Поэтому, если вы хотите, чтобы эта библиотека была создана при сборке Харбора и чтобы она работала с установленным у вас MySQL клиентом, вы должны указать путь заголовкам этого клиента:
 
<pre>set HB_WITH_MYSQL=C:\mysql\include</pre>
 
Аналогично этому:
 
<pre>set HB_WITH_ADS=C:\ads\acesdk
set HB_WITH_ALLEGRO=C:\allegro\include
set HB_WITH_BLAT=C:\blat\full\source
set HB_WITH_CAIRO=C:\cairo\include\cairo
set HB_WITH_CURL=C:\curl\include
set HB_WITH_GS=C:\ghostscript-9.01\psi
set HB_WITH_GS_BIN=C:\ghostscript-9.01\bin (on Windows)
set HB_WITH_FIREBIRD=C:\Firebird\include
set HB_WITH_FREEIMAGE=C:\FreeImage\Dist
set HB_WITH_GD=C:\gd\include
set HB_WITH_OCILIB=C:\ocilib\include
set HB_WITH_OPENSSL=C:\openssl\inc32 OR C:\openssl\include
set HB_WITH_PGSQL=C:\pgsql\include</pre>
 
На Unix/Linux системах это обычно не требуется, так как все эти ''3rd party'' компоненты расположены в строго определенных местах и программа сборки сама их найдет. Чтобы, наоборот, запретить сборку этих модулей, вам надо присвоить соответствующей переменной значение ''no''.
 
Для некоторых из таких модулей все нужные файлы, и заголовочные в том числе, уже есть в составе Харбора. В этом случае вы можете или, как и выше, указать путь к установленному у вас компоненту, или присвоить переменной значение ''local'' — чтобы были использованы те самые Харборовские файлы и заголовки, или, наоборот, ''nolocal'' — чтобы запретить использование предопределенных в Харборе файлов:
 
<pre>set HB_WITH_BZIP2=C:\bzip2
set HB_WITH_EXPAT=C:\expat\lib
set HB_WITH_JPEG=C:\jpeglib
set HB_WITH_LIBHARU=C:\libharu\include
set HB_WITH_LZF=C:\liblzf
set HB_WITH_MINILZO=C:\minilzo\
set HB_WITH_MINIZIP=C:\zlib\contrib\minizip
set HB_WITH_MXML=C:\minixml
set HB_WITH_PCRE=C:\pcre
set HB_WITH_PNG=C:\libpng
set HB_WITH_SQLITE3=C:\sqlite3
set HB_WITH_TIFF=C:\libtiff
set HB_WITH_TINYMT=C:\tinymt\tinymt
set HB_WITH_XDIFF=C:\libxdiff-0.23\xdiff
set HB_WITH_ZLIB=C:\zlib</pre>
 
Ну и, напоследок, еще одна переменная, она указывает на каталог, куда надо установить бинарники Harbour:
 
<pre>set HB_INSTALL_PREFIX</pre>
 
=== xHarbour ===
xHarbour — это другой Harbour, ответвление (fork) от Harbour. В начале 2000-х один из разработчиков (Рон Пинкас) из-за разногласий с остальными членами команды покинул проект и основал свой. Впоследствии к нему присоединилась еще группа людей. Буква '''x''' в названии нового проекта должна была означать '''extended''' — «расширенный». Код был целиком унаследован от Harbour, но Пинкас внес в него свои изменения/дополнения, многие из которых были ранее отвергнуты основными разработчиками Harbour. По ходу дальнейшей разработки xHarbour заимствовал многое из Harbour и Harbour заимствовал кое-что из xHarbour, так что оба проекта тесно связаны и в большинстве случаев, если не использовать некоторые языковые расширения, программы успешно компилируются и тем, и другим. xHarbour существует в двух ипостасях :) — [http://www.xharbour.org/ открытой] и [http://www.xharbour.com/ коммерческой]. Чем они различаются — не знаю, разбирайтесь сами, если хотите. Подробно про различия между Harbour и xHarbour можно почитать в ''xhb-diff.txt'' — этот файл есть в любом дистрибутиве Harbour в каталоге ''Doc''. Я с самого начала и до сих пор являюсь членом команды Harbour, использую исключительно его, что рекомендую и вам. Тем более, что на сегодняшний день (ноябрь 2012) Harbour надежнее, быстрее и богаче возможностями. Все, о чем здесь говорится, относится к Harbour. Многое (но не все — ''Hbmk'', например в xHarbour не включена) из этого применимо и для xHarbour.
 
== Компиляция и линковка программы ==
 
=== Общие рассуждения ===
Собрать свою программу в Harbour можно тремя способами: с помощью традиционной make-системы, которая входит в состав любого С компилятора, с помощью командных файлов (bat’ников — под Windows и shell скриптов под Unix/Linux) или используя специальную Harbour утилиту ''hbmk2''. Здесь мы рассмотрим два последних способа.
 
Hbmk2, безусловно, удобная и мощная утилита. Главное ее достоинство в том, что она позволяет строить как простенькие программы, так и большие проекты, не вдаваясь в детали работы компилятора и линкера. Hbmk2 сама находит ваш С компилятор и производит необходимые действия. Что может быть проще, чем запустить из командной строки утилиту со списком исходных файлов проекта? Для более сложных случаев — если вам надо обязательно установить какие-то особые опции компиляции, присоединить дополнительные библиотеки, или использовать динамические библиотеки, — потребуется знать специальные параметры hbmk2, или даже создавать конфигурационные файлы проекта, но все равно это будет проще, чем использовать другие способы сборки.
 
Я, тем не менее, предпочитаю традиционный способ сборки — с помощью командных файлов, так как он дает полный контроль над процессом, с ним я четко вижу, что именно я делаю и зачем. Общая последовательность действий здесь простая:
 
1. Компилируем *.prg в *.c с помощью harbour.exe.<br />
Параметры компилятора, в основном, те же, что и у Клиппера. Полный их список можно получить, запустив harbour.exe без параметров. В одной строчке можно указывать несколько prg файлов.
 
2. Компилируем *.с в объектные файлы вашим С компилятором.
 
3. Линкуем объектные файлы тем линкером, который поставляется с С компилятором.<br />
При линковке надо обязательно указать список Харборовских библиотек, которые нужны вашему приложению.
 
Все используемые с Харбором С компиляторы позволяют объединить шаги 2 и 3 — делайте, как вам нравится.
 
=== Windows, bat файл ===
Ниже приведен bat’ник, которым я обычно пользуюсь, чтобы скомпилировать один prg (Borland C, gtwin):
 
''('''для редакторов:''' тут надо как-то переформатировать, чтобы строчки с BCC32 не были столь длинными, то есть как-то организовать переносы)''
 
<pre>@set HB_BIN_INSTALL=d:\harbour\bin
@set HB_LIB_INSTALL=d:\harbour\lib
@set HB_INC_INSTALL=d:\harbour\include\
 
%HB_BIN_INSTALL%\harbour %1.prg -n -i%HB_INC_INSTALL%
bcc32 -O2 -d -I%HB_INC_INSTALL% -L%HB_LIB_INSTALL% %1.c hbdebug.lib hbvm.lib hbrtl.lib gtwin.lib hbcpage.lib hblang.lib hbrdd.lib hbmacro.lib hbpp.lib rddntx.lib rddcdx.lib rddfpt.lib hbsix.lib hbcommon.lib hbct.lib</pre>
 
Если вы хотите использовать gtwvt экранный драйвер, то последняя строчка будет выглядеть так:
 
<pre>bcc32 -O2 -tW -I%HB_INC_INSTALL% -L%HB_LIB_INSTALL% %1.c hbdebug.lib hbvm.lib hbrtl.lib gtwvt.lib hbcpage.lib hblang.lib hbrdd.lib hbmacro.lib hbpp.lib rddntx.lib rddcdx.lib rddfpt.lib hbsix.lib hbcommon.lib hbct.lib</pre>
 
Для Mingw C компилятора замените последнюю строчку на:
 
<pre>gcc -Wall -mno-cygwin -c -I%HB_INC_INSTALL% %1.c
gcc -Wall -mwindows -o%1%.exe %1.o -L%HB_LIB_INSTALL%/win/mingw -Wl,--start-group -lhbvm -lhbrtl -lgtwvt -lhblang -lhbrdd -lhbmacro -lhbpp -lrddntx -lrddcdx -lrddfpt -lhbsix -lhbcommon -lhbcpage -lhbct -luser32 -lgdi32 -lwinspool -lcomctl32 -luuid -lkernel32 -lws2_32 -Wl,--end-group</pre>
 
Если вам надо построить программу из нескольких файлов, то можно использовать что-либо вроде этого (Borland C, gtwin):
 
<pre>@set HB_BIN_INSTALL=d:\harbour\bin
@set HB_LIB_INSTALL=d:\harbour\lib
@set HB_INC_INSTALL=d:\harbour\include\
 
%HB_BIN_INSTALL%\harbour file1.prg -n -i%HB_INC_INSTALL%
%HB_BIN_INSTALL%\harbour file2.prg -n -i%HB_INC_INSTALL%
...
bcc32 -O2 -d -I%HB_INC_INSTALL% -L%HB_LIB_INSTALL% file1.c file2.c ... hbdebug.lib hbvm.lib hbrtl.lib gtwin.lib hbcpage.lib hblang.lib hbrdd.lib hbmacro.lib hbpp.lib rddntx.lib rddcdx.lib rddfpt.lib hbsix.lib hbcommon.lib hbct.lib</pre>
 
=== Linux, sh скрипт ===
Последовательность, естественно, та же, только синтаксис немножко другой (для консольного приложения с gtcrs):
 
<pre>#!/bin/sh
HB_INS="/apps/harbour"
$HB_INS/bin/harbour $1.prg -n -q0 -es2 -gc0 -I$HB_INS/include -I../include -d__LINUX__
gcc -I. -I$HB_INS/include -Wall -c $1.c -o$1.o
gcc -Wall -o$1 $1.o -L $HB_INS/lib \
-Wl,--start-group -lhbvm -lhbrtl -lhblang -lhbrdd \
-lhbmacro -lhbpp -lhbcommon -lrddntx -lrddcdx -lrddfpt -lhbsix \
-lhbct -lgttrm -lhbcpage -Wl,--end-group -lm -lgpm</pre>
 
=== Hbmk2 ===
С помощью Hbmk2 все немного проще. Чтобы откомпилировать программу из одного prg — файла (например, hello.prg), просто наберите:
 
<pre>hbmk2 hello.prg</pre>
 
Из двух prg:
 
<pre>hbmk2 mymain.prg second.prg</pre>
 
Построить приложение, используя специальный конфигурационный файл проекта:
 
<pre>hbmk2 myapp.hbp</pre>
 
Построить приложение, используя свою библиотеку:
 
<pre>hbmk2 myapp.prg -lmylib -L</pre>
 
Построить приложение, из всех prg и c файлов, расположенных в каталоге ''src'':
 
<pre>hbmk2 -omyapp src/*.prg src/*.c</pre>
 
Hbmk2 сама определяет, какой C компилятор у вас установлен, она ищет путь к нему в переменной окружения ''PATH''. Если у вас больше, чем один установленный C компилятор и хотите указать, какой именно должна использовать hbmk2, пропишите параметр ''-comp=<name>'', где <name> — условное обозначения компилятора, например:
 
— для Windows: mingw, msvc, bcc, watcom, icc, pocc, xcc, mingw64, msvc64, msvcia64, iccia64, pocc64;
 
— для Linux: gcc, clang, icc, watcom, sunpro, open64, pcc.
 
Очень полезная опция ''-trace'' выводит на экран все вызовы компиляторов и линкера со всеми их опциями, которые потребовались для сборки данного проекта — так вам проще разобраться в проблемах, если что-то пошло не так, ну и вообще, на мой взгляд, полезно знать, как именно строилось ваше приложение.
 
=== Как использовать динамические библиотеки (dll, so) ===
В результате процесса сборки, описанного в предыдущих подразделах, вы получаете исполняемый модуль, который включает в себя ваши исходный тексты, скомпилированные в p-code, виртуальную машину Harbour, которая исполняет этот p-code, RTL — Run-Time Library — библиотеку функций Harbour и, возможно, другие библиотеки, которые вы включили в проект. Поэтому этот исполняемый модуль имеет довольно-таки большой размер. Его можно существенно уменьшить, если использовать динамическую библиотеку. Бинарные дистрибутивы Harbour включают, помимо статических библиотек (.lib, .a) и динамическую (.dll, .so), которая включает в себя все функции основных библиотек Harbour. Ее название может включать в себя номер версии Harbour и название C компилятора; так, например, для Harbour 2.1, построенного с Borland C, это harbour-21-bcc.dll. Естественно, использоваться такой исполняемый модуль может только совместно с соответствующей динамической библиотекой.
 
Итак, наш bat’ник для компиляции одного prg c Borland C приобретает такой вид:
 
<pre>@set HB_BIN_INSTALL=d:\harbour\bin
@set HB_LIB_INSTALL=d:\harbour\lib
@set HB_INC_INSTALL=d:\harbour\include\
 
%HB_BIN_INSTALL%\harbour %1.prg -n -i%HB_INC_INSTALL%
bcc32 -O2 -d -I%HB_INC_INSTALL% -L%HB_LIB_INSTALL% %1.c hbmainstd.lib harbour-21-bcc.lib</pre>
 
Отличие состоит в том, что вместо длинного списка библиотек мы используем теперь только две — hbmainstd.lib и harbour-21-bcc.lib. Последняя представляет собой так называемую ''import library'' — библиотеку — указатель на функции из соответствующей dll. Такую библиотеку требуют для статической линковки с dll некоторые C компиляторы, в том числе Borland C и MSVC. Mingw и GNU C, кстати, этого не требуют. Название этой библиотеки может быть другим, если у вас другая версия Harbour — harbour-32-bcc.lib, например. Не буду здесь пояснять, для чего нужна hbmainstd.lib — все таки это Harbour для начинающих :), скажу только, что для некоторых GT, gtwvt, например, вместо нее нужно использовать hbmainwin.lib.
 
Для Mingw C компилятора замените последнюю строчку на:
 
<pre>gcc -Wall -mno-cygwin -c -I%HB_INC_INSTALL% %1.c
gcc -Wall -mwindows -o%1%.exe %1.o %HB_BIN_INSTALL%/win/mingw/harbour-21.dll -L%HB_LIB_INSTALL%/win/mingw -Wl,--start-group -lhbmainstd -luser32 -lgdi32 -lwinspool -lcomctl32 -luuid -lkernel32 -lws2_32 -Wl,--end-group</pre>
 
Для Unix/Linux и GNU C это будет выглядеть так:
 
<pre>#!/bin/sh
HB_INS="/apps/harbour"
$HB_INS/bin/harbour $1.prg -n -q0 -es2 -gc0 -I$HB_INS/include -I../include -d__LINUX__
gcc -I. -I$HB_INS/include -Wall -c $1.c -o$1.o
gcc -Wall -o$1 $1.o $HB_INS/lib/libharbour-2.1.0.so -lm -lgpm</pre>
 
то есть весь список библиотек мы заменили на libharbour-2.1.0.so (для другой версии Harbour название, соответственно, будет другим) — сама динамическую библиотеку, ''import library'', здесь не нужна.
 
С hbmk2 все существенно проще. Независимо от платформы и компилятора:
 
<pre>hbmk2 hello.prg -shared</pre>
 
Теперь о другом варианте использования динамических библиотек — о так называемых '''p-code dll'''. Вы можете откомпилировать и собрать часть ваших prg в динамическую библиотеку (dll или so) и затем использовать ее со своими приложениями; такую динамическую библиотеку мы и называем ''p-code dll''.
 
Итак, мы имеем файл ''mylib.prg'' с функцией M1(), который мы хотим собрать в виде ''p-code dll'' с тем, чтобы впоследствии использовать его с главным приложением ''myapp.prg'':
 
<pre>// mylib.prg
FUNCTION M1
? "Это функция из динамической библиотеки " + Procname()
inkey(0)
RETURN Nil</pre>
 
Наше главное приложение ''myapp'' может быть собрано со статическими библиотеками или с Harbour dll (so), как было описано в начале этого подраздела. Здесь мы рассмотрим второй вариант, когда ''myapp'' собирается с Harbour dll, поскольку первый требует пересборку Harbour с ключом set HB_USER_CFLAGS=-DHB_DYNLIB. У нас есть 2 способа сборки ''myapp'' с ''mylib'' — со статическим связыванием и с динамическим связыванием. Статическое связывание динамической библиотеки — это звучит немного странно :), но я поясню, что имеется ввиду. Статическое связывание предполагает, что уже на стадии линковки (терпеть не могу это слово, но у него недостаточно синонимов на русском) разрешаются все ссылки на внешние функции. Как уже говорилось выше, некоторые компиляторы, в частности, Borland C, MSVC, требуют для этого предварительного создания ''import library'' — статической библиотеки со ссылками на функции в соответствующей динамической библиотеке; именно эта ''import library'' будет прилинковываться к главному приложению, чтобы обеспечить статическое связывание. При статическом связывании наличие «привязанной» динамической библиотеки необходимо для запуска программы, независимо от того, будете ли вы в текущем сеансе работы использовать функции из нее или нет; без этой библиотеки ваше приложение выдаст соответствующее предупреждение и не запустится. При динамическом связывании ссылки на внешние функции разрешаются во время исполнения, надо только перед использованием этих функций загрузить динамическую библиотеку с помощью функции ''hb_LibLoad()'', ну и не забыть потом ее выгрузить при помощи ''hb_LibFree()''. В этом случае наличие динамической библиотеки потребуется не при запуске программы, а в тот момент, когда будет выполняться ''hb_LibLoad()'', если она вообще будет выполняться. При таком подходе можно сэкономить на времени загрузки программы и на занимаемой ею памяти — подгружая динамические модули только по мере необходимости.
 
При рассмотрении способов сборки будем пока для простоты пользоваться Hbmk2. Итак, статическое связывание. Собираем сначала саму динамическую библиотеку. Для Borland C и MSVC нам надо, как вы помните, создать еще и ''import library'', поэтому пишем в командной строке:
 
<pre>hbmk2 mylib.prg -shared -hbdynvm -nohblib -implib</pre>
 
Результатом этой команды станет появление mylib.dll и mylib.lib, где последняя и есть ''import library''; опция «-implib» как раз указывает hbmk2 создать эту библиотеку. Для других компиляторов (Mingw, GNU C) пишем:
 
<pre>hbmk2 mylib.prg -shared -hbdynvm -nohblib -olibmylib</pre>
 
то есть то же самое, но без «-implib», в результате получаем на выходе libmylib.dll (или libmylib.so для Linux GNU C).
 
Теперь нам надо построить само приложение ''myapp'', статически связав его с ''mylib''.
 
<pre>// myapp.prg
FUNCTION Main
hb_cdpSelect("RU866")
M1()
RETURN Nil</pre>
 
Делаем это следующим образом (для Borland C и MSVC):
 
<pre>hbmk2 myapp.prg -shared -lmylib.lib</pre>
 
или (для Mingw, GNU C):
 
<pre>hbmk2 myapp.prg -shared -L. -lmylib</pre>
 
Теперь динамическое связывание. Саму динамическую библиотку строим так же, как и для статического связывания, только нет нужды использовать «-implib», так как нам не нужна ''import library''. А вот myapp.prg придется изменить, так как нам надо загружать динамическую библиотку при помощи ''hb_LibLoad()'':
 
<pre>// myapp.prg
DYNAMIC M1
FUNCTION Main
Local hLib
 
hb_cdpSelect("RU866")
hLib := hb_LibLoad( "mylib.dll" )
if !empty( hLib )
M1()
endif
hb_LibFree( hLib )
RETURN Nil</pre>
 
Обратите внимание на строчку DYNAMIC M1. Поскольку мы не будем прилинковывать к нашей myapp.prg никакую библиотеку, а загрузим ее динамически, то для того, чтобы линкер не ругался на неразрешенные ссылки, мы должны объявить все функции из динамической библиотеки, которые мы собираемся использовать, как ''DYNAMIC''. Строим наше приложение (заметьте, никакого упоминания ''mylib'', так как она привязывается не статически во время линковки, а динамически — во время исполнения) :
 
<pre>hbmk2 myapp.prg -shared</pre>
 
== ''(далее — структура «Содержания» из англоязычного раздела)'' ==
 
== Парадигмы ==