From 0159b72dbf048b0aa7d7b9ae85715205cb801e50 Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Sun, 14 Nov 2021 18:06:58 +0100 Subject: Evaluate externals in configure step end read from config map during compilation. --- src/bootstrap.cc | 1 - src/configure.cc | 101 +++++++++++++++++++++++++++++++++++-- src/configure.h | 10 +--- src/libctor.cc | 1 + src/libctor.h | 2 + src/rebuild.cc | 43 ++++++++++++++-- src/rebuild.h | 7 +-- src/task.h | 8 +++ src/task_cc.cc | 5 ++ src/task_cc.h | 2 + src/tasks.cc | 77 +++++++++++++++++++++------- test/suite/ctor_files/ctor.cc.bar | 58 +++++++++++++++++++++ test/suite/ctor_files/ctor.cc.base | 58 +++++++++++++++++++++ test/suite/hello.cc | 6 +++ test/suite/test.sh | 77 ++++++++++++++++++++++++++++ 15 files changed, 416 insertions(+), 40 deletions(-) create mode 100644 test/suite/ctor_files/ctor.cc.bar create mode 100644 test/suite/ctor_files/ctor.cc.base create mode 100644 test/suite/hello.cc create mode 100755 test/suite/test.sh diff --git a/src/bootstrap.cc b/src/bootstrap.cc index 53018cc..0846907 100644 --- a/src/bootstrap.cc +++ b/src/bootstrap.cc @@ -18,7 +18,6 @@ #include "tasks.cc" #include "build.cc" - std::filesystem::path configurationFile("configuration.cc"); std::filesystem::path configHeaderFile("config.h"); diff --git a/src/configure.cc b/src/configure.cc index 13409ef..98f68d7 100644 --- a/src/configure.cc +++ b/src/configure.cc @@ -325,6 +325,17 @@ int regenerateCache(const Settings& default_settings, std::string build_ar = locate(build_arch, ar_prog); std::string build_ld = locate(build_arch, ld_prog); + // TODO: Centralize + // Resolv externals + ExternalConfigurations externalConfigs; + for(std::size_t i = 0; i < numExternalConfigFiles; ++i) + { + auto newExternalConfigs = externalConfigFiles[i].cb(); + externalConfigs.insert(externalConfigs.end(), + newExternalConfigs.begin(), + newExternalConfigs.end()); + } + std::cout << "Writing results to: " << configurationFile.string() << "\n"; { std::ofstream istr(configurationFile); @@ -367,10 +378,76 @@ int regenerateCache(const Settings& default_settings, ctor::libdir = ctor_libdir; } + istr << " },\n"; + istr << " .externals = {\n"; + + for(const auto& externalConfig : externalConfigs) + { + if(!externalConfig.cflags.empty()) + { + istr << " { \"" << externalConfig.name << "-cflags\",\n"; + istr << " {\n"; + for(const auto& cflag : externalConfig.cflags) + { + istr << " \"" << cflag << "\",\n"; + } + istr << " },\n"; + istr << " },\n"; + } + + if(!externalConfig.cxxflags.empty()) + { + istr << " { \"" << externalConfig.name << "-cxxflags\",\n"; + istr << " {\n"; + for(const auto& cxxflag : externalConfig.cxxflags) + { + istr << " \"" << cxxflag << "\",\n"; + } + istr << " },\n"; + istr << " },\n"; + } + + if(!externalConfig.ldflags.empty()) + { + istr << " { \"" << externalConfig.name << "-ldflags\",\n"; + istr << " {\n"; + for(const auto& ldflag : externalConfig.ldflags) + { + istr << " \"" << ldflag << "\",\n"; + } + istr << " },\n"; + istr << " },\n"; + } + + if(!externalConfig.libs.empty()) + { + istr << " { \"" << externalConfig.name << "-libs\",\n"; + istr << " {\n"; + for(const auto& lib : externalConfig.libs) + { + istr << " \"" << lib << "\",\n"; + } + istr << " },\n"; + istr << " },\n"; + } + + if(!externalConfig.asmflags.empty()) + { + istr << " { \"" << externalConfig.name << "-asmflags\",\n"; + istr << " {\n"; + for(const auto& asmflag : externalConfig.asmflags) + { + istr << " \"" << asmflag << "\",\n"; + } + istr << " },\n"; + istr << " },\n"; + } + } + istr << " },\n"; istr << " };\n"; istr << " return cfg;\n"; - istr << "}\n"; + istr << "}\n\n"; } { @@ -424,13 +501,26 @@ int configure(const Settings& global_settings, int argc, char* argv[]) return ret; } - recompileCheck(settings, 1, argv, false); + recompileCheck(settings, argc, argv, false); return 0; } int reconfigure(const Settings& settings, int argc, char* argv[]) { + bool no_rerun{false}; + + std::vector args; + for(int i = 2; i < argc; ++i) // skip executable name and 'reconfigure' arg + { + if(i == 2 && std::string(argv[i]) == "--no-rerun") + { + no_rerun = true; + continue; + } + args.push_back(argv[i]); + } + const auto& cfg = configuration(); std::cout << "Re-running configure:\n"; @@ -451,10 +541,11 @@ int reconfigure(const Settings& settings, int argc, char* argv[]) return ret; } - std::vector args; - for(int i = 2; i < argc; ++i) // skip command and the first 'reconfigure' arg + recompileCheck(settings, 1, argv, false); + + if(no_rerun) { - args.push_back(argv[i]); + return 0; // this was originally invoked by configure, don't loop } return execute(argv[0], args); diff --git a/src/configure.h b/src/configure.h index d9160a5..16499d6 100644 --- a/src/configure.h +++ b/src/configure.h @@ -6,6 +6,7 @@ #include #include #include +#include struct Settings; @@ -14,12 +15,3 @@ extern std::filesystem::path configHeaderFile; int configure(const Settings& settings, int argc, char* argv[]); int reconfigure(const Settings& settings, int argc, char* argv[]); -/* -bool hasConfiguration(const std::string& key); -const std::string& getConfiguration(const std::string& key, - const std::string& defaultValue); - -const std::map& configuration(); - -extern const std::map default_configuration; -*/ diff --git a/src/libctor.cc b/src/libctor.cc index fcd3a95..a2c873e 100644 --- a/src/libctor.cc +++ b/src/libctor.cc @@ -34,6 +34,7 @@ int main(int argc, char* argv[]) settings.builddir = getConfiguration(cfg::builddir, settings.builddir); settings.parallel_processes = std::max(1u, std::thread::hardware_concurrency()) * 2 - 1; + if(argc > 1 && std::string(argv[1]) == "configure") { return configure(settings, argc, argv); diff --git a/src/libctor.h b/src/libctor.h index bcbe3a5..a5fd249 100644 --- a/src/libctor.h +++ b/src/libctor.h @@ -73,6 +73,7 @@ struct ExternalConfiguration std::vector cflags; // flags for c compiler std::vector ldflags; // flags for linker std::vector asmflags; // flags for asm translator + std::vector libs; // libraries }; using ExternalConfigurations = std::vector; @@ -111,6 +112,7 @@ struct Configuration std::map env; // env used when last calling configure std::map tools; // tools + std::map> externals; }; const Configuration& configuration(); diff --git a/src/rebuild.cc b/src/rebuild.cc index fc95b16..ff61695 100644 --- a/src/rebuild.cc +++ b/src/rebuild.cc @@ -13,11 +13,12 @@ #include "libctor.h" #include "tasks.h" #include "build.h" +#include "execute.h" std::array configFiles; std::size_t numConfigFiles{0}; -int reg(std::vector (*cb)(), +int reg(BuildConfigurations (*cb)(), const std::source_location location) { // NOTE: std::cout cannot be used here @@ -96,7 +97,7 @@ int unreg(const char* location) std::array externalConfigFiles; std::size_t numExternalConfigFiles{0}; -int reg(std::vector (*cb)(), +int reg(ExternalConfigurations (*cb)(), const std::source_location location) { // NOTE: std::cout cannot be used here @@ -130,7 +131,7 @@ bool contains(const std::vector& sources, const std::string& file) } } -void recompileCheck(const Settings& global_settings, int argc, char* argv[], +bool recompileCheck(const Settings& global_settings, int argc, char* argv[], bool relaunch_allowed) { using namespace std::string_literals; @@ -207,7 +208,19 @@ void recompileCheck(const Settings& global_settings, int argc, char* argv[], { if(task->registerDepTasks(tasks)) { - return; + return false; + } + } + + // Find out if reconfigure is needed + bool reconfigure{false}; + for(auto task : tasks) + { + if(task->dirty() && + task->source() != "" && // only look at source files + task->source() != "configuration.cc") // don't reconfigure if only configuration.cc is changed. + { + reconfigure |= true; } } @@ -217,4 +230,26 @@ void recompileCheck(const Settings& global_settings, int argc, char* argv[], std::cout << "Rebuilding config.\n"; build(settings, "ctor", tasks); // run for real } + + if(reconfigure) + { + std::vector args; + args.push_back("reconfigure"); + if(!relaunch_allowed) + { + args.push_back("--no-rerun"); + } + for(int i = 1; i < argc; ++i) + { + args.push_back(argv[i]); + } + auto ret = execute(argv[0], args); + //if(ret != 0) + { + exit(ret); + } + + } + + return dirty_tasks; } diff --git a/src/rebuild.h b/src/rebuild.h index f14236e..0845d30 100644 --- a/src/rebuild.h +++ b/src/rebuild.h @@ -13,13 +13,13 @@ class Settings; struct BuildConfigurationEntry { const char* file; - std::vector (*cb)(); + BuildConfigurations (*cb)(); }; struct ExternalConfigurationEntry { const char* file; - std::vector (*cb)(); + ExternalConfigurations (*cb)(); }; extern std::array configFiles; @@ -31,5 +31,6 @@ extern std::size_t numExternalConfigFiles; int reg(const char* location); int unreg(const char* location); -void recompileCheck(const Settings& settings, int argc, char* argv[], +//! Returns true of recompilation was needed. +bool recompileCheck(const Settings& settings, int argc, char* argv[], bool relaunch_allowed = true); diff --git a/src/task.h b/src/task.h index 7068c8a..4cbd126 100644 --- a/src/task.h +++ b/src/task.h @@ -35,10 +35,16 @@ public: virtual int clean() = 0 ; virtual std::vector depends() const = 0; virtual std::string target() const = 0; + + //! Returns true for tasks that are non-target tasks, ie. for example derived + //! objects files from target sources. virtual bool derived() const = 0; virtual std::string toJSON() const { return {}; }; + //! Returns a reference to the originating build config. + //! Note: the build config of a derived task will be that of its parent + //! (target) task. const BuildConfiguration& buildConfig() const; TargetType targetType() const; @@ -48,6 +54,8 @@ public: std::list> getDependsTasks(); + virtual std::string source() const { return {}; } + protected: std::atomic task_state{State::Unknown}; virtual int runInner() { return 0; }; diff --git a/src/task_cc.cc b/src/task_cc.cc index a9be475..61f5977 100644 --- a/src/task_cc.cc +++ b/src/task_cc.cc @@ -236,6 +236,11 @@ std::string TaskCC::toJSON() const return json; } +std::string TaskCC::source() const +{ + return sourceFile.string(); +} + std::vector TaskCC::flags() const { switch(sourceLanguage()) diff --git a/src/task_cc.h b/src/task_cc.h index 0589ea4..c309abd 100644 --- a/src/task_cc.h +++ b/src/task_cc.h @@ -34,6 +34,8 @@ public: std::string toJSON() const override; + std::string source() const override; + protected: std::vector flags() const; std::string flagsString() const; diff --git a/src/tasks.cc b/src/tasks.cc index 8efc98e..8a85fc8 100644 --- a/src/tasks.cc +++ b/src/tasks.cc @@ -16,6 +16,7 @@ #include "task_ar.h" #include "task_so.h" #include "rebuild.h" +#include "configure.h" const std::deque& getTargets(const Settings& settings) { @@ -23,9 +24,9 @@ const std::deque& getTargets(const Settings& settings) static std::deque targets; if(!initialised) { - - // Generate externals - std::vector externalConfigs; + // TODO: Centralize + // Resolv externals + ExternalConfigurations externalConfigs; for(std::size_t i = 0; i < numExternalConfigFiles; ++i) { auto newExternalConfigs = externalConfigFiles[i].cb(); @@ -34,6 +35,7 @@ const std::deque& getTargets(const Settings& settings) newExternalConfigs.end()); } + const auto& extMap = configuration().externals; for(std::size_t i = 0; i < numConfigFiles; ++i) { std::string path = @@ -46,7 +48,6 @@ const std::deque& getTargets(const Settings& settings) for(auto& config : configs) { - // Resolv config externals for(const auto& external : config.externals) { @@ -56,18 +57,60 @@ const std::deque& getTargets(const Settings& settings) if(externalConfig.name == external) { found = true; - config.cflags.insert(config.cflags.end(), - externalConfig.cflags.begin(), - externalConfig.cflags.end()); - config.cxxflags.insert(config.cxxflags.end(), - externalConfig.cxxflags.begin(), - externalConfig.cxxflags.end()); - config.ldflags.insert(config.ldflags.end(), - externalConfig.ldflags.begin(), - externalConfig.ldflags.end()); - config.asmflags.insert(config.asmflags.end(), - externalConfig.asmflags.begin(), - externalConfig.asmflags.end()); + try + { + auto cflags = extMap.at(external+"-cflags"); + config.cflags.insert(config.cflags.end(), + cflags.begin(), + cflags.end()); + } + catch(...) + { + } + + try + { + auto cxxflags = extMap.at(external+"-cxxflags"); + config.cxxflags.insert(config.cxxflags.end(), + cxxflags.begin(), + cxxflags.end()); + } + catch(...) + { + } + + try + { + auto ldflags = extMap.at(external+"-ldflags"); + config.ldflags.insert(config.ldflags.end(), + ldflags.begin(), + ldflags.end()); + } + catch(...) + { + } + + try + { + auto asmflags = extMap.at(external+"-asmflags"); + config.asmflags.insert(config.asmflags.end(), + asmflags.begin(), + asmflags.end()); + } + catch(...) + { + } + + try + { + auto libs = extMap.at(external+"-libs"); + //config.libs.insert(config.libs.end(), + // libs.begin(), + // libs.end()); + } + catch(...) + { + } } } if(!found) @@ -75,10 +118,8 @@ const std::deque& getTargets(const Settings& settings) std::cout << "External '" << external << "' not found.\n"; exit(1); } - } - targets.push_back({config, path}); } } diff --git a/test/suite/ctor_files/ctor.cc.bar b/test/suite/ctor_files/ctor.cc.bar new file mode 100644 index 0000000..2c9df2a --- /dev/null +++ b/test/suite/ctor_files/ctor.cc.bar @@ -0,0 +1,58 @@ +// -*- c++ -*- +// Distributed under the BSD 2-Clause License. +// See accompanying file LICENSE for details. +#include +//#include "config.h" + +namespace +{ +BuildConfigurations ctorConfigs() +{ + return + { + { + .name = "hello", + .target = "hello", + .sources = { + "hello.cc", + }, + .cxxflags = { + "-std=c++20", + "-O3", + "-g", + "-Wall", + "-Werror", + }, + .externals = {"bar"}, + } + }; +} + +ExternalConfigurations ctorExtConfigs() +{ + return + { + { + .name = "bar", + .cxxflags = { "-D_A_", "-DBAR"}, + .cflags = { "-D_B_" }, + .ldflags = { "-D_C_" }, + .asmflags = { "-D_D_" }, + // Creates --with-foo-prefix arg to configure which will be used for + // -L and -I flags. + // If not specified configure will try to find them in the system paths. + }, +// { +// .name = "bar", +// .type = TargetType::ExternalPkgConfig, +// .min_version = "0.1", +// .max_version = "0.9", +// // cflags, cxxflags and ldflags deduced by pkg-config tool (or parsed +// // directly from .pc if faster) +// }, + }; +} +} + +REG(ctorConfigs); +REG(ctorExtConfigs); diff --git a/test/suite/ctor_files/ctor.cc.base b/test/suite/ctor_files/ctor.cc.base new file mode 100644 index 0000000..d9b8e4d --- /dev/null +++ b/test/suite/ctor_files/ctor.cc.base @@ -0,0 +1,58 @@ +// -*- c++ -*- +// Distributed under the BSD 2-Clause License. +// See accompanying file LICENSE for details. +#include +//#include "config.h" + +namespace +{ +BuildConfigurations ctorConfigs() +{ + return + { + { + .name = "hello", + .target = "hello", + .sources = { + "hello.cc", + }, + .cxxflags = { + "-std=c++20", + "-O3", + "-g", + "-Wall", + "-Werror", + }, + .externals = {"bar"}, + } + }; +} + +ExternalConfigurations ctorExtConfigs() +{ + return + { + { + .name = "bar", + .cxxflags = { "-D_A_", "-DFOO"}, + .cflags = { "-D_B_" }, + .ldflags = { "-D_C_" }, + .asmflags = { "-D_D_" }, + // Creates --with-foo-prefix arg to configure which will be used for + // -L and -I flags. + // If not specified configure will try to find them in the system paths. + }, +// { +// .name = "bar", +// .type = TargetType::ExternalPkgConfig, +// .min_version = "0.1", +// .max_version = "0.9", +// // cflags, cxxflags and ldflags deduced by pkg-config tool (or parsed +// // directly from .pc if faster) +// }, + }; +} +} + +REG(ctorConfigs); +REG(ctorExtConfigs); diff --git a/test/suite/hello.cc b/test/suite/hello.cc new file mode 100644 index 0000000..06e3deb --- /dev/null +++ b/test/suite/hello.cc @@ -0,0 +1,6 @@ +#include + +int main() +{ + std::cout << "Hello\n"; +} diff --git a/test/suite/test.sh b/test/suite/test.sh new file mode 100755 index 0000000..8d22206 --- /dev/null +++ b/test/suite/test.sh @@ -0,0 +1,77 @@ +#!/bin/bash + +function fail +{ + echo "*** Failure at line $1" + exit 1 +} + +function ctor +{ + echo "*** Running: ./ctor $*" + ./ctor $* +} + +# Wipe the board +rm -Rf build +rm -f configuration.cc +rm -f ctor + +cp ctor_files/ctor.cc.base ctor.cc + +# Compile bootstrap binary +g++ -pthread -std=c++20 -L../../build -lctor -I../../src ctor.cc -o ctor || fail ${LINENO} + +# No build files should have been created yet +[ -d build ] && fail ${LINENO} + +# capture md5 sum of ctor binary before configure is called +MD5=`md5sum ctor` +ctor configure --ctor-includedir ../../src --ctor-libdir ../../build + +# ctor should be rebuilt at this point, so md5 sum should have changed +(echo $MD5 | md5sum --status -c) && fail ${LINENO} + +# configuration.cc should have been generated now +[ ! -f configuration.cc ] && fail ${LINENO} + +# Shouldn't compile anything yet - only configure +[ -f build/hello-hello_cc.o ] && fail ${LINENO} + +MD5=`md5sum ctor` + +# Run normally to build project +ctor -v + +# Compiled object should now exist +[ ! -f build/hello-hello_cc.o ] && fail ${LINENO} + +# ctor should not have been rebuilt, so md5 sum should be the same +(echo $MD5 | md5sum --status -c) || fail ${LINENO} + +MOD1=`stat -c %Y build/hello-hello_cc.o` +touch hello.cc +sleep 1.1 + +# Run normally to rebuild hello.cc +ctor -v + +# Object file should have been recompiled +MOD2=`stat -c %Y build/hello-hello_cc.o` +[[ $MOD1 == $MOD2 ]] && fail ${LINENO} + +# Replacve -DFOO with -DBAR in foo external.cxxflags +cp ctor_files/ctor.cc.bar ctor.cc + +MD5C=`md5sum configuration.cc` +MD5=`md5sum ctor` +MOD1=`stat -c %Y build/hello-hello_cc.o` +sleep 1.1 + +# Run normally to reconfigure, rebuild ctor and rebuild hello.cc +ctor -v + +MOD2=`stat -c %Y build/hello-hello_cc.o` +[[ $MOD1 == $MOD2 ]] && fail ${LINENO} +(echo $MD5C | md5sum --status -c) && fail ${LINENO} +(echo $MD5 | md5sum --status -c) && fail ${LINENO} -- cgit v1.2.3