Summary: Wraps JSON compilation database with a target and mode adding database wrapper. So that driver can correctly figure out which toolchain to use. Note that clients that wants to make use of this target discovery mechanism needs to link in TargetsInfos and initialize them at startup. Reviewers: ilya-biryukov Subscribers: mgorny, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D63755 llvm-svn: 364386
142 lines
5.9 KiB
Python
142 lines
5.9 KiB
Python
import os
|
|
from clang.cindex import Config
|
|
if 'CLANG_LIBRARY_PATH' in os.environ:
|
|
Config.set_library_path(os.environ['CLANG_LIBRARY_PATH'])
|
|
|
|
from clang.cindex import CompilationDatabase
|
|
from clang.cindex import CompilationDatabaseError
|
|
from clang.cindex import CompileCommands
|
|
from clang.cindex import CompileCommand
|
|
import os
|
|
import gc
|
|
import unittest
|
|
import sys
|
|
from .util import skip_if_no_fspath
|
|
from .util import str_to_path
|
|
|
|
|
|
kInputsDir = os.path.join(os.path.dirname(__file__), 'INPUTS')
|
|
|
|
|
|
@unittest.skipIf(sys.platform == 'win32', "TODO: Fix these tests on Windows")
|
|
class TestCDB(unittest.TestCase):
|
|
def test_create_fail(self):
|
|
"""Check we fail loading a database with an assertion"""
|
|
path = os.path.dirname(__file__)
|
|
|
|
# clang_CompilationDatabase_fromDirectory calls fprintf(stderr, ...)
|
|
# Suppress its output.
|
|
stderr = os.dup(2)
|
|
with open(os.devnull, 'wb') as null:
|
|
os.dup2(null.fileno(), 2)
|
|
with self.assertRaises(CompilationDatabaseError) as cm:
|
|
cdb = CompilationDatabase.fromDirectory(path)
|
|
os.dup2(stderr, 2)
|
|
os.close(stderr)
|
|
|
|
e = cm.exception
|
|
self.assertEqual(e.cdb_error,
|
|
CompilationDatabaseError.ERROR_CANNOTLOADDATABASE)
|
|
|
|
def test_create(self):
|
|
"""Check we can load a compilation database"""
|
|
cdb = CompilationDatabase.fromDirectory(kInputsDir)
|
|
|
|
def test_lookup_succeed(self):
|
|
"""Check we get some results if the file exists in the db"""
|
|
cdb = CompilationDatabase.fromDirectory(kInputsDir)
|
|
cmds = cdb.getCompileCommands('/home/john.doe/MyProject/project.cpp')
|
|
self.assertNotEqual(len(cmds), 0)
|
|
|
|
@skip_if_no_fspath
|
|
def test_lookup_succeed_pathlike(self):
|
|
"""Same as test_lookup_succeed, but with PathLikes"""
|
|
cdb = CompilationDatabase.fromDirectory(str_to_path(kInputsDir))
|
|
cmds = cdb.getCompileCommands(str_to_path('/home/john.doe/MyProject/project.cpp'))
|
|
self.assertNotEqual(len(cmds), 0)
|
|
|
|
def test_all_compilecommand(self):
|
|
"""Check we get all results from the db"""
|
|
cdb = CompilationDatabase.fromDirectory(kInputsDir)
|
|
cmds = cdb.getAllCompileCommands()
|
|
self.assertEqual(len(cmds), 3)
|
|
expected = [
|
|
{ 'wd': '/home/john.doe/MyProject',
|
|
'file': '/home/john.doe/MyProject/project.cpp',
|
|
'line': ['clang++', '--driver-mode=g++', '-o', 'project.o', '-c',
|
|
'/home/john.doe/MyProject/project.cpp']},
|
|
{ 'wd': '/home/john.doe/MyProjectA',
|
|
'file': '/home/john.doe/MyProject/project2.cpp',
|
|
'line': ['clang++', '--driver-mode=g++', '-o', 'project2.o', '-c',
|
|
'/home/john.doe/MyProject/project2.cpp']},
|
|
{ 'wd': '/home/john.doe/MyProjectB',
|
|
'file': '/home/john.doe/MyProject/project2.cpp',
|
|
'line': ['clang++', '--driver-mode=g++', '-DFEATURE=1', '-o',
|
|
'project2-feature.o', '-c',
|
|
'/home/john.doe/MyProject/project2.cpp']},
|
|
|
|
]
|
|
for i in range(len(cmds)):
|
|
self.assertEqual(cmds[i].directory, expected[i]['wd'])
|
|
self.assertEqual(cmds[i].filename, expected[i]['file'])
|
|
for arg, exp in zip(cmds[i].arguments, expected[i]['line']):
|
|
self.assertEqual(arg, exp)
|
|
|
|
def test_1_compilecommand(self):
|
|
"""Check file with single compile command"""
|
|
cdb = CompilationDatabase.fromDirectory(kInputsDir)
|
|
file = '/home/john.doe/MyProject/project.cpp'
|
|
cmds = cdb.getCompileCommands(file)
|
|
self.assertEqual(len(cmds), 1)
|
|
self.assertEqual(cmds[0].directory, os.path.dirname(file))
|
|
self.assertEqual(cmds[0].filename, file)
|
|
expected = [ 'clang++', '--driver-mode=g++', '-o', 'project.o', '-c',
|
|
'/home/john.doe/MyProject/project.cpp']
|
|
for arg, exp in zip(cmds[0].arguments, expected):
|
|
self.assertEqual(arg, exp)
|
|
|
|
def test_2_compilecommand(self):
|
|
"""Check file with 2 compile commands"""
|
|
cdb = CompilationDatabase.fromDirectory(kInputsDir)
|
|
cmds = cdb.getCompileCommands('/home/john.doe/MyProject/project2.cpp')
|
|
self.assertEqual(len(cmds), 2)
|
|
expected = [
|
|
{ 'wd': '/home/john.doe/MyProjectA',
|
|
'line': ['clang++', '--driver-mode=g++', '-o', 'project2.o', '-c',
|
|
'/home/john.doe/MyProject/project2.cpp']},
|
|
{ 'wd': '/home/john.doe/MyProjectB',
|
|
'line': ['clang++', '--driver-mode=g++', '-DFEATURE=1', '-o',
|
|
'project2-feature.o', '-c',
|
|
'/home/john.doe/MyProject/project2.cpp']}
|
|
]
|
|
for i in range(len(cmds)):
|
|
self.assertEqual(cmds[i].directory, expected[i]['wd'])
|
|
for arg, exp in zip(cmds[i].arguments, expected[i]['line']):
|
|
self.assertEqual(arg, exp)
|
|
|
|
def test_compilecommand_iterator_stops(self):
|
|
"""Check that iterator stops after the correct number of elements"""
|
|
cdb = CompilationDatabase.fromDirectory(kInputsDir)
|
|
count = 0
|
|
for cmd in cdb.getCompileCommands('/home/john.doe/MyProject/project2.cpp'):
|
|
count += 1
|
|
self.assertLessEqual(count, 2)
|
|
|
|
def test_compilationDB_references(self):
|
|
"""Ensure CompilationsCommands are independent of the database"""
|
|
cdb = CompilationDatabase.fromDirectory(kInputsDir)
|
|
cmds = cdb.getCompileCommands('/home/john.doe/MyProject/project.cpp')
|
|
del cdb
|
|
gc.collect()
|
|
workingdir = cmds[0].directory
|
|
|
|
def test_compilationCommands_references(self):
|
|
"""Ensure CompilationsCommand keeps a reference to CompilationCommands"""
|
|
cdb = CompilationDatabase.fromDirectory(kInputsDir)
|
|
cmds = cdb.getCompileCommands('/home/john.doe/MyProject/project.cpp')
|
|
del cdb
|
|
cmd0 = cmds[0]
|
|
del cmds
|
|
gc.collect()
|
|
workingdir = cmd0.directory
|