// -*- c++ -*- // Distributed under the BSD 2-Clause License. // See accompanying file LICENSE for details. #include "rebuild.h" #include #include #include #include #include #include "configure.h" #include "libctor.h" #include "tasks.h" #include "build.h" #include "execute.h" #include "tools.h" #include "util.h" std::array configFiles; std::size_t numConfigFiles{0}; int reg(BuildConfigurations (*cb)(const Settings&), const std::source_location location) { // NOTE: std::cout cannot be used here if(numConfigFiles >= configFiles.size()) { fprintf(stderr, "Max %d build configurations currently supported.\n", (int)configFiles.size()); exit(1); } 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); configFiles[numConfigFiles].file = strdup(rel.string().data()); // NOTE: This intentionally leaks memory } else { configFiles[numConfigFiles].file = location.file_name(); } configFiles[numConfigFiles].cb = cb; ++numConfigFiles; return 0; } int reg(const char* location) { // NOTE: std::cout cannot be used here if(numConfigFiles >= configFiles.size()) { fprintf(stderr, "Max %d build configurations currently supported.\n", (int)configFiles.size()); exit(1); } configFiles[numConfigFiles].file = location; configFiles[numConfigFiles].cb = [](const Settings&){ return std::vector{}; }; ++numConfigFiles; return 0; } int unreg(const char* location) { std::size_t found{0}; for(std::size_t i = 0; i < numConfigFiles;) { if(std::string(location) == configFiles[i].file) { ++found; for(std::size_t j = i; j < numConfigFiles; ++j) { configFiles[j] = configFiles[j + 1]; } --numConfigFiles; } else { ++i; } } for(std::size_t i = 0; i < numExternalConfigFiles;) { if(std::string(location) == externalConfigFiles[i].file) { ++found; for(std::size_t j = i; j < numExternalConfigFiles; ++j) { externalConfigFiles[j] = externalConfigFiles[j + 1]; } --numExternalConfigFiles; } else { ++i; } } return found; } std::array externalConfigFiles; std::size_t numExternalConfigFiles{0}; int reg(ExternalConfigurations (*cb)(const Settings&), const std::source_location location) { // NOTE: std::cout cannot be used here if(numExternalConfigFiles >= externalConfigFiles.size()) { fprintf(stderr, "Max %d external configurations currently supported.\n", (int)externalConfigFiles.size()); exit(1); } externalConfigFiles[numExternalConfigFiles].file = location.file_name(); externalConfigFiles[numExternalConfigFiles].cb = cb; ++numExternalConfigFiles; return 0; } 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 Settings& global_settings, int argc, char* argv[], bool relaunch_allowed) { using namespace std::string_literals; if(global_settings.verbose > 1) { std::cout << "Recompile check (" << numConfigFiles << "):\n"; } std::filesystem::path settings_file(global_settings.name); std::filesystem::path argv0_file(argv[0]); if(settings_file.is_relative()) { settings_file = std::filesystem::current_path() / settings_file; } if(argv0_file.is_relative()) { argv0_file = std::filesystem::current_path() / argv0_file; } BuildConfiguration config; config.type = TargetType::Executable; config.name = "ctor"; config.system = OutputSystem::Build; auto tool_chain = getToolChain(config.system); append(config.flags.cxxflags, getOption(tool_chain, opt::optimization, "2")); append(config.flags.cxxflags, getOption(tool_chain, opt::cpp_std, "c++20")); config.flags.cxxflags.push_back("/nologo"); if(hasConfiguration(cfg::ctor_includedir)) { append(config.flags.cxxflags, getOption(tool_chain, opt::include_path, getConfiguration(cfg::ctor_includedir))); } if(hasConfiguration(cfg::ctor_libdir)) { append(config.flags.ldflags, getOption(tool_chain, opt::library_path, getConfiguration(cfg::ctor_libdir))); } // append(config.flags.ldflags, getOption(tool_chain, opt::link, "ctor")); config.flags.ldflags.push_back("build/libctor.lib"); append(config.flags.ldflags, getOption(tool_chain, opt::threads)); config.flags.ldflags.push_back("/nologo"); config.flags.ldflags.push_back("/SUBSYSTEM:CONSOLE"); Settings settings{global_settings}; settings.parallel_processes = 1; settings.verbose = 2;//-1; // Make check completely silent. settings.builddir += "/ctor"; // override builddir to use ctor subdir { std::filesystem::path buildfile = settings.builddir; std::filesystem::path currentfile = settings.name; if(currentfile.is_relative()) { currentfile = std::filesystem::current_path() / currentfile; } config.target = std::filesystem::relative(currentfile, buildfile).string(); } if(std::filesystem::exists(configurationFile)) { config.sources.push_back(configurationFile.string()); } for(std::size_t i = 0; i < numConfigFiles; ++i) { std::string location = configFiles[i].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.push_back(location); } } for(std::size_t i = 0; i < numExternalConfigFiles; ++i) { std::string location = externalConfigFiles[i].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.push_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 bool was_rebuilt{false}; if(dirty_tasks) { std::cout << "Rebuilding config.\n"; auto ret = build(settings, "ctor", tasks); // run for real if(ret != 0) { return ret; } was_rebuilt = true; } 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(settings.name, args, {}); //if(ret != 0) { exit(ret); } } return dirty_tasks; }