#include "cmake.h" #include "filesystem.h" #include "dialogs.h" #include "config.h" #include "terminal.h" #include CMake::CMake(const boost::filesystem::path &path) { const auto find_cmake_project=[this](const boost::filesystem::path &cmake_path) { for(auto &line: filesystem::read_lines(cmake_path)) { const boost::regex project_regex("^ *project *\\(.*$"); boost::smatch sm; if(boost::regex_match(line, sm, project_regex)) return true; } return false; }; auto search_path=path; auto search_cmake_path=search_path; search_cmake_path+="/CMakeLists.txt"; if(boost::filesystem::exists(search_cmake_path)) paths.emplace(paths.begin(), search_cmake_path); if(find_cmake_project(search_cmake_path)) project_path=search_path; else { do { search_path=search_path.parent_path(); search_cmake_path=search_path; search_cmake_path+="/CMakeLists.txt"; if(boost::filesystem::exists(search_cmake_path)) paths.emplace(paths.begin(), search_cmake_path); if(find_cmake_project(search_cmake_path)) { project_path=search_path; break; } } while(search_path!=search_path.root_directory()); } if(!project_path.empty()) { if(boost::filesystem::exists(project_path/"CMakeLists.txt") && !boost::filesystem::exists(project_path/"compile_commands.json")) create_compile_commands(project_path); } } bool CMake::create_compile_commands(const boost::filesystem::path &path) { Dialog::Message message("Creating "+path.string()+"/compile_commands.json"); auto exit_status=Terminal::get().process(Config::get().terminal.cmake_command+" . -DCMAKE_EXPORT_COMPILE_COMMANDS=ON", path); message.hide(); if(exit_status==EXIT_SUCCESS) { #ifdef _WIN32 //Temporary fix to MSYS2's libclang auto compile_commands_path=path; compile_commands_path+="/compile_commands.json"; auto compile_commands_file=filesystem::read(compile_commands_path); size_t pos=0; while((pos=compile_commands_file.find("-I/", pos))!=std::string::npos) { if(pos+3start_line) { auto line=file.substr(start_line, end_line-start_line); boost::smatch sm; const boost::regex set_regex("^ *set *\\( *([A-Za-z_][A-Za-z_0-9]*) +(.*)\\) *$"); if(boost::regex_match(line, sm, set_regex)) { auto data=sm[2].str(); while(data.size()>0 && data.back()==' ') data.pop_back(); parse_variable_parameters(data); variables[sm[1].str()]=data; } else { const boost::regex project_regex("^ *project *\\( *([^ ]+).*\\) *$"); if(boost::regex_match(line, sm, project_regex)) { auto data=sm[1].str(); parse_variable_parameters(data); variables["CMAKE_PROJECT_NAME"]=data; //TODO: is this variable deprecated/non-standard? variables["PROJECT_NAME"]=data; } } } pos=end_line+1; } } } void CMake::parse_variable_parameters(std::string &data) { size_t pos=0; bool inside_quote=false; char last_char=0; while(pos CMake::get_function_parameters(std::string &data) { std::vector parameters; size_t pos=0; size_t parameter_pos=0; bool inside_quote=false; char last_char=0; while(pos > > CMake::get_functions_parameters(const std::string &name) { if(!parsed) parse(); std::vector > > functions; size_t file_c=0; for(auto &file: files) { size_t pos=0; while(posstart_line) { auto line=file.substr(start_line, end_line-start_line); const boost::regex function_regex("^ *"+name+" *\\( *(.*)\\) *$"); boost::smatch sm; if(boost::regex_match(line, sm, function_regex)) { auto data=sm[1].str(); while(data.size()>0 && data.back()==' ') data.pop_back(); auto parameters=get_function_parameters(data); functions.emplace(functions.begin(), paths[file_c], parameters); } } pos=end_line+1; } file_c++; } return functions; }