До появления gccxml, был только один способ извлечь мета-информацию из Си/Теперь, писать парсер больше не нужно. Модифицированный компилятор gcc анализирует ваш код и выдает описание всех пространств имен, типов, классов и функций, встреченных в программе. Данные выдаются в формате XML и в принципе готовы для дальнейшего автоматического анализа и обработки.
Для разбора XML данных, полученных от gccxml, пригодится библиотека pygccxml. Это не просто ридер формата gccxml — библиотека предоставляет интерфейсы для изучения собранных метаданных; в частности есть готовые функции, отвечающие на вопросы вроде «совместимы ли типы T1 и T2?» или «наследует ли класс C1 от C2?». Библиотека написана на языке Python.
Знакомство с gccxml
Gccxml был разработан в Kitware (они же авторы CMake). Это модифицированный C++ парсер из GCC.
Вероятно, у вас еще не установлен gccxml. Лично я ставил gccxml с помощью менеджера пакетов и не вижу необходимости останавливаться на этом шаге подробно. Если для вашей ОСи нет пакетного менеджера, боюсь я ничем не могу помочь.
Начнем с простого определения функции.
namespace test { int fn(int a, int b); }
Компилируем:
gccxml -fxml=test.xml test.cpp
На выходе получаем test.xml такого содержания (фрагмент):
<GCC_XML> <Namespace id="_1" name="::" members="… _96 …" mangled="_Z2::" demangled="::"/> <Namespace id="_96" name="test" context="_1" members="_141 " mangled="_Z4test" demangled="test"/> <FundamentalType id="_128" name="int" size="32" align="32"/> <Function id="_141" name="fn" returns="_128" context="_96" mangled="_ZN4test2fnEii" demangled="test::fn(int, int)" location="f1:2" file="f1" line="2" extern="1" > <Argument name="a" type="_128" location="f1:2" file="f1" line="2"/> <Argument name="b" type="_128" location="f1:2" file="f1" line="2"/> </Function> <File id="f1" name="test.cpp"/> </GCC_XML>
Здесь все понятно и без документации. Я не буду приводить примеры для других конструкций языка C++ — там все аналогично. Первоочередная цель достигнута — мета-информация извлекается в формате, пригодном для дальнейшей автоматической обработки.
Извлекаем еще больше мета-информации
Иногда в исходных текстах содержится больше информации, чем предусмотрено семантикой языка C++. Пример: SAL-анотации в Windows (__in, __out и тп.)
BOOL WINAPI CreateProcess( __in_opt LPCTSTR lpApplicationName, __inout_opt LPTSTR lpCommandLine, __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes, __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, __in BOOL bInheritHandles, __in DWORD dwCreationFlags, __in_opt LPVOID lpEnvironment, __in_opt LPCTSTR lpCurrentDirectory, __in LPSTARTUPINFO lpStartupInfo, __out LPPROCESS_INFORMATION lpProcessInformation );
Пример: информация о минимальной версии Mac OS X, в которой доступна API функция.
CFErrorRef CFErrorCreate( CFAllocatorRef allocator, CFStringRef domain, CFIndex code, CFDictionaryRef userInfo ) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
Даже эту дополнительную мета-инфрмацию можно извлекать при помощи gccxml. Здесь нам поможет специфичное для gcc расширение синтаксиса языка C++ — конструкция attribute. Экспериментировать будем с определением функции fn:
#define __foo __attribute__((gccxml("__foo")) #define __bar __attribute__((gccxml("__bar")) namespace test { __foo int fn(__bar int a, int b); }
Атрибуты «применяются» к ближайшей семантической единицей в исходном тексте. Так первый атрибут относится к функции fn, а второй — к параметру a. Gcc понимает различные атрибуты, но в данном случае нас интересует только атрибут gccxml.
Gccxml выдает следующую информацию по функции fn. Как мы видим, все аннотации сохранены и доступны для дальней обработки.
<Function id="_141" name="fn" returns="_128" context="_96" mangled="_ZN4test2fnEii" demangled="test::fn(int, int)" location="f1:7" file="f1" line="7" extern="1" attributes="gccxml(__foo)"> <Argument name="a" type="_128" location="f1:7" file="f1" line="7" attributes="gccxml(__bar)"/> <Argument name="b" type="_128" location="f1:7" file="f1" line="7"/> </Function>
Знакомство с pygccxml
Pygccxml разрабатывается Roman Yakovenko и co. Цель проекта — автоматическое изготовление C++/Python биндингов при помощи boost::python. Интересно, чем их не устроил SWIG?
Pygccxml можно поставить либо через пакетный менеджер, либо вручную (качать здесь, инструкции по установке в README.txt).
Документация на pygccxml оставляет желать лучшего. Для начала работы ее достаточно, но если потребуется что-то, выходящее за рамки базовых возможностей, придется заглядывать в исходный код библиотеки. Это странно, но документация не доступна для онлайн-просмотра, ее можно только скачать.
Ниже приведен пример простешего анализатора C++ ко��а с использованием библиотеки pygccxml.
Скрипт распечатывает все функции, объявленные в прострастве имен test.
import pygccxml db = pygccxml.parser.parse(['test.cpp']) global_ns = pygccxml.declarations.get_global_namespace(db) for test_ns in global_ns.namespaces('test'): for function in test_ns.calldefs(): pygccxml.declarations.print_declarations(function)
Вот результат работы скрипта:
free_function_t: 'fn' location: [./test.cpp]:4 artificial: 'False' attributes: gccxml(__foo) demangled: test::fn(int, int) mangled: _ZN4test2fnEii return type: int arguments type: int a, int b
Идеи для вашего кода
Зачем мне программно анализировать
Вот что пишет Алексей Пахунов aka notakernelguy:
Я тут совсем недавно удивлялся почему нет библиотек, эмулирующих поддержку UTF-8 на уровне Win32 API. Т.е. такая библиотека реализует, скажем, CreateFileUtf8 в дополнение к предлагаемым системой CreateFileA и CreateFileW, а макрос CreateFile будет выбирать нужную реализацию уже из трех вариантов.В 2007 году Алексей решает создать такую библиотеку для прозрачного внедрения поддержки Unicode в программу Notepad2. Предполагалось автоматически обработать заголовочные файлы Windows и генерировать искомую библиотеку программно. Алексей не использует gccxml и в 2012 году его библиотека все еще не готова.
Следующие два примера из моей практики.
С помощью gccxml я делал
А вот второй пример. У меня есть система для обработки данных, написанная на
Ограничения gccxml
К сожалению, gccxml имеет некоторые недостатки. Из кода извлекаются только декларации, а тела функций не доступны. Декларации шаблонов также не доступны. Gccxml основан на достаточно старой версии gcc и разработка идет не слишком активно.
