Browse Source

Improved search of executables in cmake projects

merge-requests/365/head
eidheim 9 years ago
parent
commit
5bdabd6671
  1. 102
      src/cmake.cc
  2. 3
      src/cmake.h
  3. 2
      src/meson.cc
  4. 14
      tests/cmake_build_test.cc
  5. 2
      tests/compile_commands_test.cc
  6. 2
      tests/source_clang_test_files/build/compile_commands.json

102
src/cmake.cc

@ -102,54 +102,27 @@ bool CMake::update_debug_build(const boost::filesystem::path &debug_build_path,
} }
boost::filesystem::path CMake::get_executable(const boost::filesystem::path &build_path, const boost::filesystem::path &file_path) { boost::filesystem::path CMake::get_executable(const boost::filesystem::path &build_path, const boost::filesystem::path &file_path) {
auto cmake_executables = get_functions_parameters("add_executable"); // CMake does not store in compile_commands.json if an object is part of an executable or not.
// Therefore, executables are first attempted found in the cmake files. These executables
// are then used to identify if a file in compile_commands.json is part of an executable or not
auto cmake_fix_executable=[this, &build_path](std::string executable) { auto parameters = get_functions_parameters("add_executable");
size_t pos=executable.find(project_path.string());
if(pos!=std::string::npos)
executable.replace(pos, project_path.string().size(), build_path.string());
return executable;
};
if(!file_path.empty()) { std::vector<boost::filesystem::path> cmake_executables;
for(auto &executable: cmake_executables) { for(auto &parameter: parameters) {
if(executable.second.size()>1) { if(parameter.second.size()>1 && parameter.second[0].size()>0 && parameter.second[0].compare(0, 2, "${")!=0) {
for(size_t c=1;c<executable.second.size();c++) { auto executable=(parameter.first.parent_path()/parameter.second[0]).string();
if(executable.second[c]==file_path.filename()) { auto project_path_str=project_path.string();
if(executable.second[0].size()>0 && cmake_executables[0].second[0].compare(0, 2, "${")!=0) size_t pos=executable.find(project_path_str);
return cmake_fix_executable((executable.first.parent_path()/executable.second[0]).string()); if(pos!=std::string::npos)
return get_executable_from_compile_commands(build_path, file_path); executable.replace(pos, project_path_str.size(), build_path.string());
} cmake_executables.emplace_back(executable);
}
}
}
}
size_t best_match_c=-1;
size_t best_match_size=-1;
for(size_t c=0;c<cmake_executables.size();++c) {
if(cmake_executables[c].second.size()>0) {
auto size=cmake_executables[c].first.parent_path().string().size();
if(best_match_size==static_cast<size_t>(-1) || best_match_size<size) {
best_match_size=size;
best_match_c=c;
}
}
} }
if(best_match_c!=static_cast<size_t>(-1) &&
cmake_executables[best_match_c].second[0].size()>0 &&
cmake_executables[best_match_c].second[0].compare(0, 2, "${")!=0) {
return cmake_fix_executable((cmake_executables[best_match_c].first.parent_path()/cmake_executables[best_match_c].second[0]).string());
} }
return get_executable_from_compile_commands(build_path, file_path);
}
boost::filesystem::path CMake::get_executable_from_compile_commands(const boost::filesystem::path &build_path, const boost::filesystem::path &file_path) {
CompileCommands compile_commands(build_path); CompileCommands compile_commands(build_path);
std::vector<std::pair<boost::filesystem::path, boost::filesystem::path>> command_files_and_maybe_executables;
size_t compile_commands_best_match_size=-1;
boost::filesystem::path compile_commands_best_match_executable;
for(auto &command: compile_commands.commands) { for(auto &command: compile_commands.commands) {
auto command_file=filesystem::get_normal_path(command.file); auto command_file=filesystem::get_normal_path(command.file);
auto values=command.parameter_values("-o"); auto values=command.parameter_values("-o");
@ -157,26 +130,51 @@ boost::filesystem::path CMake::get_executable_from_compile_commands(const boost:
size_t pos; size_t pos;
values[0].erase(0, 11); values[0].erase(0, 11);
if((pos=values[0].find(".dir"))!=std::string::npos) { if((pos=values[0].find(".dir"))!=std::string::npos) {
boost::filesystem::path executable=values[0].substr(0, pos); auto executable=command.directory/values[0].substr(0, pos);
auto relative_path=filesystem::get_relative_path(command_file, project_path); command_files_and_maybe_executables.emplace_back(command_file, executable);
if(!relative_path.empty()) { }
executable=build_path/relative_path.parent_path()/executable; }
}
size_t best_match_size=-1;
boost::filesystem::path best_match_executable;
for(auto &cmake_executable: cmake_executables) {
for(auto &command_file_and_maybe_executable: command_files_and_maybe_executables) {
auto &command_file=command_file_and_maybe_executable.first;
auto &maybe_executable=command_file_and_maybe_executable.second;
if(cmake_executable==maybe_executable) {
if(command_file==file_path) if(command_file==file_path)
return executable; return maybe_executable;
auto command_file_directory=command_file.parent_path(); auto command_file_directory=command_file.parent_path();
if(filesystem::file_in_path(file_path, command_file_directory)) { if(filesystem::file_in_path(file_path, command_file_directory)) {
auto size=command_file_directory.string().size(); auto size=static_cast<size_t>(std::distance(command_file_directory.begin(), command_file_directory.end()));
if(compile_commands_best_match_size==static_cast<size_t>(-1) || compile_commands_best_match_size<size) { if(best_match_size==static_cast<size_t>(-1) || best_match_size<size) {
compile_commands_best_match_size=size; best_match_size=size;
compile_commands_best_match_executable=executable; best_match_executable=maybe_executable;
}
} }
} }
} }
} }
} }
if(!best_match_executable.empty())
return best_match_executable;
return compile_commands_best_match_executable; for(auto &command_file_and_maybe_executable: command_files_and_maybe_executables) {
auto &command_file=command_file_and_maybe_executable.first;
auto &maybe_executable=command_file_and_maybe_executable.second;
if(command_file==file_path)
return maybe_executable;
auto command_file_directory=command_file.parent_path();
if(filesystem::file_in_path(file_path, command_file_directory)) {
auto size=static_cast<size_t>(std::distance(command_file_directory.begin(), command_file_directory.end()));
if(best_match_size==static_cast<size_t>(-1) || best_match_size<size) {
best_match_size=size;
best_match_executable=maybe_executable;
}
}
}
return best_match_executable;
} }
void CMake::read_files() { void CMake::read_files() {

3
src/cmake.h

@ -14,9 +14,8 @@ public:
bool update_debug_build(const boost::filesystem::path &debug_build_path, bool force=false); bool update_debug_build(const boost::filesystem::path &debug_build_path, bool force=false);
boost::filesystem::path get_executable(const boost::filesystem::path &build_path, const boost::filesystem::path &file_path); boost::filesystem::path get_executable(const boost::filesystem::path &build_path, const boost::filesystem::path &file_path);
private:
boost::filesystem::path get_executable_from_compile_commands(const boost::filesystem::path &build_path, const boost::filesystem::path &file_path);
private:
std::vector<boost::filesystem::path> paths; std::vector<boost::filesystem::path> paths;
std::vector<std::string> files; std::vector<std::string> files;
std::unordered_map<std::string, std::string> variables; std::unordered_map<std::string, std::string> variables;

2
src/meson.cc

@ -102,7 +102,7 @@ boost::filesystem::path Meson::get_executable(const boost::filesystem::path &bui
return executable; return executable;
auto command_file_directory=command_file.parent_path(); auto command_file_directory=command_file.parent_path();
if(filesystem::file_in_path(file_path, command_file_directory)) { if(filesystem::file_in_path(file_path, command_file_directory)) {
auto size=command_file_directory.string().size(); auto size=static_cast<size_t>(std::distance(command_file_directory.begin(), command_file_directory.end()));
if(best_match_size==static_cast<size_t>(-1) || best_match_size<size) { if(best_match_size==static_cast<size_t>(-1) || best_match_size<size) {
best_match_size=size; best_match_size=size;
best_match_executable=executable; best_match_executable=executable;

14
tests/cmake_build_test.cc

@ -3,6 +3,7 @@
#include "project_build.h" #include "project_build.h"
#include "config.h" #include "config.h"
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include "process.hpp"
#include <iostream> #include <iostream>
using namespace std; using namespace std;
@ -14,6 +15,9 @@ int main() {
{ {
CMake cmake(project_path); CMake cmake(project_path);
Process process("cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ..", (project_path/"build").string(), [](const char *bytes, size_t n) {});
g_assert(process.get_exit_status()==0);
g_assert(cmake.get_executable(project_path/"build", project_path)==""); g_assert(cmake.get_executable(project_path/"build", project_path)=="");
g_assert(cmake.get_executable(project_path/"build"/"non_existing_file.cc", project_path)==""); g_assert(cmake.get_executable(project_path/"build"/"non_existing_file.cc", project_path)=="");
} }
@ -32,9 +36,9 @@ int main() {
auto functions_parameters=cmake.get_functions_parameters("project"); auto functions_parameters=cmake.get_functions_parameters("project");
g_assert(functions_parameters.at(0).second.at(0)=="juci"); g_assert(functions_parameters.at(0).second.at(0)=="juci");
g_assert(cmake.get_executable(project_path/"build", tests_path)==project_path/"build"/"tests"/"process_test"); g_assert(cmake.get_executable(project_path/"build", tests_path).parent_path()==project_path/"build"/"tests");
g_assert(cmake.get_executable(project_path/"build", tests_path/"cmake_build_test.cc")==project_path/"build"/"tests"/"cmake_build_test"); g_assert(cmake.get_executable(project_path/"build", tests_path/"cmake_build_test.cc")==project_path/"build"/"tests"/"cmake_build_test");
g_assert(cmake.get_executable(project_path/"build", tests_path/"non_existing_file.cc")==project_path/"build"/"tests"/"process_test"); g_assert(cmake.get_executable(project_path/"build", tests_path/"non_existing_file.cc").parent_path()==project_path/"build"/"tests");
} }
auto build=Project::Build::create(tests_path); auto build=Project::Build::create(tests_path);
@ -63,8 +67,8 @@ int main() {
g_assert(cmake.project_path==project_path); g_assert(cmake.project_path==project_path);
g_assert(cmake.get_executable(project_path/"build", project_path/"main.cpp")==project_path/"build"/"test"); g_assert(cmake.get_executable(project_path/"build", project_path/"main.cpp")==boost::filesystem::path(".")/"test");
g_assert(cmake.get_executable(project_path/"build", project_path/"non_existing_file.cpp")==project_path/"build"/"test"); g_assert(cmake.get_executable(project_path/"build", project_path/"non_existing_file.cpp")==boost::filesystem::path(".")/"test");
g_assert(cmake.get_executable(project_path/"build", project_path)==project_path/"build"/"test"); g_assert(cmake.get_executable(project_path/"build", project_path)==boost::filesystem::path(".")/"test");
} }
} }

2
tests/compile_commands_test.cc

@ -27,7 +27,7 @@ int main() {
{ {
CompileCommands compile_commands(tests_path/"source_clang_test_files"/"build"); CompileCommands compile_commands(tests_path/"source_clang_test_files"/"build");
g_assert(compile_commands.commands.at(0).directory=="build"); g_assert(compile_commands.commands.at(0).directory==".");
g_assert_cmpuint(compile_commands.commands.size(), ==, 1); g_assert_cmpuint(compile_commands.commands.size(), ==, 1);

2
tests/source_clang_test_files/build/compile_commands.json

@ -1,6 +1,6 @@
[ [
{ {
"directory": "build", "directory": ".",
"command": "c++ -std=c++1y -Wall -Wextra -Wno-unused-parameter -o CMakeFiles/test.dir/main.cpp.o main.cpp", "command": "c++ -std=c++1y -Wall -Wextra -Wno-unused-parameter -o CMakeFiles/test.dir/main.cpp.o main.cpp",
"file": "../main.cpp" "file": "../main.cpp"
} }

Loading…
Cancel
Save