summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBent Bisballe Nyeng <deva@aasimon.org>2021-07-10 21:17:49 +0200
committerBent Bisballe Nyeng <deva@aasimon.org>2021-07-10 23:43:37 +0200
commit23b150fd0dedc012e85b405ec92bc3adacfe9959 (patch)
tree2f919e89b74906eb15c14ff89e2936dab2936b74
parentbfbb506ff1a5e87401d4aa633f0707d1238082d0 (diff)
Individual target builds.
-rw-r--r--Makefile1
-rw-r--r--build.cc166
-rw-r--r--build.h18
-rw-r--r--libcppbuild.cc129
-rw-r--r--task.cc5
-rw-r--r--task.h2
6 files changed, 233 insertions, 88 deletions
diff --git a/Makefile b/Makefile
index 3cea400..6358394 100644
--- a/Makefile
+++ b/Makefile
@@ -11,6 +11,7 @@ SRC = \
configure.cc \
rebuild.cc \
tasks.cc \
+ build.cc \
OBJ = $(patsubst %.cc,%.o,$(SRC))
diff --git a/build.cc b/build.cc
new file mode 100644
index 0000000..6302a18
--- /dev/null
+++ b/build.cc
@@ -0,0 +1,166 @@
+#include "build.h"
+
+#include <future>
+#include <vector>
+#include <iostream>
+#include <chrono>
+#include <set>
+
+#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)
+ {
+ 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;
+}
diff --git a/build.h b/build.h
new file mode 100644
index 0000000..36e48ad
--- /dev/null
+++ b/build.h
@@ -0,0 +1,18 @@
+// -*- c++ -*-
+#pragma once
+
+#include <string>
+#include <list>
+#include <memory>
+
+#include "task.h"
+#include "settings.h"
+
+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);
+
+int build(const Settings& settings,
+ const std::string& name,
+ const std::list<std::shared_ptr<Task>>& all_tasks);
diff --git a/libcppbuild.cc b/libcppbuild.cc
index 0bcbad5..1174421 100644
--- a/libcppbuild.cc
+++ b/libcppbuild.cc
@@ -4,7 +4,6 @@
#include <iostream>
#include <utility>
#include <list>
-#include <chrono>
#include <thread>
#include <memory>
#include <algorithm>
@@ -14,7 +13,6 @@
#include <fstream>
#include <cstdlib>
#include <set>
-#include <future>
#include <getoptpp/getoptpp.hpp>
@@ -23,9 +21,7 @@
#include "configure.h"
#include "rebuild.h"
#include "tasks.h"
-
-using namespace std::chrono_literals;
-
+#include "build.h"
int main(int argc, char* argv[])
{
if(argc > 1 && std::string(argv[1]) == "configure")
@@ -53,7 +49,7 @@ int main(int argc, char* argv[])
int key{128};
opt.add("jobs", required_argument, 'j',
- "Number of parallel jobs. (default: cpucount * 2 - 1 )",
+ "Number of parallel jobs. (default: cpucount * 2 - 1)",
[&]() {
try
{
@@ -135,7 +131,17 @@ int main(int argc, char* argv[])
opt.add("help", no_argument, 'h',
"Print this help text.",
[&]() {
- std::cout << "usage stuff\n";
+ std::cout << "Usage: " << argv[0] << " [options] [target] ...\n";
+ std::cout <<
+R"_( where target can be either:
+ configure - run configuration step (cannot be used with other targets).
+ clean - clean all generated files.
+ all - build all targets (default)
+ or the name of a target which will be built along with its dependencies.
+ Use '-l' to see a list of possible target names.
+
+Options:
+)_";
opt.help();
exit(0);
return 0;
@@ -186,11 +192,11 @@ int main(int argc, char* argv[])
std::filesystem::path builddir(settings.builddir);
std::filesystem::create_directories(builddir);
- auto tasks = getTasks(settings);
+ auto all_tasks = getTasks(settings);
if(list_targets)
{
- for(const auto& task : tasks)
+ for(const auto& task : all_tasks)
{
if(task->targetType() != TargetType::Object)
{
@@ -205,7 +211,7 @@ int main(int argc, char* argv[])
std::ofstream istr(compilation_database);
istr << "[";
bool first{true};
- for(auto task : tasks)
+ for(auto task : all_tasks)
{
auto s = task->toJSON();
if(!s.empty())
@@ -241,118 +247,65 @@ int main(int argc, char* argv[])
return 0;
}
- for(auto task : tasks)
+ for(auto task : all_tasks)
{
- if(task->registerDepTasks(tasks))
+ if(task->registerDepTasks(all_tasks))
{
return 1;
}
}
- std::list<std::shared_ptr<Task>> dirtyTasks;
- for(auto task : tasks)
+ bool build_all{true};
+ for(auto const &arg : opt.arguments())
{
- if(task->dirty())
+ if(arg == "configure")
{
- dirtyTasks.push_back(task);
+ std::cerr << "The 'configure' target must be the first argument.\n";
+ return 1;
}
- }
- for(auto const &arg : opt.arguments())
- {
if(arg == "clean")
{
+ build_all = false;
+
std::cout << "Cleaning\n";
- for(auto& task : tasks)
+ for(auto& task : all_tasks)
{
if(task->clean() != 0)
{
return 1;
}
}
-
- return 0;
}
-
- if(arg == "configure")
- {
- std::cerr << "The 'configure' target must be the first argument.\n";
- return 1;
- }
- }
-
- if(dirtyTasks.empty())
- {
- return 0;
- }
-
- std::cout << "Building\n";
- std::list<std::future<int>> processes;
-
- // Start all tasks
- bool done{false};
- while(!done)
- {
- bool started_one{false};
- while(processes.size() < settings.parallel_processes)
+ else
{
- if(dirtyTasks.empty())
- {
- done = true;
- break;
- }
+ build_all = false;
- auto task = getNextTask(tasks, dirtyTasks);
- if(task == nullptr)
+ if(arg == "all")
{
- break;
- //return 1;
+ auto ret = build(settings, "all", all_tasks, all_tasks);
+ if(ret != 0)
+ {
+ return ret;
+ }
}
-
- 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())
+ else
{
- if(process->get() != 0)
+ auto ret = build(settings, arg, all_tasks);
+ if(ret != 0)
{
- return 1;
+ return ret;
}
- 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)
+ if(build_all)
{
- process->wait();
- auto ret = process->get();
+ auto ret = build(settings, "all", all_tasks, all_tasks);
if(ret != 0)
{
- return 1;
+ return ret;
}
}
diff --git a/task.cc b/task.cc
index 8c48543..962a02b 100644
--- a/task.cc
+++ b/task.cc
@@ -139,3 +139,8 @@ std::string Task::compiler() const
break;
}
}
+
+std::list<std::shared_ptr<Task>> Task::getDependsTasks()
+{
+ return dependsTasks;
+}
diff --git a/task.h b/task.h
index 6e71db6..98363a1 100644
--- a/task.h
+++ b/task.h
@@ -44,6 +44,8 @@ public:
OutputSystem outputSystem() const;
std::string compiler() const;
+ std::list<std::shared_ptr<Task>> getDependsTasks();
+
protected:
std::atomic<State> task_state{State::Unknown};
virtual int runInner() { return 0; };