Rambler's Top100
"Knowledge itself is power"
F.Bacon
Поиск | Карта сайта | Помощь | О проекте | ТТХ  
 Круглый стол
  
Правила КС
>> Настройки

Фильтр вопросов
>> Новые вопросы
отслеживать по
>> Новые ответы

Избранное

Страница вопросов
Поиск по КС


Специальные проекты:
>> К л ю к в а
>> Г о л о в о л о м к и

Вопрос №

Задать вопрос
Off-topic вопросы

Помощь

 
 К н и г и
 
Книжная полка
 
 
Библиотека
 
  
  
 


Поиск
 
Поиск по КС
Поиск в статьях
Яndex© + Google©
Поиск книг

 
  
Тематический каталог
Все манускрипты

 
  
Карта VCL
ОШИБКИ
Сообщения системы

 
Форумы
 
Круглый стол
Новые вопросы

 
  
Базарная площадь
Городская площадь

 
   
С Л С

 
Летопись
 
Королевские Хроники
Рыцарский Зал
Глас народа!

 
  
ТТХ
Конкурсы
Королевская клюква

 
Разделы
 
Hello, World!
Лицей

Квинтана

 
  
Сокровищница
Подземелье Магов
Подводные камни
Свитки

 
  
Школа ОБЕРОНА

 
  
Арсенальная башня
Фолианты
Полигон

 
  
Книга Песка
Дальние земли

 
  
АРХИВЫ

 
 

Сейчас на сайте присутствуют:
 
  
 
Во Флориде и в Королевстве сейчас  23:51[Войти] | [Зарегистрироваться]
Ответ на вопрос № 82087

16-07-2013 23:24
Здравствуйте! Перевожу (пытаюсь) заголовочник C на Delphi. Типы данных и объявления функций, экспортируемых DLL. Существует несколько версий этой DLL, двоично несовместимых между собой. В заголовочнике C это учитывается с помощью директив условной компиляции. Выглядит это примерно так:

config.h:

#define LIB_VERSION 3


header.h:

#include "config.h"
#if LIB_VERSION >= 2
..
#endif
...
#if LIB_VERSION >= 3
...
#else
...
#endif


Эту же самую LIB_VERSION нужно передавать одним из параметров в функцию инициализации библиотеки. Мне видится такой вариант:

header.pas:

const
  LIB_VERSION = 3
...
{$IF LIB_VERSION >= 2}
...
{$ENDIF}
...


Проблема в том, что основные настройки компиляции хотелось бы запихнуть в файл config.inc, по примеру оригинала. Насколько идеологически правильно убирать в него константу? Стоит ли так делать (идея была в том, что режим компиляции настраивается без правки header.pas)? Можно ли сделать как-то по-другому?

[+] Добавить в избранные вопросы

Отслеживать ответы на этот вопрос по RSS

Ответы:


Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице.
Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.

22-07-2013 14:27 | Сообщение от автора вопроса
Python,
>>>А что находится ПОД директивами условной компиляции?
Кратко: директивами условной компиляции определяется наличие или отсутствие в записи некоторых полей, общее количество которых превышает 50 :D

22-07-2013 14:26 | Сообщение от автора вопроса
В общем, у меня появилась такая идея...
1. Привести libJPEG.pas в соответствие актуальному jpeglib.h из поставки libjpeg-turbo
2. Сделать заголовочник для TurboJPEG API, переведя turbojpeg.h
3. Двоичной совместимостью с DLL libJPEG v6b (jpeg62.dll) управлять с помощью директив условной компиляции, как это сделано в jpeglib.h
4. Статическим / динамическим подключением DLL управлять с помощью директив условной компиляции
5. Написать объектную обертку над libJPEG — TLibJpegCodec, инкапсулирующий структуры для кодирования / декодирования и обработку ошибок
6. Написать клон TJPEGImage, повторяющий интерфейс оригинального класса, а внутри являющийся переходником к TLibJpegCodec
7. Совместимость с Delphi 5-7+
8. Совместимость с FPC, раз уж она заявлена в libJPEG.pas
9. Потокобезопасность, раз уж она реализована в libJPEG
10. Документация в HTML (сейчас она прямо в исходном коде, в соответствии с оригиналом, но мне не очень нравится)

Прогресс:
1-4 - частично
5 - набросок public-части, меняется в процессе копания в библиотеке
6 - в планах
7 - автоматически :)
8 - в планах
9 - частично, плохо знаю тему
10 - на стадии чтения мануала к FPDoc :)

Этот вопрос был по п. 1-4. Сейчас мне видится такая схема:
jpeglib.h -> libJPEG.pas
turbojpeg.h -> TurboJPEG.pas
+ libJPEG_config.pas — тут директивы условной компиляции для п. 1-4 плюс реализация динамической загрузки DLL по запросу. Этот модуль должен использоваться двумя другими. Не знаю, почему я сначала подумал про INC-файл.

22-07-2013 14:24 | Сообщение от автора вопроса
Была libJPEG v6b. На ней, кстати, основан стандартный дельфийский TJPEGImage. Там тупо libJPEG скомпилирована в *.obj и прилинкована в таком виде к заголовочнику *.pas. Для libJPEG v6b в виде динамически подключаемой DLL, есть еще заголовочник libJPEG.pas 2008 года (по идее, совместимый с FPC, но не проверял), который больше не поддерживается. С тех пор libJPEG ушла далеко вперед. В версиях 7 и 8 появились новые возможности, из-за которых пришлось сломать обратную двоичную совместимость с 6-й версией. Там в функции кодирования и декодирования передаются огромные записи jpeg_compress_struct и jpeg_decompress_struct, больше 50 полей в каждой. Так вот, в версиях 7 и 8 в этих записях появились новые поля, что делает невозможным (без перекомпиляции) использование новых версий DLL программами, рассчитанными на 6-ю версию.

У libJPEG есть форк, libjpeg-turbo. Функции оптимизированы с использованием инструкций MMX, SSE2, NEON. Разработчики решили поддерживать двоичный интерфейс libJPEG v6b, поэтому DLL libjpeg-turbo можно спокойно использовать с заголовочником libJPEG.pas, рассчитанным на эту версию. Получается быстрее стандартного TJPEGImage примерно в 5-6 раз. Можете посмотреть демо-программу Sapersky, которую он предложил мне в »вопрос КС №82040«.

В примере Sapersky как раз используется libJPEG.pas. Проблема в том, что libJPEG декодирует изображение в формат RGB, а в TBitmap используется обратный порядок BGR. Поэтому в том примере после декодирования потом еще "вручную" преставляются байты. Я посмотрел в современные заголовочники libjpeg-turbo, а там уже есть возможность декодирования в нужный формат:

#define JCS_EXTENSIONS 1
#define JCS_ALPHA_EXTENSIONS 1

typedef enum {
           JCS_UNKNOWN,                     /* error/unspecified */
           JCS_GRAYSCALE,                     /* monochrome */
           JCS_RGB,                     /* red/green/blue as specified by the RGB_RED, RGB_GREEN,
                                          RGB_BLUE, and RGB_PIXELSIZE macros */
           JCS_YCbCr,                     /* Y/Cb/Cr (also known as YUV) */
           JCS_CMYK,                     /* C/M/Y/K */
           JCS_YCCK,                     /* Y/Cb/Cr/K */
           JCS_EXT_RGB,                     /* red/green/blue */
           JCS_EXT_RGBX,                     /* red/green/blue/x */
           JCS_EXT_BGR,                     /* blue/green/red */
           JCS_EXT_BGRX,                     /* blue/green/red/x */
           JCS_EXT_XBGR,                     /* x/blue/green/red */
           JCS_EXT_XRGB,                     /* x/red/green/blue */
           /* When out_color_space it set to JCS_EXT_RGBX, JCS_EXT_BGRX,
            JCS_EXT_XBGR, or JCS_EXT_XRGB during decompression, the X byte is
            undefined, and in order to ensure the best performance,
            libjpeg-turbo can set that byte to whatever value it wishes.  Use
            the following colorspace constants to ensure that the X byte is set
            to 0xFF, so that it can be interpreted as an opaque alpha
            channel. */
           JCS_EXT_RGBA,                     /* red/green/blue/alpha */
           JCS_EXT_BGRA,                     /* blue/green/red/alpha */
           JCS_EXT_ABGR,                     /* alpha/blue/green/red */
           JCS_EXT_ARGB                     /* alpha/red/green/blue */
}
J_COLOR_SPACE;



Одно из полей записи jpeg_decompress_struct как раз имеет тип J_COLOR_SPACE. Я безболезненно дописал libJPEG.pas и получил еще 24% рост производительности. Тут можно было вляпаться с выравниванием, но, к счастью, все работает на ура.


{$MINENUMSIZE 4}
...
// New in libJPEG-turbo
{$DEFINE JCS_EXTENSIONS}
{$DEFINE JCS_ALPHA_EXTENSIONS}

  // jpeglib.h line 219
  J_COLOR_SPACE = (
    JCS_UNKNOWN,    { error/unspecified }
    JCS_GRAYSCALE,  { monochrome }
    JCS_RGB,        { red/green/blue }
    JCS_YCbCr,      { Y/Cb/Cr (also known as YUV) }
    JCS_CMYK,      { C/M/Y/K }
    JCS_YCCK        { Y/Cb/Cr/K }
    {$IFDEF JCS_EXTENSIONS},
    JCS_EXT_RGB,                     { red/green/blue }
    JCS_EXT_RGBX,                     { red/green/blue/x }
    JCS_EXT_BGR,                     { blue/green/red }
    JCS_EXT_BGRX,                     { blue/green/red/x }
    JCS_EXT_XBGR,                     { x/blue/green/red }
    JCS_EXT_XRGB                     { x/red/green/blue }
    {$IFDEF JCS_ALPHA_EXTENSIONS},
    { When out_color_space it set to JCS_EXT_RGBX, JCS_EXT_BGRX,
      JCS_EXT_XBGR, or JCS_EXT_XRGB during decompression, the X byte is
      undefined, and in order to ensure the best performance,
      libjpeg-turbo can set that byte to whatever value it wishes.  Use
      the following colorspace constants to ensure that the X byte is set
      to 0xFF, so that it can be interpreted as an opaque alpha
      channel. }

    JCS_EXT_RGBA,                     { red/green/blue/alpha }
    JCS_EXT_BGRA,                     { blue/green/red/alpha }
    JCS_EXT_ABGR,                     { alpha/blue/green/red }
    JCS_EXT_ARGB                     { alpha/red/green/blue }
    {$ENDIF}
    {$ENDIF}
  );



В принципе, на этом можно было бы и успокоиться. Десятикратное декодирование фотографии 4000x3000 на Core i3-2100 выполняется примерно за 1150 мс (со старым заголовочником ~1500). Но libjpeg-turbo поддерживает еще и эмуляцию API/ABI libJPEG v7+. Из-за упомянутой двоичной несовместимости, это управляется директивами условной компиляции:

struct jpeg_compress_struct {
  ...
#if JPEG_LIB_VERSION >= 70
  unsigned int scale_num, scale_denom; /* fraction by which to scale image */

  JDIMENSION jpeg_width;           /* scaled JPEG image width */
  JDIMENSION jpeg_height;           /* scaled JPEG image height */
  /* Dimensions of actual JPEG image that will be written to file,
  * derived from input dimensions by scaling factors above.
  * These fields are computed by jpeg_start_compress().
  * You can also use jpeg_calc_jpeg_dimensions() to determine these values
  * in advance of calling jpeg_start_compress().
  */
#endif
  ...
#if JPEG_LIB_VERSION >= 70
  int q_scale_factor[NUM_QUANT_TBLS];
#endif
  ...
#if JPEG_LIB_VERSION >= 70
  boolean do_fancy_downsampling; /* TRUE=apply fancy downsampling */
#endif
  ...
#if JPEG_LIB_VERSION >= 70
  int min_DCT_h_scaled_size;           /* smallest DCT_h_scaled_size of any component */
  int min_DCT_v_scaled_size;           /* smallest DCT_v_scaled_size of any component */
#endif
  ...
#if JPEG_LIB_VERSION >= 80
  int block_size;                     /* the basic DCT block size: 1..16 */
  const int * natural_order;           /* natural-order position array */
  int lim_Se;                               /* min( Se, DCTSIZE2-1 ) */
#endif
  ...
}
;


(где "..." = "многабукв" :)

Кроме того, libjpeg-turbo содержит более высокоуровневый TurboJPEG API, который тоже хотелось бы иметь возможность использовать в Delphi...
Ладно, предысторию а-ля "что это" и "зачем оно нужно" как-то рассказал :) Что хочу сделать — в следующем сообщении, а то это уже почти 6,5 К.

22-07-2013 04:48
А что находится ПОД директивами условной компиляции? Там объявлены разные типы данных? Там объявлены разные типы процедур и функций? От этого зависит итоговое решение.
Типы стоит унифицировать. То есть если у нас есть такой колхоз:

Type TData=record A,B:integer;end; // для библиотеки 1 версии
Type TData=record A,B:integer;C:float;end; // для библиотеки второй версии


То стоит породить "общий знаменатель" всех типов и передавать его в процедуры-обёртки. Обёртки, в свою очередь, должны "запаковать" переданные данные (основываясь на версии библиотеки) и "распаковать" их обратно. Ровно также работать с функциями-процедурами-"обёртками" - в зависимости от переданного номера версии, подгружать (динамически) либо один, либо другой вариант функции. Мало того, можно при таком подходе "на лету", не перекомпилируя программу, переключаться между версиями одной и той же библиотеки. Другое дело - надо ли это...
Ну а так - выложите более полный вариант Вашего .h файла. Попробую перевести на паскаль. Не думаю, что это невыполнимая задача.

19-07-2013 02:15
Да, вы правильно меня поняли. Можно вынести эту константу в отдельный файл и включать его где нужно директивой {$I}, но дело в том, что в Дельфи механизм включения файлом работает иначе чем в С/С++, где можно проверить был ли файл уже включен или нет. Дельфи будет каждый раз включать файл, и наплодит вам много одинаковых констант LIB_VERSION (хотя наверное это совсем не проблема)

17-07-2013 12:27 | Сообщение от автора вопроса
Просто во всех попадавшихся мне настроечных INC-файлах, входящих в дельфийские библиотеки, я видел только директивы условной компиляции, констант там нету (если только строковые). Из этого я предположил, что убирать константы во включаемые файлы "не принято", что ли... Компилятору-то, насколько я понимаю, пофиг, там можно хоть классы объявлять (смысла только нет). Тут вопрос дизайна — с одной стороны, удобно запихнуть весь интерфейс библиотеки в один-единственный файл PAS. С другой, настройки режимов компиляции логично сгруппировать в каком-то одном месте (там их достаточно много наберется: разные версии компилятора, разные версии самой DLL, кросплатформенность, совместимость с Free Pascal и т.п.) Это может быть либо "шапка" модуля, либо отдельный файл.

~AQUARIUS~, вы, значит, склоняетесь к варианту вытащить эту константу повыше и написать над ней комментарий, какие значения и зачем ей присваивать, и на что это влияет?

17-07-2013 12:00
Gary_Ch

Вариант как в вашем вопросе - практически и есть копия 1 в 1. Если config.h еще где-то используется, его можно сделать отдельным файлом, и потом включить с помощью директивы {$I filename}, если нет - тогда ваш вариант вполне нормальный

17-07-2013 08:25 | Сообщение от автора вопроса
Т.е. слепить примерно вот такой колхоз?


{.$DEFINE LIB_VER_1}
{.$DEFINE LIB_VER_2}
{$DEFINE LIB_VER_3}

{$IFDEF LIB_VER_3}
  {$DEFINE LIB_VER_2}
{$ENDIF}

{$IFDEF LIB_VER_2}
  {$DEFINE LIB_VER_1}
{$ENDIF}

const
{$IFDEF LIB_VER_3}
  LIB_VERSION = 3;
{$ELSE}
{$IFDEF LIB_VER_2}
  LIB_VERSION = 2;
{$ELSE}
  LIB_VERSION = 1;
{$ENDIF}
{$ENDIF}

implementation

{$IFDEF LIB_VER_2}
...
{$ENDIF}

{$IFDEF_LIB_VER_3}
...
{$ELSE}
...
{$ENDIF}

initialization
  LibInit(LIB_VERSION);
finalization
  LibFree;
end.


17-07-2013 03:02
Надо лепить примерно вот такие конструкции:


// RAD Studio XE3 (BDS 10.0) DELPHI and BCB are no longer defined, only COMPILER
{$ifdef VER240}
  {$define COMPILER_17}
{$endif VER230}

// RAD Studio XE2 (BDS 9.0) DELPHI and BCB are no longer defined, only COMPILER
{$ifdef VER230}
  {$define COMPILER_16}
{$endif VER230}

// RAD Studio 2010 (BDS 7.0) DELPHI and BCB are no longer defined, only COMPILER
{$ifdef VER210}
  {$define COMPILER_14}
{$endif VER210}




{$ifdef COMPILER_14}
{$define COMPILER_1_UP}
{$define COMPILER_2_UP}
{$define COMPILER_3_UP}
{$define COMPILER_4_UP}
{$define COMPILER_5_UP}
{$define COMPILER_6_UP}
{$define COMPILER_7_UP}
{$define COMPILER_8_UP}
{$define COMPILER_9_UP}
{$define COMPILER_10_UP}
{$define COMPILER_11_UP}
{$define COMPILER_12_UP}
{$define COMPILER_14_UP}
// Backwards compatibility
{$define DELPHI_2_UP}
{$define DELPHI_3_UP}
{$define DELPHI_4_UP}
{$define DELPHI_5_UP}
{$define DELPHI_6_UP}
{$define DELPHI_7_UP}
{$define DELPHI_8_UP}
{$define DELPHI_9_UP}
{$define CPPB_3_UP}
{$define CPPB_4_UP}
{$define CPPB_5_UP}
{$define CPPB_6_UP}


{$ifdef BCB}
  {$define CPPB}
{$else}
  {$define DELPHI}
{$endif}


{$endif}


{$ifdef COMPILER_16}
{$define COMPILER_1_UP}
{$define COMPILER_2_UP}
{$define COMPILER_3_UP}
{$define COMPILER_4_UP}
{$define COMPILER_5_UP}
{$define COMPILER_6_UP}
{$define COMPILER_7_UP}
{$define COMPILER_8_UP}
{$define COMPILER_9_UP}
{$define COMPILER_10_UP}
{$define COMPILER_11_UP}
{$define COMPILER_12_UP}
{$define COMPILER_14_UP}
{$define COMPILER_16_UP}
{$define BDS_9_UP}
// Backwards compatibility
{$define DELPHI_2_UP}
{$define DELPHI_3_UP}
{$define DELPHI_4_UP}
{$define DELPHI_5_UP}
{$define DELPHI_6_UP}
{$define DELPHI_7_UP}
{$define DELPHI_8_UP}
{$define DELPHI_9_UP}
{$define CPPB_3_UP}
{$define CPPB_4_UP}
{$define CPPB_5_UP}
{$define CPPB_6_UP}


{$ifdef BCB}
  {$define CPPB}
{$else}
  {$define DELPHI}
{$endif}


{$endif}


{$ifdef COMPILER_17}
{$define COMPILER_1_UP}
{$define COMPILER_2_UP}
{$define COMPILER_3_UP}
{$define COMPILER_4_UP}
{$define COMPILER_5_UP}
{$define COMPILER_6_UP}
{$define COMPILER_7_UP}
{$define COMPILER_8_UP}
{$define COMPILER_9_UP}
{$define COMPILER_10_UP}
{$define COMPILER_11_UP}
{$define COMPILER_12_UP}
{$define COMPILER_14_UP}
{$define COMPILER_16_UP}
{$define COMPILER_17_UP}
{$define BDS_9_UP}
// Backwards compatibility
{$define DELPHI_2_UP}
{$define DELPHI_3_UP}
{$define DELPHI_4_UP}
{$define DELPHI_5_UP}
{$define DELPHI_6_UP}
{$define DELPHI_7_UP}
{$define DELPHI_8_UP}
{$define DELPHI_9_UP}
{$define CPPB_3_UP}
{$define CPPB_4_UP}
{$define CPPB_5_UP}
{$define CPPB_6_UP}


{$ifdef BCB}
  {$define CPPB}
{$else}
  {$define DELPHI}
{$endif}


{$endif}





VERХХХ - это версия компилятора, она есть всегда, на ее основе определяется версия делфей, а на основе версии - уже логические определения типа  DELPHI_9_UP, что означает, что это Делфи 9 и выше.

Добавьте свое cообщение

Вашe имя:  [Войти]
Ваш адрес (e-mail):На Королевстве все адреса защищаются от спам-роботов
контрольный вопрос:
Раз дощечка, два дощечка будет лесенка. Раз словечко, два словечко, будет ЧТО?
в качестве ответа на вопрос или загадку следует давать только одно слово в именительном падеже и именно в такой форме, как оно используется в оригинале.
Надоело отвечать на странные вопросы? Зарегистрируйтесь на сайте.
Тип сообщения:
Текст:
Жирный шрифт  Наклонный шрифт  Подчеркнутый шрифт  Выравнивание по центру  Список  Заголовок  Разделительная линия  Код  Маленький шрифт  Крупный шрифт  Цитирование блока текста  Строчное цитирование
  • вопрос Круглого стола № XXX

  • вопрос № YYY в тесте № XXX Рыцарской Квинтаны

  • сообщение № YYY в теме № XXX Базарной площади
  • обсуждение темы № YYY Базарной площади
  •  
     Правила оформления сообщений на Королевстве

    Страница избранных вопросов Круглого стола.
      
    Время на сайте: GMT минус 5 часов

    Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter.
    Функция может не работать в некоторых версиях броузеров.

    Web hosting for this web site provided by DotNetPark (ASP.NET, SharePoint, MS SQL hosting)  
    Software for IIS, Hyper-V, MS SQL. Tools for Windows server administrators. Server migration utilities  

     
    © При использовании любых материалов «Королевства Delphi» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
    Все используемые на сайте торговые марки являются собственностью их производителей.

    Яндекс цитирования