OberonCore

Библиотека  Wiki  Форум  BlackBox  Компоненты  Проекты
Текущее время: Вторник, 08 Июль, 2025 01:34

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 404 ]  На страницу Пред.  1 ... 16, 17, 18, 19, 20, 21  След.
Автор Сообщение
СообщениеДобавлено: Четверг, 19 Декабрь, 2024 09:42 

Зарегистрирован: Воскресенье, 23 Октябрь, 2022 12:23
Сообщения: 10
Привет!
Можешь привести пример данных в переменных и массивах, чтобы можно было запустить минимальный пример и не лезть в недра компилятора.+
Например, что лежит в массиве OPT.GlbMod и других переменных?


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 19 Декабрь, 2024 12:31 

Зарегистрирован: Воскресенье, 23 Октябрь, 2022 12:23
Сообщения: 10
Цитата:
Ожидается, что секция BEGIN модудя TextOut будет выполняться самой первой, а секция CLOSE - самой последней, т.к. этот модуль импортируется всеми другими модулями.

В первом приближении можно посчитать количество импортов для каждого модуля и отсортировать от большего к меньшему и также закрывать эти модули.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 19 Декабрь, 2024 13:14 
Аватара пользователя

Зарегистрирован: Вторник, 28 Август, 2007 00:55
Сообщения: 586
Откуда: Украина, Днепропетровская обл.
TheAthlete писал(а):
Можешь привести пример данных в переменных и массивах, чтобы можно было запустить минимальный пример и не лезть в недра компилятора.+
Например, что лежит в массиве OPT.GlbMod и других переменных?
Гмм, тут в двух словах не расскажешь.

OPT.GlbMod это ARRAY maxImps OF Object, где Object указатель на запись ObjDesc, в которой хранится структура каждого объекта (модуль тоже объект).

В браузере есть процедура Objects, которая перебирает внутренние структуры модуля по заданному критерию. Не получится ли у нас на её базе сделать перебор импортированных модулей?

Пример использования (из того же браузера):
Код:
         Header("CONST"); Objects(OPT.GlbMod[0].right, {Con}); CheckHeader;
         Header("TYPE"); Objects(OPT.GlbMod[0].right, {Typ}); CheckHeader;
         Header("VAR"); Objects(OPT.GlbMod[0].right, {Var}); CheckHeader;
         Objects(OPT.GlbMod[0].right, {XProc, IProc, CProc});

Залезть в недра компилятора всё-таки придётся, потому что сбоку воссоздавать для себя те же структуры - контрпродуктивно. Проще один раз понять как пересобирать Ofront+, и дальше уже экспериментировать прямо по живому, внося свои правки.

В общем, всё сводится к поиску модуля самого верхнего уровня, в котором есть секция CLOSE. Потом генерируем вызов, снимаем флажок, что эта секция есть, и продолжаем пока остались ещё модули с секцией CLOSE. Видимо, придётся перебирать импорты каждого модуля...

Хотелось бы сделать поиск как-то рекурсивно, если это вообще возможно.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 20 Декабрь, 2024 03:09 
Аватара пользователя

Зарегистрирован: Вторник, 28 Август, 2007 00:55
Сообщения: 586
Откуда: Украина, Днепропетровская обл.
Что же, проблема оказалась гораздо сложнее, чем казалось на первый взгляд. В Ofront'е нет хранимого дерева всех модулей со всеми сопутствующими импортами. Когда происходит компиляция - он довольствуется только символьными файлами верхнего уровня (которые импортированы из главного модуля). Т.е. если в каком-нить Files, который где-то в зависимостях есть, но прямо не импортирован из Main, есть секция CLOSE, то даже, прочитав все символьники, импортированные из Main, мы никак не узнаем об этой секции.

Думаю дальше. Возможно, что это вообще не решить малой кровью, а надо дорабатывать формат sym, чтобы каждый символьник содержал информацию о секциях CLOSE всех импортированных в нём модулей. Грустная вообще картина получается. Надо Темплу написать. Впрочем, вряд ли он здесь поможет.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 20 Декабрь, 2024 07:20 
Аватара пользователя

Зарегистрирован: Воскресенье, 09 Декабрь, 2018 15:14
Сообщения: 144
Откуда: Equestria
Ээ. А зачем всё инициализировать/финализировать в одном месте?
Каждый модуль должен знать только о своих прямых импортах. Пинать тело. В теле должен быть флажок "уже инициализирован". Пинаем инициализацию/финализацию рекурсивно. Если такой флажок есть - тупо пропускать повторную инициализацию/финализацию.
В main() пинать только модули перечисленные для линковки, дальше оно само разберётся в каком порядке выполнять секции модулей. (не знаю как у тебя точно работает загрузка программы)

Код:
MODULE Root;
  IMPORT A, B, C;
END Root.
Код:
static int Root__initialized;

void Root_BEGIN (void) {
  if (Root__initialized == 0) {
    Root__initialized = 1;
    A_BEGIN();
    B_BEGIN();
    C_BEGIN();
    // Root BEGIN statements here
  }
}

void Root_CLOSE (void) {
  if (Root__initialized == 1) {
    Root__initialized = 0;
    // Root CLOSE statements here
    C_CLOSE();
    B_CLOSE();
    A_CLOSE();
  }
}
Для A B C картина должна быть аналогичная.

А ещё лучше делать всё это в каком-нибудь Kernel. В рантайме должно быть уже известно всё о модулях (при наличии соответствующих метаданных).


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 20 Декабрь, 2024 17:31 

Зарегистрирован: Вторник, 01 Март, 2011 09:34
Сообщения: 594
Откуда: Москва
SovietPony писал(а):
А ещё лучше делать всё это в каком-нибудь Kernel. В рантайме должно быть уже известно всё о модулях (при наличии соответствующих метаданных).

Есть Kernel.imports с порядком импортирования. Думаю, не надо трогать sym файлы компилятора, а пробежаться по этому списку и вызвать Close для модулей с секцией Close. Решать на уровне рантайма.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 20 Декабрь, 2024 18:06 

Зарегистрирован: Вторник, 01 Март, 2011 09:34
Сообщения: 594
Откуда: Москва
Вот в Kernel от BlackBox есть завершение
Код:
   PROCEDURE Quit* (exitCode: INTEGER);
      VAR m: Module; term: Command; t: BOOLEAN;
   BEGIN
      trapViewer := NIL; trapChecker := NIL; restart := NIL;
      t := terminating; terminating := TRUE; m := modList;
      WHILE m # NIL DO   (* call terminators *)
         IF ~static OR ~t THEN
            term := m.term; m.term := NIL;
            IF term # NIL THEN term() END
         END;
         ReleaseIPtrs(m);
         m := m.next
      END;
      CallFinalizers;
      hotFinalizers := finalizers; finalizers := NIL;
      CallFinalizers;
      WinOle.OleUninitialize();
      IF ~inDll THEN
         RemoveExcp(excpPtr^);
         WinApi.ExitProcess(exitCode)   (* never returns *)
      END
   END Quit;


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 20 Декабрь, 2024 19:53 

Зарегистрирован: Понедельник, 28 Ноябрь, 2005 10:28
Сообщения: 1437
SovietPony писал(а):


Код:
void Root_CLOSE (void) {
  if (Root__initialized == 1) {
    Root__initialized = 0;
    // Root CLOSE statements here
    C_CLOSE();
    B_CLOSE();
    A_CLOSE();
  }
}
Для A B C картина должна быть аналогичная.

А потом окажется, что не только Root импортировал A, B и C.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 20 Декабрь, 2024 23:23 
Аватара пользователя

Зарегистрирован: Воскресенье, 09 Декабрь, 2018 15:14
Сообщения: 144
Откуда: Equestria
Trurl писал(а):
А потом окажется, что не только Root импортировал A, B и C.
В чём проблема-то? Ну добавить до кучи счётчик импортов модуля X рядом с X__initialized.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 23 Декабрь, 2024 09:28 

Зарегистрирован: Понедельник, 28 Ноябрь, 2005 10:28
Сообщения: 1437
А не проще atexit вызывать?


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 23 Декабрь, 2024 18:35 
Аватара пользователя

Зарегистрирован: Воскресенье, 09 Декабрь, 2018 15:14
Сообщения: 144
Откуда: Equestria
Лишняя зависимость от либц с ограниченным количеством регистраций (гаранитируется 32).
Тогда уж обрабатывать списки модулей в kernel. Это самое правильное решение.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 26 Декабрь, 2024 05:30 
Аватара пользователя

Зарегистрирован: Вторник, 28 Август, 2007 00:55
Сообщения: 586
Откуда: Украина, Днепропетровская обл.
Спасибо всем за советы.

Я всё-таки сделал это, притом единственно правильным для Ofront'а способом.

Мои большие затруднения возникли оттого, что я хотел сконцентрировать все вызовы функций __close в главном модуле и отсортировать их в процессе трансляции. Но такой подход плохо ложится на принцип работы Ofront'а. У нас в процессе трансляции под рукой нет символьников всех импортированных модулей (есть только те, которые импортированы прямо из главного, т.е. для которых генерится макрос __IMPORT с вызовом функции __init). В общем, если бы делать так, как я хотел, пришлось бы перепахивать Ofront, чего конечно не хотелось.

Я сделал симметрично механизму __init: к Heap.INCREF добавил функцию DECREF; по аналогии с макросом __IMPORT добавил макрос __CLOSE, который сейчас выглядит вот так:

Код:
#define __IMPORT(name__init)  Heap_INCREF(name__init())
#define __CLOSE(name__init, name__close) if (Heap_DECREF(name__init())) name__close()

Зачем в __CLOSE дублируется ещё раз параметром __init? Сначала я хотел вытащить переменную-ссылку на модуль в общее пространство видимости. Но потом увидел, что ровно то же самое делает вызов __init, поэтому ничего специально делать не пришлось. Пришлось ввести доп. флажок close, и если в модуле есть секция CLOSE, то она также неявно будет во всех модулях, которые его импортируют (чтобы правильно вызвать __close для этого модуля). Если этого не сделать, модуль с секцией CLOSE просто затеряется и никто о его функции __close и не вспомнит.

Решение ещё надо тестировать. Фикс залит, но в процессе я нашёл пару косячков, с которыми вы вряд ли столкнётесь, их буду править вскоре.

GameHunter, Ваш пример работает:


Вложения:
Main.png
Main.png [ 40.37 КБ | Просмотров: 16996 ]
Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Воскресенье, 29 Декабрь, 2024 05:16 

Зарегистрирован: Вторник, 22 Май, 2007 15:38
Сообщения: 238
Откуда: Питер
Ещё один вопрос.

В документации oFront сказано, что имеются inline-процедуры, и в целом они работают. Но если в качестве параметра процедуры использовать запись, то модуль транслируется, но не компилируется в си. Это так и должно быть?

Вот пример:
Код:
MODULE Mod1;

IMPORT
  SYSTEM;

TYPE
  Rec * = RECORD
    x:INTEGER;
  END;

PROCEDURE [inline] Asdf * ( VAR r:Rec );
  BEGIN
    r.x:=0;
  END Asdf;

BEGIN
END Mod1.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Воскресенье, 29 Декабрь, 2024 06:18 
Аватара пользователя

Зарегистрирован: Вторник, 28 Август, 2007 00:55
Сообщения: 586
Откуда: Украина, Днепропетровская обл.
Информирую, что работа над поддержкой правильного порядка вызова секций CLOSE закончена. Все известные на данный момент проблемы исправлены. Бинари пересобрал и залил в реп.

По inline. Какой компилятор Си используете? Как его вызываете? Покажите как выглядит вывод ошибки компиляции.

У меня скомпилировалось. В GCC 8.1.0 (i686-win32-dwarf-rev0, Built by MinGW-W64 project и x86_64-win32-seh-rev0, Built by MinGW-W64 project):
Код:
MODULE Mod1;

IMPORT
  SYSTEM;

TYPE
  Rec * = RECORD
    x:INTEGER;
  END;

VAR rec: Rec;

PROCEDURE [inline] Asdf * ( VAR r:Rec );
  BEGIN
    r.x:=0;
  END Asdf;

BEGIN
  Asdf(rec)
END Mod1.
Код:
/* Ofront+ 1.0 -mxtwC -48 */
#include "SYSTEM.oh"

typedef
  struct Mod1_Rec {
    INTEGER x;
  } Mod1_Rec;


static Mod1_Rec Mod1_rec;

export void **Mod1_Rec__typ;

export inline void Mod1_Asdf (Mod1_Rec *r, void **r__typ);


/*============================================================================*/

inline void Mod1_Asdf (Mod1_Rec *r, void **r__typ)
{
  (*r).x = 0;
}

/*----------------------------------------------------------------------------*/
__TDESC(Mod1_Rec__desc, 2, 0) = {__TDFLDS("Rec", 4), {-4}};

int main (int argc, char **argv)
{
  __INIT(argc, argv);
  __REGMAIN("Mod1", 0);
  __INITYP(Mod1_Rec, Mod1_Rec, 0);
/* BEGIN */
  Mod1_Asdf(&Mod1_rec, Mod1_Rec__typ);
  __FINI;
}


Вложения:
gcc.jpg
gcc.jpg [ 149.92 КБ | Просмотров: 16611 ]
Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Воскресенье, 29 Декабрь, 2024 13:24 

Зарегистрирован: Вторник, 22 Май, 2007 15:38
Сообщения: 238
Откуда: Питер
У меня тоже mingw-w64, скачано с winlibs.com.
Пользуюсь версией gcc 7.5.0, специально для теста скачал gcc 8.5.0.

Не компилируется.

Все файлы и снимок экрана во вложении.


Вложения:
Screenshot.png
Screenshot.png [ 45.54 КБ | Просмотров: 16598 ]
Test.rar [94.49 КБ]
Скачиваний: 198
Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Суббота, 04 Январь, 2025 06:13 
Аватара пользователя

Зарегистрирован: Вторник, 28 Август, 2007 00:55
Сообщения: 586
Откуда: Украина, Днепропетровская обл.
Исправил.

Учитывайте, что на процедуры [inline] накладывается больше ограничений, связанных с областью видимости.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Суббота, 04 Январь, 2025 20:23 

Зарегистрирован: Вторник, 22 Май, 2007 15:38
Сообщения: 238
Откуда: Питер
У меня опять не компилируется в gcc, причём тест я не изменял.


Вложения:
ScreenShot.png
ScreenShot.png [ 20.9 КБ | Просмотров: 16104 ]
Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Суббота, 04 Январь, 2025 21:56 
Аватара пользователя

Зарегистрирован: Вторник, 28 Август, 2007 00:55
Сообщения: 586
Откуда: Украина, Днепропетровская обл.
Помогает экспорт поля x.
Код:
TYPE
  Rec* = RECORD
    x*:INTEGER;
  END;

Я же предупредил Вас насчёт областей видимости. Смотрите. Процедура inline экспортируется не просто как точка входа, а как кусок кода, работающий извне его родного модуля. И снаружи модуля не видно, что из себя представляет запись, и что у неё есть поле x.

Так ли уж необходимо делать эту процедуру inline и использовать нестандартный флаг? (я вообще удивлён, что его кто-то использует, кроме меня)


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Вторник, 07 Январь, 2025 00:40 

Зарегистрирован: Вторник, 22 Май, 2007 15:38
Сообщения: 238
Откуда: Питер
С новым годом!

Теперь не компилируется с сообщением об ошибке undefined reference to `Mod1_Asdf'


Вложения:
Test.7z [102.78 КБ]
Скачиваний: 179
Screenshot.png
Screenshot.png [ 47.7 КБ | Просмотров: 16043 ]
Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Вторник, 07 Январь, 2025 19:31 
Аватара пользователя

Зарегистрирован: Вторник, 28 Август, 2007 00:55
Сообщения: 586
Откуда: Украина, Днепропетровская обл.
Фикс.

Немного о проблеме:
ChatGPT писал(а):
Ошибка линковки возникает из-за различий в области видимости и способе компоновки функций с ключевыми словами inline и static inline в C.

1. inline без static

Функция, объявленная с ключевым словом inline, имеет inline linkage, что означает, что компилятор пытается встроить (inline) её код туда, где функция вызывается. Однако, если компилятор решает не встраивать функцию, он требует, чтобы для неё существовало одно глобальное определение в одном из объектных файлов.

Если у вас есть только определение функции inline в заголовочном файле (или в нескольких исходниках), а ни в одном объектном файле нет "внешнего" (не inline) определения, то компоновщик не сможет найти эту функцию. Это приводит к ошибке undefined reference.

2. static inline

Добавление static изменяет область видимости функции: она становится локальной для текущего объектного файла. Это означает, что каждая единица трансляции (каждый .c файл) имеет свою копию функции. При этом компилятор также пытается встроить её, но если это не удаётся, никакого глобального определения не требуется.

Таким образом, использование static inline гарантирует, что компоновщик не будет искать внешнее определение функции, избегая ошибки undefined reference.

Итог

Если функция предназначена только для использования в пределах одного .c файла, используйте static inline.
Если функция должна быть доступна между разными объектными файлами, убедитесь, что одно "внешнее" определение функции существует (т.е., без inline или с отдельным extern определением).
В вашем случае, ошибка вызвана отсутствием глобального определения функции Mod1_Asdf, если она объявлена только как inline. Добавление static решает эту проблему за счёт локализации области видимости функции.

Я решил, что inline без static выглядит слишком устрашающе, остановимся на static inline.


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 404 ]  На страницу Пред.  1 ... 16, 17, 18, 19, 20, 21  След.

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
cron
Вся информация, размещаемая участниками на конференции (тексты сообщений, вложения и пр.) © 2005-2025, участники конференции «OberonCore», если специально не оговорено иное.
Администрация не несет ответственности за мнения, стиль и достоверность высказываний участников, равно как и за безопасность материалов, предоставляемых участниками во вложениях.
Без разрешения участников и ссылки на конференцию «OberonCore» любое воспроизведение и/или копирование высказываний полностью и/или по частям запрещено.
Powered by phpBB® Forum Software © phpBB Group
Русская поддержка phpBB