Перейти к содержанию
Fire Monkey от А до Я

Billy Bones

Пользователи
  • Постов

    8
  • Зарегистрирован

  • Посещение

  • Победитель дней

    2

Сообщения, опубликованные Billy Bones

  1. Имя rt используется как параметр для компоновщика (в *nix системах ), а он, в свою очередь, компонует библиотеку, которая называется librt.so или librt.a (если используется статическая, версия библиотеки rt).

    Поэтому в Delphi нужно писать так:

    Unit Posix.Shm; // Посмотрите, может уже такой модуль есть ?
    
    Interface
      
    	function shm_open(name : PAnsiChar; oflag : LongInt; mode : mode_t);
    
    Implementation
      
    Const
    	LibRT = 'librt.so'; // Имя библиотеки. Нечего эту константу светить в секции Interface !
    
    	function shm_open(name : PAnsiChar; oflag : LongInt; mode : mode_t); external LibRT name 'shm_open';
    
    End.

    PS:

    Рекомендую почитать книгу: Уильям Стивенс UNIX взаимодействие процессов. Там описано, если я точно помню, 2 механизма разделяемой памяти для Unix систем:

    1. Разделяемая память систем, являющихся потомками Unix Sys V.
    2. Разделяемая память Posix.
  2. В 27.03.2021 в 21:34, Billy Bones сказал:

    Альтернативный способ состоит в том, чтобы напрямую (без библиотеки libc ) выполнить системный вызов stat, обратившись непосредственно к ядру ОС.

    Коли хвастался, значит нужно показать как это делается:

    Пишем такое консольное приложение:

    Program ownof;
    
    {$APPTYPE CONSOLE}
    
    {$R *.res}
    
    Type
    	kernel_ulong_t = UInt64;
    	kernel_long_t  =  Int64;
    
    	TStat  = packed record
    		st_dev        : kernel_ulong_t;
    		st_ino        : kernel_ulong_t;
    		st_nlink      : kernel_ulong_t;
    		st_mode       : UInt32;
    		st_uid        : UInt32;
    		st_gid        : UInt32;
    		__pad0        : UInt32;
    		st_rdev       : kernel_ulong_t;
    		st_size       : kernel_long_t;
    		st_blksize    : kernel_long_t;
    		st_blocks     : kernel_long_t;
    		st_atime      : kernel_ulong_t;
    		st_atime_nsec : kernel_ulong_t;
    		st_mtime      : kernel_ulong_t;
    		st_mtime_nsec : kernel_ulong_t;
    		st_ctime      : kernel_ulong_t;
    		st_ctime_nsec : kernel_ulong_t;
    		__unused      : array[0..2] of kernel_long_t;
    	end;
    
    	(*
    		Функция mystat реализована на ассемблере. Откомпилирована в Linux и
    		объектный файл перенесен в проект.
    	*)
    	function mystat(path_to_file : PAnsiChar; var S : TStat) : NativeUInt;
    		external 'mystat.o'
    
    var
    	S : TStat;
    
    Begin
    	// Файл a.txt создан руками в том-же каталоге, куда помещается исполняемый
    	// модуль данной программы.
    	mystat('a.txt', S);
    
    	Writeln('Owner is ', S.st_uid);
    End.

    Исходный код для mystat.asm:

    		.text
    
    #	function mystat(path_to_file : PAnsiChar; var S : TStat) : NativeUInt;
    #
    #	Параметры:
    #		rdi - path_to_file
    #		rsi - @S
    #
    #	Параметры функции помещаются, в те-же регистры, что и требует интерфейс системных
    #	вызовов - не делаем ничего лишнего !
    #
    #	После выхода из режима ядра в регистре rax будет содержаться рузультат работы
    #	системного вызова. Наша функция тоже возвращает рузультат в rax - не делаем
    #	ничего лишнего !
    
    		.global	mystat
    		.align	16
    mystat:	
    		movq	$4,	%rax	# поместим номер системного вызова в регистр rax
    		syscall			# переходим в режим ядра			
    		ret
    

    Все данные для написания этой программы получены из исходных кодов ядра Linux 5.11.10.

    Данная реализация привязана к нескольким вещам:

    1. К архитектуре процессора (т.к. mystat написана на x86_64 ассемблере )
    2. К ядру Linux (т.е. программа не будет работать на других Unix подобных ОС)
    3. К структуре с которой работает системный вызов sys_newstat (так называется, та процедура в ядре, что выполнает нужные нам действия).
    4. Способу выполнения системных вызовов (сам способ привязан к архитектуре процессора и к ядру ОС)

    Пока ничего из этого не поменяется всё будет ОК. И никаких Вам libc.

    PS:

    1. Номер системного вызова и его имя взято из файла arch/x86/entry/syscalls/syscall_64.tbl .
    2. Как делать системный вызов написано тут: arch/x86/entry/entry_64.S .
    3. Описание структуры взято из файла arch/x86/include/uapi/asm/stat.h

     

  3. 6 минут назад, Олег Киреев сказал:

    Файл Posix.SysStat.dcu  у меня лежит в C:\Program Files (x86)\Embarcadero\Studio\20.0\lib\iossimulator\debug

    Этот не подходит, т.к должен быть файл, конкретно, для платформы Linux: lib\linux64\release\Posix.SysStat.dcu.

    В своем прошлом посте, Я, описал процедуру, как самому собрать модуль Posix.SysStat.dcu:

    1. Создать проект консольного приложения.
    2. Скопировать в каталог с проектом файлы (см. список файлов и их расположение в прошлом посте - я его менял добавляя информацию).
    3. Включить в проект файл Posix.SysStat.pas - он сам добавится в uses.
    4. Добавить платформу Linux64 и сделать её активной.
    5. Выбрать кофигурацию Release
    6. Собрать консольное приложение - автоматически будет собран Posix.SysStat.dcu - он лежит в подкаталоге проекта linux64\Release.
    7. Выложить Posix.SysStat.dcu в lib\linux64\release.

    Всё.

  4. 2 минуты назад, krapotkin сказал:

    нет. готовых компонентов, которые позволяют не держать в памяти полную модель данных, вы, скорее всего не найдете.

    Это уже понятно :) .

    2 минуты назад, krapotkin сказал:

    Кроме того для десктопа пара тысяч элементов в ListView особых проблем обычно не вызывает

    Тормозить, при изменении размеров окна (и вместе с ним ListView), начинает уже от 1000, а виртуалный ListBox в VCL и при 65535 не тормозит !

    Очень не хотелось свои компоненты писать !

  5. В 29.03.2021 в 08:38, Олег Киреев сказал:

    Почему у меня при прописывании  Uses Posix.SysStat RAD Studio 10.3  "ругается" что cannot resolve unit filename Posix.SysStat at line...???? Хотя в библиотеке путь source\rtl\posix прописан.

    Компилировать самому модуль Posix.SysStat.pas не нужно, т.к. он уже откомпилирован и лежит в:

    lib\linux64\debug - отладочная версия

    lib\linux64\release - релизная версия

    Компилятор его найдет, если путь к модулю указан в Tools | Options | Language | Delphi | Libraries | Library Path.

    А он, по умолчанию, там указан: $(BDSLIB)\$(Platform)\release

    Проверьте есть ли там откомпилированный модуль и прописан ли путь.

    Если модуля нет, то его можно откомпилировать самому - в каталоге source\rtl лежит файл buildrtl.bat -  он собирает все библиотеки rtl. Процедура его использования не очень прозрачная. Где -то, в документации Embarcadero, написано как его правильно запустить.

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

    Помню, что правил bin\rsvars.bat, и поменял там, все пути в стиле C:\Program Files (x86)\Embarcadero\Studio\21.0\XXXX на C:\RADStudio\XXX.  Где RADStudio получен с помощью mklink /J RADStudio "С:\Program Files (x86)\Embarcadero\Studio\21.0" . Это нужно, т.к. многие утилиты командной строки, например make, не понимают пути с пробелами. Без этого rtl библиотеки не соберутся ! (по крайней мере не собираются c++ rtl, где всё на make построено)

    После того, как соберете rtl библиотеки, просто найдите Posix.SysStat.dcu (релизную версию, конечно :)), и положите его в lib\linux64\release.

    Если, вдруг, модуль Posix.SysStat.dcu не соберется, то нужно будет искать, куда его нужно прописать, чтобы он собирался.

    Ха, Ха, Ха - а rll для Linux не собирается с помощью buildrtl.bat :) - только для Win32, Win64, OSX32.

    Значит нужно самому собрать. Создать свой проект, воткнуть туда исходники, прописать пути, если нужно, и откомпилировать. Изучите исходный код Posix.SysStat.pas - туда куча файлов включается includ'ом.

    На самом деле, к себе в проект (например консольного приложения), нужно скопиповать эти файлы (сохраняя структуру каталогов):

    source\rtl\posix в проекте как posix

        Posix.SysStat.pas

        Posix.SysStatAPI.inc

        Posix.Base.pas

        Posix.SysTypes.pas

    source\rtl\posix\linux в проекте как posix\linux

        BaseTypes.inc

        SysStatTypes.inc

        SysTypesTypes.inc

    Потом включить Posix.SysStat.pas, Posix.Base.pas, Posix.SysTypes.pas так:

    Uses
    	Posix.SysStat  in 'posix\Posix.SysStat.pas',
    	Posix.Base     in 'posix\Posix.Base.pas',
    	Posix.SysTypes in 'posix\Posix.SysTypes.pas';

    Добавляем платформу Linux64 и компилируем - Дело в шляпе.

    Выкладываем скомпилированный модуль в lib\linux64\release и дальше не паримся.

    В RAD Studio 10.4.2 по умолчанию всё на месте. Uses Posix.SysStat прекрасно работает.

  6. Получить UID (идентификатор пользователя - владельца) можно с помошью функции stat (Описана в POSIX стандарте : https://pubs.opengroup.org/onlinepubs/9699919799/ ). Далее есть файл /etc/passwd где UID пользователей сопоставлены с их именами.

    В Linux документацию на stat можно посмотреть командой man 2 stat (В случае если установлены средства разработки на языках C/C++).

    Если не ошибаюсь, она находится в библиотеке libc. Значит задача состоит в том, чтобы загрузить "dll" библиотеку libc ( например /usr/lib64/libc.so.6 ) и вызвать функцию stat. Для загрузки динамических библиотек (разделяемых объектов - shared object - so) используется вызов dlopen.

    Альтернативный способ состоит в том, чтобы напрямую (без библиотеки libc ) выполнить системный вызов stat, обратившись непосредственно к ядру ОС. Для этого, нужно, найти документацию на системный вызов stat, и вызвать его самому - вы по сути сами реализуете функционал библиотеки libc.

    Второй способ, хоть и кажется сложнее, на самом деле реализуется буквально несколькими assembler'ными инструкциями.

    Возможно в Delphi это уже сделали (не исключаю, что в какой-то библиотеке, уже есть функция Stat ).

    В RAD Studio, в каталоге source\rtl\posix, есть файл SysStatAPI.inc - он включен в posix.sysstat.pas.

    Значит просто: Uses Posix.SysStat и используйте функцию stat.

  7. 15 часов назад, krapotkin сказал:

    вроде уж везде написали что ListBox не предназначен для 20+ элементов. используйте ListView 

    https://www.youtube.com/watch?v=XRj3qjUjBlc

    Спасибо за совет, я не видел данного видео. ListView существенно экономнее расходует ОП, но вопрос был о том, имеется ли в FMX функционал, подобный виртуальному ListBox из VCL.

    Я посмотрел исходные коды для ListView и наверное, я сумею изобразить, что-то похожее, на виртуальный ListBox, установив свойство Adapter, у ListView, на определенный мной, класс - наследник от IListViewAdapter.

    Но увиденное в исходных кодах, немного настораживает, т.к. ListView, в некоторых своих методах, обращается, одновременно, и к элементу номер X, и к элементу номер Y - т.е. предполагается, что в данный момент времени, они оба существуют (Скорее всего, предполагается, что существуют элементы в диапазоне от 0 до Adapter.Count ). Я же, хотел избежать, выделения памяти, для структуры из элементов TListViewItem, содержащей Adapter.Count элементов. Именно этим свойством обладает виртуальный ListBox из VCL.

    15 часов назад, krapotkin сказал:

    ну и да, 50000+ элементов это несколько трешовый UI

    Естественно, столько элементов не будет, но потенциально, может быть сколько угодно. И нужно быть к этому готовым.

    Данный функционал, нужен для настольного приложения под Linux. В Windows хватает и VCL. На смартфонах приложение разворачивать не планирутся никогда.

  8. У управляющего элемента TListBox, в библиотеке VCL, есть возможность, работать в виртуальном режиме ( Style = lbVirtual ), когда данные, для элементов списка, поставляет метод, связанный с событием OnData:

    Спойлер
    
    Unit main;
    
    Interface
    
    Uses
        System.Classes,
        Vcl.Forms,
        Vcl.Controls,
        Vcl.StdCtrls;
    
    Type
        TfmMain = class(TForm)
            lbItems: TListBox;
            procedure lbItemsData(Control: TWinControl; Index: Integer; var Data : string);
            procedure FormShow(Sender: TObject);
        public
            constructor Create(AOwner : TComponent); override;
        end;
    
    Var
        fmMain : TfmMain;
    
    Implementation
    
    Uses
        System.SysUtils;
    
    {$R *.dfm}
    
    Const
        MaxLines = 65536;
    
        {--------------------------------------------------------------------------}
        constructor TfmMain.Create(AOwner : TComponent);
        begin
            inherited Create(AOwner);
            lbItems.Count := MaxLines;
        end;
    
        {--------------------------------------------------------------------------}
        procedure TfmMain.FormShow(Sender: TObject);
        begin
            lbItems.ItemIndex := MaxLines - 1;
        end;
    
        {--------------------------------------------------------------------------}
        procedure TfmMain.lbItemsData(    Control : TWinControl;
                                          Index   : Integer;
                                      var Data    : string);
        begin
            Data := 'Item ' + IntToStr(Index);
        end;
    End.

     

    Есть ли что-нибудь похожее в FireMonkey (FMX) ?

    Или придется для каждого элемента списка создавать объект класса TListBoxItem ?

    Попытка создать, таким образом, ListBox на 65536 элементов, приводит к диким расходам ОП - 248 MB:

    Спойлер
    
    Const
        MaxLines = 65536;
    
        procedure TfmMain.btAddItemsClick(Sender: TObject);
        var
            I      : Integer;
            M      : TListBoxItem;
            T0, T1 : TDateTime;
        begin
            T0 := Now;
            lbItems.BeginUpdate;
            try
                for I := 0 to MaxLines - 1 do
                    begin
                        M := TListBoxItem.Create(nil);
                        M.Parent := lbItems;
                        M.Text   := 'Item ' + IntToStr(I);
                    end;
            finally
                lbItems.EndUpdate;
            end;
            T1 := Now;
            edTime.Text := IntToStr(SecondsBetween(T0, T1));
        end;

     

     

×
×
  • Создать...