Расширения PHP и Doxygen
Генерация документации для расширений PHP с использованием Doxygen
Любимые разработчиками PHP макросы и их уровень вложенности зачастую оказываются плохо совместимыми с системой документирования исходных текстов Doxygen.
В зависимости от настроек препроцессора Doxygen (в частности, директивы SKIP_FUNCTION_MACROS) отдельные блоки кода могут быть вообще пропущены; например, в коде:
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 требуются следующие модификации:
- В
config.m4добавляется строка[-]View Code TextPHP_ADD_MAKEFILE_FRAGMENT - Создаётся
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должен иметь в зависимостях все файлы проекта, исключая заголовочные.Вся магия заключается в параметре
В результате Doxygen будет брать определения всех макросов из этого файла, и на выходе получится более-менее нормальный результат.-dMпрепроцессора (работатьэто будет, видимо, только сgcc), которая генерирует список объявлений#defineдля всех макросов, определённых во время выполнения препроцессора; список включает также предопределённые макросы. - В директиве
INPUTDoxygen я явно перечисляю все файлы проекта, при этом важно, чтобыmacros.hшел первым. - Использование файла
macros.hимеет один побочный эффект: в файле определяются все константы, защищающие заголовочные файлы от повторного включения. К счастью, проблема решается просто:- В Doxyfile добавляется директива
PREDEFINED = DOXYGEN; - В заголовочные файлы помещается код, который делает
#undefмакросу-защитнику (centinel), если определён макросDOXYGEN, например:[-]View Code C#ifdef DOXYGEN
#undef PHP_CHUID_H
#endif
#ifndef PHP_CHUID_H
#define PHP_CHUID_H
/* ... */
#endif
- В Doxyfile добавляется директива
Такая конфигурация позволила сгенерировать вполне читаемую документацию.
Единственное «но»: всё же не все макросы раскрываются успешно: например, для самого первого примера получился такой код:
{ 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 $@ нужно поставить:
В результате получается файл меньшего размера, и этот файл Doxygen’у использовать проще, в результате чего макросы раскрываются лучше:
{ 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. Опять же, это рекомендация, полученная из экспериментов.
Сен
2009
Комментарии к статье «Расширения PHP и Doxygen» »
Пожалуйста, не используйте эту форму для комментирования! Данная форма предназначена исключительно для ботов.
Оставить комментарий к записи «Расширения PHP и Doxygen»
गते गते पारगते पारसंगते बोधि स्वाहा
Меня зовут Владимир, я программист-фрилансер, специализирующийся на Web-программировании и програмировании под Linux.
По совместительству занимаюсь администрированием LAMP/LNMP-серверов и техническим переводом.

