diff options
-rw-r--r-- | .gitmodules | 3 | ||||
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | cppbuild.cc | 82 | ||||
m--------- | getoptpp | 0 | ||||
-rw-r--r-- | libcppbuild.cc | 184 | ||||
-rw-r--r-- | libcppbuild.h | 1 | ||||
-rw-r--r-- | settings.h | 1 | ||||
-rw-r--r-- | task.cc | 70 | ||||
-rw-r--r-- | task.h | 21 | ||||
-rw-r--r-- | task_ar.cc | 188 | ||||
-rw-r--r-- | task_ar.h | 42 | ||||
-rw-r--r-- | task_cc.cc | 14 | ||||
-rw-r--r-- | task_cc.h | 4 | ||||
-rw-r--r-- | task_ld.cc | 54 | ||||
-rw-r--r-- | task_ld.h | 5 |
15 files changed, 565 insertions, 106 deletions
diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..1c313f3 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "getoptpp"] + path = getoptpp + url = git://git.drumgizmo.org/getoptpp.git @@ -4,6 +4,8 @@ SRC = \ libcppbuild.cc \ task_cc.cc \ task_ld.cc \ + task_ar.cc \ + task.cc \ execute.cc \ OBJ = $(patsubst %.cc,%.o,$(SRC)) diff --git a/cppbuild.cc b/cppbuild.cc index 370e179..737ba83 100644 --- a/cppbuild.cc +++ b/cppbuild.cc @@ -23,11 +23,8 @@ std::vector<BuildConfiguration> configs() return { { - // target - "plugingui", - - // source files - { + .target = "plugingui", + .sources = { "drumgizmo/src/audiocache.cc", "drumgizmo/src/audiocacheeventhandler.cc", "drumgizmo/src/audiocachefile.cc", @@ -69,6 +66,50 @@ std::vector<BuildConfiguration> configs() "drumgizmo/src/velocityfilter.cc", "drumgizmo/src/versionstr.cc", "drumgizmo/src/zrwrapper.cc", + "drumgizmo/zita-resampler/libs/cresampler.cc", + "drumgizmo/zita-resampler/libs/resampler-table.cc", + "drumgizmo/zita-resampler/libs/resampler.cc", + "drumgizmo/zita-resampler/libs/vresampler.cc", + "drumgizmo/hugin/hugin.c", + "drumgizmo/pugixml/src/pugixml.cpp", + "drumgizmo/plugingui/lodepng/lodepng.cpp", + }, + .depends = { + "plugingui.a", + }, + .cxxflags = { + "-DUI_X11", + "-O3", + "-g", + "-Wall", + "-Werror", + "-std=c++11", + "-Idrumgizmo/getoptpp", + "-Idrumgizmo/", + "-Idrumgizmo/hugin", + "-Idrumgizmo/plugingui/", + "-Idrumgizmo/src/", + "-Idrumgizmo/zita-resampler/libs", + "-Idrumgizmo/pugixml/src", + }, + .cflags = { + "-g", + //"-O3", + "-Wall", + "-Werror", + }, + .ldflags = { + "-lm", + "-lX11", + "-lXext", + "-lsndfile", + "-pthread", + } + }, + + { + .target = "plugingui.a", + .sources = { "drumgizmo/plugingui/abouttab.cc", "drumgizmo/plugingui/bleedcontrolframecontent.cc", "drumgizmo/plugingui/button.cc", @@ -130,18 +171,11 @@ std::vector<BuildConfiguration> configs() "drumgizmo/plugingui/voicelimitframecontent.cc", "drumgizmo/plugingui/widget.cc", "drumgizmo/plugingui/window.cc", - "drumgizmo/zita-resampler/libs/cresampler.cc", - "drumgizmo/zita-resampler/libs/resampler-table.cc", - "drumgizmo/zita-resampler/libs/resampler.cc", - "drumgizmo/zita-resampler/libs/vresampler.cc", - "drumgizmo/hugin/hugin.c", - "drumgizmo/pugixml/src/pugixml.cpp", - "drumgizmo/plugingui/lodepng/lodepng.cpp", }, - - // cxx flags - { + .depends = {}, + .cxxflags = { "-DUI_X11", + "-O3", "-g", "-Wall", "-Werror", @@ -154,22 +188,8 @@ std::vector<BuildConfiguration> configs() "-Idrumgizmo/zita-resampler/libs", "-Idrumgizmo/pugixml/src", }, - - // c flags - { - "-g", - "-Wall", - "-Werror", - }, - - // linker flags - { - "-lm", - "-lX11", - "-lXext", - "-pthread", - "-lsndfile", - } + .cflags = {}, + .ldflags = {} }, }; } diff --git a/getoptpp b/getoptpp new file mode 160000 +Subproject 9ff20ef857429619267e3f156a4f81ad9e1eb8c diff --git a/libcppbuild.cc b/libcppbuild.cc index bf1a7fa..7f0a355 100644 --- a/libcppbuild.cc +++ b/libcppbuild.cc @@ -7,16 +7,67 @@ #include <chrono> #include <thread> #include <memory> +#include <algorithm> +#include <list> #include "libcppbuild.h" #include "task_cc.h" #include "task_ld.h" +#include "task_ar.h" #include "settings.h" #include <unistd.h> using namespace std::chrono_literals; +std::list<std::shared_ptr<Task>> taskFactory(const BuildConfiguration& config, + const Settings& settings) +{ + std::vector<std::string> objects; + std::list<std::shared_ptr<Task>> tasks; + for(const auto& file : config.sources) + { + tasks.emplace_back(std::make_shared<TaskCC>(config, settings, file)); + objects.push_back(tasks.back()->target()); + } + + std::filesystem::path targetFile(config.target); + if(targetFile.extension() == ".a") + { + // static lib + tasks.emplace_back(std::make_shared<TaskAR>(config, settings, config.target, + objects)); + } + else + { + // binary + tasks.emplace_back(std::make_shared<TaskLD>(config, settings, config.target, + objects)); + + } + + return tasks; +} + +std::shared_ptr<Task> getNextTask(const std::list<std::shared_ptr<Task>>& allTasks, + std::list<std::shared_ptr<Task>>& dirtyTasks) +{ + for(auto dirtyTask = dirtyTasks.begin(); + dirtyTask != dirtyTasks.end(); + ++dirtyTask) + { + //std::cout << "Examining target " << (*dirtyTask)->target() << "\n"; + if((*dirtyTask)->ready()) + { + dirtyTasks.erase(dirtyTask); + return *dirtyTask; + } + } + + //std::cout << "No task ready ... \n"; + return nullptr; +} + int main(int argc, const char* argv[]) { Settings settings; @@ -27,84 +78,79 @@ int main(int argc, const char* argv[]) settings.parallel_processes = std::max(1u, std::thread::hardware_concurrency() * 2 - 1); + settings.verbose = 0; + std::filesystem::path builddir(settings.builddir); std::filesystem::create_directories(builddir); auto build_configs = configs(); + std::list<std::shared_ptr<Task>> tasks; for(const auto& build_config : build_configs) { std::vector<std::string> objects; - std::vector<std::unique_ptr<Task>> tasks; - for(const auto& file : build_config.sources) - { - tasks.emplace_back(std::make_unique<TaskCC>(build_config, settings, file)); - objects.push_back(tasks.back()->target()); - } + auto t = taskFactory(build_config, settings); + tasks.insert(tasks.end(), t.begin(), t.end()); + } - TaskLD task_ld(build_config, settings, build_config.target, objects); + for(auto task : tasks) + { + task->registerDepTasks(tasks); + } - if(argc == 2 && std::string(argv[1]) == "clean") + std::list<std::shared_ptr<Task>> dirtyTasks; + for(auto task : tasks) + { + if(task->dirty()) { - std::cout << "Cleaning\n"; - //std::filesystem::remove_all(builddir); - for(auto& task : tasks) - { - if(task->clean() != 0) - { - return 1; - } - } + dirtyTasks.push_back(task); + } + } - if(task_ld.clean() != 0) + if(argc == 2 && std::string(argv[1]) == "clean") + { + std::cout << "Cleaning\n"; + //std::filesystem::remove_all(builddir); + for(auto& task : tasks) + { + if(task->clean() != 0) { return 1; } - - return 0; } - std::cout << "Building\n"; + return 0; + } - std::list<std::future<int>> processes; + std::cout << "Building\n"; + std::list<std::future<int>> processes; - // Start all tasks - auto task = tasks.begin(); - while(task != tasks.end()) + // Start all tasks + bool done{false}; + while(!done) + { + bool started_one{false}; + while(processes.size() < settings.parallel_processes) { - while(processes.size() < settings.parallel_processes && - task != tasks.end()) + if(dirtyTasks.empty()) { - if(!(*task)->dirty()) - { - ++task; - continue; - } - - processes.emplace_back( - std::async(std::launch::async, - [&t = *task]() - { - return t->run(); - })); - ++task; - std::this_thread::sleep_for(2ms); + done = true; + break; } - for(auto process = processes.begin(); - process != processes.end(); - ++process) + auto task = getNextTask(tasks, dirtyTasks); + if(task == nullptr) { - if(process->valid()) - { - if(process->get() != 0) - { - return 1; - } - processes.erase(process); - break; - } + break; + //return 1; } + processes.emplace_back( + std::async(std::launch::async, + [task]() + { + return task->run(); + })); + started_one = true; std::this_thread::sleep_for(2ms); } @@ -112,18 +158,36 @@ int main(int argc, const char* argv[]) process != processes.end(); ++process) { - process->wait(); - auto ret = process->get(); - if(ret != 0) + if(process->valid()) { - return 1; + if(process->get() != 0) + { + return 1; + } + processes.erase(process); + break; } } - std::cout << "Linking\n"; - if(task_ld.dirty()) + 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 task_ld.run(); + return 1; } } diff --git a/libcppbuild.h b/libcppbuild.h index 6cc04ac..50b4459 100644 --- a/libcppbuild.h +++ b/libcppbuild.h @@ -8,6 +8,7 @@ struct BuildConfiguration { std::string target; std::vector<std::string> sources; + std::vector<std::string> depends; std::vector<std::string> cxxflags; std::vector<std::string> cflags; std::vector<std::string> ldflags; @@ -7,4 +7,5 @@ struct Settings { std::string builddir; std::size_t parallel_processes; + int verbose{1}; }; @@ -0,0 +1,70 @@ +#include "task.h" + +#include <unistd.h> +#include <iostream> + +Task::Task(const std::vector<std::string>& depends) + : dependsStr(depends) +{ +} + +void Task::registerDepTasks(const std::list<std::shared_ptr<Task>>& tasks) +{ + for(auto const& depStr : dependsStr) + { + for(const auto& task : tasks) + { + if(task->target() == depStr) + { + dependsTasks.push_back(task); + } + } + } +} + +bool Task::dirty() +{ + for(const auto& task : dependsTasks) + { + if(task->dirty()) + { + return true; + } + } + + return dirtyInner(); +} + +bool Task::ready() +{ + for(const auto& task : dependsTasks) + { + if(task->dirty() && !task->done()) + { + return false; + } + } + + return true; +} + +int Task::run() +{ + if(is_done.load()) + { + return 0; + } + + auto ret = runInner(); + if(ret == 0) + { + is_done.store(true); + } + + return ret; +} + +bool Task::done() const +{ + return is_done.load(); +} @@ -3,13 +3,30 @@ #include <vector> #include <string> +#include <atomic> +#include <list> +#include <memory> class Task { public: - virtual bool dirty() = 0; - virtual int run() = 0; + Task(const std::vector<std::string>& depends); + + void registerDepTasks(const std::list<std::shared_ptr<Task>>& tasks); + + bool dirty(); + bool ready(); + int run(); + bool done() const; virtual int clean() = 0 ; virtual std::vector<std::string> depends() const = 0; virtual std::string target() const = 0; + +protected: + std::atomic<bool> is_done{false}; + virtual int runInner() { return 0; }; + virtual bool dirtyInner() { return false; } + + std::vector<std::string> dependsStr; + std::list<std::shared_ptr<Task>> dependsTasks; }; diff --git a/task_ar.cc b/task_ar.cc new file mode 100644 index 0000000..c133875 --- /dev/null +++ b/task_ar.cc @@ -0,0 +1,188 @@ +#include "task_ar.h" + +#include <iostream> +#include <fstream> + +#include "libcppbuild.h" +#include "settings.h" +#include "execute.h" + +namespace +{ +std::string readFile(const std::string &fileName) +{ + std::ifstream ifs(fileName.c_str(), + std::ios::in | std::ios::binary | std::ios::ate); + + std::ifstream::pos_type fileSize = ifs.tellg(); + ifs.seekg(0, std::ios::beg); + + std::vector<char> bytes(fileSize); + ifs.read(bytes.data(), fileSize); + + return std::string(bytes.data(), fileSize); +} + +std::vector<std::string> addPrefix(const std::vector<std::string>& lst, + const Settings& settings) +{ + std::vector<std::string> out; + for(const auto& item : lst) + { + std::filesystem::path file = settings.builddir; + file /= item; + out.push_back(file.string()); + } + return out; +} +} // namespace :: + +TaskAR::TaskAR(const BuildConfiguration& config, + const Settings& settings, + const std::string& target, + const std::vector<std::string>& objects) + : Task(addPrefix(config.depends, settings)) + , config(config) + , settings(settings) +{ + targetFile = settings.builddir; + targetFile /= target; + for(const auto& object : objects) + { + std::filesystem::path objectFile = object; + objectFiles.push_back(objectFile); + dependsStr.push_back(objectFile); + } + + for(const auto& dep : config.depends) + { + std::filesystem::path depFile = settings.builddir; + depFile /= dep; + depFiles.push_back(depFile); + } + + flagsFile = settings.builddir / targetFile.stem(); + flagsFile += ".flags"; +} + +bool TaskAR::dirtyInner() +{ + if(!std::filesystem::exists(targetFile)) + { + return true; + } + + if(!std::filesystem::exists(flagsFile)) + { + return true; + } + + for(const auto& objectFile : objectFiles) + { + if(std::filesystem::last_write_time(targetFile) <= + std::filesystem::last_write_time(objectFile)) + { + return true; + } + } + + { + auto lastFlags = readFile(flagsFile); + if(flagsString() != lastFlags) + { + //std::cout << "The compiler flags changed\n"; + return true; + } + } + + return false; +} + +int TaskAR::runInner() +{ + std::string objectlist; + for(const auto& objectFile : objectFiles) + { + if(!objectlist.empty()) + { + objectlist += " "; + } + objectlist += std::string(objectFile); + } + + std::vector<std::string> args; + args.push_back("rcs"); + args.push_back(std::string(targetFile)); + for(const auto& objectFile : objectFiles) + { + args.push_back(std::string(objectFile)); + } + for(const auto& flag : config.ldflags) + { + args.push_back(flag); + } + + { // Write flags to file. + std::ofstream flagsStream(flagsFile); + flagsStream << flagsString(); + } + + if(settings.verbose == 0) + { + std::cout << "AR => " << targetFile.string() << "\n"; + } + + return execute("/usr/bin/ar", args, settings.verbose > 0); +} + +int TaskAR::clean() +{ + if(std::filesystem::exists(targetFile)) + { + std::cout << "Removing " << std::string(targetFile) << "\n"; + std::filesystem::remove(targetFile); + } + + if(std::filesystem::exists(flagsFile)) + { + std::cout << "Removing " << std::string(flagsFile) << "\n"; + std::filesystem::remove(flagsFile); + } + + return 0; +} + +std::vector<std::string> TaskAR::depends() const +{ + std::vector<std::string> deps; + for(const auto& objectFile : objectFiles) + { + deps.push_back(objectFile.string()); + } + + for(const auto& depFile : depFiles) + { + deps.push_back(depFile.string()); + } + + return deps; +} + +std::string TaskAR::target() const +{ + return targetFile.string(); +} + +std::string TaskAR::flagsString() const +{ + std::string flagsStr; + for(const auto& flag : config.ldflags) + { + if(!flagsStr.empty()) + { + flagsStr += " "; + } + flagsStr += flag; + } + return flagsStr; +} diff --git a/task_ar.h b/task_ar.h new file mode 100644 index 0000000..bfa21a2 --- /dev/null +++ b/task_ar.h @@ -0,0 +1,42 @@ +// -*- c++ -*- +#pragma once + +#include "task.h" + +#include <vector> +#include <string> +#include <future> +#include <filesystem> + +struct BuildConfiguration; +struct Settings; + +class TaskAR + : public Task +{ +public: + TaskAR(const BuildConfiguration& config, + const Settings& settings, + const std::string& target, + const std::vector<std::string>& objects); + + bool dirtyInner() override; + + int runInner() override; + int clean() override; + + std::vector<std::string> depends() const override; + + std::string target() const override; + +private: + std::string flagsString() const; + + std::vector<std::filesystem::path> objectFiles; + std::vector<std::filesystem::path> depFiles; + std::filesystem::path targetFile; + std::filesystem::path flagsFile; + + const BuildConfiguration& config; + const Settings& settings; +}; @@ -85,7 +85,8 @@ std::vector<std::string> readDeps(const std::string& depFile) TaskCC::TaskCC(const BuildConfiguration& config, const Settings& settings, const std::string& source) - : config(config) + : Task({}) + , config(config) , settings(settings) { sourceFile = source; @@ -100,7 +101,7 @@ TaskCC::TaskCC(const BuildConfiguration& config, const Settings& settings, flagsFile += ".flags"; } -bool TaskCC::dirty() +bool TaskCC::dirtyInner() { if(!std::filesystem::exists(sourceFile)) { @@ -164,7 +165,7 @@ bool TaskCC::dirty() return false; } -int TaskCC::run() +int TaskCC::runInner() { if(!std::filesystem::exists(sourceFile)) { @@ -192,7 +193,12 @@ int TaskCC::run() flagsStream << flagsString(); } - return execute(comp, args); + if(settings.verbose == 0) + { + std::cout << compiler() << " " << sourceFile.string() << " => " << + targetFile.string() << "\n"; + } + return execute(comp, args, settings.verbose > 0); } int TaskCC::clean() @@ -19,9 +19,9 @@ public: const Settings& settings, const std::string& source); - bool dirty() override; + bool dirtyInner() override; - int run() override; + int runInner() override; int clean() override; std::vector<std::string> depends() const override; @@ -21,13 +21,27 @@ std::string readFile(const std::string &fileName) return std::string(bytes.data(), fileSize); } + +std::vector<std::string> addPrefix(const std::vector<std::string>& lst, + const Settings& settings) +{ + std::vector<std::string> out; + for(const auto& item : lst) + { + std::filesystem::path file = settings.builddir; + file /= item; + out.push_back(file.string()); + } + return out; +} } // namespace :: TaskLD::TaskLD(const BuildConfiguration& config, const Settings& settings, const std::string& target, const std::vector<std::string>& objects) - : config(config) + : Task(addPrefix(config.depends, settings)) + , config(config) , settings(settings) { targetFile = settings.builddir; @@ -36,13 +50,21 @@ TaskLD::TaskLD(const BuildConfiguration& config, { std::filesystem::path objectFile = object; objectFiles.push_back(objectFile); + dependsStr.push_back(objectFile); + } + + for(const auto& dep : config.depends) + { + std::filesystem::path depFile = settings.builddir; + depFile /= dep; + depFiles.push_back(depFile); } flagsFile = settings.builddir / targetFile.stem(); flagsFile += ".flags"; } -bool TaskLD::dirty() +bool TaskLD::dirtyInner() { if(!std::filesystem::exists(targetFile)) { @@ -75,7 +97,7 @@ bool TaskLD::dirty() return false; } -int TaskLD::run() +int TaskLD::runInner() { std::string objectlist; for(const auto& objectFile : objectFiles) @@ -92,6 +114,12 @@ int TaskLD::run() { args.push_back(std::string(objectFile)); } + + for(const auto& depFile : depFiles) + { + args.push_back(depFile.string()); + } + for(const auto& flag : config.ldflags) { args.push_back(flag); @@ -104,7 +132,12 @@ int TaskLD::run() flagsStream << flagsString(); } - return execute("/usr/bin/g++", args); + if(settings.verbose == 0) + { + std::cout << "LD => " << targetFile.string() << "\n"; + } + + return execute("/usr/bin/g++", args, settings.verbose > 0); } int TaskLD::clean() @@ -126,7 +159,18 @@ int TaskLD::clean() std::vector<std::string> TaskLD::depends() const { - return {}; + std::vector<std::string> deps; + for(const auto& objectFile : objectFiles) + { + deps.push_back(objectFile.string()); + } + + for(const auto& depFile : depFiles) + { + deps.push_back(depFile.string()); + } + + return deps; } std::string TaskLD::target() const @@ -20,9 +20,9 @@ public: const std::string& target, const std::vector<std::string>& objects); - bool dirty() override; + bool dirtyInner() override; - int run() override; + int runInner() override; int clean() override; std::vector<std::string> depends() const override; @@ -33,6 +33,7 @@ private: std::string flagsString() const; std::vector<std::filesystem::path> objectFiles; + std::vector<std::filesystem::path> depFiles; std::filesystem::path targetFile; std::filesystem::path flagsFile; |