// -*- c++ -*- // Distributed under the BSD 2-Clause License. // See accompanying file LICENSE for details. #include "tasks.h" #include #include #include #include #include "settings.h" #include "libctor.h" #include "task.h" #include "task_cc.h" #include "task_ld.h" #include "task_ar.h" #include "task_so.h" #include "rebuild.h" const std::deque& getTargets(const Settings& settings) { static bool initialised{false}; static std::deque targets; if(!initialised) { // Generate externals std::vector externalConfigs; for(std::size_t i = 0; i < numExternalConfigFiles; ++i) { auto newExternalConfigs = externalConfigFiles[i].cb(); externalConfigs.insert(externalConfigs.end(), newExternalConfigs.begin(), newExternalConfigs.end()); } for(std::size_t i = 0; i < numConfigFiles; ++i) { std::string path = std::filesystem::path(configFiles[i].file).parent_path().string(); if(settings.verbose > 1) { std::cout << configFiles[i].file << " in path " << path << "\n"; } auto configs = configFiles[i].cb(); for(auto& config : configs) { // Resolv config externals for(const auto& external : config.externals) { bool found{false}; for(const auto& externalConfig : externalConfigs) { 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()); } } if(!found) { std::cout << "External '" << external << "' not found.\n"; exit(1); } } targets.push_back({config, path}); } } initialised = true; } return targets; } std::list> taskFactory(const BuildConfiguration& config, const Settings& settings, const std::string& sourceDir) { std::filesystem::path targetFile(config.target); TargetType target_type{config.type}; if(target_type == TargetType::Auto) { if(targetFile.extension() == ".a") { target_type = TargetType::StaticLibrary; } else if(targetFile.extension() == ".so") { target_type = TargetType::DynamicLibrary; } else if(targetFile.extension() == "") { target_type = TargetType::Executable; } else { std::cerr << "Could not deduce target type from target " << targetFile.string() << " please specify.\n"; exit(1); } } std::vector objects; std::list> tasks; for(const auto& file : config.sources) { tasks.emplace_back(std::make_shared(config, settings, sourceDir, file)); objects.push_back(tasks.back()->target()); } switch(target_type) { case TargetType::Auto: // The target_type cannot be Auto break; case TargetType::StaticLibrary: tasks.emplace_back(std::make_shared(config, settings, config.target, objects, sourceDir)); break; #ifndef BOOTSTRAP case TargetType::DynamicLibrary: // TODO: Use C++20 starts_with if(targetFile.stem().string().substr(0, 3) != "lib") { std::cerr << "Dynamic library target must have 'lib' prefix\n"; exit(1); } tasks.emplace_back(std::make_shared(config, settings, config.target, objects, sourceDir)); break; case TargetType::Executable: case TargetType::UnitTest: tasks.emplace_back(std::make_shared(config, settings, config.target, objects, sourceDir)); break; case TargetType::Object: break; #else default: break; #endif } return tasks; } std::shared_ptr getNextTask(const std::list>& allTasks, std::list>& dirtyTasks) { for(auto dirtyTask = dirtyTasks.begin(); dirtyTask != dirtyTasks.end(); ++dirtyTask) { //std::cout << "Examining target " << (*dirtyTask)->target() << "\n"; if((*dirtyTask)->ready()) { dirtyTasks.erase(dirtyTask); return *dirtyTask; } } //std::cout << "No task ready ... \n"; return nullptr; } std::list> getTasks(const Settings& settings, const std::vector names) { auto& targets = getTargets(settings); std::list> tasks; for(const auto& target : targets) { if(names.empty() || std::find(std::begin(names), std::end(names), target.config.target) != std::end(names)) { std::vector objects; auto t = taskFactory(target.config, settings, target.path); tasks.insert(tasks.end(), t.begin(), t.end()); } } return tasks; }