inline args_t load_compilation_database(std::string const &file, fs::path filename) { static const std::string source_extensions[] {".c", ".cpp", ".cc"}; static const std::string header_extensions[] {".h", ".hpp", ".hh"}; std::string error; #if LLVM_VERSION_MAJOR >= 4 auto const database_ptr ( ::clang::tooling::JSONCompilationDatabase::loadFromFile ( file, error, ::clang::tooling::JSONCommandLineSyntax::Gnu ) ); #else auto const database_ptr ( ::clang::tooling::JSONCompilationDatabase::loadFromFile ( file, error ) ); #endif 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 {}; } // Skip argv[0] which is the name of the clang executable. args_t commands((compile_commands[0].CommandLine.begin() + 1), compile_commands[0].CommandLine.end()); // Get rid of the source filename itself. // NOTE: '-o <output>' and '-c' will be automatically ignored by libclang. commands.erase(std::remove(commands.begin(), commands.end(), filename), commands.end()); commands.erase(std::remove(commands.begin(), commands.end(), compile_commands[0].Filename), commands.end()); return commands; }