c71e249a4e
First substantive commit: the entire Sprinter C compiler tree on top of
the bare README+gitignore initial commit.
What's in here:
bin/sprinter-cc — driver script invoking SDCC + linker + mkexe
libc/ — Sprinter-specific libc layer over ESTEX/BIOS
(conio, gfx, io, mem, stdio + headers)
runtime/ — crt0 variants (default/small/banked/minimal)
+ heap + bank trampolines
toolchain/ — mkexe (SprintEXE packer, C + tests)
examples/ — 30 demo programs (gfx, file I/O, env, time, …)
lib/Makefile — builds the libc archive (sprinter.lib)
docs/ — converted Sprinter manuals + asm reference samples
third_party/ — solid-c reference compiler dump + sdcc setup script
release_docs/ — packaging / release notes
gitignore overhaul:
• Drop dangerous blanket patterns: *.asm (would hide docs/samples/*.asm)
and *.exe (case-insensitive match was hiding third_party/solid-c/*.EXE
on macOS APFS). Replaced with examples/*/*.{asm,exe,…} and lib/*.lib.
• Restore tracking of toolchain/mkexe/tests/{one,big}.bin — those are
INPUT fixtures, not build outputs.
• Collapse the duplicated SDCC/C/Sdcc sections into one section per
concern (build outputs / vendored / OS-junk).
• Add .sprinter-cc-*/, build/ (catches lib/build/ too), .claude/.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
229 lines
9.4 KiB
Plaintext
229 lines
9.4 KiB
Plaintext
СОЗДАНИЕ БИБЛИОТЕК
|
|
|
|
|
|
Известны два способа создания библиотеки. Оба они будут описаны в следующих
|
|
параграфах. Первый из них, метод "а" - быстрый и легкий по исполнению, однако
|
|
к собираемым пользовательским программам прилинковываются в том числе и такие
|
|
функции, которые не обязательно будут использоваться.
|
|
В отличие от первого, способ "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
|
|
|
|
При сборке программы, точно таким же образом, как и для сборки Си-программы
|
|
из модулей, должна соблюдаться последовательность записи исходного текста, а
|
|
именно: вызываемая функция должна быть записана прежде, а вызывающая ее, вслед
|
|
за ней.
|