2016-04-15 9 views
6

Mam następujący skrypt, który próbuje wydrukować wszystkie węzły AST w danym pliku C++. Działa to dobrze, gdy używa się go na prostym pliku z zawartością trywialną (plik nagłówkowy w tym samym katalogu itp.).Jak korzystać z compile_commands.json z powiązaniami python clang?

#!/usr/bin/env python 
from argparse import ArgumentParser, FileType 
from clang import cindex 


def node_info(node): 
    return {'kind': node.kind, 
      'usr': node.get_usr(), 
      'spelling': node.spelling, 
      'location': node.location, 
      'file': node.location.file.name, 
      'extent.start': node.extent.start, 
      'extent.end': node.extent.end, 
      'is_definition': node.is_definition() 
      } 


def get_nodes_in_file(node, filename, ls=None): 
    ls = ls if ls is not None else [] 
    for n in node.get_children(): 
     if n.location.file is not None and n.location.file.name == filename: 
      ls.append(n) 
      get_nodes_in_file(n, filename, ls) 
    return ls 


def main(): 
    arg_parser = ArgumentParser() 
    arg_parser.add_argument('source_file', type=FileType('r+'), 
          help='C++ source file to parse.') 
    arg_parser.add_argument('compilation_database', type=FileType('r+'), 
          help='The compile_commands.json to use to parse the source file.') 
    args = arg_parser.parse_args() 
    compilation_database_path = args.compilation_database.name 
    source_file_path = args.source_file.name 
    clang_args = ['-x', 'c++', '-std=c++11', '-p', compilation_database_path] 
    index = cindex.Index.create() 
    translation_unit = index.parse(source_file_path, clang_args) 
    file_nodes = get_nodes_in_file(translation_unit.cursor, source_file_path) 
    print [p.spelling for p in file_nodes] 


if __name__ == '__main__': 
    main() 

Jednak dostaję clang.cindex.TranslationUnitLoadError: Error parsing translation unit. kiedy uruchomić skrypt i podać prawidłowy plik C++, który posiada plik compile_commands.json w jego katalogu nadrzędnego. Ten kod działa i buduje dobrze przy użyciu CMake z clang, ale nie mogę wydawać się dowiedzieć, jak przekazać argument za wskazanie na compile_commands.json poprawnie.

Też miałem trudności ze znalezieniem tej opcji w dokumentacji klang i nie mogłem uzyskać -ast-dump do pracy. Jednak sprawdzanie clang działa dobrze po prostu przekazując ścieżkę pliku!

Odpowiedz

7

Twoja własna zaakceptowana odpowiedź jest nieprawidłowa. libclangdoes support compilation databases i so does cindex.py, powiązanie pythora libclang.

Głównym źródłem nieporozumień może być to, że kompilacja flagi, którą libclang zna/wykorzystuje, jest tylko podzbiorem wszystkich argumentów, które można przekazać do interfejsu klang. Baza danych kompilacji jest obsługiwana, ale nie działa automatycznie: musi być załadowana i odpytana ręcznie. Coś takiego powinno zadziałać:

#!/usr/bin/env python 
from argparse import ArgumentParser, FileType 
from clang import cindex 

compilation_database_path = args.compilation_database.name 
source_file_path = args.source_file.name 
index = cindex.Index.create() 

# Step 1: load the compilation database 
compdb = cindex.CompilationDatabase.fromDirectory(compilation_database_path) 

# Step 2: query compilation flags 
try: 
    file_args = compdb.getCompileCommands(source_file_path) 
    translation_unit = index.parse(source_file_path, file_args) 
    file_nodes = get_nodes_in_file(translation_unit.cursor, source_file_path) 
    print [p.spelling for p in file_nodes] 
except CompilationDatabaseError: 
    print 'Could not load compilation flags for', source_file_path 
+0

Jaką wersję klangu wprowadzono po raz pierwszy? Kiedy napisałem to pytanie, używałem clanga 3.4 zarówno dla libclang, jak i dla cindex.py. – Lucas

+0

Nie mam pojęcia, ale jestem prawie pewien, że w tamtym czasie było już 3,8, które miało go od wieków. –

+0

Wygląda na to, że jest również w wersji 3.4, musiał tego przegapić. – Lucas

0

Z tego, co mogę powiedzieć, Libclang nie obsługuje bazy danych kompilacji, ale robi to Libtooling. Aby obejść ten problem, podałem ścieżkę do compile_commands.json jako argumentu i skończono analizowanie go w celu odnalezienia interesującego go pliku i uwzględniono go w tym (dotyczy to także -I i -isystem).

+0

Moja odpowiedź nie jest poprawna, proszę zobaczyć zaakceptowaną odpowiedź. – Lucas