diff options
Diffstat (limited to 'src/build.cc')
-rw-r--r-- | src/build.cc | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/src/build.cc b/src/build.cc new file mode 100644 index 0000000..445979e --- /dev/null +++ b/src/build.cc @@ -0,0 +1,173 @@ +#include "build.h" + +#include <future> +#include <vector> +#include <iostream> +#include <chrono> +#include <set> +#include <thread> + +#include "tasks.h" + +using namespace std::chrono_literals; + +int build(const Settings& settings, + const std::string& name, + const std::list<std::shared_ptr<Task>>& tasks, + const std::list<std::shared_ptr<Task>>& all_tasks) +{ + if(settings.verbose > 1) + { + std::cout << "Building '" << name << "'\n"; + } + + std::list<std::shared_ptr<Task>> dirtyTasks; + for(auto task : tasks) + { + if(task->dirty()) + { + dirtyTasks.push_back(task); + } + } + + if(dirtyTasks.empty()) + { + std::cout << "Nothing to be done for '"<< name << "'\n"; + return 0; + } + + std::list<std::future<int>> processes; + + // Start all tasks + bool done{false}; + while(!done) + { + bool started_one{false}; + while(processes.size() < settings.parallel_processes) + { + if(dirtyTasks.empty()) + { + done = true; + break; + } + + auto task = getNextTask(all_tasks, dirtyTasks); + if(task == nullptr) + { + if(processes.empty() && !dirtyTasks.empty()) + { + // No running processes, yet no process to run. This is a dead-lock... + std::cout << "Dead-lock detected.\n"; + return 1; + } + break; + } + + processes.emplace_back( + std::async(std::launch::async, + [task]() + { + return task->run(); + })); + started_one = true; + std::this_thread::sleep_for(2ms); + } + + for(auto process = processes.begin(); + process != processes.end(); + ++process) + { + if(process->valid()) + { + if(process->get() != 0) + { + // TODO: Wait for other processes to finish before returning + return 1; + } + processes.erase(process); + break; + } + } + + if(started_one) + { + std::this_thread::sleep_for(2ms); + } + else + { + std::this_thread::sleep_for(200ms); + } + } + + for(auto process = processes.begin(); + process != processes.end(); + ++process) + { + process->wait(); + auto ret = process->get(); + if(ret != 0) + { + return 1; + } + } + + return 0; +} + +namespace +{ +std::set<std::shared_ptr<Task>> getDepTasks(std::shared_ptr<Task> task) +{ + std::set<std::shared_ptr<Task>> tasks; + tasks.insert(task); + + auto deps = task->getDependsTasks(); + for(const auto& dep : deps) + { + auto depSet = getDepTasks(dep); + for(const auto& dep : depSet) + { + tasks.insert(dep); + } + } + + return tasks; +} +} + +int build(const Settings& settings, + const std::string& name, + const std::list<std::shared_ptr<Task>>& all_tasks) +{ + bool task_found{false}; + for(auto task : all_tasks) + { + if(task->name() == name || task->target() == name) + { + std::cout << name << "\n"; + task_found = true; + + auto depSet = getDepTasks(task); + std::list<std::shared_ptr<Task>> ts; + for(const auto& task : depSet) + { + ts.push_back(task); + } + auto ret = build(settings, name, ts, all_tasks); + if(ret != 0) + { + return ret; + } + + break; + } + } + + if(!task_found) + { + std::cerr << "*** No rule to make target '" << name << "'. Stop.\n"; + return 1; + } + + return 0; +} |