Добрый день, Аркадий! Компилятор включает как стадию компиляции — порождение объектного модуля, так и стадию компоновки — сборки из этих объектных модулей исполнимого файла операционной системы.
Компиляция в узком смысле либо порождает из одного исходника один файл с расширением .rasl — он содержит интерпретируемый двоичный код, либо пару файлов .rasl+.cpp, если исходный файл содержал нативные вставки или была включена оптимизация прямой кодогенерации. Стадия компоновки по-разному выполняется для случая отсутствия и наличия файлов .cpp. Если файлов .cpp нет, то файлы .rasl конкатенируются с интерпретатором и получается исполнимый файл операционной системы. Если они есть, то Рефал-5λ вызывает компилятор C++ для сборки нового интерпретатора из файлов рантайма и файлов .cpp с кодом из нативных вставок. После этого к новому интерпретатору конкатенируются файлы .rasl. А с проблемами в исходном письме я разобрался. Сейчас занят уже динамической загрузкой модулей с зависимостями. Исполнимый файл или библиотека могут зависеть от других библиотек, их интерпретатор должен находить и подгружать. Библиотеки могут быть как файлами, целиком состоящими из двоичного интерпретируемого кода, так и быть динамическими библиотеками операционной системы (.dll/.so) с приклеенным к ним интерпретируемым кодом (как и исполнимые файлы). Файлы интерпретируемого кода у меня уже генерируются и загружаются (но без зависимостей и с некоторыми недоработками), разделяемые библиотеки операционной системы пока в планах. С уважением, Александр Коновалов From: Arkady Klimov [mailto:[email protected]] Sent: Tuesday, August 7, 2018 7:19 PM To: [email protected] Subject: Re: FW: Как мне сделать динамическую загрузку модулей? Добрый день, Александр! После отпуска разгребаю почту и потихоньку отвечаю, когда чувствую, что надо. В Вашем письме мне непонятно вот что. Вы пишете: Компилятор Рефал-5λ создаёт исполнимые файлы операционной системы Но почему не "объектные модули"? Во всех известных мне рефалах компилируется не вся программа, а какая-то ее часть, оформленная как файл. А потом эти "объектные модули" собираются в один исполнимый файл (или грузятся как в рефале-6, или конкатенируются) У вас в рефале-5л есть раздельная компиляция? Если да, то результат компиляции одного файла уже не может быть исполнимым, не так ли? И есть ли у Вас что-то вроде сборки (отдельной от компиляции)? Возможно, нечеткость в этих вопросах и стала причиной Ваших трудностей? Аркадий 27 июля 2018 г., 17:35 пользователь Alexander Konovalov aka Маздайщик <[email protected] <mailto:[email protected]> > написал: Переотправлю письмо через Яндекс, а то с Mail.Ru какие-то проблемы. Добрый день всем! Как многие в рассылке знают, я работаю над компилятором Рефала-5λ — точного надмножества Рефала-5. Одним из полезных расширений языка являются нативные вставки — вставки кода C++ в исходном коде на Рефале. Например, /* это файл на Рефале */ %% #include <stdio.h> %% $ENTRY Go { = <Hello> <Hello> } Hello { %% printf("Hello!\n"); refalrts::splice_to_freelist(arg_begin, arg_end); return refalrts::cSuccess; %% } Как это работает. Компилятор Рефал-5λ создаёт исполнимые файлы операционной системы (.exe-файлы для Windows, ELF для Linux, какие-то ещё для macOS). Скомпилированный файл устроен на манер SFX-архива: он состоит из префикса-интерпретатора, исполнимого файла операционной системы, и суффикса-интерпретируемого кода — двоичного языка сборки. Как если бы в конец интерпретатора refgo приписали бы несколько .rsl-файлов. Когда компилятор транслирует файлы без нативных вставок, то он берёт уже готовый префикс-интерпретатор (скомпилированный ранее) и в конец к нему приписывает файлы языка сборки. Если среди исходных файлов есть файлы с нативными вставками, то компилятор из таких файлов создаёт исходники на C++, содержащие текст этих самых нативных вставок. Потом вызывает компилятор C++, передавая ему исходники интерпретатора языка сборки и эти самые файлы с текстом вставок. Получается исполнимый файл, который становится префиксом-интерпретатором. Функции, описанные на C++ (вроде функции Hello в примере выше) становятся своего рода встроенными в интерпретатор функциями. Кстати, все библиотечные функции (Prout, Add, Sub, Type) тоже описаны в файле на Рефале примерно таким образом: https://github.com/bmstu-iu9/simple-refal/blob/master/src/srlib/Library.sref Но уже давно я планирую реализовать динамическую загрузку модулей на манер .dll/.so. В этом случае компилятор сможет порождать не-.exe модули, которые могут подгружаться как статически (если прописана соответствующая ссылка в языке сборки), так и динамически (вызывается соответствующая библиотечная функция для загрузки модуля и поиска функции в нём). Если исходные файлы модуля не содержат нативных вставок, то создаётся динамически загружаемый модуль только с одним языком сборки. Если содержат — вызывается компилятор C++, который создаёт .dll/.so операционной системы с нативными функциями, и к нему в хвост приписывает язык сборки как раньше. На этом пути много технических проблем, я с ними справлюсь, скорее всего. Но вот возникла одна архитектурная, про которую я не вижу красивого гладкого решения. Нужно (как и в случае .dll/.so) обеспечить корректную обработку повторной загрузки модуля. Т.е. если некоторый файл был загружен, не грузить его повторно, а только увеличивать у него счётчик ссылок. Но вот как понять, что он уже был загружен? По пути к файлу это сделать сложно. На UNIX-системах один и тот же файл может быть доступен как subdir/filename, ./subdir/./././filename /home/user/subdir/filename, /home//user///subdir////filename, /home/otheruser/../user/otherdir/../subdir/filename и т.д. На Windows ещё веселее: добавляются тонкости с регистром символов в именах, синонимичность / и \ и текущие папки на разных дисках. Эмулировать всё это слишком громоздко и тем самым некрасиво. Можно к каждому файлу добавлять хэш, таким образом обнаруживать идентичные модули по их содержимому (даже если у них разные имена файлов). Но мне почему-то это кажется костылём. С уважением, Александр Коновалов -- _______________ С уважением, Аркадий Климов, с.н.с. ИППМ РАН, +7(499)135-32-95 +7(916)072-81-48
