Расширения PHP и Doxygen

Vladimir
Опубликовано в: C/C++, PHP

Генерация документации для расширений PHP с использованием Doxygen

Любимые разработчиками PHP макросы и их уровень вложенности зачастую оказываются плохо совместимыми с системой документирования исходных текстов Doxygen.

В зависимости от настроек препроцессора Doxygen (в частности, директивы SKIP_FUNCTION_MACROS) отдельные блоки кода могут быть вообще пропущены; например, в коде:

[-]
View Code C
PHP_INI_BEGIN()
    STD_PHP_INI_BOOLEAN("chuid.disable_posix_setuid_family", "1",     PHP_INI_SYSTEM, OnUpdateBool,   disable_setuid, zend_chuid_globals, chuid_globals)
    STD_PHP_INI_BOOLEAN("chuid.never_root",                  "1",     PHP_INI_SYSTEM, OnUpdateBool,   never_root,     zend_chuid_globals, chuid_globals)
    STD_PHP_INI_BOOLEAN("chuid.cli_disable",                 "1",     PHP_INI_SYSTEM, OnUpdateBool,   cli_disable,    zend_chuid_globals, chuid_globals)
    STD_PHP_INI_BOOLEAN("chuid.be_secure",                   "1",     PHP_INI_SYSTEM, OnUpdateBool,   be_secure,      zend_chuid_globals, chuid_globals)
    STD_PHP_INI_ENTRY("chuid.default_uid",                   "65534", PHP_INI_SYSTEM, OnUpdateLong,   default_uid,    zend_chuid_globals, chuid_globals)
    STD_PHP_INI_ENTRY("chuid.default_gid",                   "65534", PHP_INI_SYSTEM, OnUpdateLong,   default_gid,    zend_chuid_globals, chuid_globals)
    STD_PHP_INI_ENTRY("chuid.global_chroot",                 NULL,    PHP_INI_SYSTEM, OnUpdateString, global_chroot,  zend_chuid_globals, chuid_globals)
PHP_INI_END()

Блок PHP_INI_BEGIN()PHP_INI_END() может быть рассмотрен как функциональный макрос и проигнорироваться Doxygen. Либо, если директива SKIP_FUNCTION_MACROS установлена в No, распознать декларации PHP_INI_BEGIN() и ZEND_DECLARE_MODULE_GLOBALS() как функции.

У меня не получилось никаким настройками (кроме ручного задания соответствия макросов) заставить Doxygen развернуть макросы из zend_module_entry или всякие PHP_MINIT_FUNCTION.

Решение, которое я нашел, не идеально, но всё же лучше, чем ничего.

Применительно к расширениям PHP требуются следующие модификации:

  1. В config.m4 добавляется строка
    [-]
    View Code Text
    PHP_ADD_MAKEFILE_FRAGMENT
  2. Создаётся Makefile.frag следующего содержания:
    [-]
    View Code (Unknown Language)
    htmldocs: docs/html/index.html Doxyfile

    docs/html/index.html: caps.h compatibility.h config.h helpers.h php_chuid.h caps.c chuid.c compatibility.c helpers.c Doxyfile macros.h
        doxygen Doxyfile

    macros.h: caps.c chuid.c compatibility.c helpers.c
        $(CPP) $(COMMON_FLAGS) -dM $^ -o $@

    Вместо docs/html/index.html подставляется имя одного из генерируемых файлов документации (я предпочитаю HTML). Этот файл должен зависеть от всех исходных файлов проекта (по крайней мере тех, по которым генерируется документация), Doxyfile (файл конфигурации Doxygen) и специального файла macros.h.

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

    Вся магия заключается в параметре -dM препроцессора (работатьэто будет, видимо, только с gcc), которая генерирует список объявлений #define для всех макросов, определённых во время выполнения препроцессора; список включает также предопределённые макросы.

    В результате Doxygen будет брать определения всех макросов из этого файла, и на выходе получится более-менее нормальный результат.
  3. В директиве INPUT Doxygen я явно перечисляю все файлы проекта, при этом важно, чтобы macros.h шел первым.
  4. Использование файла macros.h имеет один побочный эффект: в файле определяются все константы, защищающие заголовочные файлы от повторного включения. К счастью, проблема решается просто:
    1. В Doxyfile добавляется директива PREDEFINED = DOXYGEN;
    2. В заголовочные файлы помещается код, который делает #undef макросу-защитнику (centinel), если определён макрос DOXYGEN, например:
      [-]
      View Code C
      #ifdef DOXYGEN
      #undef PHP_CHUID_H
      #endif

      #ifndef PHP_CHUID_H
      #define PHP_CHUID_H

      /* ... */

      #endif

Такая конфигурация позволила сгенерировать вполне читаемую документацию.

Единственное «но»: всё же не все макросы раскрываются успешно: например, для самого первого примера получился такой код:

[-]
View Code C
 {
     { 0,  (1<<2) ,  "chuid.disable_posix_setuid_family" , sizeof( "chuid.disable_posix_setuid_family" ),  OnUpdateBool ,  (void *) ((long) (((char *) (&((( zend_chuid_globals * ) ((void *)0) )-> disable_setuid ))) - ((char *)  ((void *)0) ))) ,  (void *) & chuid_globals ,   ((void *)0)  ,  "1" , sizeof( "1" )-1,  ((void *)0) , 0, 0,  zend_ini_boolean_displayer_cb  },
     { 0,  (1<<2) ,  "chuid.never_root" , sizeof( "chuid.never_root" ),  OnUpdateBool ,  (void *) ((long) (((char *) (&((( zend_chuid_globals * ) ((void *)0) )-> never_root ))) - ((char *)  ((void *)0) ))) ,  (void *) & chuid_globals ,   ((void *)0)  ,  "1" , sizeof( "1" )-1,  ((void *)0) , 0, 0,  zend_ini_boolean_displayer_cb  },
     { 0,  (1<<2) ,  "chuid.cli_disable" , sizeof( "chuid.cli_disable" ),  OnUpdateBool ,  (void *) ((long) (((char *) (&((( zend_chuid_globals * ) ((void *)0) )-> cli_disable ))) - ((char *)  ((void *)0) ))) ,  (void *) & chuid_globals ,   ((void *)0)  ,  "1" , sizeof( "1" )-1,  ((void *)0) , 0, 0,  zend_ini_boolean_displayer_cb  },
     { 0,  (1<<2) ,  "chuid.be_secure" , sizeof( "chuid.be_secure" ),  OnUpdateBool ,  (void *) ((long) (((char *) (&((( zend_chuid_globals * ) ((void *)0) )-> be_secure ))) - ((char *)  ((void *)0) ))) ,  (void *) & chuid_globals ,   ((void *)0)  ,  "1" , sizeof( "1" )-1,  ((void *)0) , 0, 0,  zend_ini_boolean_displayer_cb  },
    STD_PHP_INI_ENTRY("chuid.default_uid",                   "65534",   (1<<2)  , OnUpdateLong,   default_uid,    zend_chuid_globals, chuid_globals)
    STD_PHP_INI_ENTRY("chuid.default_gid",                   "65534",   (1<<2)  , OnUpdateLong,   default_gid,    zend_chuid_globals, chuid_globals)
    STD_PHP_INI_ENTRY("chuid.global_chroot",                  ((void *)0) ,      (1<<2)  , OnUpdateString, global_chroot,  zend_chuid_globals, chuid_globals)
 { 0, 0,  ((void *)0) , 0,  ((void *)0) ,  ((void *)0) ,  ((void *)0) ,  ((void *)0) ,  ((void *)0) , 0,  ((void *)0) , 0, 0,  ((void *)0)  } }

Увы, Doxygen не смог раскрыть макрос STD_PHP_INI_ENTRY. Пожалуй, это один недочёт во всей документации.

UPDATE: я только что нашёл другое решение: в Makefile.frag вместо $(CPP) $(COMMON_FLAGS) -dM $^ -o $@ нужно поставить:

[-]
View Code Text
$(CPP) $(COMMON_FLAGS) -dD $^ | $(CPP) $(DEFS) $(CPPFLAGS) -dM - > $@

В результате получается файл меньшего размера, и этот файл Doxygen’у использовать проще, в результате чего макросы раскрываются лучше:

[-]
View Code C
{
     { 0,  (1<<2) ,  "chuid.disable_posix_setuid_family" , sizeof( "chuid.disable_posix_setuid_family" ),  OnUpdateBool ,  (void *) ((long) (((char *) (&((( zend_chuid_globals * ) ((void *)0) )-> disable_setuid ))) - ((char *)  ((void *)0) ))) ,  (void *) & chuid_globals ,   ((void *)0)  ,  "1" , sizeof( "1" )-1,  ((void *)0) , 0, 0,  zend_ini_boolean_displayer_cb  },
     { 0,  (1<<2) ,  "chuid.never_root" , sizeof( "chuid.never_root" ),  OnUpdateBool ,  (void *) ((long) (((char *) (&((( zend_chuid_globals * ) ((void *)0) )-> never_root ))) - ((char *)  ((void *)0) ))) ,  (void *) & chuid_globals ,   ((void *)0)  ,  "1" , sizeof( "1" )-1,  ((void *)0) , 0, 0,  zend_ini_boolean_displayer_cb  },
     { 0,  (1<<2) ,  "chuid.cli_disable" , sizeof( "chuid.cli_disable" ),  OnUpdateBool ,  (void *) ((long) (((char *) (&((( zend_chuid_globals * ) ((void *)0) )-> cli_disable ))) - ((char *)  ((void *)0) ))) ,  (void *) & chuid_globals ,   ((void *)0)  ,  "1" , sizeof( "1" )-1,  ((void *)0) , 0, 0,  zend_ini_boolean_displayer_cb  },
     { 0,  (1<<2) ,  "chuid.be_secure" , sizeof( "chuid.be_secure" ),  OnUpdateBool ,  (void *) ((long) (((char *) (&((( zend_chuid_globals * ) ((void *)0) )-> be_secure ))) - ((char *)  ((void *)0) ))) ,  (void *) & chuid_globals ,   ((void *)0)  ,  "1" , sizeof( "1" )-1,  ((void *)0) , 0, 0,  zend_ini_boolean_displayer_cb  },
     { 0,  (1<<2) ,  "chuid.default_uid" , sizeof( "chuid.default_uid" ),  OnUpdateLong ,  (void *) ((long) (((char *) (&((( zend_chuid_globals * ) ((void *)0) )-> default_uid ))) - ((char *)  ((void *)0) ))) ,  (void *) & chuid_globals ,   ((void *)0)  ,  "65534" , sizeof( "65534" )-1,  ((void *)0) , 0, 0,  ((void *)0)  },
     { 0,  (1<<2) ,  "chuid.default_gid" , sizeof( "chuid.default_gid" ),  OnUpdateLong ,  (void *) ((long) (((char *) (&((( zend_chuid_globals * ) ((void *)0) )-> default_gid ))) - ((char *)  ((void *)0) ))) ,  (void *) & chuid_globals ,   ((void *)0)  ,  "65534" , sizeof( "65534" )-1,  ((void *)0) , 0, 0,  ((void *)0)  },
     { 0,  (1<<2) ,  "chuid.global_chroot" , sizeof( "chuid.global_chroot" ),  OnUpdateString ,  (void *) ((long) (((char *) (&((( zend_chuid_globals * ) ((void *)0) )-> global_chroot ))) - ((char *)  ((void *)0) ))) ,  (void *) & chuid_globals ,   ((void *)0)  ,  ((void *)0) , sizeof( ((void *)0) )-1,  ((void *)0) , 0, 0,  ((void *)0)  },
 { 0, 0,  ((void *)0) , 0,  ((void *)0) ,  ((void *)0) ,  ((void *)0) ,  ((void *)0) ,  ((void *)0) , 0,  ((void *)0) , 0, 0,  ((void *)0)  } }

Если читабельность кода приоритетнее, чем точность подстановок, то вместо -dD следует использовать -dU. Опять же, это рекомендация, полученная из экспериментов.

Добавить в закладки

Связанные записи

6
Сен
2009

Комментарии к статье «Расширения PHP и Doxygen»  »

К статье «Расширения PHP и Doxygen» комментариев пока нет. Не хотите ли стать первым?

Подписаться на RSS-ленту комментариев к статье «Расширения PHP и Doxygen» Trackback URL: http://blog.sjinks.org.ua/php/626-php-extensions-doxygen/trackback/

Оставить комментарий к записи «Расширения PHP и Doxygen»

Вы можете использовать данные тэги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Оставляя комментарий, Вы выражаете своё согласие с Правилами комментирования.

Подписаться, не комментируя