СОЗДАНИЕ БИБЛИОТЕК Известны два способа создания библиотеки. Оба они будут описаны в следующих параграфах. Первый из них, метод "а" - быстрый и легкий по исполнению, однако к собираемым пользовательским программам прилинковываются в том числе и такие функции, которые не обязательно будут использоваться. В отличие от первого, способ "b" реализуется сложнее и требует большего вре- мени, но получаемые в соответствии с ним пользовательские программы будут со- держать в себе только те функции, которые заведомо применяются в программе. Стандартная библиотека компилятора "clib.irl" создается именно по способу "b". 1. Простой способ создания библиотеки Рассмотрим пример двух функций "power" и "log2": int power(x,e) int x,e; { int y; for(y=1; e>0; e--) y *= x; return(y); } int log2(x) int x; { int y; for(y=0; x>1; x>>=1) y++; return(y); } Если эти функции помещаются в файл с именем XLIB.C, последовательность создания библиотеки выглядит следующим образом: cc1 xlib cc2 xlib as xlib При выполнении этой последовательности будет создана библиотека с именем XLIB.REL. Ниже приведена команда сборки программы, которая вызывает функции из этой библиотеки: ld prog,xlib,clib/l/gXMAIN В этом случае нет необходимости писать ключ /l после имени библиотеки XLIB, т.к. даже если его написать, тем не менее все функции, входящие в библиотеку XLIB, будут скомпонованы с программой "prog". Здесь будет описан способ включения в библиотеку программ, написанных на Ассемблере. В качестве примеров взяты функции hex, ror и rol, помещенные в файл ALIB.ASM: public hex_, ror_, rol_ cseg hex_: ; convert 0..F -> '0'..'F' and 0Fh add a,90h daa adc a,40h daa ret ror_: ; ror(c,n) n bit rotate right char inc e rorl: dec e ret z rrca jp rorl rol_: ; rol(c,n) n bit rotate left char inc e roll: dec e ret z rlca jp roll Включение этих функций в библиотеку производится путем выполнения следующей команды: as alib.asm Следующая команда вызывает линковку программы, как и в случае Си-программы: ld prog,alib,clib/l/gXMAIN Как видно из приведенных выше примеров, самый простой способ формирования библиотеки - включение в нее тех программ, из которых компонуется программа. Однако этот способ не совершенен, так как вызывает подключение всей библиотеки. В следующем параграфе будет описан способ создания библиотеки, при котором программа компонуется только из тех функций, к которым предполагаются обраще- ния. 2. Создание полной библиотеки 2.1. Включение Си-программ в библиотеку Здесь будет приведен тот же пример, что и выше - включение файла XLIB.C, содержащего тексты функций POWER и LOG2 в библиотеку. Вначале нужно "разделить" файл XLIB.C на составляющие его функции, записав их в отдельные файлы POWER.C и LOG2.C. Далее необходимо выполнить следующие команды: cc1 power cc1 log2 cc2 power cc2 log2 as power as log2 ol a xlib.irl power log2 При выполнении этой последовательности команд, происходит следующее: 1. Си-тексты функций транслируются в ассемблерные листинги. 2. В результате ассемблирования получаем модули с расширением ".rel". 3. С помощью библиотекаря OL из двух модулей с расширением ".rel" создается библиотека XLIB.IRL. После создания библиотеки XLIB.IRL, файлы POWER.REL и LOG2.REL уже не нужны и их можно удалить. Применение библиотеки XLIB.IRL определяется следующей командой: ld prog,xlib/l,clib/l/gXMAIN После имени библиотеки XLIB нужен ключ /l как указание линкеру подключить к программе только необходимые ей функции. При сборке программ, состоящих из большого числа файлов (функций), имеет значение порядок расположения функций. Ниже приведены два примера: один из них правильный, а другой неправильный. Правильный пример: char islower(c) char c; { return('a'<=c && c<='z'); } char toupper(c) char c; { return(islower(c) ? c-'a'-'A' : c); } В данном примере в библиотеку включается файл X.C, состоящий из двух функций. В этом случае функция "islower" расположена в файле X.REL перед функцией "toupper". Поэтому при редактировании связей по ключу /l линкер не выдаст диагностику об ошибке типа отсутствия определения. Но если написать вначале текст функции "toupper", возникает следующий неправильный пример: char toupper(c) char c; { char islower(); return(islower(c) ? c-'a'-'A' : c); } char islower(c) char c; { return('a'<=c && c<='z'); } В результате расположение модулей в библиотечном файле будет неправильным. Подводя итоги сказанному, можно резюмировать, что для правильного порядка расположения модулей в библиотеке нужно в исходной программе вначале писать вызываемую функцию, а после нее - вызывающую. 2.2. Создание библиотеки модулей на Ассемблере По сравнению с описанием включения в библиотеку, которое было дано в п.1, здесь, файл ALIB.ASM следует предварительно разделить на следующие три файла "hex.asm", "ror.asm" и "rol.asm": HEX.ASM: cseg hex_:: and 0Fh add a,90h daa adc a,40h daa ret ROR.ASM: cseg ror_:: inc e rorl: dec e ret z rrca jp rorl ROL.ASM: cseg rol_:: inc e roll: dec e ret z rlca jp roll После того, как каждый из них будет ассемблирован и получен файл с расши- рением ".rel", вызывается библиотекарь OL для создания библиотеки: as hex as ror as rol ol a alib.irl hex ror rol Применение библиотеки ALIB.IRL определяется следующей командой: ld prog,alib/l,clib/l/gXMAIN При сборке программы, точно таким же образом, как и для сборки Си-программы из модулей, должна соблюдаться последовательность записи исходного текста, а именно: вызываемая функция должна быть записана прежде, а вызывающая ее, вслед за ней.