From 23b150fd0dedc012e85b405ec92bc3adacfe9959 Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Sat, 10 Jul 2021 21:17:49 +0200 Subject: Individual target builds. --- Makefile | 1 + build.cc | 166 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ build.h | 18 +++++++ libcppbuild.cc | 129 ++++++++++++++------------------------------ task.cc | 5 ++ task.h | 2 + 6 files changed, 233 insertions(+), 88 deletions(-) create mode 100644 build.cc create mode 100644 build.h 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 +#include +#include +#include +#include + +#include "tasks.h" + +using namespace std::chrono_literals; + +int build(const Settings& settings, + const std::string& name, + const std::list>& tasks, + const std::list>& all_tasks) +{ + if(settings.verbose > 1) + { + std::cout << "Building '" << name << "'\n"; + } + + std::list> 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> 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> getDepTasks(std::shared_ptr task) +{ + std::set> 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>& 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> 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 +#include +#include + +#include "task.h" +#include "settings.h" + +int build(const Settings& settings, + const std::string& name, + const std::list>& tasks, + const std::list>& all_tasks); + +int build(const Settings& settings, + const std::string& name, + const std::list>& 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 #include #include -#include #include #include #include @@ -14,7 +13,6 @@ #include #include #include -#include #include @@ -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> 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> 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> 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> getDependsTasks(); + protected: std::atomic task_state{State::Unknown}; virtual int runInner() { return 0; }; -- cgit v1.2.3