Skip to content

Commit

Permalink
Merge pull request jeaye#99 from UnrealQuester/compile_commands
Browse files Browse the repository at this point in the history
Add initial support for JSONCompilationDatabase
  • Loading branch information
jeaye authored Jan 27, 2017
2 parents c3b4d73 + 431626f commit 8c52560
Show file tree
Hide file tree
Showing 8 changed files with 156 additions and 27 deletions.
24 changes: 15 additions & 9 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,29 @@ addons:
apt:
sources:
- ubuntu-toolchain-r-test
#- llvm-toolchain-precise-3.8
- llvm-toolchain-precise-3.9
packages:
- libstdc++-4.9-dev
- liblua5.1-0-dev
- lua5.1
- libboost-dev
- g++-4.9
- g++-5
#- clang-3.8
#- libclang-3.8-dev
#- llvm-3.8
- clang-3.9
- libclang-3.9-dev
- llvm-3.9
- llvm-3.9-dev

env:
- DOWNLOAD_CLANG=1 COMPILER=g++-4.9 GCC_VERSION=4.9
#- DOWNLOAD_CLANG=0 COMPILER=g++-4.9 GCC_VERSION=4.9 LLVM_CONFIG="llvm-config-3.8"
#- DOWNLOAD_CLANG=1 COMPILER=clang++-3.8 CLANG_VERSION=3.8
#- DOWNLOAD_CLANG=0 COMPILER=clang++-3.8 CLANG_VERSION=3.8 LLVM_CONFIG="llvm-config-3.8"
env:
- DOWNLOAD_CLANG=1 COMPILER=g++-4.9 GCC_VERSION=4.9
# - DOWNLOAD_CLANG=0 COMPILER=g++-4.9 GCC_VERSION=4.9 LLVM_CONFIG="llvm-config-3.8"
- DOWNLOAD_CLANG=1 COMPILER=clang++-3.9 CLANG_VERSION=3.9
# - DOWNLOAD_CLANG=0 COMPILER=clang++-3.8 CLANG_VERSION=3.8 LLVM_CONFIG="llvm-config-3.8"

matrix:
exclude:
- os: osx
env: DOWNLOAD_CLANG=1 COMPILER=g++-4.9 GCC_VERSION=4.9

before_install:
- if [ -n "$GCC_VERSION" ]; then export CXX="g++-${GCC_VERSION}" CC="gcc-${GCC_VERSION}"; fi
Expand Down
15 changes: 13 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,8 @@ endif()

target_link_libraries(${PROJECT_NAME}
${CLANG_LIBS}
${LLVM_LIBS}
${LLVM_LIBRARIES}
${LLVM_LDFLAGS}
)

target_link_libraries(${PROJECT_NAME}
Expand All @@ -130,9 +131,19 @@ include_directories(
lib/jest/include
test/include
)
add_definitions(
-D__STDC_CONSTANT_MACROS
-D__STDC_LIMIT_MACROS
)
if(${DOWNLOAD_CLANG})
add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0)
endif()
add_executable(${PROJECT_NAME}_config_test ${CMAKE_CURRENT_LIST_DIR}/test/src/config/main.cpp)
target_link_libraries(${PROJECT_NAME}_config_test
${PROJECT_NAME}_boost
${CLANG_LIBS}
${LLVM_LIBRARIES}
${LLVM_LDFLAGS}
${PROJECT_NAME}_boost
${LUA_LIBRARIES}
${CURSES_LIBRARY}
${ZLIB_LIBRARIES}
Expand Down
8 changes: 4 additions & 4 deletions cmake/FindLibClang.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,17 @@ if (LLVM_FOUND AND LLVM_LIBRARY_DIRS)
find_library(CLANG_LIBCLANG_LIB NAMES clang libclang HINTS ${LLVM_LIBRARY_DIRS}) # LibClang: high-level C interface

FIND_AND_ADD_CLANG_LIB(clang)
FIND_AND_ADD_CLANG_LIB(clangTooling)
FIND_AND_ADD_CLANG_LIB(clangToolingCore)
FIND_AND_ADD_CLANG_LIB(clangIndex)
FIND_AND_ADD_CLANG_LIB(clangFrontend)
FIND_AND_ADD_CLANG_LIB(clangFrontendTool)
FIND_AND_ADD_CLANG_LIB(clangDriver)
FIND_AND_ADD_CLANG_LIB(clangFormat)
FIND_AND_ADD_CLANG_LIB(clangCodeGen)
FIND_AND_ADD_CLANG_LIB(clangEdit)
FIND_AND_ADD_CLANG_LIB(clangParse)
FIND_AND_ADD_CLANG_LIB(clangSema)
FIND_AND_ADD_CLANG_LIB(clangEdit)
FIND_AND_ADD_CLANG_LIB(clangChecker)
FIND_AND_ADD_CLANG_LIB(clangAnalysis)
FIND_AND_ADD_CLANG_LIB(clangSerialization)
Expand All @@ -66,11 +69,8 @@ if (LLVM_FOUND AND LLVM_LIBRARY_DIRS)
FIND_AND_ADD_CLANG_LIB(clangAST)
FIND_AND_ADD_CLANG_LIB(clangASTMatchers)
FIND_AND_ADD_CLANG_LIB(clangDynamicASTMatchers)
FIND_AND_ADD_CLANG_LIB(clangParse)
FIND_AND_ADD_CLANG_LIB(clangLex)
FIND_AND_ADD_CLANG_LIB(clangBasic)
FIND_AND_ADD_CLANG_LIB(clangTooling)
FIND_AND_ADD_CLANG_LIB(clangToolingCore)

find_path(CLANG_INCLUDE_DIRS clang/Basic/Version.h HINTS ${LLVM_INCLUDE_DIRS})
else()
Expand Down
3 changes: 2 additions & 1 deletion include/conf/find.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ namespace color_coded
static fs::directory_iterator const end;

static auto constexpr file_name(".color_coded");
static auto constexpr compilation_database("compile_commands.json");
auto const typed_file_name(std::string{ file_name } + "_" + filetype);
std::string const flag_files[] {typed_file_name, file_name};
std::string const flag_files[] {typed_file_name, compilation_database, file_name};

while(true)
{
Expand Down
84 changes: 79 additions & 5 deletions include/conf/load.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,15 @@
#include <boost/filesystem.hpp>

#include "defaults.hpp"
#include <clang/Tooling/JSONCompilationDatabase.h>

namespace color_coded
{
namespace core
{
std::string const& last_error(std::string const &e);
}

namespace conf
{
namespace fs = boost::filesystem;
Expand All @@ -37,28 +43,96 @@ namespace color_coded
}
}

inline args_t load(std::string const &file, std::string const &filetype)
inline args_t load_compilation_database(std::string const &file, fs::path filename)
{
if(file.empty())
{ return defaults(filetype); }
static const std::string source_extensions[] {".c", ".cpp", ".cc"};
static const std::string header_extensions[] {".h", ".hpp", ".hh"};
std::string error;
auto const database_ptr(::clang::tooling::JSONCompilationDatabase::loadFromFile(file, error));
if(!database_ptr)
{
core::last_error(error);
return {};
}

std::vector<fs::path> files{filename};
auto const ext(filename.extension());
if(std::find(begin(header_extensions), end(header_extensions), ext) != end(header_extensions))
{
auto path = filename.string();
auto const include_it = path.rfind("include");
if(include_it != std::string::npos)
{
filename = path.replace(include_it, 7, "src");
}
for(auto const &extension : source_extensions)
{
files.emplace_back(filename.replace_extension(extension));
}
}

std::vector<::clang::tooling::CompileCommand> compile_commands;
for(auto const &file : files)
{
compile_commands = database_ptr->getCompileCommands(file.string());

if(!compile_commands.empty())
{
filename = file;
break;
}

}

if(compile_commands.empty())
{ return {}; }

auto commands(compile_commands[0].CommandLine);
commands.erase(std::remove(commands.begin(), commands.end(), filename), commands.end());

return commands;
}

inline args_t load_color_coded(std::string const &file, std::string const &filetype)
{
std::ifstream ifs{ file };
if(!ifs.is_open())
{ return defaults(filetype); }
{ return {}; }

auto const pre_additions(pre_constants(filetype));
static auto const post_additions(post_constants());
args_t args{ pre_additions };

auto const &base(fs::path{ file }.parent_path());
std::string tmp;
while(std::getline(ifs, tmp))
{ args.emplace_back(detail::make_absolute(std::move(tmp), base)); }

return args;
}

inline args_t load(std::string const &file, std::string const &filetype, std::string const &filename)
{
if(file.empty())
{ return defaults(filetype); }

static auto const post_additions(post_constants());

args_t args;
if (fs::path(file).filename() == "compile_commands.json")
{ args = load_compilation_database(file, filename); }
else
{ args = load_color_coded(file, filetype); }

if(args.empty())
{ return defaults(filetype); }

std::copy(post_additions.begin(), post_additions.end(),
std::back_inserter(args));

return args;
}

inline args_t load(std::string const &file, std::string const &filetype)
{ return load(file, filetype, "");}
}
}
4 changes: 2 additions & 2 deletions include/core.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,15 @@ namespace color_coded
if(config_it != config_paths.end() && config_it->second.empty())
{
config_it->second = conf::load
(conf::find(t.name, t.filetype), t.filetype);
(conf::find(t.name, t.filetype), t.filetype, t.name);
}
else if(config_it == config_paths.end())
{
config_it = config_paths.insert
(
{
t.name,
conf::load(conf::find(t.name, t.filetype), t.filetype)
conf::load(conf::find(t.name, t.filetype), t.filetype, t.name)
}
).first;
}
Expand Down
7 changes: 7 additions & 0 deletions test/config/compile_commands.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[
{
"directory": "/usr/src/color_coded/",
"command": "/usr/bin/c++ -std=c++11 -I/etc/ -foo -o myfile.cpp.o -c /usr/src/color_coded/myfile.cpp",
"file": "/usr/src/color_coded/myfile.cpp"
}
]
38 changes: 34 additions & 4 deletions test/include/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@

#include <jest/jest.hpp>

#include "env/environment.hpp"
#include "conf/load.hpp"
#include "conf/find.hpp"
#include "conf/defaults.hpp"
#include "core.hpp"

namespace color_coded
{
Expand All @@ -31,6 +28,10 @@ namespace jest
auto constexpr test_config_dir("test/config");
auto constexpr test_config("test/config/.color_coded");
auto constexpr test_config_typed("test/config/.color_coded_foo");
auto constexpr compile_commands("test/config/compile_commands.json");
auto constexpr test_file("/usr/src/color_coded/myfile.cpp");
auto constexpr test_header("/usr/src/color_coded/myfile.hpp");
auto constexpr test_include("/usr/include/color_coded/myfile.hpp");

template <> template <>
void color_coded::config_group::test<0>() /* Empty defaults. */
Expand Down Expand Up @@ -122,4 +123,33 @@ namespace jest
auto const file(color_coded::conf::find(test_config, "foo"));
expect_equal(file, test_config_typed);
}

template <> template <>
void color_coded::config_group::test<5>() /* compilation database, valid file. */
{
auto const args(color_coded::conf::load(compile_commands, "c++", test_file));
expect(std::find(args.begin(), args.end(), "-I/etc/") != args.end());
expect(std::find(args.begin(), args.end(), "-foo") != args.end());
expect(std::find(args.begin(), args.end(), test_file) == args.end());
}

template <> template <>
void color_coded::config_group::test<6>() /* compilation database, header without flags. */
{
auto const args_source(color_coded::conf::load(compile_commands, "c++", test_file));
auto const args_header(color_coded::conf::load(compile_commands, "c++", test_header));
auto const args_include(color_coded::conf::load(compile_commands, "c++", test_include));
expect_equal(args_source, args_header);
expect_equal(args_source, args_include);
}

template <> template <>
void color_coded::config_group::test<7>() /* compilation database, non-existent file defaults. */
{
expect_equal
(
color_coded::conf::load("compile_commands.json", "c++" "nonexistent/file"),
color_coded::conf::defaults("c++")
);
}
}

0 comments on commit 8c52560

Please sign in to comment.