diff options
Diffstat (limited to 'Builder.cpp')
-rw-r--r-- | Builder.cpp | 124 |
1 files changed, 82 insertions, 42 deletions
diff --git a/Builder.cpp b/Builder.cpp index 86f6920..57f731e 100644 --- a/Builder.cpp +++ b/Builder.cpp @@ -17,6 +17,7 @@ #include <unordered_set> #include <vector> +#include <boost/process.hpp> #include <boost/property_tree/ptree.hpp> #include <boost/property_tree/xml_parser.hpp> @@ -25,25 +26,36 @@ #include <libreichwein/file.h> #include <libreichwein/stringhelper.h> +namespace bp = boost::process; namespace fs = std::filesystem; namespace pt = boost::property_tree; using namespace std::chrono_literals; using namespace std::string_literals; namespace { + const std::string topelement{"ymake"}; + + bool is_match(const pt::ptree::value_type& element, const std::string& target) { + if (target == "*") { + return true; + } else { + return element.first == target; + } + } + // get name of single target, ptree is <build> subtree fs::path get_target(const pt::ptree& ptree) { return ptree.get<std::string>("name"); } // ptree is main tree - std::vector<fs::path> get_all_targets(const pt::ptree& ptree) { + std::vector<fs::path> get_all_targets(const pt::ptree& ptree, const std::string& target) { std::vector<fs::path> result; // iterate over all <build> elements - for (const auto& build: ptree.get_child("ymake")) { - if (build.first == "build") { - result.push_back(build.second.get<std::string>("name")); + for (const auto& element: ptree.get_child(topelement)) { + if (is_match(element, target)) { + result.push_back(element.second.get<std::string>("name")); } } @@ -60,25 +72,15 @@ namespace { return sources; } - // get link libs of single target, ptree is <build> subtree - std::vector<std::string> get_link_libs_of_build(const pt::ptree& ptree) { - std::vector<std::string> linklibs; - for (const pt::ptree::value_type &v: ptree) { - if (v.first == "linklib") - linklibs.push_back(v.second.data()); - } - return linklibs; - } - // ptree is main tree - std::vector<fs::path> get_all_sources(const pt::ptree& ptree) { + std::vector<fs::path> get_all_sources(const pt::ptree& ptree, const std::string& target) { std::vector<fs::path> result; // iterate over all <build> elements - for (const auto& build: ptree.get_child("ymake")) { - if (build.first == "build") { + for (const auto& element: ptree.get_child(topelement)) { + if (is_match(element, target)) { // iterate over all <source> elements - for (const auto& source: build.second) { + for (const auto& source: element.second) { if (source.first == "source") { result.push_back(source.second.data()); } @@ -100,8 +102,8 @@ namespace { } // ptree is main tree - std::vector<fs::path> get_all_objects(const pt::ptree& ptree) { - std::vector<fs::path> objects{get_all_sources(ptree)}; + std::vector<fs::path> get_all_objects(const pt::ptree& ptree, const std::string& target) { + std::vector<fs::path> objects{get_all_sources(ptree, target)}; for (auto &i: objects) { i.replace_extension("o"); } @@ -134,28 +136,44 @@ namespace { return depfile; } - std::unordered_map<fs::path, std::vector<std::string>> get_link_libs(const pt::ptree& ptree) { - std::unordered_map<fs::path, std::vector<std::string>> link_libs_map; + // T = std::string, fs::path + template<typename T> + // get specified subelements (as list) of single target, ptree is <build> subtree + std::vector<T> get_subelements_of_build(const pt::ptree& ptree, const std::string& subelement) { + std::vector<T> result; + for (const pt::ptree::value_type &v: ptree) { + if (v.first == subelement) { + result.push_back(v.second.data()); + } + } + return result; + } - for (const auto& build: ptree.get_child("ymake")) { - if (build.first == "build") { - std::vector<std::string> link_libs{get_link_libs_of_build(build.second)}; - if (!link_libs.empty()) { - link_libs_map.emplace(get_target(build.second), link_libs); + // T = std::string, fs::path + template<typename T> + std::unordered_map<fs::path, std::vector<T>> get_subelements(const pt::ptree& ptree, const std::string& target, const std::string& subelement) { + std::unordered_map<fs::path, std::vector<T>> result_map; + + for (const auto& element: ptree.get_child(topelement)) { + if (is_match(element, target)) { + std::vector<T> subelements{get_subelements_of_build<T>(element.second, subelement)}; + if (!subelements.empty()) { + result_map.emplace(get_target(element.second), subelements); } } } - return link_libs_map; + return result_map; } - } -Builder::Builder(const pt::ptree& ptree): +Builder::Builder(const pt::ptree& ptree, const std::string& target): _ptree(ptree), - _all_targets{get_all_targets(ptree)}, - _all_objects{get_all_objects(ptree)}, - _link_libs{get_link_libs(ptree)} + _target(target), + _all_targets{get_all_targets(ptree, target)}, + _all_objects{get_all_objects(ptree, target)}, + _include_paths{get_subelements<fs::path>(ptree, target, "includepath")}, + _link_libs{get_subelements<std::string>(ptree, target, "linklib")} { // intentionally defer creation of _dependencies to build() // to prevent creation of .d files in clean() @@ -179,6 +197,15 @@ std::vector<std::string> Builder::link_libs_of(const fs::path& p) const } } +std::vector<fs::path> Builder::include_paths_of(const fs::path& p) const +{ + try { + return _include_paths.at(p); + } catch (const std::out_of_range& ex) { + return {}; // empty by default + } +} + // outdated according to dependency tree, recursively bool Builder::is_outdated(const fs::path& p) const { @@ -236,11 +263,11 @@ std::unordered_map<fs::path, std::vector<fs::path>> Builder::get_dependencies(co { std::unordered_map<fs::path, std::vector<fs::path>> dependencies; - for (const auto& build: ptree.get_child("ymake")) { - if (build.first == "build") { - dependencies.emplace(get_target(build.second), get_objects(build.second)); + for (const auto& element: ptree.get_child(topelement)) { + if (is_match(element, _target)) { + dependencies.emplace(get_target(element.second), get_objects(element.second)); - std::vector<fs::path> sources{get_sources(build.second)}; + std::vector<fs::path> sources{get_sources(element.second)}; for (const auto& p: sources) { fs::path p_obj{p}; p_obj.replace_extension("o"); @@ -266,7 +293,8 @@ void Builder::build_file(const fs::path& p) { if (it == source_files.end()) { throw std::runtime_error(fmt::format("No source file found for {}", p.string())); } - command = _lang.getCompileCommand(p, *it); + //std::cout << "DEBUG: " << (*_include_paths.begin()).first << " " << (*_include_paths.begin()).second.size() << " " << p.string() << std::endl; + command = _lang.getCompileCommand(p, *it, include_paths_of(p)); } else { // link std::vector<fs::path> objects{dependencies_of(p)}; @@ -278,7 +306,7 @@ void Builder::build_file(const fs::path& p) { _runner.spawn(p.string(), command.c_str()); } -void Builder::cleanup() { +void Builder::cleanup_buildlist() { std::string path; int exit_code{_runner.wait_one(path)}; _activelist.erase(fs::path{path}); @@ -322,7 +350,7 @@ void Builder::build_filelist() { if (current.empty()) { std::this_thread::sleep_for(10ms); // short wait before retry if (_runner.finished() > 0) { - cleanup(); + cleanup_buildlist(); } } } @@ -332,7 +360,7 @@ void Builder::build_filelist() { // wait until process slot is available while (_runner.full() || _runner.finished() > 0) { - cleanup(); + cleanup_buildlist(); } build_file(current); // calls spawn() on _runner @@ -340,7 +368,7 @@ void Builder::build_filelist() { // final cleanup while (_runner.finished() != 0 || _runner.running() != 0) { - cleanup(); + cleanup_buildlist(); } if (!_activelist.empty()) { @@ -409,3 +437,15 @@ void Builder::clean() const { } } +// build tests and run them +void Builder::run_tests() { + for (const auto& i: _all_targets) { + std::string command{(fs::path("./") / i).string()}; + std::cout << "Running test: " << command << std::endl; + int result {bp::system(command)}; + if (result != 0) { + throw std::runtime_error("Test failed: " + i.string() + ", exit code: " + std::to_string(result)); + } + } +} + |