summaryrefslogtreecommitdiff
path: root/libcppbuild.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libcppbuild.cc')
-rw-r--r--libcppbuild.cc401
1 files changed, 4 insertions, 397 deletions
diff --git a/libcppbuild.cc b/libcppbuild.cc
index 2a2c40d..6d1d6e5 100644
--- a/libcppbuild.cc
+++ b/libcppbuild.cc
@@ -14,411 +14,18 @@
#include <fstream>
#include <cstdlib>
#include <set>
+#include <future>
#include <getoptpp/getoptpp.hpp>
#include "libcppbuild.h"
-#include "task_cc.h"
-#include "task_ld.h"
-#include "task_ar.h"
-#include "task_so.h"
#include "settings.h"
-#include "execute.h"
-
-#include <unistd.h>
-
-
-namespace
-{
-std::filesystem::path configurationFile("configuration.cc");
-const std::map<std::string, std::string> default_configuration{};
-}
-const std::map<std::string, std::string>& __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;
-}
+#include "configure.h"
+#include "rebuild.h"
+#include "tasks.h"
using namespace std::chrono_literals;
-std::list<std::shared_ptr<Task>> 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<std::string> objects;
- std::list<std::shared_ptr<Task>> tasks;
- for(const auto& file : config.sources)
- {
- tasks.emplace_back(std::make_shared<TaskCC>(config, settings,
- sourceDir, file));
- objects.push_back(tasks.back()->target());
- }
-
- switch(target_type)
- {
- case TargetType::StaticLibrary:
- tasks.emplace_back(std::make_shared<TaskAR>(config, settings, config.target,
- objects));
- break;
-
- case TargetType::DynamicLibrary:
- 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<TaskSO>(config, settings, config.target,
- objects));
- break;
-
- case TargetType::Executable:
- tasks.emplace_back(std::make_shared<TaskLD>(config, settings, config.target,
- objects));
- break;
- }
-
- return tasks;
-}
-
-std::shared_ptr<Task> getNextTask(const std::list<std::shared_ptr<Task>>& allTasks,
- std::list<std::shared_ptr<Task>>& 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;
-}
-
-namespace
-{
-struct BuildConfigurationEntry
-{
- const char* file;
- std::vector<BuildConfiguration> (*cb)();
-};
-std::array<BuildConfigurationEntry, 1024> configFiles;
-std::size_t numConfigFiles{0};
-}
-
-// TODO: Use c++20 when ready, somehing like this:
-//int reg(const std::source_location location = std::source_location::current())
-int reg(const char* location, std::vector<BuildConfiguration> (*cb)())
-{
- // 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 = cb;
- ++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;
- }
- }
-
- return found;
-}
-
-void recompileCheck(const Settings& settings, int argc, char* argv[],
- bool force = false)
-{
- bool dirty{force};
-
- std::vector<std::string> args;
- args.push_back("-s");
- args.push_back("-O3");
- args.push_back("-std=c++17");
- args.push_back("-pthread");
-
- 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";
- }
-
- for(std::size_t i = 0; i < numConfigFiles; ++i)
- {
- std::string location = configFiles[i].file;
- if(settings.verbose > 1)
- {
- std::cout << " - " << location << "\n";
- }
- std::filesystem::path configFile(location);
- if(std::filesystem::last_write_time(binFile) <=
- std::filesystem::last_write_time(configFile))
- {
- dirty = true;
- }
-
- // Support adding multiple config functions from the same file
- if(std::find(args.begin(), args.end(), location) == std::end(args))
- {
- args.push_back(location);
- }
- }
- args.push_back("libcppbuild.a");
- args.push_back("-o");
- args.push_back(binFile.string());
-
- if(dirty)
- {
- std::cout << "Rebuilding config\n";
- auto tool = getConfiguration(cfg::host_cpp, "/usr/bin/g++");
- auto ret = execute(tool, args, settings.verbose > 0);
- if(ret != 0)
- {
- std::cerr << "Failed: ." << ret << "\n";
- exit(1);
- }
- else
- {
- std::cout << "Re-launch\n";
- std::vector<std::string> args;
- for(int i = 1; i < argc; ++i)
- {
- args.push_back(argv[i]);
- }
- exit(execute(argv[0], args, settings.verbose > 0));
- }
- }
-}
-
-std::list<std::shared_ptr<Task>> getTasks(const Settings& settings)
-{
- static std::deque<BuildConfiguration> build_configs;
- std::list<std::shared_ptr<Task>> tasks;
- for(std::size_t 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<std::string> objects;
- auto t = taskFactory(build_config, settings, path);
- tasks.insert(tasks.end(), t.begin(), t.end());
- }
- }
-
- return tasks;
-}
-
-/*
-int configure(int argc, char* argv[])
-{
- Settings settings;
-
- settings.builddir = "build";
-
- std::string cmd_str;
- for(int i = 0; i < argc; ++i)
- {
- if(i > 0)
- {
- cmd_str += " ";
- }
- cmd_str += argv[i];
- }
-
- dg::Options opt;
- int key{256};
-
- std::string build_arch;
- std::string host_arch;
-
- opt.add("build-dir", required_argument, 'b',
- "Set output directory for build files (default: '" +
- settings.builddir + "').",
- [&]() {
- settings.builddir = optarg;
- return 0;
- });
-
- opt.add("verbose", no_argument, 'v',
- "Be verbose. Add multiple times for more verbosity.",
- [&]() {
- settings.verbose++;
- return 0;
- });
-
- opt.add("build", required_argument, key++,
- "Configure for building on specified architecture.",
- [&]() {
- build_arch = optarg;
- return 0;
- });
-
- opt.add("host", required_argument, key++,
- "Cross-compile to build programs to run on specified architecture.",
- [&]() {
- host_arch = optarg;
- return 0;
- });
-
- opt.add("help", no_argument, 'h',
- "Print this help text.",
- [&]() {
- std::cout << "configure usage stuff\n";
- opt.help();
- exit(0);
- return 0;
- });
-
- opt.process(argc, argv);
-
- if(host_arch.empty())
- {
- host_arch = build_arch;
- }
-
- auto tasks = getTasks(settings);
-
- bool needs_cpp{false};
- bool needs_c{false};
- bool needs_ar{false};
- for(const auto& task :tasks)
- {
- switch(task->sourceLanguage())
- {
- 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<std::string, std::string>& configuration()\n";
- istr << "{\n";
- istr << " static std::map<std::string, std::string> c =\n";
- istr << " {\n";
- istr << " { \"cmd\", \"" << cmd_str << "\" },\n";
- istr << " { \"" << cfg::builddir << "\", \"" << settings.builddir << "\" },\n";
- istr << " { \"" << cfg::target_cc << "\", \"/usr/bin/gcc\" },\n";
- istr << " { \"" << cfg::target_cpp << "\", \"/usr/bin/g++\" },\n";
- istr << " { \"" << cfg::target_ar << "\", \"/usr/bin/ar\" },\n";
- istr << " { \"" << cfg::target_ld << "\", \"/usr/bin/ld\" },\n";
- istr << " { \"" << cfg::host_cc << "\", \"/usr/bin/gcc\" },\n";
- istr << " { \"" << cfg::host_cpp << "\", \"/usr/bin/g++\" },\n";
- istr << " { \"" << cfg::host_ar << "\", \"/usr/bin/ar\" },\n";
- istr << " { \"" << cfg::host_ld << "\", \"/usr/bin/ld\" },\n";
- istr << " };\n";
- istr << " return c;\n";
- istr << "}\n";
- }
-
-
- return 0;
-}
-
int main(int argc, char* argv[])
{
if(argc > 1 && std::string(argv[1]) == "configure")