mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-13 19:24:21 +00:00
[libclang] add CompilationDatabase support
llvm-svn: 159484
This commit is contained in:
parent
8a6290721e
commit
0fe28a1a84
143
clang/include/clang-c/CXCompilationDatabase.h
Normal file
143
clang/include/clang-c/CXCompilationDatabase.h
Normal file
@ -0,0 +1,143 @@
|
||||
/*===-- clang-c/CXCompilationDatabase.h - Compilation database ---*- C -*-===*\
|
||||
|* *|
|
||||
|* The LLVM Compiler Infrastructure *|
|
||||
|* *|
|
||||
|* This file is distributed under the University of Illinois Open Source *|
|
||||
|* License. See LICENSE.TXT for details. *|
|
||||
|* *|
|
||||
|*===----------------------------------------------------------------------===*|
|
||||
|* *|
|
||||
|* This header provides a public inferface to use CompilationDatabase without *|
|
||||
|* the full Clang C++ API. *|
|
||||
|* *|
|
||||
\*===----------------------------------------------------------------------===*/
|
||||
|
||||
#ifndef CLANG_CXCOMPILATIONDATABASE_H
|
||||
#define CLANG_CXCOMPILATIONDATABASE_H
|
||||
|
||||
#include "clang-c/Platform.h"
|
||||
#include "clang-c/CXString.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \defgroup COMPILATIONDB CompilationDatabase functions
|
||||
* \ingroup CINDEX
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Represents clang::tooling::CompilationDatabase
|
||||
*
|
||||
* Must be freed by \c clang_tooling_CompilationDatabase_dispose
|
||||
*/
|
||||
typedef void * CXCompilationDatabase;
|
||||
|
||||
/**
|
||||
* \brief Contains the results of a search in the compilation database
|
||||
*
|
||||
* When searching for the compile command for a file, the compilation db can
|
||||
* return several commands, as the file may have been compiled with
|
||||
* different options in different places of the project. This choice of compile
|
||||
* commands is wrapped in this opaque data structure. It must be freed by
|
||||
* \c clang_tooling_CompileCommands_dispose.
|
||||
*/
|
||||
typedef void * CXCompileCommands;
|
||||
|
||||
/**
|
||||
* \brief Represents the command line invocation to compile a specific file.
|
||||
*/
|
||||
typedef void * CXCompileCommand;
|
||||
|
||||
/**
|
||||
* \brief Error codes for Compilation Database
|
||||
*/
|
||||
typedef enum {
|
||||
/*
|
||||
* \brief No error occured
|
||||
*/
|
||||
CXCompilationDatabase_NoError = 0,
|
||||
|
||||
/*
|
||||
* \brief Database can not be loaded
|
||||
*/
|
||||
CXCompilationDatabase_CanNotLoadDatabase = 1
|
||||
|
||||
} CXCompilationDatabase_Error;
|
||||
|
||||
/**
|
||||
* \brief Creates a compilation database from the database found in directory
|
||||
* buildDir. It must be freed by \c clang_tooling_CompilationDatabase_dispose.
|
||||
*/
|
||||
CINDEX_LINKAGE CXCompilationDatabase
|
||||
clang_tooling_CompilationDatabase_fromDirectory(
|
||||
const char *BuildDir,
|
||||
CXCompilationDatabase_Error *ErrorCode);
|
||||
|
||||
/**
|
||||
* \brief Free the given compilation database
|
||||
*/
|
||||
CINDEX_LINKAGE void
|
||||
clang_tooling_CompilationDatabase_dispose(CXCompilationDatabase);
|
||||
|
||||
/**
|
||||
* \brief Find the compile commands used for a file. The compile commands
|
||||
* must be freed by \c clang_tooling_CompileCommands_dispose.
|
||||
*/
|
||||
CINDEX_LINKAGE CXCompileCommands
|
||||
clang_tooling_CompilationDatabase_getCompileCommands(
|
||||
CXCompilationDatabase,
|
||||
const char *CompleteFileName);
|
||||
|
||||
/**
|
||||
* \brief Free the given CompileCommands
|
||||
*/
|
||||
CINDEX_LINKAGE void clang_tooling_CompileCommands_dispose(CXCompileCommands);
|
||||
|
||||
/**
|
||||
* \brief Get the number of CompileCommand we have for a file
|
||||
*/
|
||||
CINDEX_LINKAGE unsigned
|
||||
clang_tooling_CompileCommands_getSize(CXCompileCommands);
|
||||
|
||||
/**
|
||||
* \brief Get the I'th CompileCommand for a file
|
||||
*
|
||||
* Note : 0 <= i < clang_tooling_CompileCommands_getSize(CXCompileCommands)
|
||||
*/
|
||||
CINDEX_LINKAGE CXCompileCommand
|
||||
clang_tooling_CompileCommands_getCommand(CXCompileCommands, unsigned I);
|
||||
|
||||
/**
|
||||
* \brief Get the working directory where the CompileCommand was executed from
|
||||
*/
|
||||
CINDEX_LINKAGE CXString
|
||||
clang_tooling_CompileCommand_getDirectory(CXCompileCommand);
|
||||
|
||||
/**
|
||||
* \brief Get the number of arguments in the compiler invocation.
|
||||
*
|
||||
*/
|
||||
CINDEX_LINKAGE unsigned
|
||||
clang_tooling_CompileCommand_getNumArgs(CXCompileCommand);
|
||||
|
||||
/**
|
||||
* \brief Get the I'th argument value in the compiler invocations
|
||||
*
|
||||
* Invariant :
|
||||
* - argument 0 is the compiler executable
|
||||
*/
|
||||
CINDEX_LINKAGE CXString
|
||||
clang_tooling_CompileCommand_getArg(CXCompileCommand, unsigned I);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
27
clang/test/Index/compile_commands.json
Normal file
27
clang/test/Index/compile_commands.json
Normal file
@ -0,0 +1,27 @@
|
||||
[
|
||||
{
|
||||
"directory": "/home/john.doe/MyProject",
|
||||
"command": "clang++ -o project.o -c /home/john.doe/MyProject/project.cpp",
|
||||
"file": "/home/john.doe/MyProject/project.cpp"
|
||||
},
|
||||
{
|
||||
"directory": "/home/john.doe/MyProjectA",
|
||||
"command": "clang++ -o project2.o -c /home/john.doe/MyProject/project2.cpp",
|
||||
"file": "/home/john.doe/MyProject/project2.cpp"
|
||||
},
|
||||
{
|
||||
"directory": "/home/john.doe/MyProjectB",
|
||||
"command": "clang++ -DFEATURE=1 -o project2-feature.o -c /home/john.doe/MyProject/project2.cpp",
|
||||
"file": "/home/john.doe/MyProject/project2.cpp"
|
||||
}
|
||||
]
|
||||
# RUN: c-index-test -compilation-db %s
|
||||
# RUN: c-index-test -compilation-db lookup file_does_not_exists.cpp %s | FileCheck -check-prefix=FILE-NOT-FOUND %s
|
||||
# FILE-NOT-FOUND: file file_does_not_exists.cpp not found in compilation db
|
||||
|
||||
# RUN: c-index-test -compilation-db lookup /home/john.doe/MyProject/project.cpp %s | FileCheck -check-prefix=FILE-1-CMD %s
|
||||
# FILE-1-CMD: workdir:'/home/john.doe/MyProject' cmdline:'clang++ -o project.o -c /home/john.doe/MyProject/project.cpp'
|
||||
|
||||
# RUN: c-index-test -compilation-db lookup /home/john.doe/MyProject/project2.cpp %s | FileCheck -check-prefix=FILE-2-CMD %s
|
||||
# FILE-2-CMD: workdir:'/home/john.doe/MyProjectA' cmdline:'clang++ -o project2.o -c /home/john.doe/MyProject/project2.cpp'
|
||||
# FILE-2-CMD: workdir:'/home/john.doe/MyProjectB' cmdline:'clang++ -DFEATURE=1 -o project2-feature.o -c /home/john.doe/MyProject/project2.cpp'
|
@ -1,6 +1,7 @@
|
||||
/* c-index-test.c */
|
||||
|
||||
#include "clang-c/Index.h"
|
||||
#include "clang-c/CXCompilationDatabase.h"
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
@ -25,8 +26,25 @@ char *basename(const char* path)
|
||||
|
||||
return((char*)path);
|
||||
}
|
||||
char *dirname(char* path)
|
||||
{
|
||||
char* base1 = (char*)strrchr(path, '/');
|
||||
char* base2 = (char*)strrchr(path, '\\');
|
||||
if (base1 && base2)
|
||||
if (base1 > base2)
|
||||
*base1 = 0;
|
||||
else
|
||||
*base2 = 0;
|
||||
else if (base1)
|
||||
*base1 = 0
|
||||
else if (base2)
|
||||
*base2 = 0
|
||||
|
||||
return path;
|
||||
}
|
||||
#else
|
||||
extern char *basename(const char *);
|
||||
extern char *dirname(char *);
|
||||
#endif
|
||||
|
||||
/** \brief Return the default parsing options. */
|
||||
@ -2361,6 +2379,89 @@ int perform_token_annotation(int argc, const char **argv) {
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
static int
|
||||
perform_test_compilation_db(const char *database, int argc, const char **argv) {
|
||||
CXCompilationDatabase db;
|
||||
CXCompileCommands CCmds;
|
||||
CXCompileCommand CCmd;
|
||||
CXCompilationDatabase_Error ec;
|
||||
CXString wd;
|
||||
CXString arg;
|
||||
int errorCode = 0;
|
||||
char *tmp;
|
||||
unsigned len;
|
||||
char *buildDir;
|
||||
int i, j, a, numCmds, numArgs;
|
||||
|
||||
len = strlen(database);
|
||||
tmp = (char *) malloc(len+1);
|
||||
memcpy(tmp, database, len+1);
|
||||
buildDir = dirname(tmp);
|
||||
|
||||
db = clang_tooling_CompilationDatabase_fromDirectory(buildDir, &ec);
|
||||
|
||||
if (db) {
|
||||
|
||||
if (ec!=CXCompilationDatabase_NoError) {
|
||||
printf("unexpected error %d code while loading compilation database\n", ec);
|
||||
errorCode = -1;
|
||||
goto cdb_end;
|
||||
}
|
||||
|
||||
for (i=0; i<argc && errorCode==0; ) {
|
||||
if (strcmp(argv[i],"lookup")==0){
|
||||
CCmds = clang_tooling_CompilationDatabase_getCompileCommands(db, argv[i+1]);
|
||||
|
||||
if (!CCmds) {
|
||||
printf("file %s not found in compilation db\n", argv[i+1]);
|
||||
errorCode = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
numCmds = clang_tooling_CompileCommands_getSize(CCmds);
|
||||
|
||||
if (numCmds==0) {
|
||||
fprintf(stderr, "should not get an empty compileCommand set for file"
|
||||
" '%s'\n", argv[i+1]);
|
||||
errorCode = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
for (j=0; j<numCmds; ++j) {
|
||||
CCmd = clang_tooling_CompileCommands_getCommand(CCmds, j);
|
||||
|
||||
wd = clang_tooling_CompileCommand_getDirectory(CCmd);
|
||||
printf("workdir:'%s'", clang_getCString(wd));
|
||||
clang_disposeString(wd);
|
||||
|
||||
printf(" cmdline:'");
|
||||
numArgs = clang_tooling_CompileCommand_getNumArgs(CCmd);
|
||||
for (a=0; a<numArgs; ++a) {
|
||||
if (a) printf(" ");
|
||||
arg = clang_tooling_CompileCommand_getArg(CCmd, a);
|
||||
printf("%s", clang_getCString(arg));
|
||||
clang_disposeString(arg);
|
||||
}
|
||||
printf("'\n");
|
||||
}
|
||||
|
||||
clang_tooling_CompileCommands_dispose(CCmds);
|
||||
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
clang_tooling_CompilationDatabase_dispose(db);
|
||||
} else {
|
||||
printf("database loading failed with error code %d.\n", ec);
|
||||
errorCode = -1;
|
||||
}
|
||||
|
||||
cdb_end:
|
||||
free(tmp);
|
||||
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* USR printing. */
|
||||
/******************************************************************************/
|
||||
@ -2800,6 +2901,8 @@ static void print_usage(void) {
|
||||
" c-index-test -print-usr [<CursorKind> {<args>}]*\n"
|
||||
" c-index-test -print-usr-file <file>\n"
|
||||
" c-index-test -write-pch <file> <compiler arguments>\n");
|
||||
fprintf(stderr,
|
||||
" c-index-test -compilation-db [lookup <filename>] database\n");
|
||||
fprintf(stderr,
|
||||
" c-index-test -read-diagnostics <file>\n\n");
|
||||
fprintf(stderr,
|
||||
@ -2886,7 +2989,9 @@ int cindextest_main(int argc, const char **argv) {
|
||||
return print_usrs_file(argv[2]);
|
||||
else if (argc > 2 && strcmp(argv[1], "-write-pch") == 0)
|
||||
return write_pch_file(argv[2], argc - 3, argv + 3);
|
||||
|
||||
else if (argc > 2 && strcmp(argv[1], "-compilation-db") == 0)
|
||||
return perform_test_compilation_db(argv[argc-1], argc - 3, argv + 2);
|
||||
|
||||
print_usage();
|
||||
return 1;
|
||||
}
|
||||
|
130
clang/tools/libclang/CIndexCompilationDB.cpp
Normal file
130
clang/tools/libclang/CIndexCompilationDB.cpp
Normal file
@ -0,0 +1,130 @@
|
||||
#include "clang-c/CXCompilationDatabase.h"
|
||||
#include "clang/Tooling/CompilationDatabase.h"
|
||||
#include "CXString.h"
|
||||
|
||||
using namespace clang;
|
||||
using namespace clang::tooling;
|
||||
using namespace clang::cxstring;
|
||||
|
||||
extern "C" {
|
||||
|
||||
// FIXME: do something more usefull with the error message
|
||||
CXCompilationDatabase
|
||||
clang_tooling_CompilationDatabase_fromDirectory(
|
||||
const char *BuildDir,
|
||||
CXCompilationDatabase_Error *ErrorCode)
|
||||
{
|
||||
std::string ErrorMsg;
|
||||
CXCompilationDatabase_Error Err = CXCompilationDatabase_NoError;
|
||||
|
||||
CompilationDatabase *db = CompilationDatabase::loadFromDirectory(BuildDir,
|
||||
ErrorMsg);
|
||||
|
||||
if (!db) {
|
||||
fprintf(stderr, "LIBCLANG TOOLING ERROR: %s\n", ErrorMsg.c_str());
|
||||
Err = CXCompilationDatabase_CanNotLoadDatabase;
|
||||
}
|
||||
|
||||
if (ErrorCode)
|
||||
*ErrorCode = Err;
|
||||
|
||||
return db;
|
||||
}
|
||||
|
||||
void
|
||||
clang_tooling_CompilationDatabase_dispose(CXCompilationDatabase CDb)
|
||||
{
|
||||
delete static_cast<CompilationDatabase *>(CDb);
|
||||
}
|
||||
|
||||
struct AllocatedCXCompileCommands
|
||||
{
|
||||
std::vector<CompileCommand> CCmd;
|
||||
|
||||
AllocatedCXCompileCommands(const std::vector<CompileCommand>& Cmd)
|
||||
: CCmd(Cmd)
|
||||
{ }
|
||||
};
|
||||
|
||||
CXCompileCommands
|
||||
clang_tooling_CompilationDatabase_getCompileCommands(CXCompilationDatabase CDb,
|
||||
const char *CompleteFileName)
|
||||
{
|
||||
if (CompilationDatabase *db = static_cast<CompilationDatabase *>(CDb)) {
|
||||
const std::vector<CompileCommand>
|
||||
CCmd(db->getCompileCommands(CompleteFileName));
|
||||
if (!CCmd.empty())
|
||||
return new AllocatedCXCompileCommands( CCmd );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
clang_tooling_CompileCommands_dispose(CXCompileCommands Cmds)
|
||||
{
|
||||
delete static_cast<AllocatedCXCompileCommands *>(Cmds);
|
||||
}
|
||||
|
||||
unsigned
|
||||
clang_tooling_CompileCommands_getSize(CXCompileCommands Cmds)
|
||||
{
|
||||
if (!Cmds)
|
||||
return 0;
|
||||
|
||||
AllocatedCXCompileCommands *ACC =
|
||||
static_cast<AllocatedCXCompileCommands *>(Cmds);
|
||||
|
||||
return ACC->CCmd.size();
|
||||
}
|
||||
|
||||
CXCompileCommand
|
||||
clang_tooling_CompileCommands_getCommand(CXCompileCommands Cmds, unsigned I)
|
||||
{
|
||||
if (!Cmds)
|
||||
return 0;
|
||||
|
||||
AllocatedCXCompileCommands *ACC =
|
||||
static_cast<AllocatedCXCompileCommands *>(Cmds);
|
||||
|
||||
if (I >= ACC->CCmd.size())
|
||||
return 0;
|
||||
|
||||
return &ACC->CCmd[I];
|
||||
}
|
||||
|
||||
CXString
|
||||
clang_tooling_CompileCommand_getDirectory(CXCompileCommand CCmd)
|
||||
{
|
||||
if (!CCmd)
|
||||
return createCXString((const char*)NULL);
|
||||
|
||||
CompileCommand *cmd = static_cast<CompileCommand *>(CCmd);
|
||||
return createCXString(cmd->Directory);
|
||||
}
|
||||
|
||||
unsigned
|
||||
clang_tooling_CompileCommand_getNumArgs(CXCompileCommand CCmd)
|
||||
{
|
||||
if (!CCmd)
|
||||
return 0;
|
||||
|
||||
return static_cast<CompileCommand *>(CCmd)->CommandLine.size();
|
||||
}
|
||||
|
||||
CXString
|
||||
clang_tooling_CompileCommand_getArg(CXCompileCommand CCmd, unsigned Arg)
|
||||
{
|
||||
if (!CCmd)
|
||||
return createCXString((const char*)NULL);
|
||||
|
||||
CompileCommand *Cmd = static_cast<CompileCommand *>(CCmd);
|
||||
|
||||
if (Arg >= Cmd->CommandLine.size())
|
||||
return createCXString((const char*)NULL);
|
||||
|
||||
return createCXString(Cmd->CommandLine[Arg]);
|
||||
}
|
||||
|
||||
|
||||
} // end: extern "C"
|
@ -8,6 +8,7 @@ set(SOURCES
|
||||
CIndex.cpp
|
||||
CIndexCXX.cpp
|
||||
CIndexCodeCompletion.cpp
|
||||
CIndexCompilationDB.cpp
|
||||
CIndexDiagnostic.cpp
|
||||
CIndexDiagnostic.h
|
||||
CIndexHigh.cpp
|
||||
@ -47,6 +48,7 @@ set(LIBRARIES
|
||||
clangEdit
|
||||
clangAST
|
||||
clangLex
|
||||
clangTooling
|
||||
clangBasic
|
||||
)
|
||||
|
||||
|
@ -204,5 +204,14 @@ clang_saveTranslationUnit
|
||||
clang_sortCodeCompletionResults
|
||||
clang_toggleCrashRecovery
|
||||
clang_tokenize
|
||||
clang_tooling_CompilationDatabase_fromDirectory
|
||||
clang_tooling_CompilationDatabase_dispose
|
||||
clang_tooling_CompilationDatabase_getCompileCommands
|
||||
clang_tooling_CompileCommands_dispose
|
||||
clang_tooling_CompileCommands_getSize
|
||||
clang_tooling_CompileCommands_getCommand
|
||||
clang_tooling_CompileCommand_getDirectory
|
||||
clang_tooling_CompileCommand_getNumArgs
|
||||
clang_tooling_CompileCommand_getArg
|
||||
clang_visitChildren
|
||||
clang_visitChildrenWithBlock
|
||||
|
Loading…
Reference in New Issue
Block a user