summaryrefslogtreecommitdiff
path: root/src/build.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/build.cc')
-rw-r--r--src/build.cc173
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;
+}