#include "compile_commands.h" #include "clangmm.h" #include #include std::vector CompileCommands::Command::parameter_values(const std::string ¶meter_name) const { std::vector parameter_values; bool found_argument=false; for(auto ¶meter: parameters) { if(found_argument) { parameter_values.emplace_back(parameter); found_argument=false; } else if(parameter==parameter_name) found_argument=true; } return parameter_values; } CompileCommands::CompileCommands(const boost::filesystem::path &build_path) { try { boost::property_tree::ptree root_pt; boost::property_tree::json_parser::read_json((build_path/"compile_commands.json").string(), root_pt); auto commands_pt=root_pt.get_child(""); for(auto &command: commands_pt) { boost::filesystem::path directory=command.second.get("directory"); auto parameters_str=command.second.get("command"); boost::filesystem::path file=command.second.get("file"); std::vector parameters; bool backslash=false; bool single_quote=false; bool double_quote=false; size_t parameter_start_pos=std::string::npos; size_t parameter_size=0; auto add_parameter=[¶meters, ¶meters_str, ¶meter_start_pos, ¶meter_size] { auto parameter=parameters_str.substr(parameter_start_pos, parameter_size); // Remove escaping for(size_t c=0;c CompileCommands::get_arguments(const boost::filesystem::path &build_path, const boost::filesystem::path &file_path) { std::string default_std_argument="-std=c++1y"; std::vector arguments; if(!build_path.empty()) { clangmm::CompilationDatabase db(build_path.string()); if(db) { clangmm::CompileCommands commands(file_path.string(), db); auto cmds = commands.get_commands(); for (auto &cmd : cmds) { auto cmd_arguments = cmd.get_arguments(); bool ignore_next=false; for (size_t c = 1; c < cmd_arguments.size(); c++) { if(ignore_next) { ignore_next=false; continue; } else if(cmd_arguments[c]=="-o" || cmd_arguments[c]=="-c" || cmd_arguments[c]=="-x") { // Remove language arguments since some tools add languages not understood by clang ignore_next=true; continue; } arguments.emplace_back(cmd_arguments[c]); } } } else arguments.emplace_back(default_std_argument); } else arguments.emplace_back(default_std_argument); auto clang_version_string=clangmm::to_string(clang_getClangVersion()); const static std::regex clang_version_regex(R"(^[A-Za-z ]+([0-9.]+).*$)"); std::smatch sm; if(std::regex_match(clang_version_string, sm, clang_version_regex)) { auto clang_version=sm[1].str(); arguments.emplace_back("-I/usr/lib/clang/"+clang_version+"/include"); arguments.emplace_back("-I/usr/lib64/clang/"+clang_version+"/include"); // For Fedora #if defined(__APPLE__) && CINDEX_VERSION_MAJOR==0 && CINDEX_VERSION_MINOR<32 // TODO: remove during 2018 if llvm3.7 is no longer in homebrew (CINDEX_VERSION_MINOR=32 equals clang-3.8 I think) arguments.emplace_back("-I/usr/local/Cellar/llvm/"+clang_version+"/lib/clang/"+clang_version+"/include"); arguments.emplace_back("-I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1"); arguments.emplace_back("-I/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1"); //Added for OS X 10.11 #endif #ifdef _WIN32 auto env_msystem_prefix=std::getenv("MSYSTEM_PREFIX"); if(env_msystem_prefix!=nullptr) arguments.emplace_back("-I"+(boost::filesystem::path(env_msystem_prefix)/"lib/clang"/clang_version/"include").string()); #endif } arguments.emplace_back("-fretain-comments-from-system-headers"); auto extension=file_path.extension().string(); bool is_header=CompileCommands::is_header(file_path) || extension.empty(); // Include std C++ headers that are without extensions if(is_header) { arguments.emplace_back("-Wno-pragma-once-outside-header"); arguments.emplace_back("-Wno-pragma-system-header-outside-header"); arguments.emplace_back("-Wno-include-next-outside-header"); } if(extension==".cu" || extension==".cuh") { arguments.emplace_back("-xcuda"); arguments.emplace_back("-D__CUDACC__"); arguments.emplace_back("-include"); arguments.emplace_back("cuda_runtime.h"); arguments.emplace_back("-ferror-limit=1000"); // CUDA headers redeclares some std functions } else if(extension==".cl") { arguments.emplace_back("-xcl"); arguments.emplace_back("-cl-std=CL2.0"); arguments.emplace_back("-Xclang"); arguments.emplace_back("-finclude-default-header"); arguments.emplace_back("-Wno-gcc-compat"); } else if(is_header) arguments.emplace_back("-xc++"); if(!build_path.empty()) { arguments.emplace_back("-working-directory"); arguments.emplace_back(build_path.string()); } return arguments; } bool CompileCommands::is_header(const boost::filesystem::path &path) { auto ext = path.extension(); if(ext == ".h" || // c headers ext == ".hh" || ext == ".hp" || ext == ".hpp" || ext == ".h++" || ext == ".tcc" || // c++ headers ext == ".cuh") // CUDA headers return true; else return false; } bool CompileCommands::is_source(const boost::filesystem::path &path) { auto ext = path.extension(); if(ext == ".c" || // c sources ext == ".cpp" || ext == ".cxx" || ext == ".cc" || ext == ".C" || ext == ".c++" || // c++ sources ext == ".cu" || // CUDA sources ext == ".cl") // OpenCL sources return true; else return false; }