13
0

Add small llvm/libclang util to exctract doxygen comments

This commit is contained in:
Robin Gareus 2016-03-24 19:53:27 +01:00
parent 940c165a31
commit 6188315791
3 changed files with 240 additions and 0 deletions

2
.gitignore vendored
View File

@ -131,4 +131,6 @@ tags
/icons/win32/msvc_resources.rc
/tools/osx_packaging/Ardour/*.app
/tools/doxy2json/doxy2json
/MSVCvst_scan/vst_scan.rc

55
tools/doxy2json/ardourdoc.sh Executable file
View File

@ -0,0 +1,55 @@
#!/bin/bash
set -e
make
cd ../..
test -f libs/ardour/ardour/ardour.h
LLVMINCLUDE="-I /usr/lib/llvm-3.6/include -I /usr/lib/llvm-3.6/lib/clang/3.6.2/include/"
TMPFILE=`mktemp`
trap 'rm -f $TMPFILE' exit SIGINT SIGTERM
echo "# analyzing source.. -> $TMPFILE"
./tools/doxy2json/doxy2json \
`pkg-config --cflags glib-2.0 glibmm-2.4 cairomm-1.0 gtkmm-2.4 | sed 's/-std=c++11 //;s/-pthread //'` \
$LLVMINCLUDE -I /usr/include/linux \
-I libs/ardour -I libs/pbd -I libs/lua -I gtk2_ardour -I libs/timecode \
-I libs/ltc -I libs/evoral \
libs/ardour/ardour/* libs/pbd/pbd/* \
gtk2_ardour/*.h \
/usr/include/cairomm-1.0/cairomm/context.h \
> $TMPFILE
ls -lh $TMPFILE
echo "# consolidating JSON"
php << EOF
<?php
\$json = file_get_contents ('$TMPFILE');
\$api = array ();
foreach (json_decode (\$json, true) as \$a) {
if (!isset (\$a['decl'])) { continue; }
if (empty (\$a['decl'])) { continue; }
if (\$a['decl'] == '::') { continue; }
if (substr (\$a['decl'], 0, 1) == '_') { continue; }
if (substr (\$a['decl'], 0, 2) == '::') { continue; }
if (substr (\$a['decl'], 0, 4) == 'sigc') { continue; }
if (substr (\$a['decl'], 0, 5) == 'Atk::') { continue; }
if (substr (\$a['decl'], 0, 5) == 'Gdk::') { continue; }
if (substr (\$a['decl'], 0, 5) == 'Gtk::') { continue; }
if (substr (\$a['decl'], 0, 5) == 'Gio::') { continue; }
if (substr (\$a['decl'], 0, 6) == 'Glib::') { continue; }
if (substr (\$a['decl'], 0, 7) == 'Pango::') { continue; }
if (substr (\$a['decl'], 0, 11) == 'luabridge::') { continue; }
\$a['decl'] = str_replace ('size_t', 'unsigned long', \$a['decl']);
\$canon = str_replace (' *', '*', \$a['decl']);
\$api[\$canon] = \$a;
}
\$jout = array ();
foreach (\$api as \$k => \$a) {
\$jout[] = \$a;
}
file_put_contents('doc/ardourapi.json', json_encode (\$jout, JSON_PRETTY_PRINT));
EOF
ls -l doc/ardourapi.json

View File

@ -0,0 +1,183 @@
/* extract doxygen comments from C++ header files
*
* Copyright (C) 2016 Robin Gareus <robin@gareus.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include <cstdio>
#include <cstring>
#include <sstream>
#include <iomanip>
#include <clang-c/Index.h>
#include <clang-c/Documentation.h>
static const char*
kind_to_txt (CXCursor cursor)
{
CXCursorKind kind = clang_getCursorKind (cursor);
switch (kind) {
case CXCursor_StructDecl : return "Struct";
case CXCursor_EnumDecl : return "Enum";
case CXCursor_UnionDecl : return "Union";
case CXCursor_FunctionDecl : return "C Function";
case CXCursor_VarDecl : return "Variable";
case CXCursor_ClassDecl : return "C++ Class";
case CXCursor_CXXMethod : return "C++ Method";
case CXCursor_Namespace : return "C++ Namespace";
case CXCursor_Constructor : return "C++ Constructor";
case CXCursor_Destructor : return "C++ Destructor";
case CXCursor_FieldDecl : return "Data Member/Field";
default: break;
}
return "";
}
static std::string
escape_json (const std::string &s)
{
std::ostringstream o;
for (auto c = s.cbegin (); c != s.cend (); c++) {
switch (*c) {
case '"': o << "\\\""; break;
case '\\': o << "\\\\"; break;
case '\n': o << "\\n"; break;
case '\r': o << "\\r"; break;
case '\t': o << "\\t"; break;
default:
if ('\x00' <= *c && *c <= '\x1f') {
o << "\\u" << std::hex << std::setw (4) << std::setfill ('0') << (int)*c;
} else {
o << *c;
}
}
}
return o.str ();
}
static void recurse_parents (CXCursor cr) {
CXCursor pc = clang_getCursorSemanticParent (cr);
if (CXCursor_TranslationUnit == clang_getCursorKind (pc)) {
return;
}
if (!clang_Cursor_isNull (pc)) {
recurse_parents (pc);
printf ("%s::", clang_getCString (clang_getCursorDisplayName (pc)));
}
}
static enum CXChildVisitResult
traverse (CXCursor cr, CXCursor /*parent*/, CXClientData)
{
CXComment c = clang_Cursor_getParsedComment (cr);
if (clang_Comment_getKind (c) != CXComment_Null
&& clang_isDeclaration (clang_getCursorKind (cr))
&& 0 != strlen (kind_to_txt (cr))
) {
printf ("{ \"decl\" : \"");
recurse_parents (cr);
// TODO: resolve typedef enum { .. } name;
// use clang_getCursorDefinition (clang_getCanonicalCursor (cr)) ??
printf ("%s\",\n", clang_getCString (clang_getCursorDisplayName (cr)));
if (clang_Cursor_isVariadic (cr)) {
printf (" \"variadic\" : true,\n");
}
printf (" \"kind\" : \"%s\",\n", kind_to_txt (cr));
CXSourceLocation loc = clang_getCursorLocation (cr);
CXFile file; unsigned line, col, off;
clang_getFileLocation (loc, &file, &line, &col, &off);
printf (" \"src\" : \"%s:%d\",\n",
clang_getCString (clang_getFileName (file)), line);
printf (" \"doc\" : \"%s\"\n",
escape_json (clang_getCString (clang_FullComment_getAsHTML (c))).c_str ());
printf ("},\n");
}
return CXChildVisit_Recurse;
}
static void
process_file (int argc, char **args, const char *fn)
{
CXIndex index = clang_createIndex (0, 0);
CXTranslationUnit tu = clang_createTranslationUnitFromSourceFile (index, fn, argc, args, 0, 0);
if (tu == NULL) {
fprintf (stderr, "Cannot create translation unit for src: %s\n", fn);
return;
}
clang_visitChildren (clang_getTranslationUnitCursor (tu), traverse, 0);
clang_disposeTranslationUnit (tu);
clang_disposeIndex (index);
}
static void
usage (int status)
{
printf ("doxy2json - extract doxygen doc from C++ headers.\n\n");
fprintf (stderr, "Usage: dox2json [-I path]* <filename> [filename]*\n");
exit (status);
}
int main (int argc, char **argv)
{
int cnt = 2;
char **args = (char**) malloc (cnt * sizeof (char*));
args[0] = strdup ("-x");
args[1] = strdup ("c++");
int c;
while (EOF != (c = getopt (argc, argv, "I:"))) {
switch (c) {
case 'I':
args = (char**) realloc (args, (cnt + 2) * sizeof (char*));
args[cnt++] = strdup ("-I");
args[cnt++] = strdup (optarg);
break;
case 'h':
usage (0);
default:
usage (EXIT_FAILURE);
break;
}
}
if (optind >= argc) {
usage (EXIT_FAILURE);
}
printf ("[\n");
for (int i = optind; i < argc; ++i) {
process_file (cnt, args, argv[i]);
}
printf ("{} ]\n");
for (int i = 0; i < cnt; ++i) {
free (args[i]);
}
free (args);
return 0;
}