From c53e622b648635539e4870fd0c9159c5d8c3be4a Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Sun, 20 Jun 2021 20:21:58 +0200 Subject: Introduction of configuration generation for controlling tool-chain. --- libcppbuild.cc | 163 ++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 137 insertions(+), 26 deletions(-) (limited to 'libcppbuild.cc') diff --git a/libcppbuild.cc b/libcppbuild.cc index 927fe72..1fa1bc3 100644 --- a/libcppbuild.cc +++ b/libcppbuild.cc @@ -25,6 +25,35 @@ #include + +namespace +{ +std::filesystem::path configurationFile("configuration.cc"); +const std::map default_configuration{}; +} +const std::map& __attribute__((weak)) configuration() +{ + return default_configuration; +} + +bool hasConfiguration(const std::string& key) +{ + const auto& c = configuration(); + return c.find(key) != c.end(); +} + +const std::string& getConfiguration(const std::string& key, + const std::string& defaultValue) +{ + const auto& c = configuration(); + if(hasConfiguration(key)) + { + return c.at(key); + } + + return defaultValue; +} + using namespace std::chrono_literals; std::list> taskFactory(const BuildConfiguration& config, @@ -151,6 +180,24 @@ void recompileCheck(const Settings& settings, int argc, char* argv[]) std::filesystem::path binFile("cppbuild"); + if(std::filesystem::exists(configurationFile)) + { + args.push_back(configurationFile.string()); + + 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; + } + } + if(settings.verbose > 1) { std::cout << "Recompile check (" << numConfigFiles << "):\n"; @@ -183,10 +230,11 @@ void recompileCheck(const Settings& settings, int argc, char* argv[]) if(dirty) { std::cout << "Rebuilding config\n"; - auto ret = execute("/usr/bin/g++", args); + auto tool = getConfiguration("host-cpp", "/usr/bin/g++"); + auto ret = execute(tool, args, settings.verbose > 0); if(ret != 0) { - std::cerr << "Failed.\n"; + std::cerr << "Failed: ." << ret << "\n"; exit(1); } else @@ -197,16 +245,87 @@ void recompileCheck(const Settings& settings, int argc, char* argv[]) { args.push_back(argv[i]); } - exit(execute(argv[0], args, settings.verbose)); + exit(execute(argv[0], args, settings.verbose > 0)); } } } +std::list> getTasks(const Settings& settings) +{ + static std::deque build_configs; + std::list> tasks; + for(int i = 0; i < numConfigFiles; ++i) + { + std::string path = + std::filesystem::path(configFiles[i].file).parent_path(); + if(settings.verbose > 1) + { + std::cout << configFiles[i].file << " in path " << path << "\n"; + } + auto configs = configFiles[i].cb(); + for(const auto& config : configs) + { + build_configs.push_back(config); + const auto& build_config = build_configs.back(); + std::vector objects; + auto t = taskFactory(build_config, settings, path); + tasks.insert(tasks.end(), t.begin(), t.end()); + } + } + + return tasks; +} + +int configure(int argc, char* argv[],const Settings& settings) +{ + auto tasks = getTasks(settings); + + bool needs_cpp{false}; + bool needs_c{false}; + bool needs_ar{false}; + for(const auto& task :tasks) + { + switch(task->language()) + { + case Language::Auto: + std::cerr << "TargetLanguage not deduced!\n"; + exit(1); + break; + case Language::C: + needs_cpp = false; + break; + case Language::Cpp: + needs_c = true; + break; + } + } + std::ofstream istr(configurationFile); + istr << "#include \"libcppbuild.h\"\n\n"; + istr << "const std::map& configuration()\n"; + istr << "{\n"; + istr << " static std::map c =\n"; + istr << " {\n"; + istr << " { \"builddir\", \"build\" },\n"; + istr << " { \"host-cc\", \"/usr/bin/gcc\" },\n"; + istr << " { \"host-cpp\", \"/usr/bin/g++\" },\n"; + istr << " { \"host-ar\", \"/usr/bin/ar\" },\n"; + istr << " { \"host-ld\", \"/usr/bin/ld\" },\n"; + istr << " { \"target-cc\", \"/usr/bin/gcc\" },\n"; + istr << " { \"target-cpp\", \"/usr/bin/g++\" },\n"; + istr << " { \"target-ar\", \"/usr/bin/ar\" },\n"; + istr << " { \"target-ld\", \"/usr/bin/ld\" },\n"; + istr << " };\n"; + istr << " return c;\n"; + istr << "}\n"; + + return 0; +} + int main(int argc, char* argv[]) { Settings settings{}; - settings.builddir = "build/"; + settings.builddir = getConfiguration("builddir", "build"); settings.parallel_processes = std::max(1u, std::thread::hardware_concurrency() * 2 - 1); settings.verbose = 0; @@ -214,6 +333,11 @@ int main(int argc, char* argv[]) bool write_compilation_database{false}; std::string compilation_database; + if(argc > 1 && std::string(argv[1]) == "configure") + { + return configure(argc, argv, settings); + } + dg::Options opt; opt.add("jobs", required_argument, 'j', @@ -232,7 +356,8 @@ int main(int argc, char* argv[]) }); opt.add("build-dir", required_argument, 'b', - "Set output directory for build files (default: build).", + "Overload output directory for build files (default: '" + + settings.builddir + "').", [&]() { settings.builddir = optarg; return 0; @@ -269,26 +394,7 @@ int main(int argc, char* argv[]) std::filesystem::path builddir(settings.builddir); std::filesystem::create_directories(builddir); - std::deque build_configs; - std::list> tasks; - for(int i = 0; i < numConfigFiles; ++i) - { - std::string path = - std::filesystem::path(configFiles[i].file).parent_path(); - if(settings.verbose > 1) - { - std::cout << configFiles[i].file << " in path " << path << "\n"; - } - auto configs = configFiles[i].cb(); - for(const auto& config : configs) - { - build_configs.push_back(config); - const auto& build_config = build_configs.back(); - std::vector objects; - auto t = taskFactory(build_config, settings, path); - tasks.insert(tasks.end(), t.begin(), t.end()); - } - } + auto tasks = getTasks(settings); if(write_compilation_database) { @@ -337,7 +443,6 @@ int main(int argc, char* argv[]) if(arg == "clean") { std::cout << "Cleaning\n"; - //std::filesystem::remove_all(builddir); for(auto& task : tasks) { if(task->clean() != 0) @@ -348,6 +453,12 @@ int main(int argc, char* argv[]) return 0; } + + if(arg == "configure") + { + std::cerr << "The 'configure' target must be the first argument.\n"; + return 1; + } } if(dirtyTasks.empty()) -- cgit v1.2.3