Skip to content
This repository was archived by the owner on Jun 25, 2020. It is now read-only.

Commit 7638e5a

Browse files
committed
Improved CMake::get_executable, now also looks in compile_commands.json if no executable was found previously.
1 parent 112fe55 commit 7638e5a

File tree

5 files changed

+100
-51
lines changed

5 files changed

+100
-51
lines changed

src/cmake.cc

Lines changed: 54 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "config.h"
55
#include "terminal.h"
66
#include <regex>
7+
#include "compile_commands.h"
78

89
CMake::CMake(const boost::filesystem::path &path) {
910
const auto find_cmake_project=[this](const boost::filesystem::path &cmake_path) {
@@ -110,29 +111,69 @@ bool CMake::update_debug_build(const boost::filesystem::path &debug_build_path,
110111
return false;
111112
}
112113

113-
boost::filesystem::path CMake::get_executable(const boost::filesystem::path &file_path) {
114-
auto executables = get_functions_parameters("add_executable");
114+
boost::filesystem::path CMake::get_executable(const boost::filesystem::path &build_path, const boost::filesystem::path &file_path) {
115+
auto cmake_executables = get_functions_parameters("add_executable");
115116

116-
//Attempt to find executable based add_executable files and opened tab
117-
boost::filesystem::path executable_path;
117+
//Attempt to find executable based on add_executable in cmake files
118118
if(!file_path.empty()) {
119-
for(auto &executable: executables) {
119+
for(auto &executable: cmake_executables) {
120120
if(executable.second.size()>1) {
121121
for(size_t c=1;c<executable.second.size();c++) {
122-
if(executable.second[c]==file_path.filename()) {
123-
executable_path=executable.first.parent_path()/executable.second[0];
124-
break;
122+
if(executable.second[c]==file_path.filename() &&
123+
executable.second[0].size()>0 && cmake_executables[0].second[0].substr(0, 2)!="${") {
124+
auto found_executable=(executable.first.parent_path()/executable.second[0]).string();
125+
size_t pos=found_executable.find(project_path.string());
126+
if(pos!=std::string::npos)
127+
found_executable.replace(pos, project_path.string().size(), build_path.string());
128+
return found_executable;
129+
}
130+
}
131+
}
132+
}
133+
}
134+
if(cmake_executables.size()>0 && cmake_executables[0].second.size()>0 && cmake_executables[0].second[0].size()>0 &&
135+
cmake_executables[0].second[0].substr(0, 2)!="${") {
136+
auto found_executable=(cmake_executables[0].first.parent_path()/cmake_executables[0].second[0]).string();
137+
size_t pos=found_executable.find(project_path.string());
138+
if(pos!=std::string::npos)
139+
found_executable.replace(pos, project_path.string().size(), build_path.string());
140+
return found_executable;
141+
}
142+
143+
//Attempt to find executable based on compile_commands.json
144+
CompileCommands compile_commands(build_path);
145+
size_t compile_commands_best_match_size=-1;
146+
boost::filesystem::path compile_commands_best_match_executable;
147+
for(auto &command: compile_commands.commands) {
148+
boost::system::error_code ec;
149+
auto command_file=boost::filesystem::canonical(command.file, ec);
150+
if(!ec) {
151+
auto values=command.paramter_values("-o");
152+
if(!values.empty()) {
153+
size_t pos;
154+
values[0].erase(0, 11);
155+
if((pos=values[0].find(".dir"))!=std::string::npos) {
156+
boost::filesystem::path executable=values[0].substr(0, pos);
157+
auto relative_path=filesystem::get_relative_path(command_file, project_path);
158+
if(!relative_path.empty()) {
159+
executable=build_path/relative_path.parent_path()/executable;
160+
if(command_file==file_path)
161+
return executable;
162+
auto command_file_directory=command_file.parent_path();
163+
if(filesystem::file_in_path(file_path, command_file_directory)) {
164+
auto size=command_file_directory.string().size();
165+
if(compile_commands_best_match_size==static_cast<size_t>(-1) || compile_commands_best_match_size<size) {
166+
compile_commands_best_match_size=size;
167+
compile_commands_best_match_executable=executable;
168+
}
169+
}
125170
}
126171
}
127172
}
128-
if(!executable_path.empty())
129-
break;
130173
}
131174
}
132-
if(executable_path.empty() && executables.size()>0 && executables[0].second.size()>0)
133-
executable_path=executables[0].first.parent_path()/executables[0].second[0];
134175

135-
return executable_path;
176+
return compile_commands_best_match_executable;
136177
}
137178

138179
void CMake::read_files() {

src/cmake.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class CMake {
1313
bool update_default_build(const boost::filesystem::path &default_build_path, bool force=false);
1414
bool update_debug_build(const boost::filesystem::path &debug_build_path, bool force=false);
1515

16-
boost::filesystem::path get_executable(const boost::filesystem::path &file_path);
16+
boost::filesystem::path get_executable(const boost::filesystem::path &build_path, const boost::filesystem::path &file_path);
1717
private:
1818
std::vector<boost::filesystem::path> paths;
1919
std::vector<std::string> files;

src/project_build.cc

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -97,11 +97,7 @@ bool Project::CMakeBuild::update_debug(bool force) {
9797
}
9898

9999
boost::filesystem::path Project::CMakeBuild::get_executable(const boost::filesystem::path &path) {
100-
auto executable=cmake.get_executable(path).string();
101-
size_t pos=executable.find(project_path.string());
102-
if(pos!=std::string::npos)
103-
executable.replace(pos, project_path.string().size(), get_default_path().string());
104-
return executable;
100+
return cmake.get_executable(get_default_path(), path).string();
105101
}
106102

107103
Project::MesonBuild::MesonBuild(const boost::filesystem::path &path) : Project::Build(), meson(path) {

tests/cmake_build_test.cc

Lines changed: 42 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,34 +6,46 @@
66

77
int main() {
88
auto tests_path=boost::filesystem::canonical(JUCI_TESTS_PATH);
9-
auto project_path=boost::filesystem::canonical(tests_path/"..");
10-
11-
CMake cmake(tests_path);
12-
13-
g_assert(cmake.project_path==project_path);
14-
15-
auto functions_parameters=cmake.get_functions_parameters("project");
16-
g_assert(functions_parameters.at(0).second.at(0)=="juci");
17-
18-
g_assert(cmake.get_executable(tests_path/"cmake_build_test.cc").filename()=="cmake_build_test");
19-
20-
auto build=Project::Build::create(tests_path);
21-
g_assert(dynamic_cast<Project::CMakeBuild*>(build.get()));
22-
23-
build=Project::Build::create(tests_path/"stubs");
24-
g_assert(dynamic_cast<Project::CMakeBuild*>(build.get()));
25-
g_assert(build->project_path==project_path);
26-
27-
Config::get().project.default_build_path="./build";
28-
g_assert(build->get_default_path()==project_path/"./build");
29-
30-
Config::get().project.debug_build_path="<default_build_path>/debug";
31-
g_assert(build->get_debug_path()==project_path/"./build/debug");
32-
33-
auto project_path_filename=project_path.filename();
34-
Config::get().project.debug_build_path="../debug_<project_directory_name>";
35-
g_assert(build->get_debug_path()==project_path/("../debug_"+project_path_filename.string()));
36-
37-
Config::get().project.default_build_path="../build_<project_directory_name>";
38-
g_assert(build->get_default_path()==project_path/("../build_"+project_path_filename.string()));
9+
{
10+
auto project_path=boost::filesystem::canonical(tests_path/"..");
11+
12+
CMake cmake(tests_path);
13+
14+
g_assert(cmake.project_path==project_path);
15+
16+
auto functions_parameters=cmake.get_functions_parameters("project");
17+
g_assert(functions_parameters.at(0).second.at(0)=="juci");
18+
19+
g_assert(cmake.get_executable(project_path/"build", tests_path/"cmake_build_test.cc").filename()=="cmake_build_test");
20+
21+
auto build=Project::Build::create(tests_path);
22+
g_assert(dynamic_cast<Project::CMakeBuild*>(build.get()));
23+
24+
build=Project::Build::create(tests_path/"stubs");
25+
g_assert(dynamic_cast<Project::CMakeBuild*>(build.get()));
26+
g_assert(build->project_path==project_path);
27+
28+
Config::get().project.default_build_path="./build";
29+
g_assert(build->get_default_path()==project_path/"./build");
30+
31+
Config::get().project.debug_build_path="<default_build_path>/debug";
32+
g_assert(build->get_debug_path()==project_path/"./build/debug");
33+
34+
auto project_path_filename=project_path.filename();
35+
Config::get().project.debug_build_path="../debug_<project_directory_name>";
36+
g_assert(build->get_debug_path()==project_path/("../debug_"+project_path_filename.string()));
37+
38+
Config::get().project.default_build_path="../build_<project_directory_name>";
39+
g_assert(build->get_default_path()==project_path/("../build_"+project_path_filename.string()));
40+
}
41+
{
42+
auto project_path=tests_path/"source_clang_test_files";
43+
CMake cmake(project_path);
44+
45+
g_assert(cmake.project_path==project_path);
46+
47+
g_assert(cmake.get_executable(project_path/"build", project_path/"main.cpp")==project_path/"build"/"test");
48+
g_assert(cmake.get_executable(project_path/"build", project_path/"non_existing_file.cpp")==project_path/"build"/"test");
49+
g_assert(cmake.get_executable(project_path/"build", project_path)==project_path/"build"/"test");
50+
}
3951
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[
22
{
33
"directory": "build",
4-
"command": "c++ -std=c++1y -Wall -Wextra -Wno-unused-parameter main.cpp",
5-
"file": "main.cpp"
4+
"command": "c++ -std=c++1y -Wall -Wextra -Wno-unused-parameter -o CMakeFiles/test.dir/main.cpp.o main.cpp",
5+
"file": "../main.cpp"
66
}
77
]

0 commit comments

Comments
 (0)