From: Arnaud A. de Grandmaison Date: Sat, 30 Jun 2012 11:27:57 +0000 (+0000) Subject: [libclang] add CompilationDatabase support X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=db29318326aba9e0c5c1bbba093687dccc38fc39;p=clang [libclang] add CompilationDatabase support git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@159484 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang-c/CXCompilationDatabase.h b/include/clang-c/CXCompilationDatabase.h new file mode 100644 index 0000000000..e4da6273d8 --- /dev/null +++ b/include/clang-c/CXCompilationDatabase.h @@ -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 + diff --git a/test/Index/compile_commands.json b/test/Index/compile_commands.json new file mode 100644 index 0000000000..89d9f0dd52 --- /dev/null +++ b/test/Index/compile_commands.json @@ -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' diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index 73e3e589ce..7f60925984 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -1,6 +1,7 @@ /* c-index-test.c */ #include "clang-c/Index.h" +#include "clang-c/CXCompilationDatabase.h" #include #include #include @@ -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 {}]*\n" " c-index-test -print-usr-file \n" " c-index-test -write-pch \n"); + fprintf(stderr, + " c-index-test -compilation-db [lookup ] database\n"); fprintf(stderr, " c-index-test -read-diagnostics \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; } diff --git a/tools/libclang/CIndexCompilationDB.cpp b/tools/libclang/CIndexCompilationDB.cpp new file mode 100644 index 0000000000..a537c9d6f9 --- /dev/null +++ b/tools/libclang/CIndexCompilationDB.cpp @@ -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(CDb); +} + +struct AllocatedCXCompileCommands +{ + std::vector CCmd; + + AllocatedCXCompileCommands(const std::vector& Cmd) + : CCmd(Cmd) + { } +}; + +CXCompileCommands +clang_tooling_CompilationDatabase_getCompileCommands(CXCompilationDatabase CDb, + const char *CompleteFileName) +{ + if (CompilationDatabase *db = static_cast(CDb)) { + const std::vector + CCmd(db->getCompileCommands(CompleteFileName)); + if (!CCmd.empty()) + return new AllocatedCXCompileCommands( CCmd ); + } + + return 0; +} + +void +clang_tooling_CompileCommands_dispose(CXCompileCommands Cmds) +{ + delete static_cast(Cmds); +} + +unsigned +clang_tooling_CompileCommands_getSize(CXCompileCommands Cmds) +{ + if (!Cmds) + return 0; + + AllocatedCXCompileCommands *ACC = + static_cast(Cmds); + + return ACC->CCmd.size(); +} + +CXCompileCommand +clang_tooling_CompileCommands_getCommand(CXCompileCommands Cmds, unsigned I) +{ + if (!Cmds) + return 0; + + AllocatedCXCompileCommands *ACC = + static_cast(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(CCmd); + return createCXString(cmd->Directory); +} + +unsigned +clang_tooling_CompileCommand_getNumArgs(CXCompileCommand CCmd) +{ + if (!CCmd) + return 0; + + return static_cast(CCmd)->CommandLine.size(); +} + +CXString +clang_tooling_CompileCommand_getArg(CXCompileCommand CCmd, unsigned Arg) +{ + if (!CCmd) + return createCXString((const char*)NULL); + + CompileCommand *Cmd = static_cast(CCmd); + + if (Arg >= Cmd->CommandLine.size()) + return createCXString((const char*)NULL); + + return createCXString(Cmd->CommandLine[Arg]); +} + + +} // end: extern "C" diff --git a/tools/libclang/CMakeLists.txt b/tools/libclang/CMakeLists.txt index a1090fb51f..ee401ed44c 100644 --- a/tools/libclang/CMakeLists.txt +++ b/tools/libclang/CMakeLists.txt @@ -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 ) diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports index c28b3b4083..bba883fdda 100644 --- a/tools/libclang/libclang.exports +++ b/tools/libclang/libclang.exports @@ -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