Browse Source

Added support for the Meson Build System

merge-requests/365/head
eidheim 9 years ago
parent
commit
9b623dd0e0
  1. 2
      CMakeLists.txt
  2. 4
      README.md
  3. 2
      src/CMakeLists.txt
  4. 4
      src/cmake.cc
  5. 5
      src/cmake.h
  6. 79
      src/compile_commands.cc
  7. 23
      src/compile_commands.h
  8. 6
      src/config.cc
  9. 15
      src/config.h
  10. 21
      src/files.h
  11. 130
      src/meson.cc
  12. 19
      src/meson.h
  13. 82
      src/project.cc
  14. 40
      src/project_build.cc
  15. 12
      src/project_build.h
  16. 10
      tests/CMakeLists.txt
  17. 36
      tests/compile_commands_test.cc
  18. 34
      tests/meson_build_test.cc
  19. 5
      tests/meson_test_files/a_subdir/main.cpp
  20. 1
      tests/meson_test_files/a_subdir/meson.build
  21. 5
      tests/meson_test_files/another_file.cpp
  22. 27
      tests/meson_test_files/build/compile_commands.json
  23. 5
      tests/meson_test_files/main.cpp
  24. 11
      tests/meson_test_files/meson.build

2
CMakeLists.txt

@ -1,7 +1,7 @@
cmake_minimum_required (VERSION 2.8.8)
project(juci)
set(JUCI_VERSION "1.2.2")
set(JUCI_VERSION "1.2.2.1")
set(CPACK_PACKAGE_NAME "jucipp")
set(CPACK_PACKAGE_CONTACT "Ole Christian Eidheim <eidheim@gmail.com>")

4
README.md

@ -14,7 +14,9 @@ towards libclang with speed, stability, and ease of use in mind.
* C++ warnings and errors on the fly
* C++ Fix-its
* Debug integration, both local and remote, through lldb
* Automated CMake processing, including support for external libraries
* Supports the following build systems:
* CMake
* Meson
* Git support through libgit2
* Fast C++ autocompletion
* Keyword and buffer autocompletion for other file types

2
src/CMakeLists.txt

@ -22,10 +22,12 @@ set(project_files
#Files used both in ../src and ../tests
set(project_shared_files
cmake.cc
compile_commands.cc
ctags.cc
dispatcher.cc
filesystem.cc
git.cc
meson.cc
project_build.cc
source.cc
source_clang.cc

4
src/cmake.cc

@ -55,7 +55,7 @@ bool CMake::update_default_build(const boost::filesystem::path &default_build_pa
auto compile_commands_path=default_build_path/"compile_commands.json";
Dialog::Message message("Creating/updating default build");
auto exit_status=Terminal::get().process(Config::get().project.cmake_command+" "+
auto exit_status=Terminal::get().process(Config::get().project.cmake.command+' '+
filesystem::escape_argument(project_path)+" -DCMAKE_EXPORT_COMPILE_COMMANDS=ON", default_build_path);
message.hide();
if(exit_status==EXIT_SUCCESS) {
@ -102,7 +102,7 @@ bool CMake::update_debug_build(const boost::filesystem::path &debug_build_path,
return true;
Dialog::Message message("Creating/updating debug build");
auto exit_status=Terminal::get().process(Config::get().project.cmake_command+" "+
auto exit_status=Terminal::get().process(Config::get().project.cmake.command+' '+
filesystem::escape_argument(project_path)+" -DCMAKE_BUILD_TYPE=Debug", debug_build_path);
message.hide();
if(exit_status==EXIT_SUCCESS)

5
src/cmake.h

@ -9,15 +9,13 @@ class CMake {
public:
CMake(const boost::filesystem::path &path);
boost::filesystem::path project_path;
std::vector<boost::filesystem::path> paths;
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);
std::vector<std::pair<boost::filesystem::path, std::vector<std::string> > > get_functions_parameters(const std::string &name);
private:
std::vector<boost::filesystem::path> paths;
std::vector<std::string> files;
std::unordered_map<std::string, std::string> variables;
void read_files();
@ -28,6 +26,7 @@ private:
void parse_variable_parameters(std::string &data);
void parse();
std::vector<std::string> get_function_parameters(std::string &data);
std::vector<std::pair<boost::filesystem::path, std::vector<std::string> > > get_functions_parameters(const std::string &name);
bool parsed=false;
};
#endif //JUCI_CMAKE_H_

79
src/compile_commands.cc

@ -0,0 +1,79 @@
#include "compile_commands.h"
#include <boost/property_tree/json_parser.hpp>
std::vector<std::string> CompileCommands::Command::paramter_values(const std::string &paramter_name) const {
std::vector<std::string> parameter_values;
bool found_argument=false;
for(auto &parameter: parameters) {
if(found_argument) {
parameter_values.emplace_back(parameter);
found_argument=false;
}
else if(parameter==paramter_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<std::string>("directory");
auto parameters_str=command.second.get<std::string>("command");
boost::filesystem::path file=command.second.get<std::string>("file");
std::vector<std::string> parameters;
bool backslash=false;
bool single_quote=false;
bool double_quote=false;
size_t parameter_start_pos=-1;
size_t parameter_size=0;
auto add_parameter=[&parameters, &parameters_str, &parameter_start_pos, &parameter_size] {
auto parameter=parameters_str.substr(parameter_start_pos, parameter_size);
// Remove escaping
for(size_t c=0;c<parameter.size()-1;++c) {
if(parameter[c]=='\\')
parameter.replace(c, 2, std::string()+parameter[c+1]);
}
parameters.emplace_back(parameter);
};
for(size_t c=0;c<parameters_str.size();++c) {
if(backslash)
backslash=false;
else if(parameters_str[c]=='\\')
backslash=true;
else if((parameters_str[c]==' ' || parameters_str[c]=='\t') && !backslash && !single_quote && !double_quote) {
if(parameter_start_pos!=static_cast<size_t>(-1)) {
add_parameter();
parameter_start_pos=-1;
parameter_size=0;
}
continue;
}
else if(parameters_str[c]=='\'' && !backslash && !double_quote) {
single_quote=!single_quote;
continue;
}
else if(parameters_str[c]=='\"' && !backslash && !single_quote) {
double_quote=!double_quote;
continue;
}
if(parameter_start_pos==static_cast<size_t>(-1))
parameter_start_pos=c;
++parameter_size;
}
if(parameter_start_pos!=static_cast<size_t>(-1))
add_parameter();
commands.emplace_back(Command{directory, parameters, boost::filesystem::absolute(file, build_path)});
}
}
catch(...) {}
}

23
src/compile_commands.h

@ -0,0 +1,23 @@
#ifndef JUCI_COMPILE_COMMANDS_H_
#define JUCI_COMPILE_COMMANDS_H_
#include <boost/filesystem.hpp>
#include <vector>
#include <string>
class CompileCommands {
public:
class Command {
public:
boost::filesystem::path directory;
std::vector<std::string> parameters;
boost::filesystem::path file;
std::vector<std::string> paramter_values(const std::string &parameter_name) const;
};
CompileCommands(const boost::filesystem::path &build_path);
std::vector<Command> commands;
};
#endif // JUCI_COMPILE_COMMANDS_H_

6
src/config.cc

@ -90,8 +90,10 @@ void Config::retrieve_config() {
project.default_build_path=cfg.get<std::string>("project.default_build_path");
project.debug_build_path=cfg.get<std::string>("project.debug_build_path");
project.make_command=cfg.get<std::string>("project.make_command");
project.cmake_command=cfg.get<std::string>("project.cmake_command");
project.cmake.command=cfg.get<std::string>("project.cmake.command");
project.cmake.compile_command=cfg.get<std::string>("project.cmake.compile_command");
project.meson.command=cfg.get<std::string>("project.meson.command");
project.meson.compile_command=cfg.get<std::string>("project.meson.compile_command");
project.save_on_compile_or_run=cfg.get<bool>("project.save_on_compile_or_run");
project.clear_terminal_on_compile=cfg.get<bool>("project.clear_terminal_on_compile");
project.ctags_command=cfg.get<std::string>("project.ctags_command");

15
src/config.h

@ -36,10 +36,21 @@ public:
class Project {
public:
class CMake {
public:
std::string command;
std::string compile_command;
};
class Meson {
public:
std::string command;
std::string compile_command;
};
std::string default_build_path;
std::string debug_build_path;
std::string cmake_command;
std::string make_command;
CMake cmake;
Meson meson;
bool save_on_compile_or_run;
bool clear_terminal_on_compile;
std::string ctags_command;

21
src/files.h

@ -156,16 +156,29 @@ R"RAW(
"default_build_path_comment": "Use <project_directory_name> to insert the project top level directory name",
"default_build_path": "./build",
"debug_build_path_comment": "Use <project_directory_name> to insert the project top level directory name, and <default_build_path> to insert your default_build_path setting.",
"debug_build_path": "<default_build_path>/debug",)RAW"
"debug_build_path": "<default_build_path>/debug",
"cmake": {)RAW"
#ifdef _WIN32
R"RAW(
"cmake_command": "cmake -G\"MSYS Makefiles\"",)RAW"
"command": "cmake -G\"MSYS Makefiles\"",)RAW"
#else
R"RAW(
"cmake_command": "cmake",)RAW"
"command": "cmake",)RAW"
#endif
R"RAW(
"make_command": "cmake --build .",
"compile_command": "cmake --build ."
},
"meson": {)RAW"
#ifdef __APPLE__
R"RAW(
"command": "meson.py",)RAW"
#else
R"RAW(
"command": "meson",)RAW"
#endif
R"RAW(
"compile_command": "ninja"
},
"save_on_compile_or_run": true,
"clear_terminal_on_compile": true,
"ctags_command": "ctags"

130
src/meson.cc

@ -0,0 +1,130 @@
#include "meson.h"
#include "filesystem.h"
#include "compile_commands.h"
#include <regex>
#include "terminal.h"
#include "dialogs.h"
#include "config.h"
Meson::Meson(const boost::filesystem::path &path) {
const auto find_project=[this](const boost::filesystem::path &file_path) {
for(auto &line: filesystem::read_lines(file_path)) {
const static std::regex project_regex("^ *project *\\(.*$", std::regex::icase);
std::smatch sm;
if(std::regex_match(line, sm, project_regex))
return true;
}
return false;
};
auto search_path=boost::filesystem::is_directory(path)?path:path.parent_path();
while(true) {
auto search_file=search_path/"meson.build";
if(boost::filesystem::exists(search_file)) {
if(find_project(search_file)) {
project_path=search_path;
break;
}
}
if(search_path==search_path.root_directory())
break;
search_path=search_path.parent_path();
}
}
bool Meson::update_default_build(const boost::filesystem::path &default_build_path, bool force) {
if(project_path.empty())
return false;
if(!boost::filesystem::exists(project_path/"meson.build"))
return false;
if(default_build_path.empty())
return false;
if(!boost::filesystem::exists(default_build_path)) {
boost::system::error_code ec;
boost::filesystem::create_directories(default_build_path, ec);
if(ec) {
Terminal::get().print("Error: could not create "+default_build_path.string()+": "+ec.message()+"\n", true);
return false;
}
}
auto compile_commands_path=default_build_path/"compile_commands.json";
bool compile_commands_exists=boost::filesystem::exists(compile_commands_path);
if(!force && compile_commands_exists)
return true;
Dialog::Message message("Creating/updating default build");
auto exit_status=Terminal::get().process(Config::get().project.meson.command+' '+(compile_commands_exists?"--internal regenerate ":"")+
filesystem::escape_argument(project_path), default_build_path);
message.hide();
if(exit_status==EXIT_SUCCESS)
return true;
return false;
}
bool Meson::update_debug_build(const boost::filesystem::path &debug_build_path, bool force) {
if(project_path.empty())
return false;
if(!boost::filesystem::exists(project_path/"meson.build"))
return false;
if(debug_build_path.empty())
return false;
if(!boost::filesystem::exists(debug_build_path)) {
boost::system::error_code ec;
boost::filesystem::create_directories(debug_build_path, ec);
if(ec) {
Terminal::get().print("Error: could not create "+debug_build_path.string()+": "+ec.message()+"\n", true);
return false;
}
}
bool compile_commands_exists=boost::filesystem::exists(debug_build_path/"compile_commands.json");
if(!force && compile_commands_exists)
return true;
Dialog::Message message("Creating/updating debug build");
auto exit_status=Terminal::get().process(Config::get().project.meson.command+' '+(compile_commands_exists?"--internal regenerate ":"")+
"--buildtype debug "+filesystem::escape_argument(project_path), debug_build_path);
message.hide();
if(exit_status==EXIT_SUCCESS)
return true;
return false;
}
boost::filesystem::path Meson::get_executable(const boost::filesystem::path &build_path, const boost::filesystem::path &file_path) {
CompileCommands compile_commands(build_path);
size_t best_match_size=-1;
boost::filesystem::path 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;
if((pos=values[0].find("@"))!=std::string::npos) {
if(pos+1<values[0].size() && values[0].substr(pos+1, 3)=="exe") {
auto executable=build_path/values[0].substr(0, pos);
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(best_match_size==static_cast<size_t>(-1) || best_match_size<size) {
best_match_size=size;
best_match_executable=executable;
}
}
}
}
}
}
}
return best_match_executable;
}

19
src/meson.h

@ -0,0 +1,19 @@
#ifndef JUCI_MESON_H_
#define JUCI_MESON_H_
#include <boost/filesystem.hpp>
#include <vector>
class Meson {
public:
Meson(const boost::filesystem::path &path);
boost::filesystem::path project_path;
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 &build_path, const boost::filesystem::path &file_path);
};
#endif //JUCI_MESON_H_

82
src/project.cc

@ -42,16 +42,23 @@ void Project::on_save(size_t index) {
auto view=Notebook::get().get_view(index);
if(!view)
return;
boost::filesystem::path build_path;
if(view->language && view->language->get_id()=="cmake") {
boost::filesystem::path cmake_path;
if(view->file_path.filename()=="CMakeLists.txt")
cmake_path=view->file_path;
build_path=view->file_path;
else
cmake_path=filesystem::find_file_in_path_parents("CMakeLists.txt", view->file_path.parent_path());
build_path=filesystem::find_file_in_path_parents("CMakeLists.txt", view->file_path.parent_path());
}
else if(view->language && view->language->get_id()=="meson") {
if(view->file_path.filename()=="meson.build")
build_path=view->file_path;
else
build_path=filesystem::find_file_in_path_parents("meson.build", view->file_path.parent_path());
}
if(!cmake_path.empty()) {
auto build=Build::create(cmake_path);
if(dynamic_cast<CMakeBuild*>(build.get())) {
if(!build_path.empty()) {
auto build=Build::create(build_path);
if(dynamic_cast<CMakeBuild*>(build.get()) || dynamic_cast<MesonBuild*>(build.get())) {
build->update_default(true);
if(boost::filesystem::exists(build->get_debug_path()))
build->update_debug(true);
@ -65,7 +72,6 @@ void Project::on_save(size_t index) {
}
}
}
}
}
void Project::debug_update_status(const std::string &new_debug_status) {
@ -140,7 +146,7 @@ std::unique_ptr<Project::Base> Project::create() {
else
build=Build::create(Directories::get().path);
if(dynamic_cast<CMakeBuild*>(build.get()))
if(dynamic_cast<CMakeBuild*>(build.get()) || dynamic_cast<MesonBuild*>(build.get()))
return std::unique_ptr<Project::Base>(new Project::Clang(std::move(build)));
else
return std::unique_ptr<Project::Base>(new Project::Base(std::move(build)));
@ -213,14 +219,10 @@ std::pair<std::string, std::string> Project::Clang::get_run_arguments() {
if(arguments.empty()) {
auto view=Notebook::get().get_current_view();
auto executable=build->get_executable(view?view->file_path:"").string();
auto executable=build->get_executable(view?view->file_path:Directories::get().path).string();
if(executable!="") {
size_t pos=executable.find(project_path);
if(pos!=std::string::npos)
executable.replace(pos, project_path.size(), build_path.string());
if(!executable.empty())
arguments=filesystem::escape_argument(executable);
}
else
arguments=filesystem::escape_argument(build->get_default_path());
}
@ -238,7 +240,12 @@ void Project::Clang::compile() {
compiling=true;
Terminal::get().print("Compiling project "+build->project_path.string()+"\n");
Terminal::get().async_process(Config::get().project.make_command, default_build_path, [this](int exit_status) {
std::string compile_command;
if(dynamic_cast<CMakeBuild*>(build.get()))
compile_command=Config::get().project.cmake.compile_command;
else if(dynamic_cast<MesonBuild*>(build.get()))
compile_command=Config::get().project.meson.compile_command;
Terminal::get().async_process(compile_command, default_build_path, [this](int exit_status) {
compiling=false;
});
}
@ -257,15 +264,12 @@ void Project::Clang::compile_and_run() {
if(arguments.empty()) {
auto view=Notebook::get().get_current_view();
arguments=build->get_executable(view?view->file_path:"").string();
arguments=build->get_executable(view?view->file_path:Directories::get().path).string();
if(arguments.empty()) {
Terminal::get().print("Warning: could not find executable.\n");
Terminal::get().print("Solution: either use Project Set Run Arguments, or open a source file within a directory where add_executable is set.\n", true);
Terminal::get().print("Solution: either use Project Set Run Arguments, or open a source file within a directory where an executable is defined.\n", true);
return;
}
size_t pos=arguments.find(project_path.string());
if(pos!=std::string::npos)
arguments.replace(pos, project_path.string().size(), default_build_path.string());
arguments=filesystem::escape_argument(arguments);
}
@ -274,7 +278,12 @@ void Project::Clang::compile_and_run() {
compiling=true;
Terminal::get().print("Compiling and running "+arguments+"\n");
Terminal::get().async_process(Config::get().project.make_command, default_build_path, [this, arguments, project_path](int exit_status){
std::string compile_command;
if(dynamic_cast<CMakeBuild*>(build.get()))
compile_command=Config::get().project.cmake.compile_command;
else if(dynamic_cast<MesonBuild*>(build.get()))
compile_command=Config::get().project.meson.compile_command;
Terminal::get().async_process(compile_command, default_build_path, [this, arguments, project_path](int exit_status){
compiling=false;
if(exit_status==EXIT_SUCCESS) {
Terminal::get().async_process(arguments, project_path, [this, arguments](int exit_status){
@ -339,8 +348,9 @@ void Project::Clang::recreate_build() {
#ifdef JUCI_ENABLE_DEBUG
std::pair<std::string, std::string> Project::Clang::debug_get_run_arguments() {
auto build_path=build->get_debug_path();
if(build_path.empty())
auto debug_build_path=build->get_debug_path();
auto default_build_path=build->get_default_path();
if(debug_build_path.empty())
return {"", ""};
auto project_path=build->project_path.string();
@ -351,12 +361,12 @@ std::pair<std::string, std::string> Project::Clang::debug_get_run_arguments() {
if(arguments.empty()) {
auto view=Notebook::get().get_current_view();
auto executable=build->get_executable(view?view->file_path:"").string();
auto executable=build->get_executable(view?view->file_path:Directories::get().path).string();
if(executable!="") {
size_t pos=executable.find(project_path);
if(!executable.empty()) {
size_t pos=executable.find(default_build_path.string());
if(pos!=std::string::npos)
executable.replace(pos, project_path.size(), build_path.string());
executable.replace(pos, default_build_path.string().size(), debug_build_path.string());
arguments=filesystem::escape_argument(executable);
}
else
@ -376,6 +386,9 @@ void Project::Clang::debug_start() {
auto debug_build_path=build->get_debug_path();
if(debug_build_path.empty() || !build->update_debug())
return;
auto default_build_path=build->get_default_path();
if(default_build_path.empty())
return;
auto project_path=std::make_shared<boost::filesystem::path>(build->project_path);
auto run_arguments_it=debug_run_arguments.find(project_path->string());
@ -385,15 +398,15 @@ void Project::Clang::debug_start() {
if(run_arguments->empty()) {
auto view=Notebook::get().get_current_view();
*run_arguments=build->get_executable(view?view->file_path:"").string();
*run_arguments=build->get_executable(view?view->file_path:Directories::get().path).string();
if(run_arguments->empty()) {
Terminal::get().print("Warning: could not find executable.\n");
Terminal::get().print("Solution: either use Debug Set Run Arguments, or open a source file within a directory where add_executable is set.\n", true);
Terminal::get().print("Solution: either use Debug Set Run Arguments, or open a source file within a directory where an executable is defined.\n", true);
return;
}
size_t pos=run_arguments->find(project_path->string());
size_t pos=run_arguments->find(default_build_path.string());
if(pos!=std::string::npos)
run_arguments->replace(pos, project_path->string().size(), debug_build_path.string());
run_arguments->replace(pos, default_build_path.string().size(), debug_build_path.string());
*run_arguments=filesystem::escape_argument(*run_arguments);
}
@ -402,7 +415,12 @@ void Project::Clang::debug_start() {
debugging=true;
Terminal::get().print("Compiling and debugging "+*run_arguments+"\n");
Terminal::get().async_process(Config::get().project.make_command, debug_build_path, [this, run_arguments, project_path](int exit_status){
std::string compile_command;
if(dynamic_cast<CMakeBuild*>(build.get()))
compile_command=Config::get().project.cmake.compile_command;
else if(dynamic_cast<MesonBuild*>(build.get()))
compile_command=Config::get().project.meson.compile_command;
Terminal::get().async_process(compile_command, debug_build_path, [this, run_arguments, project_path](int exit_status){
if(exit_status!=EXIT_SUCCESS)
debugging=false;
else {

40
src/project_build.cc

@ -2,10 +2,28 @@
#include "config.h"
std::unique_ptr<Project::Build> Project::Build::create(const boost::filesystem::path &path) {
auto search_path=boost::filesystem::is_directory(path)?path:path.parent_path();
while(true) {
if(boost::filesystem::exists(search_path/"CMakeLists.txt")) {
std::unique_ptr<Project::Build> cmake(new CMakeBuild(path));
if(!cmake->project_path.empty())
return cmake;
else
return std::make_unique<Project::Build>();
}
if(boost::filesystem::exists(search_path/"meson.build")) {
std::unique_ptr<Project::Build> meson(new MesonBuild(path));
if(!meson->project_path.empty())
return meson;
}
if(search_path==search_path.root_directory())
break;
search_path=search_path.parent_path();
}
return std::make_unique<Project::Build>();
}
@ -79,5 +97,25 @@ bool Project::CMakeBuild::update_debug(bool force) {
}
boost::filesystem::path Project::CMakeBuild::get_executable(const boost::filesystem::path &path) {
return cmake.get_executable(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;
}
Project::MesonBuild::MesonBuild(const boost::filesystem::path &path) : Project::Build(), meson(path) {
project_path=meson.project_path;
}
bool Project::MesonBuild::update_default(bool force) {
return meson.update_default_build(get_default_path(), force);
}
bool Project::MesonBuild::update_debug(bool force) {
return meson.update_debug_build(get_debug_path(), force);
}
boost::filesystem::path Project::MesonBuild::get_executable(const boost::filesystem::path &path) {
return meson.get_executable(get_default_path(), path);
}

12
src/project_build.h

@ -3,6 +3,7 @@
#include <boost/filesystem.hpp>
#include "cmake.h"
#include "meson.h"
namespace Project {
class Build {
@ -32,6 +33,17 @@ namespace Project {
boost::filesystem::path get_executable(const boost::filesystem::path &path) override;
};
class MesonBuild : public Build {
Meson meson;
public:
MesonBuild(const boost::filesystem::path &path);
bool update_default(bool force=false) override;
bool update_debug(bool force=false) override;
boost::filesystem::path get_executable(const boost::filesystem::path &path) override;
};
}
#endif // JUCI_PROJECT_BUILD_H_

10
tests/CMakeLists.txt

@ -19,11 +19,21 @@ add_executable(process_test process_test.cc
target_link_libraries(process_test ${global_libraries})
add_test(process_test process_test)
add_executable(compile_commands_test compile_commands_test.cc
$<TARGET_OBJECTS:project_shared> $<TARGET_OBJECTS:stubs>)
target_link_libraries(compile_commands_test ${global_libraries})
add_test(compile_commands_test compile_commands_test)
add_executable(cmake_build_test cmake_build_test.cc
$<TARGET_OBJECTS:project_shared> $<TARGET_OBJECTS:stubs>)
target_link_libraries(cmake_build_test ${global_libraries})
add_test(cmake_build_test cmake_build_test)
add_executable(meson_build_test meson_build_test.cc
$<TARGET_OBJECTS:project_shared> $<TARGET_OBJECTS:stubs>)
target_link_libraries(meson_build_test ${global_libraries})
add_test(meson_build_test meson_build_test)
add_executable(source_test source_test.cc
$<TARGET_OBJECTS:project_shared> $<TARGET_OBJECTS:stubs>)
target_link_libraries(source_test ${global_libraries})

36
tests/compile_commands_test.cc

@ -0,0 +1,36 @@
#include "compile_commands.h"
#include <glib.h>
int main() {
auto tests_path=boost::filesystem::canonical(JUCI_TESTS_PATH);
{
CompileCommands compile_commands(tests_path/"meson_test_files"/"build");
g_assert(compile_commands.commands.at(0).directory=="jucipp/tests/meson_test_files/build");
g_assert_cmpuint(compile_commands.commands.size(), ==, 5);
g_assert_cmpstr(compile_commands.commands.at(4).parameters.at(0).c_str(), ==, "te's\"t");
g_assert_cmpstr(compile_commands.commands.at(4).parameters.at(1).c_str(), ==, "te st");
g_assert_cmpstr(compile_commands.commands.at(4).parameters.at(2).c_str(), ==, "test");
g_assert_cmpstr(compile_commands.commands.at(4).parameters.at(3).c_str(), ==, "te\\st");
g_assert_cmpstr(compile_commands.commands.at(4).parameters.at(4).c_str(), ==, "te\\\\st");
auto parameter_values=compile_commands.commands.at(0).paramter_values("-o");
g_assert_cmpuint(parameter_values.size(), ==, 1);
g_assert_cmpstr(parameter_values.at(0).c_str(), ==, "hello_lib@sta/main.cpp.o");
g_assert(boost::filesystem::canonical(compile_commands.commands.at(0).file) == tests_path/"meson_test_files"/"main.cpp");
}
{
CompileCommands compile_commands(tests_path/"source_clang_test_files"/"build");
g_assert(compile_commands.commands.at(0).directory=="build");
g_assert_cmpuint(compile_commands.commands.size(), ==, 1);
g_assert_cmpstr(compile_commands.commands.at(0).parameters.at(2).c_str(), ==, "-Wall");
}
}

34
tests/meson_build_test.cc

@ -0,0 +1,34 @@
#include "meson.h"
#include <glib.h>
#include "project.h"
int main() {
auto tests_path=boost::filesystem::canonical(JUCI_TESTS_PATH);
auto meson_test_files_path=boost::filesystem::canonical(tests_path/"meson_test_files");
{
Meson meson(meson_test_files_path/"a_subdir");
g_assert(meson.project_path==meson_test_files_path);
}
{
Meson meson(meson_test_files_path);
g_assert(meson.project_path==meson_test_files_path);
g_assert(meson.get_executable(meson_test_files_path/"build", meson_test_files_path/"main.cpp")==meson_test_files_path/"build"/"hello");
g_assert(meson.get_executable(meson_test_files_path/"build", meson_test_files_path/"another_file.cpp")==meson_test_files_path/"build"/"another_executable");
g_assert(meson.get_executable(meson_test_files_path/"build", meson_test_files_path/"a_subdir"/"main.cpp")==meson_test_files_path/"build"/"a_subdir"/"hello2");
g_assert(meson.get_executable(meson_test_files_path/"build", meson_test_files_path/"non_existing_file.cpp")==meson_test_files_path/"build"/"hello");
g_assert(meson.get_executable(meson_test_files_path/"build", meson_test_files_path)==meson_test_files_path/"build"/"hello");
g_assert(meson.get_executable(meson_test_files_path/"build", meson_test_files_path/"a_subdir")==meson_test_files_path/"build"/"a_subdir"/"hello2");
g_assert(meson.get_executable(meson_test_files_path/"build", meson_test_files_path/"a_subdir"/"non_existing_file.cpp")==meson_test_files_path/"build"/"a_subdir"/"hello2");
}
auto build=Project::Build::create(meson_test_files_path);
g_assert(dynamic_cast<Project::MesonBuild*>(build.get()));
build=Project::Build::create(meson_test_files_path/"a_subdir");
g_assert(dynamic_cast<Project::MesonBuild*>(build.get()));
}

5
tests/meson_test_files/a_subdir/main.cpp

@ -0,0 +1,5 @@
#include <iostream>
int main() {
std::cout << "Hello World\n";
}

1
tests/meson_test_files/a_subdir/meson.build

@ -0,0 +1 @@
executable('hello2', 'main.cpp', cpp_args: compiler_args)

5
tests/meson_test_files/another_file.cpp

@ -0,0 +1,5 @@
#include <iostream>
int main() {
std::cout << "Hello World\n";
}

27
tests/meson_test_files/build/compile_commands.json

@ -0,0 +1,27 @@
[
{
"directory": "jucipp/tests/meson_test_files/build",
"command": "c++ '-Ihello_lib@sta' '-I..' '-I.' '-Wall' '-Winvalid-pch' '-Wnon-virtual-dtor' '-std=c++11' '-Wall' '-Wextra' '-O0' '-g' '-MMD' '-MQ' 'hello_lib@sta/main.cpp.o' '-MF' 'hello_lib@sta/main.cpp.o.d' -o 'hello_lib@sta/main.cpp.o' -c ../main.cpp",
"file": "../main.cpp"
},
{
"directory": "jucipp/tests/meson_test_files/build",
"command": "c++ '-Ihello@exe' '-I..' '-I.' '-Wall' '-Winvalid-pch' '-Wnon-virtual-dtor' '-std=c++11' '-Wall' '-Wextra' '-O0' '-g' '-MMD' '-MQ' 'hello@exe/main.cpp.o' '-MF' 'hello@exe/main.cpp.o.d' -o 'hello@exe/main.cpp.o' -c ../main.cpp",
"file": "../main.cpp"
},
{
"directory": "jucipp/tests/meson_test_files/build",
"command": "c++ '-Ia_subdir/hello2@exe' '-I../a_subdir' '-Ia_subdir' '-Wall' '-Winvalid-pch' '-Wnon-virtual-dtor' '-std=c++11' '-Wall' '-Wextra' '-O0' '-g' '-MMD' '-MQ' 'a_subdir/hello2@exe/main.cpp.o' '-MF' 'a_subdir/hello2@exe/main.cpp.o.d' -o 'a_subdir/hello2@exe/main.cpp.o' -c ../a_subdir/main.cpp",
"file": "../a_subdir/main.cpp"
},
{
"directory": "jucipp/tests/meson_test_files/build",
"command": "c++ '-Ianother_executable@exe' '-I..' '-I.' '-Wall' '-Winvalid-pch' '-Wnon-virtual-dtor' '-std=c++11' '-Wall' '-Wextra' '-O0' '-g' '-MMD' '-MQ' 'another_executable@exe/another_file.cpp.o' '-MF' 'another_executable@exe/another_file.cpp.o.d' -o 'another_executable@exe/another_file.cpp.o' -c ../another_file.cpp",
"file": "../another_file.cpp"
},
{
"directory": "jucipp/tests/meson_test_files/build",
"command": "'te\\'s\"t' te\\ st test te\\\\st te\\\\\\\\st",
"file": "../parse_test.cpp"
}
]

5
tests/meson_test_files/main.cpp

@ -0,0 +1,5 @@
#include <iostream>
int main() {
std::cout << "Hello World\n";
}

11
tests/meson_test_files/meson.build

@ -0,0 +1,11 @@
project('hello.world', 'cpp')
compiler_args = ['-std=c++11', '-Wall', '-Wextra']
static_library('hello_lib', 'main.cpp', cpp_args: compiler_args)
executable('hello', 'main.cpp', cpp_args: compiler_args)
executable('another_executable', 'another_file.cpp', cpp_args: compiler_args)
subdir('a_subdir')
Loading…
Cancel
Save