Loment
RU

Система · поставляется с 0.1.4.6

LibL

Грань libc стандартной библиотеки Loment. Те же имена, тот же порядок аргументов и та же семантика возврата, что у libc, — для тех, кто уже знает C. Это вторая грань одной библиотеки, а не вторая библиотека.

Доступен с 0.1.4.6

С 0.1.4.6 выпускная сборка принимает use libl, а выпускная сборка может слинковать настоящий libc.so.6 системы и довести его до конца. Замок, который держал и то, и другое в 0.1.4.5, открыт, и примечания к выпуску это говорят.

«Доступен» — не «полон». Каждое имя здесь проверено против glibc системы, а недостающий набор выписан ниже, а не оставлен читателю на стадию линковки. Страница сохраняет и причины: грань libc без них — обещание, которое никто не может проверить.

Почему вторая грань

Стандартная библиотека уже существовала, и в ней не было ни одного имени libc — ни strlen, ни printf, ни malloc. Это было не упущение, а форма. Её функции принимают явную длину, а не ищут терминатор, адресуют буфер со смещением и никогда не принимают переменное число аргументов. В языке нет строк, завершающихся NUL, и нет функций с переменным числом аргументов, поэтому библиотека написана так, как устроен язык.

Эта форма верна для тех, кто пишет на Loment, и она — стена для тех, кто знает C. Вторая грань отвечает на другой вопрос: как это называлось бы, если бы вы никогда не слышали о Loment? strcmp, возвращающий то же, что и в C. qsort. isdigit. Учить нечего.

Обе грани указывают на одни и те же байты. isdigit вызывает собственный предикат символа библиотеки; memcpy вызывает собственную процедуру копирования. Так что сбой, которого можно было бы ждать от двух граней, — один и тот же байт отвечает по-разному в зависимости от того, по какому имени спросили, — структурно невозможен, а не просто избегнут.

Два входа

LibL — имя библиотеки; std по-прежнему имя пакета. Оба входа ведут в один и тот же пакет и различаются тем, сколько они тянут за собой.

use std

Весь пакет. То, что уже делает всё написанное до LibL, и продолжает работать. Цена — вход на уровне всего пакета стягивает каждый модуль в одну единицу, а пространство испускаемых символов в этом языке плоское, поэтому все эти имена верхнего уровня должны быть уникальны вместе, и время компиляции растёт быстрее числа модулей.

use libl

Четыре грани libc и то, от чего они зависят, — шесть модулей. Маленькая грань: компилируется быстро, и сталкиваться почти не с чем. Это вход, когда нужны только имена libc.

Что он покрывает

Один заголовок libc отображается на один модуль, и само это отображение — часть следования libc.

<string.h>

strlen, strcpy, strncpy, strcat, strcmp, strncmp, strchr, strrchr, strstr, strspn, strcspn, strpbrk, strtok_r, memchr, memcmp, memcpy, memmove, memset.

<ctype.h>

isdigit, isalpha, isalnum, isspace, isupper, islower, isxdigit, ispunct, isprint, и остальной набор, с toupper и tolower.

<stdlib.h>

Та половина, которую можно построить без кучи: atoi, atol, strtol, strtoul, abs, labs, llabs, qsort, bsearch.

<stdio.h>

Половина форматирования: snprintf, sprintf и остальные форматы printf. Файловая половина пришла в 0.1.4.6 отдельным модулем host — fopen, fclose, fread, fwrite, fseek, ftell, fflush, feof, fgets, fputs, puts, putchar, getchar — потому что им нужны системные вызовы, а основная библиотека не делает ни одного.

Плюс одна функция, которой нет в libc, — и она самая интересная; см. ниже.

Контрольный образец — сама libc

Каждая другая часть стандартной библиотеки судится сравнением того, что вычисляет Loment, с тем, что вычисляет Python. Это неверный контрольный образец для этого вопроса, и доказуемо: ровно на гранях, которые определяют «ведёт себя как libc», — обнуляет ли strncpy, возвращает ли strcmp знак или разность, находит ли strchr терминатор, безопасен ли memmove при перекрытии диапазонов, — Python и libc дают не один и тот же ответ. Сравнение с Python позволило бы двум реализациям ошибиться вместе и пройти.

Поэтому критерий компилирует программу на C против настоящей glibc системы, прогоняет один и тот же набор вызовов с обеих сторон и сравнивает стандартный вывод побайтово, сообщая первую отличающуюся строку. Две нормализации нарочны, иначе тест измерял бы детали реализации, а не семантику: стандарт обещает только знак strcmp, поэтому проверяются и знак, и разность; а предикаты символов glibc возвращают битовую маску, а не 1, поэтому обе стороны сводятся к «да или нет» перед сравнением.

Что навязал язык

Правилом для этой работы было «как libc это реализует, так LibL это и реализует». Язык — не C, поэтому в четырёх местах пришлось отойти и в одном — добавить. Каждое записано, а не спрятано.

Строковый литерал не несёт терминатор

Поэтому strlen на литерале читает за концом. В первом зонде он вернул 17 для пустой строки, пройдя дальше, пока случайно не встретил нулевой байт. C не нуждается здесь в функции, потому что "abc" в C уже несёт свой NUL. Это не упущение — два типа str не одно и то же: str этого языка несёт длину, str в C — нет. LibL добавляет cstr_of, чтобы преобразовать одно в другое, и каждая NUL-строковая функция в библиотеке в нём нуждается.

Нет функций с переменным числом аргументов

Поэтому snprintf принимает на один аргумент больше, чем в libc: snprintf(buf, cap, fmt, args, nargs), где args указывает на массив 64-битных значений. Спецификатор преобразования по-прежнему решает, как прочитано каждое, точно как в libc. Это единственная сигнатура в библиотеке, которая отклоняется, и это не чистая потеря: libc не может посчитать свои аргументы, поэтому при слишком малом их числе читается что угодно из стека; здесь же при слишком малом числе преобразование останавливается, а произведённое до сих пор завершается правильно.

Нет указателей на функцию

Поэтому четвёртый аргумент qsort — перечисление, говорящее, по чему сравнивать, а не функция сравнения. Это настоящее различие, и оно не понижение в одну сторону: оно переносит «по чему сравнивает эта сортировка» из адреса времени выполнения в константу в артефакте, так что на это можно ответить, не читая исходник. Цена заявлена вместе с этим: порядок, который не один из встроенных видов, выразить нельзя — цикл пишете сами.

Нет изменяемой глобальной на уровне модуля

Поэтому strtok становится strtok_r, с курсором у вызывающего, — что POSIX уже предлагает, так что это не понижение. rand, хранящий скрытое зерно, тоже не может существовать; форма, которую использует этот язык, берёт состояние у вызывающего, и она нарочно не названа rand. И нет errno: strtol насыщается до граничного значения и возвращается нормально, так что вызывающий вместо этого сравнивает с границей.

Чем оно не является

Не замена libc

LibL — это библиотека исходного кода, а не архив, против которого можно слинковать объектный файл C. Код C не может вызвать её; для этого нужен путь «Loment в объектный файл», которого не существует. То, что она заменяет, — уже, и это стоит сказать точно: программу на Loment, которой приходилось бы писать strcmp вручную.

Не вся libc

realloc и free отсутствуют намеренно: realloc нужна старая длина, а старая длина живёт в заголовке кучи, приватном для компилятора; имя free уже занято встроенным, так что функция библиотеки с этим именем не разрешилась бы в точке вызова. malloc и calloc есть с 0.1.4.6 — это написания поверх встроенной кучи без собственного заголовка длины, что и позволяет встроенному free принимать то, что они возвращают. stdin, stdout и stderr были бы изменяемыми глобалами уровня модуля, а языка их нет. Из семейства процессов и окружения, кроме exit и abort, нет ничего. А %f/%e/%g — это не «не сделано», а «пока нельзя»: вышестоящий форматтер — программная плавающая точка, и его обратное направление требует широкого деления, которого этот слой намеренно не имеет.

Не завершено и не притворяется завершённым

Написание её выявило дефекты в окружающей системе — среди них помощник, чья проверка перекрытия сравнивала смещения там, где libc сравнивает адреса, форматтер, испускающий IR, который отвергает системный ассемблер, и проверка зависимостей, которая винит не тот модуль. Они заведены как issues, а не исправлены мимоходом, и собственный критерий библиотеки нарочно узок: он заявляет, что эти модули — допустимые единицы, и не заявляет, что таковы их зависимости.