воскресенье, 13 декабря 2015 г.

Perl изнутри: файл EXTERN.h

Получаем исходники

 

Идём в perlgit, находим способ для получения репозитария исходников perl:
% git clone git://perl5.git.perl.org/perl.git perl 

Любуемся и приступаем к изучению, а заодно вспомним C. Начнём с файла заголовков "EXTERN.h". Вот его основное содержимое:

/*
 * EXT  designates a global var which is defined in perl.h
 * dEXT designates a global var which is defined in another
 *      file, so we can't count on finding it in perl.h
 *      (this practice should be avoided).
 */
#undef EXT
#undef dEXT
#undef EXTCONST
#undef dEXTCONST

#  if (defined(WIN32) || defined(__SYMBIAN32__)) && \
      !defined(PERL_STATIC_SYMS)
#    if defined(PERL_IS_MINIPERL) && !defined(UNDER_CE) && \
        defined(_MSC_VER)
#      define EXT extern
#      define dEXT 
#      define EXTCONST extern const
#      define dEXTCONST const
#    else
#      if defined(PERLDLL) || defined(__SYMBIAN32__)
#        define EXT EXTERN_C __declspec(dllexport)
#        define dEXT 
#        define EXTCONST EXTERN_C __declspec(dllexport) const
#        define dEXTCONST const
#      else
#        define EXT EXTERN_C __declspec(dllimport)
#        define dEXT 
#        define EXTCONST EXTERN_C __declspec(dllimport) const
#        define dEXTCONST const
#      endif
#    endif
#  else
#    if defined(__CYGWIN__) && defined(USEIMPORTLIB)
#      define EXT extern __declspec(dllimport)
#      define dEXT 
#      define EXTCONST extern __declspec(dllimport) const
#      define dEXTCONST const
#    else
#      define EXT extern
#      define dEXT
#      define EXTCONST extern const
#      define dEXTCONST const
#    endif
#  endif

#undef INIT
#define INIT(x)

#undef DOINIT

Вспоминаем С

 

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

Например.
#include <foo.h>
#include "foo.h"

Как видно разница в кавычках: при использовании <> файл ищется в системных каталогах,
а при "" в каталоге, где расположен текущий файл.

Определение функций (прототипы) - это обычная функция, только без "тела", её логики.
Необходимы для информирования компилятора о типе возвращаемого значения и о типах
параметров, которые принимает функция, а так же об их количестве.
Имеют вид: <тип возвращаемого значения> + <имя функции> + (<тип(ы) параметра(ов)>).

Макросы - это строка, которая при анализе кода препроцессором будет заменена на другую строку. Для написания макроса необходимо использовать "define". Весьма часто макросы используются в роли констант, например #define PI 3.14; но так же могут выступать в роли функций или еще каких-либо конструкций языка, например: #define FOO printf("Hello world\n").

Используемые конструкции в EXTERN.h

 

undef - обнуляем предыдущее определение макроса, бывает необходимо когда нужно вызвать именно функцию, а не макрос, в случае, если они имеют одинаковое название.
defined - инструкция для проверки на определённость, по аналогии с #ifdef.
extern - указывания для компоновщика (англ. linker), о том, что переменную следует
искать в другом месте программы.
if, else, endif - обычные конструкции для условных проверок.
Макросы WIN32, PERLDLL и др - предустоновленные макросы в вашей системе, список
которых можете получить с помощью подобной команды:

gcc -E -dM - < /dev/null

Опция -E говорит о том, что как только препроцессор отработает, то прекращаем дальнейшую работу gcc, без выполнения компиляции как таковой. -dM - выводит список всех #define инструкций, в том числе и предустоновленных.

Назначение файла


Таким образом задача данного файла заголовков в том, чтобы определить данные макросы: EXT, dEXT, EXTCONST, dEXTCONST с учетом особенностей ОС. Ну и помимо этого он так же обнуляет INIT, DOINIT и определяет INIT(x), который ничего не делает.

Подытожим. Подключая файл заголовков EXTERN.h в код, мы получим такой функционал (пример для linux):

#include "EXTERN.h"

void main(void) {
    EXT  int b;    // extern int b
    dEXT int c;    // int c

    EXTCONST  d;    // extern const d
    dEXTCONST e;    // const e
    INIT();         // пусто
}

Для чего это нужно частично описано в комментарии к файлу.

/*
 * EXT  designates a global var which is defined in perl.h
 * dEXT designates a global var which is defined in another
 *      file, so we can't count on finding it in perl.h
 *      (this practice should be avoided).
 */

Т.е. EXT переменные объявляются в файле perl.h, а dEXT могут располагаться где-то еще.

Комментариев нет:

Отправить комментарий