Browse Source

Improved CMake::get_executable, now also looks in compile_commands.json if no executable was found previously.

merge-requests/365/head
eidheim 9 years ago
parent
commit
7ec8f03039
  1. 65
      src/cmake.cc
  2. 2
      src/cmake.h
  3. 6
      src/project_build.cc
  4. 33
      tests/cmake_build_test.cc
  5. 4
      tests/source_clang_test_files/build/compile_commands.json

65
src/cmake.cc

@ -4,6 +4,7 @@
#include "config.h"
#include "terminal.h"
#include <regex>
#include "compile_commands.h"
CMake::CMake(const boost::filesystem::path &path) {
const auto find_cmake_project=[this](const boost::filesystem::path &cmake_path) {
@ -110,29 +111,67 @@ bool CMake::update_debug_build(const boost::filesystem::path &debug_build_path,
return false;
}
boost::filesystem::path CMake::get_executable(const boost::filesystem::path &file_path) {
auto executables = get_functions_parameters("add_executable");
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");
//Attempt to find executable based add_executable files and opened tab
boost::filesystem::path executable_path;
//Attempt to find executable based on add_executable in cmake files
auto cmake_fix_executable=[this, &build_path](std::string 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()) {
for(auto &executable: executables) {
for(auto &executable: cmake_executables) {
if(executable.second.size()>1) {
for(size_t c=1;c<executable.second.size();c++) {
if(executable.second[c]==file_path.filename()) {
executable_path=executable.first.parent_path()/executable.second[0];
break;
if(executable.second[c]==file_path.filename() &&
executable.second[0].size()>0 && cmake_executables[0].second[0].substr(0, 2)!="${") {
return cmake_fix_executable((executable.first.parent_path()/executable.second[0]).string());
}
}
}
}
}
if(cmake_executables.size()>0 && cmake_executables[0].second.size()>0 && cmake_executables[0].second[0].size()>0 &&
cmake_executables[0].second[0].substr(0, 2)!="${") {
return cmake_fix_executable((cmake_executables[0].first.parent_path()/cmake_executables[0].second[0]).string());
}
//Attempt to find executable based on compile_commands.json
CompileCommands compile_commands(build_path);
size_t compile_commands_best_match_size=-1;
boost::filesystem::path compile_commands_best_match_executable;
for(auto &command: compile_commands.commands) {
boost::system::error_code ec;
auto command_file=boost::filesystem::canonical(command.file, ec);
if(!ec) {
auto values=command.paramter_values("-o");
if(!values.empty()) {
size_t pos;
values[0].erase(0, 11);
if((pos=values[0].find(".dir"))!=std::string::npos) {
boost::filesystem::path executable=values[0].substr(0, pos);
auto relative_path=filesystem::get_relative_path(command_file, project_path);
if(!relative_path.empty()) {
executable=build_path/relative_path.parent_path()/executable;
if(command_file==file_path)
return executable;
auto command_file_directory=command_file.parent_path();
if(filesystem::file_in_path(file_path, command_file_directory)) {
auto size=command_file_directory.string().size();
if(compile_commands_best_match_size==static_cast<size_t>(-1) || compile_commands_best_match_size<size) {
compile_commands_best_match_size=size;
compile_commands_best_match_executable=executable;
}
}
}
}
}
if(!executable_path.empty())
break;
}
}
if(executable_path.empty() && executables.size()>0 && executables[0].second.size()>0)
executable_path=executables[0].first.parent_path()/executables[0].second[0];
return executable_path;
return compile_commands_best_match_executable;
}
void CMake::read_files() {

2
src/cmake.h

@ -13,7 +13,7 @@ public:
bool update_default_build(const boost::filesystem::path &default_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 &file_path);
boost::filesystem::path get_executable(const boost::filesystem::path &build_path, const boost::filesystem::path &file_path);
private:
std::vector<boost::filesystem::path> paths;
std::vector<std::string> files;

6
src/project_build.cc

@ -97,11 +97,7 @@ bool Project::CMakeBuild::update_debug(bool force) {
}
boost::filesystem::path Project::CMakeBuild::get_executable(const boost::filesystem::path &path) {
auto executable=cmake.get_executable(path).string();
size_t pos=executable.find(project_path.string());
if(pos!=std::string::npos)
executable.replace(pos, project_path.string().size(), get_default_path().string());
return executable;
return cmake.get_executable(get_default_path(), path).string();
}
Project::MesonBuild::MesonBuild(const boost::filesystem::path &path) : Project::Build(), meson(path) {

33
tests/cmake_build_test.cc

@ -4,10 +4,27 @@
#include "config.h"
#include <boost/filesystem.hpp>
#include <iostream>
using namespace std;
int main() {
auto tests_path=boost::filesystem::canonical(JUCI_TESTS_PATH);
{
auto project_path=boost::filesystem::canonical(tests_path/"..");
{
CMake cmake(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)=="");
}
{
CMake cmake(project_path/"src");
g_assert(cmake.get_executable(project_path/"build", project_path/"src")==project_path/"build"/"src"/"juci");
g_assert(cmake.get_executable(project_path/"build", project_path/"src"/"cmake.cc")==project_path/"build"/"src"/"juci");
g_assert(cmake.get_executable(project_path/"build", project_path/"src"/"juci.cc")==project_path/"build"/"src"/"juci");
g_assert(cmake.get_executable(project_path/"build", project_path/"src"/"non_existing_file.cc")==project_path/"build"/"src"/"juci");
}
{
CMake cmake(tests_path);
g_assert(cmake.project_path==project_path);
@ -15,7 +32,10 @@ int main() {
auto functions_parameters=cmake.get_functions_parameters("project");
g_assert(functions_parameters.at(0).second.at(0)=="juci");
g_assert(cmake.get_executable(tests_path/"cmake_build_test.cc").filename()=="cmake_build_test");
g_assert(cmake.get_executable(project_path/"build", tests_path)==project_path/"build"/"tests"/"git_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"/"git_test");
}
auto build=Project::Build::create(tests_path);
g_assert(dynamic_cast<Project::CMakeBuild*>(build.get()));
@ -36,4 +56,15 @@ int main() {
Config::get().project.default_build_path="../build_<project_directory_name>";
g_assert(build->get_default_path()==project_path/("../build_"+project_path_filename.string()));
}
{
auto project_path=tests_path/"source_clang_test_files";
CMake cmake(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/"non_existing_file.cpp")==project_path/"build"/"test");
g_assert(cmake.get_executable(project_path/"build", project_path)==project_path/"build"/"test");
}
}

4
tests/source_clang_test_files/build/compile_commands.json

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