From c0eacf8e85003844b95e71b9004fa464d4586a38 Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Thu, 14 Oct 2021 22:19:26 +0200 Subject: Use dependency system and build system for compiling ctor on config changes. --- bootstrap.sh | 5 ++- src/build.cc | 5 ++- src/configure.cc | 7 +--- src/configure.h | 4 +- src/libctor.cc | 21 ++++++---- src/libctor.h | 15 +++----- src/rebuild.cc | 110 ++++++++++++++++++++++++----------------------------- src/settings.h | 6 +-- src/task.cc | 7 +++- src/task_cc.cc | 27 ++++++++++++- src/tasks.cc | 3 -- src/tasks.h | 6 +++ test/ctor.cc | 3 ++ test/tasks_test.cc | 22 +++++------ 14 files changed, 136 insertions(+), 105 deletions(-) diff --git a/bootstrap.sh b/bootstrap.sh index fd9b605..06cd903 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -1,6 +1,7 @@ #!/bin/sh echo "Bootstrapping..." -g++ -std=c++17 -O3 -Isrc -pthread src/bootstrap.cc ctor.cc test/ctor.cc -o ctor && \ +g++ -std=c++17 -Wall -O3 -Isrc -pthread src/bootstrap.cc ctor.cc test/ctor.cc -o ctor && \ ./ctor && \ -g++ -std=c++17 -O3 -Isrc -pthread ctor.cc test/ctor.cc -Lbuild -lctor -o ctor && \ +g++ -std=c++17 -Wall -O3 -Isrc -pthread ctor.cc test/ctor.cc -Lbuild -lctor -o ctor && \ +./ctor configure --ctor-includedir=src --ctor-libdir=build && \ echo "Done. Now run ./ctor to (re)build." diff --git a/src/build.cc b/src/build.cc index 777f5e8..2412b84 100644 --- a/src/build.cc +++ b/src/build.cc @@ -33,7 +33,10 @@ int build(const Settings& settings, if(dirtyTasks.empty()) { - std::cout << "Nothing to be done for '"<< name << "'\n"; + if(settings.verbose > -1) + { + std::cout << "Nothing to be done for '"<< name << "'\n"; + } return 0; } diff --git a/src/configure.cc b/src/configure.cc index 9eca0d6..675699d 100644 --- a/src/configure.cc +++ b/src/configure.cc @@ -120,12 +120,9 @@ std::string locate(const std::string& arch, const std::string& app) return {}; } -int configure(int argc, char* argv[]) +int configure(const Settings& global_settings, int argc, char* argv[]) { - Settings settings; - - settings.builddir = "build"; - + Settings settings{global_settings}; std::string cmd_str; for(int i = 0; i < argc; ++i) { diff --git a/src/configure.h b/src/configure.h index de1b7e0..a350820 100644 --- a/src/configure.h +++ b/src/configure.h @@ -7,10 +7,12 @@ #include #include +struct Settings; + extern std::filesystem::path configurationFile;; extern std::filesystem::path configHeaderFile; -int configure(int argc, char* argv[]); +int configure(const Settings& settings, int argc, char* argv[]); bool hasConfiguration(const std::string& key); const std::string& getConfiguration(const std::string& key, diff --git a/src/libctor.cc b/src/libctor.cc index 4d0d6d9..ca60de2 100644 --- a/src/libctor.cc +++ b/src/libctor.cc @@ -26,19 +26,19 @@ #include "tasks.h" #include "build.h" #include "unittest.h" + int main(int argc, char* argv[]) { - if(argc > 1 && std::string(argv[1]) == "configure") - { - return configure(argc, argv); - } - Settings settings{}; - settings.builddir = getConfiguration(cfg::builddir, "build"); + settings.builddir = getConfiguration(cfg::builddir, settings.builddir); settings.parallel_processes = std::max(1u, std::thread::hardware_concurrency() * 2 - 1); - settings.verbose = 0; + + if(argc > 1 && std::string(argv[1]) == "configure") + { + return configure(settings, argc, argv); + } bool write_compilation_database{false}; std::string compilation_database; @@ -85,6 +85,13 @@ int main(int argc, char* argv[]) return 0; }); + opt.add("quiet", no_argument, 'q', + "Be completely silent.", + [&]() { + settings.verbose = -1; + return 0; + }); + opt.add("add", required_argument, 'a', "Add specified file to the build configurations.", [&]() { diff --git a/src/libctor.h b/src/libctor.h index 6026ffb..5c22614 100644 --- a/src/libctor.h +++ b/src/libctor.h @@ -35,14 +35,10 @@ enum class OutputSystem struct Source { - Source(const char* file) - : file(file) {} - Source(const std::string& file) - : file(file) {} - Source(const char* file, Language language) - : file(file), language(language) {} - Source(const std::string& file, Language language) - : file(file), language(language) {} + Source(const char* file) : file(file) {} + Source(const std::string& file) : file(file) {} + Source(const char* file, Language lang) : file(file), language(lang) {} + Source(const std::string& file, Language lang) : file(file), language(lang) {} std::string file; Language language{Language::Auto}; @@ -50,9 +46,10 @@ struct Source struct BuildConfiguration { + std::string name; // Name - used for referring in other configurations. TargetType type{TargetType::Auto}; OutputSystem system{OutputSystem::Host}; - std::string target; + std::string target; // Output target file for this configuration std::vector sources; // source list std::vector depends; // internal dependencies std::vector cxxflags; // flags for c++ compiler diff --git a/src/rebuild.cc b/src/rebuild.cc index 7c90fca..e017d92 100644 --- a/src/rebuild.cc +++ b/src/rebuild.cc @@ -7,10 +7,11 @@ #include #include -#include "execute.h" #include "configure.h" #include "settings.h" #include "libctor.h" +#include "tasks.h" +#include "build.h" std::array configFiles; std::size_t numConfigFiles{0}; @@ -57,100 +58,87 @@ int unreg(const char* location) return found; } -void recompileCheck(const Settings& settings, int argc, char* argv[], +namespace +{ +bool contains(const std::vector& sources, const std::string& file) +{ + for(const auto& source : sources) + { + if(source.file == file) + { + return true; + } + } + + return false; +} +} + +void recompileCheck(const Settings& global_settings, int argc, char* argv[], bool force, bool relaunch_allowed) { using namespace std::string_literals; - bool dirty{force}; + if(global_settings.verbose > 1) + { + std::cout << "Recompile check (" << numConfigFiles << "):\n"; + } - std::vector args; - args.push_back("-s"); - args.push_back("-O3"); - args.push_back("-std=c++17"); + BuildConfiguration config; + config.name = "ctor"; + config.cxxflags = std::vector({ "-s", "-O3", "-std=c++17" }); if(hasConfiguration(cfg::ctor_includedir)) { - args.push_back("-I"s + getConfiguration(cfg::ctor_includedir)); + config.cxxflags.push_back("-I"s + getConfiguration(cfg::ctor_includedir)); } if(hasConfiguration(cfg::ctor_libdir)) { - args.push_back("-L"s + getConfiguration(cfg::ctor_libdir)); + config.ldflags.push_back("-L"s + getConfiguration(cfg::ctor_libdir)); } - args.push_back("-lctor"); - args.push_back("-pthread"); + config.ldflags.push_back("-lctor"); + config.ldflags.push_back("-pthread"); - std::filesystem::path binFile(argv[0]); - if(std::filesystem::exists(configurationFile)) - { - args.push_back(configurationFile.string()); + Settings settings{global_settings}; + settings.verbose = -1; // Make check completely silent. + settings.builddir += "/ctor"; // override builddir to use ctor subdir - if(std::filesystem::last_write_time(binFile) <= - std::filesystem::last_write_time(configurationFile)) - { - dirty = true; - } - - const auto& c = configuration(); - if(&c == &default_configuration) - { - // configuration.cc exists, but currently compiled with the default one. - dirty = true; - } + { + std::filesystem::path buildfile = settings.builddir; + std::filesystem::path currentfile = argv[0]; + config.target = std::filesystem::relative(currentfile, buildfile).string(); } - if(settings.verbose > 1) + if(std::filesystem::exists(configurationFile)) { - std::cout << "Recompile check (" << numConfigFiles << "):\n"; + config.sources.push_back(configurationFile.string()); } for(std::size_t i = 0; i < numConfigFiles; ++i) { std::string location = configFiles[i].file; - if(settings.verbose > 1) + if(global_settings.verbose > 1) { std::cout << " - " << location << "\n"; } - std::filesystem::path configFile(location); - if(std::filesystem::last_write_time(binFile) <= - std::filesystem::last_write_time(configFile)) - { - dirty = true; - } - // Support adding multiple config functions from the same file - if(std::find(args.begin(), args.end(), location) == std::end(args)) + // Ensure that files containing multiple configurations are only added once. + if(!contains(config.sources, location)) { - args.push_back(location); + config.sources.push_back(location); } } - args.push_back("-o"); - args.push_back(binFile.string()); + auto tasks = taskFactory({config}, settings, {}); - if(dirty) + for(auto task : tasks) { - std::cout << "Rebuilding config\n"; - auto tool = getConfiguration(cfg::build_cxx, "/usr/bin/g++"); - auto ret = execute(tool, args, settings.verbose > 0); - if(ret != 0) + if(task->registerDepTasks(tasks)) { - std::cerr << "Failed: ." << ret << "\n"; - exit(1); - } - else - { - if(relaunch_allowed) - { - std::cout << "Re-launch\n"; - std::vector args; - for(int i = 1; i < argc; ++i) - { - args.push_back(argv[i]); - } - exit(execute(argv[0], args, settings.verbose > 0)); - } + return; } } + + build(settings, "ctor", tasks); } diff --git a/src/settings.h b/src/settings.h index d71717a..48e3619 100644 --- a/src/settings.h +++ b/src/settings.h @@ -7,7 +7,7 @@ struct Settings { - std::string builddir; - std::size_t parallel_processes; - int verbose{1}; + std::string builddir{"build"}; + std::size_t parallel_processes{1}; + int verbose{0}; // -1: completely silent, 0: normal, 1: verbose, ... }; diff --git a/src/task.cc b/src/task.cc index 1c6c233..8a9eefa 100644 --- a/src/task.cc +++ b/src/task.cc @@ -38,7 +38,12 @@ int Task::registerDepTasks(const std::list>& tasks) std::string Task::name() const { - return config.target; + // If config name is not set, use target instead. + if(config.name.empty()) + { + return config.target; + } + return config.name; } bool Task::dirty() diff --git a/src/task_cc.cc b/src/task_cc.cc index 73297f2..e4bd7aa 100644 --- a/src/task_cc.cc +++ b/src/task_cc.cc @@ -12,6 +12,31 @@ #include "execute.h" #include "util.h" +namespace +{ +bool isClean(char c) +{ + return c != '.' && c != '/'; +} + +std::string cleanUp(const std::string& path) +{ + std::string cleaned; + for(const auto& c : path) + { + if(isClean(c)) + { + cleaned += c; + } + else + { + cleaned += '_'; + } + } + return cleaned; +} +} + TaskCC::TaskCC(const BuildConfiguration& config, const Settings& settings, const std::string& sourceDir, const Source& source) : Task(config) @@ -26,7 +51,7 @@ TaskCC::TaskCC(const BuildConfiguration& config, const Settings& settings, base /= sourceFile.parent_path(); std::filesystem::create_directories(base); - base /= config.target; + base /= cleanUp(config.target); base += "-"; base += sourceFile.stem(); diff --git a/src/tasks.cc b/src/tasks.cc index c280fb2..56988f9 100644 --- a/src/tasks.cc +++ b/src/tasks.cc @@ -43,8 +43,6 @@ const std::deque& getTargets(const Settings& settings) return targets; } -namespace -{ std::list> taskFactory(const BuildConfiguration& config, const Settings& settings, const std::string& sourceDir) @@ -121,7 +119,6 @@ std::list> taskFactory(const BuildConfiguration& config, return tasks; } -} std::shared_ptr getNextTask(const std::list>& allTasks, std::list>& dirtyTasks) diff --git a/src/tasks.h b/src/tasks.h index 54591a4..aaa3510 100644 --- a/src/tasks.h +++ b/src/tasks.h @@ -33,3 +33,9 @@ std::shared_ptr getNextTask(const std::list>& allTas //! dependency tasks (ie. objects tasks from their sources). std::list> getTasks(const Settings& settings, const std::vector names = {}); + +//! Generate list of targets from a single configuration, including the final +//! link target and all its objects files (if any). +std::list> taskFactory(const BuildConfiguration& config, + const Settings& settings, + const std::string& sourceDir); diff --git a/test/ctor.cc b/test/ctor.cc index 3d05e7f..61c3515 100644 --- a/test/ctor.cc +++ b/test/ctor.cc @@ -22,6 +22,7 @@ BuildConfigurations ctorTestConfigs() "-I../src", "-Iuunit", "-DOUTPUT=\"execute\"", }, + .ldflags = { "-pthread" }, }, { .type = TargetType::UnitTest, @@ -36,6 +37,7 @@ BuildConfigurations ctorTestConfigs() "-I../src", "-Iuunit", "-DOUTPUT=\"tasks\"", }, + .ldflags = { "-pthread" }, }, { .type = TargetType::UnitTest, @@ -50,6 +52,7 @@ BuildConfigurations ctorTestConfigs() "-I../src", "-Iuunit", "-DOUTPUT=\"source_type\"", }, + .ldflags = { "-pthread" }, }, }; } diff --git a/test/tasks_test.cc b/test/tasks_test.cc index 612d899..3c9243c 100644 --- a/test/tasks_test.cc +++ b/test/tasks_test.cc @@ -95,34 +95,34 @@ public: void getTasks_test() { using namespace std::string_literals; - Settings settings{}; + Settings settings{ .builddir = "foo" }; { auto tasks = getTasks(settings); uASSERT_EQUAL(6u, tasks.size()); auto task = tasks.begin(); - uASSERT_EQUAL("test/target1-foo_cc.o"s, (*task)->target()); + uASSERT_EQUAL("foo/test/target1-foo_cc.o"s, (*task)->target()); task++; - uASSERT_EQUAL("test/target1-bar_c.o"s, (*task)->target()); + uASSERT_EQUAL("foo/test/target1-bar_c.o"s, (*task)->target()); task++; - uASSERT_EQUAL("test/target1"s, (*task)->target()); + uASSERT_EQUAL("foo/test/target1"s, (*task)->target()); task++; - uASSERT_EQUAL("test/target2"s, (*task)->target()); + uASSERT_EQUAL("foo/test/target2"s, (*task)->target()); task++; - uASSERT_EQUAL("test/target3"s, (*task)->target()); + uASSERT_EQUAL("foo/test/target3"s, (*task)->target()); task++; - uASSERT_EQUAL("test/target4"s, (*task)->target()); + uASSERT_EQUAL("foo/test/target4"s, (*task)->target()); } { auto tasks = getTasks(settings, {"target1", "target3"}); uASSERT_EQUAL(4u, tasks.size()); auto task = tasks.begin(); - uASSERT_EQUAL("test/target1-foo_cc.o"s, (*task)->target()); + uASSERT_EQUAL("foo/test/target1-foo_cc.o"s, (*task)->target()); task++; - uASSERT_EQUAL("test/target1-bar_c.o"s, (*task)->target()); + uASSERT_EQUAL("foo/test/target1-bar_c.o"s, (*task)->target()); task++; - uASSERT_EQUAL("test/target1"s, (*task)->target()); + uASSERT_EQUAL("foo/test/target1"s, (*task)->target()); task++; - uASSERT_EQUAL("test/target3"s, (*task)->target()); + uASSERT_EQUAL("foo/test/target3"s, (*task)->target()); } { auto tasks = getTasks(settings, {"no-such-target"}); -- cgit v1.2.3