// -*- c++ -*- // Distributed under the BSD 2-Clause License. // See accompanying file LICENSE for details. #include "rebuild.h" #include #include #include #include #include #include #include #include "configure.h" #include "ctor.h" #include "tasks.h" #include "build.h" #include "execute.h" #include "tools.h" #include "util.h" std::vector& getConfigFileList() { static std::vector configFiles; return configFiles; } std::vector& getExternalConfigFileList() { static std::vector externalConfigFiles; return externalConfigFiles; } namespace ctor { int reg(std::function cb, const std::source_location location) { BuildConfigurationEntry entry; auto loc = std::filesystem::path(location.file_name()); if(loc.is_absolute()) { auto pwd = std::filesystem::current_path(); auto rel = std::filesystem::relative(loc, pwd); entry.file = rel.string(); } else { entry.file = location.file_name(); } entry.cb = cb; auto& configFiles = getConfigFileList(); configFiles.push_back(entry); return 0; } } // ctor:: int reg(const char* location) { BuildConfigurationEntry entry; entry.file = location; entry.cb = [](const ctor::settings&) { return std::vector{}; }; auto& configFiles = getConfigFileList(); configFiles.push_back(entry); return 0; } int unreg(const char* location) { auto& configFiles = getConfigFileList(); auto erasedConfigs = std::erase_if(configFiles, [&](const BuildConfigurationEntry& entry) { return entry.file == location; }); auto& externalConfigFiles = getExternalConfigFileList(); auto erasedExternals = std::erase_if(externalConfigFiles, [&](const ExternalConfigurationEntry& entry) { return entry.file == location; }); return static_cast(erasedConfigs) + static_cast(erasedExternals); } namespace ctor { int reg(std::function cb, const std::source_location location) { ExternalConfigurationEntry entry; entry.file = location.file_name(); entry.cb = cb; auto& externalConfigFiles = getExternalConfigFileList(); externalConfigFiles.push_back(entry); return 0; } } // namespace ctor:: namespace { bool contains(const std::vector& sources, const std::string& file) { for(const auto& source : sources) { if(source.file == file) { return true; } } return false; } } bool recompileCheck(const ctor::settings& global_settings, int argc, char* argv[], bool relaunch_allowed) { auto args_span = std::span(argv, static_cast(argc)); using namespace std::string_literals; const auto& configFiles = getConfigFileList(); if(global_settings.verbose > 1) { std::cout << "Recompile check (" << configFiles.size() << "):\n"; } ctor::build_configuration config; config.type = ctor::target_type::executable; config.name = "ctor"; config.system = ctor::output_system::build; config.flags.cxxflags.emplace_back(ctor::cxx_opt::optimization, "3"); config.flags.cxxflags.emplace_back(ctor::cxx_opt::cpp_std, "c++20"); const auto& c = ctor::get_configuration(); if(c.has(ctor::cfg::ctor_includedir)) { config.flags.cxxflags.emplace_back(ctor::cxx_opt::include_path, c.get(ctor::cfg::ctor_includedir)); } if(c.has(ctor::cfg::ctor_libdir)) { config.flags.ldflags.emplace_back(ctor::ld_opt::library_path, c.get(ctor::cfg::ctor_libdir)); } config.flags.ldflags.emplace_back(ctor::ld_opt::link, "ctor"); config.flags.ldflags.emplace_back(ctor::ld_opt::threads); ctor::settings settings{global_settings}; settings.verbose = -1; // Make check completely silent. // override builddir to use ctor subdir auto ctor_builddir = std::filesystem::path(settings.builddir) / "ctor"; settings.builddir = ctor_builddir.string(); { std::filesystem::path buildfile = settings.builddir; std::filesystem::path currentfile = args_span[0]; config.target = std::filesystem::relative(currentfile, buildfile).string(); } if(std::filesystem::exists(configurationFile)) { config.sources.emplace_back(configurationFile.string()); } for(const auto& configFile : configFiles) { std::string location = configFile.file; if(global_settings.verbose > 1) { std::cout << " - " << location << "\n"; } // Ensure that files containing multiple configurations are only added once. if(!contains(config.sources, location)) { config.sources.emplace_back(location); } } const auto& externalConfigFiles = getExternalConfigFileList(); for(const auto& externalConfigFile : externalConfigFiles) { std::string location = externalConfigFile.file; if(global_settings.verbose > 1) { std::cout << " - " << location << "\n"; } // Ensure that files containing multiple configurations are only added once. if(!contains(config.sources, location)) { config.sources.emplace_back(location); } } auto tasks = taskFactory({config}, settings, {}, true); for(auto task : tasks) { if(task->registerDepTasks(tasks)) { 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; } } auto dirty_tasks = build(settings, "ctor", tasks, true); // dryrun if(dirty_tasks) { std::cout << "Rebuilding config.\n"; auto ret = build(settings, "ctor", tasks); // run for real if(ret != 0) { return ret; } } if(reconfigure) { std::vector args; args.emplace_back("reconfigure"); if(!relaunch_allowed) { args.emplace_back("--no-rerun"); } for(std::size_t i = 1; i < args_span.size(); ++i) { args.emplace_back(args_span[i]); } auto ret = execute(settings, args_span[0], args); //if(ret != 0) { exit(ret); } } return dirty_tasks; }