diff options
Diffstat (limited to 'src/configure.cc')
-rw-r--r-- | src/configure.cc | 611 |
1 files changed, 470 insertions, 141 deletions
diff --git a/src/configure.cc b/src/configure.cc index a81f8ad..c08ed88 100644 --- a/src/configure.cc +++ b/src/configure.cc @@ -11,10 +11,12 @@ #include <getoptpp/getoptpp.hpp> #include "execute.h" -#include "libctor.h" +#include "ctor.h" #include "tasks.h" #include "rebuild.h" #include "externals.h" +#include "tools.h" +#include "util.h" std::filesystem::path configurationFile("configuration.cc"); std::filesystem::path configHeaderFile("config.h"); @@ -22,105 +24,78 @@ std::filesystem::path configHeaderFile("config.h"); std::map<std::string, std::string> external_includedir; std::map<std::string, std::string> external_libdir; -const Configuration default_configuration{}; -const Configuration& __attribute__((weak)) configuration() +const ctor::configuration& __attribute__((weak)) ctor::get_configuration() { - return default_configuration; + static ctor::configuration cfg; + static bool initialised{false}; + if(!initialised) + { + cfg.build_toolchain = getToolChain(cfg.get(ctor::cfg::build_cxx, "/usr/bin/g++")); + initialised = true; + } + return cfg; } -namespace ctor -{ +namespace ctor { std::optional<std::string> includedir; std::optional<std::string> libdir; -} +std::optional<std::string> builddir; +std::map<std::string, std::string> conf_values; +} // ctor:: -bool hasConfiguration(const std::string& key) +bool ctor::configuration::has(const std::string& key) const { - if(key == cfg::ctor_includedir && ctor::includedir) + if(key == ctor::cfg::ctor_includedir && ctor::includedir) { return true; } - if(key == cfg::ctor_libdir && ctor::libdir) + if(key == ctor::cfg::ctor_libdir && ctor::libdir) { return true; } - const auto& c = configuration(); - return c.tools.find(key) != c.tools.end(); + if(key == ctor::cfg::builddir && ctor::builddir) + { + return true; + } + + if(ctor::conf_values.find(key) != ctor::conf_values.end()) + { + return true; + } + + return tools.find(key) != tools.end(); } -const std::string& getConfiguration(const std::string& key, - const std::string& defaultValue) +const std::string& ctor::configuration::get(const std::string& key, const std::string& default_value) const { - if(key == cfg::ctor_includedir && ctor::includedir) + if(key == ctor::cfg::ctor_includedir && ctor::includedir) { return *ctor::includedir; } - if(key == cfg::ctor_libdir && ctor::libdir) + if(key == ctor::cfg::ctor_libdir && ctor::libdir) { return *ctor::libdir; } - const auto& c = configuration(); - if(hasConfiguration(key)) + if(key == ctor::cfg::builddir && ctor::builddir) { - return c.tools.at(key); + return *ctor::builddir; } - return defaultValue; -} - -std::string locate(const std::string& arch, const std::string& app) -{ - std::string path_env = std::getenv("PATH"); - //std::cout << path_env << "\n"; - - std::string program = app; - if(!arch.empty()) + if(ctor::conf_values.find(key) != ctor::conf_values.end()) { - program = arch + "-" + app; + return ctor::conf_values[key]; } - std::cout << "Looking for: " << program << "\n"; - std::vector<std::string> paths; + if(has(key)) { - std::stringstream ss(path_env); - std::string path; - while (std::getline(ss, path, ':')) - { - paths.push_back(path); - } - } - for(const auto& path_str : paths) - { - std::filesystem::path path(path_str); - auto prog_path = path / program; - if(std::filesystem::exists(prog_path)) - { - std::cout << "Found file " << app << " in path: " << path << "\n"; - auto perms = std::filesystem::status(prog_path).permissions(); - if((perms & std::filesystem::perms::owner_exec) != std::filesystem::perms::none) - { - //std::cout << " - executable by owner\n"; - } - if((perms & std::filesystem::perms::group_exec) != std::filesystem::perms::none) - { - //std::cout << " - executable by group\n"; - } - if((perms & std::filesystem::perms::others_exec) != std::filesystem::perms::none) - { - //std::cout << " - executable by others\n"; - } - - return prog_path.string(); - } + return tools.at(key); } - std::cerr << "Could not locate " << app << " for the " << arch << " architecture\n"; - exit(1); - return {}; + return default_value; } class Args @@ -146,22 +121,100 @@ public: } }; +namespace { +std::ostream& operator<<(std::ostream& stream, const ctor::toolchain& toolchain) +{ + switch(toolchain) + { + case ctor::toolchain::any: + stream << "ctor::toolchain::any"; + break; + case ctor::toolchain::none: + stream << "ctor::toolchain::none"; + break; + case ctor::toolchain::gcc: + stream << "ctor::toolchain::gcc"; + break; + case ctor::toolchain::clang: + stream << "ctor::toolchain::clang"; + break; + } + return stream; +} + +std::ostream& operator<<(std::ostream& stream, const ctor::arch& arch) +{ + switch(arch) + { + case ctor::arch::unix: + stream << "ctor::arch::unix"; + break; + case ctor::arch::apple: + stream << "ctor::arch::apple"; + break; + case ctor::arch::windows: + stream << "ctor::arch::windows"; + break; + case ctor::arch::unknown: + stream << "ctor::arch::unknown"; + break; + } + return stream; +} + +std::ostream& operator<<(std::ostream& ostr, const ctor::c_flag& flag) +{ + for(const auto& s : to_strings(ctor::toolchain::any, flag)) + { + ostr << s; + } + return ostr; +} + +std::ostream& operator<<(std::ostream& ostr, const ctor::cxx_flag& flag) +{ + for(const auto& s : to_strings(ctor::toolchain::any, flag)) + { + ostr << s; + } + return ostr; +} + +std::ostream& operator<<(std::ostream& ostr, const ctor::ld_flag& flag) +{ + for(const auto& s : to_strings(ctor::toolchain::any, flag)) + { + ostr << s; + } + return ostr; +} + +std::ostream& operator<<(std::ostream& ostr, const ctor::asm_flag& flag) +{ + for(const auto& s : to_strings(ctor::toolchain::any, flag)) + { + ostr << s; + } + return ostr; +} +} + // helper constant for the visitor template<class> inline constexpr bool always_false_v = false; -int regenerateCache(const Settings& default_settings, +int regenerateCache(ctor::settings& settings, + const std::string& name, const std::vector<std::string>& args, const std::map<std::string, std::string>& env) { - Settings settings{default_settings}; Args vargs(args); dg::Options opt; int key{128}; - std::string build_arch; + std::string build_arch_prefix; std::string build_path; - std::string host_arch; + std::string host_arch_prefix; std::string host_path; std::string cc_prog = "gcc"; std::string cxx_prog = "g++"; @@ -169,12 +222,14 @@ int regenerateCache(const Settings& default_settings, std::string ld_prog = "ld"; std::string ctor_includedir; std::string ctor_libdir; + std::string builddir; opt.add("build-dir", required_argument, 'b', "Set output directory for build files (default: '" + settings.builddir + "').", [&]() { settings.builddir = optarg; + builddir = optarg; return 0; }); @@ -216,7 +271,7 @@ int regenerateCache(const Settings& default_settings, opt.add("build", required_argument, key++, "Configure for building on specified architecture.", [&]() { - build_arch = optarg; + build_arch_prefix = optarg; return 0; }); @@ -230,7 +285,7 @@ int regenerateCache(const Settings& default_settings, opt.add("host", required_argument, key++, "Cross-compile to build programs to run on specified architecture.", [&]() { - host_arch = optarg; + host_arch_prefix = optarg; return 0; }); @@ -256,7 +311,7 @@ int regenerateCache(const Settings& default_settings, }); // Resolv externals - ExternalConfigurations externalConfigs; + ctor::external_configurations externalConfigs; for(std::size_t i = 0; i < numExternalConfigFiles; ++i) { auto newExternalConfigs = externalConfigFiles[i].cb(settings); @@ -288,7 +343,7 @@ int regenerateCache(const Settings& default_settings, std::visit([&](auto&& arg) { using T = std::decay_t<decltype(arg)>; - if constexpr (std::is_same_v<T, ExternalManual>) + if constexpr (std::is_same_v<T, ctor::external_manual>) { add_path_args(ext.name); } @@ -303,7 +358,9 @@ int regenerateCache(const Settings& default_settings, opt.add("help", no_argument, 'h', "Print this help text.", [&]() { - std::cout << "configure usage stuff\n"; + std::cout << "Configure how to build with " << name << "\n"; + std::cout << "Usage: " << name << " configure [options]\n\n"; + std::cout << "Options:\n"; opt.help(); exit(0); return 0; @@ -311,37 +368,107 @@ int regenerateCache(const Settings& default_settings, opt.process(vargs.size(), vargs.data()); - if(host_arch.empty()) + if(host_arch_prefix.empty()) { - host_arch = build_arch; + host_arch_prefix = build_arch_prefix; } auto tasks = getTasks(settings, {}, false); -/* - bool needs_cpp{false}; - bool needs_c{false}; - bool needs_ar{false}; - bool needs_asm{false}; + + bool needs_build{true}; // we always need to compile ctor itself + bool needs_build_c{false}; + bool needs_build_cxx{true}; // we always need to compile ctor itself + bool needs_build_ld{true}; // we always need to compile ctor itself + bool needs_build_ar{false}; + bool needs_build_asm{false}; + + bool needs_host_c{false}; + bool needs_host{false}; + bool needs_host_cxx{false}; + bool needs_host_ld{false}; + bool needs_host_ar{false}; + bool needs_host_asm{false}; + for(const auto& task :tasks) { - switch(task->sourceLanguage()) + switch(task->outputSystem()) { - 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; + case ctor::output_system::build: + needs_build = true; + switch(task->targetType()) + { + case ctor::target_type::executable: + case ctor::target_type::unit_test: + case ctor::target_type::dynamic_library: + needs_build_ld = true; + break; + case ctor::target_type::static_library: + case ctor::target_type::unit_test_library: + needs_build_ar = true; + break; + case ctor::target_type::object: + switch(task->sourceLanguage()) + { + case ctor::language::automatic: + std::cerr << "TargetLanguage not deduced!\n"; + exit(1); + break; + case ctor::language::c: + needs_build_c = true; + break; + case ctor::language::cpp: + needs_build_cxx = true; + break; + case ctor::language::assembler: + needs_build_asm = true; + break; + } + break; + case ctor::target_type::function: + case ctor::target_type::automatic: + case ctor::target_type::unknown: + break; + } break; - case Language::Asm: - needs_asm = true; + case ctor::output_system::host: + needs_host = true; + switch(task->targetType()) + { + case ctor::target_type::executable: + case ctor::target_type::unit_test: + case ctor::target_type::dynamic_library: + needs_host_ld = true; + break; + case ctor::target_type::static_library: + case ctor::target_type::unit_test_library: + needs_host_ar = true; + break; + case ctor::target_type::object: + switch(task->sourceLanguage()) + { + case ctor::language::automatic: + std::cerr << "TargetLanguage not deduced!\n"; + exit(1); + break; + case ctor::language::c: + needs_host_c = true; + break; + case ctor::language::cpp: + needs_host_cxx = true; + break; + case ctor::language::assembler: + needs_host_asm = true; + break; + } + break; + case ctor::target_type::function: + case ctor::target_type::automatic: + case ctor::target_type::unknown: + break; + } break; } } -*/ auto cc_env = env.find("CC"); if(cc_env != env.end()) @@ -367,54 +494,248 @@ int regenerateCache(const Settings& default_settings, ld_prog = ld_env->second; } - std::string host_cc = locate(host_arch, cc_prog); - std::string host_cxx = locate(host_arch, cxx_prog); - std::string host_ar = locate(host_arch, ar_prog); - std::string host_ld = locate(host_arch, ld_prog); - std::string build_cc = locate(build_arch, cc_prog); - std::string build_cxx = locate(build_arch, cxx_prog); - std::string build_ar = locate(build_arch, ar_prog); - std::string build_ld = locate(build_arch, ld_prog); + auto paths = get_paths(); + + auto path_env = env.find("PATH"); + if(path_env != env.end()) + { + paths = get_paths(path_env->second); + } + + std::string host_cc; + std::string host_cxx; + std::string host_ld; + std::string host_ar; + ctor::toolchain host_toolchain{ctor::toolchain::none}; + ctor::arch host_arch{ctor::arch::unknown}; + if(needs_host) + { + // Host detection + if(needs_host_c) + { + host_cc = locate(cc_prog, paths, host_arch_prefix); + if(host_cc.empty()) + { + std::cerr << "Could not locate host_cc prog" << std::endl; + return 1; + } + } + + if(needs_host_cxx) + { + host_cxx = locate(cxx_prog, paths, host_arch_prefix); + if(host_cxx.empty()) + { + std::cerr << "Could not locate host_cxx prog" << std::endl; + return 1; + } + } + + if(needs_host_ar) + { + host_ar = locate(ar_prog, paths, host_arch_prefix); + if(host_ar.empty()) + { + std::cerr << "Could not locate host_ar prog" << std::endl; + return 1; + } + } + + if(needs_host_ld) + { + host_ld = locate(ld_prog, paths, host_arch_prefix); + if(host_ld.empty()) + { + std::cerr << "Could not locate host_ld prog" << std::endl; + return 1; + } + } + + if(needs_host_asm) + { + // TODO + } + + host_toolchain = getToolChain(host_cxx); + auto host_arch_str = get_arch(ctor::output_system::host); + host_arch = get_arch(ctor::output_system::host, host_arch_str); + + std::cout << "** Host architecture '" << host_arch_str << "': " << host_arch << std::endl; + + if(host_arch == ctor::arch::unknown) + { + std::cerr << "Could not detect host architecture" << std::endl; + return 1; + } + } + + std::string build_cc; + std::string build_cxx; + std::string build_ld; + std::string build_ar; + ctor::toolchain build_toolchain{ctor::toolchain::none}; + ctor::arch build_arch{ctor::arch::unknown}; + if(needs_build) + { + // Build detection + if(needs_build_c) + { + build_cc = locate(cc_prog, paths, build_arch_prefix); + if(build_cc.empty()) + { + std::cerr << "Could not locate build_cc prog" << std::endl; + return 1; + } + } + + if(needs_build_cxx) + { + build_cxx = locate(cxx_prog, paths, build_arch_prefix); + if(build_cxx.empty()) + { + std::cerr << "Could not locate build_cxx prog" << std::endl; + return 1; + } + } + + if(needs_build_ar) + { + build_ar = locate(ar_prog, paths, build_arch_prefix); + if(build_ar.empty()) + { + std::cerr << "Could not locate build_ar prog" << std::endl; + return 1; + } + } + + if(needs_build_ld) + { + build_ld = locate(ld_prog, paths, build_arch_prefix); + if(build_ld.empty()) + { + std::cerr << "Could not locate build_ld prog" << std::endl; + return 1; + } + } + + if(needs_build_asm) + { + // TODO + } + + build_toolchain = getToolChain(build_cxx); + auto build_arch_str = get_arch(ctor::output_system::build); + build_arch = get_arch(ctor::output_system::build, build_arch_str); + + std::cout << "** Build architecture '" << build_arch_str << "': " << build_arch << std::endl; + + if(build_arch == ctor::arch::unknown) + { + std::cerr << "Could not detect build architecture" << std::endl; + return 1; + } + } + + + // Store current values for execution in this execution context. + if(!ctor_includedir.empty()) + { + ctor::conf_values[ctor::cfg::ctor_includedir] = ctor_includedir; + } + if(!ctor_libdir.empty()) + { + ctor::conf_values[ctor::cfg::ctor_libdir] = ctor_libdir; + } + if(!builddir.empty()) + { + ctor::conf_values[ctor::cfg::builddir] = builddir; + } + ctor::conf_values[ctor::cfg::host_cxx] = host_cxx; + ctor::conf_values[ctor::cfg::build_cxx] = build_cxx; std::cout << "Writing results to: " << configurationFile.string() << "\n"; { std::ofstream istr(configurationFile); - istr << "#include <libctor.h>\n\n"; - istr << "const Configuration& configuration()\n"; + istr << "#include <ctor.h>\n\n"; + istr << "const ctor::configuration& ctor::get_configuration()\n"; istr << "{\n"; - istr << " static Configuration cfg =\n"; + istr << " static ctor::configuration cfg =\n"; istr << " {\n"; + if(needs_host) + { + istr << " .host_toolchain = " << host_toolchain << ",\n"; + istr << " .host_arch = " << host_arch << ",\n"; + } + if(needs_build) + { + istr << " .build_toolchain = " << build_toolchain << ",\n"; + istr << " .build_arch = " << build_arch << ",\n"; + } istr << " .args = {"; for(const auto& arg : args) { - istr << "\"" << arg << "\","; + istr << "\"" << esc(arg) << "\","; } istr << "},\n"; - istr << " .env = {"; + istr << " .env = {\n"; for(const auto& e : env) { - istr << "{\"" << e.first << "\", \"" << e.second << "\"}, "; + istr << " {\"" << esc(e.first) << "\", \"" << esc(e.second) << "\"},\n"; } - istr << "},\n"; + istr << " },\n"; istr << " .tools = {\n"; - istr << " { \"" << cfg::builddir << "\", \"" << settings.builddir << "\" },\n"; - istr << " { \"" << cfg::host_cc << "\", \"" << host_cc << "\" },\n"; - istr << " { \"" << cfg::host_cxx << "\", \"" << host_cxx << "\" },\n"; - istr << " { \"" << cfg::host_ar << "\", \"" << host_ar << "\" },\n"; - istr << " { \"" << cfg::host_ld << "\", \"" << host_ld << "\" },\n"; - istr << " { \"" << cfg::build_cc << "\", \"" << build_cc << "\" },\n"; - istr << " { \"" << cfg::build_cxx << "\", \"" << build_cxx << "\" },\n"; - istr << " { \"" << cfg::build_ar << "\", \"" << build_ar << "\" },\n"; - istr << " { \"" << cfg::build_ld << "\", \"" << build_ld << "\" },\n"; + if(!builddir.empty()) + { + istr << " { \"" << ctor::cfg::builddir << "\", \"" << esc(builddir) << "\" },\n"; + ctor::builddir = builddir; + } + if(needs_host) + { + if(needs_host_c) + { + istr << " { \"" << ctor::cfg::host_cc << "\", \"" << esc(host_cc) << "\" },\n"; + } + if(needs_host_cxx) + { + istr << " { \"" << ctor::cfg::host_cxx << "\", \"" << esc(host_cxx) << "\" },\n"; + } + if(needs_host_ar) + { + istr << " { \"" << ctor::cfg::host_ar << "\", \"" << esc(host_ar) << "\" },\n"; + } + if(needs_host_ld) + { + istr << " { \"" << ctor::cfg::host_ld << "\", \"" << esc(host_ld) << "\" },\n"; + } + } + if(needs_build) + { + if(needs_build_c) + { + istr << " { \"" << ctor::cfg::build_cc << "\", \"" << esc(build_cc) << "\" },\n"; + } + if(needs_build_cxx) + { + istr << " { \"" << ctor::cfg::build_cxx << "\", \"" << esc(build_cxx) << "\" },\n"; + } + if(needs_build_ar) + { + istr << " { \"" << ctor::cfg::build_ar << "\", \"" << esc(build_ar) << "\" },\n"; + } + if(needs_build_ld) + { + istr << " { \"" << ctor::cfg::build_ld << "\", \"" << esc(build_ld) << "\" },\n"; + } + } if(!ctor_includedir.empty()) { - istr << " { \"" << cfg::ctor_includedir << "\", \"" << ctor_includedir << "\" },\n"; + istr << " { \"" << ctor::cfg::ctor_includedir << "\", \"" << esc(ctor_includedir) << "\" },\n"; ctor::includedir = ctor_includedir; } if(!ctor_libdir.empty()) { - istr << " { \"" << cfg::ctor_libdir << "\", \"" << ctor_libdir << "\" },\n"; + istr << " { \"" << ctor::cfg::ctor_libdir << "\", \"" << esc(ctor_libdir) << "\" },\n"; ctor::libdir = ctor_libdir; } @@ -423,12 +744,12 @@ int regenerateCache(const Settings& default_settings, for(const auto& ext : externalConfigs) { - istr << " { \"" << ext.name << "\", {\n"; - Flags resolved_flags; - if(std::holds_alternative<ExternalManual>(ext.external)) + istr << " { \"" << esc(ext.name) << "\", {\n"; + ctor::flags resolved_flags; + if(std::holds_alternative<ctor::external_manual>(ext.external)) { if(auto ret = resolv(settings, ext, - std::get<ExternalManual>(ext.external), + std::get<ctor::external_manual>(ext.external), resolved_flags)) { return ret; @@ -440,22 +761,22 @@ int regenerateCache(const Settings& default_settings, return 1; } - if(!resolved_flags.cxxflags.empty()) + if(!resolved_flags.cflags.empty()) { - istr << " .cxxflags = {"; - for(const auto& flag : resolved_flags.cxxflags) + istr << " .cflags = {"; + for(const auto& flag : resolved_flags.cflags) { - istr << "\"" << flag << "\","; + istr << flag << ","; } istr << "},\n"; } - if(!resolved_flags.cflags.empty()) + if(!resolved_flags.cxxflags.empty()) { - istr << " .cflags = {"; - for(const auto& flag : resolved_flags.cflags) + istr << " .cxxflags = {"; + for(const auto& flag : resolved_flags.cxxflags) { - istr << "\"" << flag << "\","; + istr << flag << ","; } istr << "},\n"; } @@ -465,7 +786,7 @@ int regenerateCache(const Settings& default_settings, istr << " .ldflags = {"; for(const auto& flag : resolved_flags.ldflags) { - istr << "\"" << flag << "\","; + istr << flag << ","; } istr << "},\n"; } @@ -475,7 +796,7 @@ int regenerateCache(const Settings& default_settings, istr << " .asmflags = {"; for(const auto& flag : resolved_flags.asmflags) { - istr << "\"" << flag << "\","; + istr << flag << ","; } istr << "},\n"; } @@ -485,7 +806,7 @@ int regenerateCache(const Settings& default_settings, istr << " },\n"; istr << " };\n"; istr << " return cfg;\n"; - istr << "}\n\n"; + istr << "}\n"; } { @@ -498,9 +819,9 @@ int regenerateCache(const Settings& default_settings, return 0; } -int configure(const Settings& global_settings, int argc, char* argv[]) +int configure(const ctor::settings& global_settings, int argc, char* argv[]) { - Settings settings{global_settings}; + ctor::settings settings{global_settings}; std::vector<std::string> args; for(int i = 2; i < argc; ++i) // skip command and the first 'configure' arg @@ -533,7 +854,13 @@ int configure(const Settings& global_settings, int argc, char* argv[]) env["LD"] = ld_env; } - auto ret = regenerateCache(settings, args, env); + auto path_env = getenv("PATH"); + if(path_env) + { + env["PATH"] = path_env; + } + + auto ret = regenerateCache(settings, argv[0], args, env); if(ret != 0) { return ret; @@ -544,8 +871,10 @@ int configure(const Settings& global_settings, int argc, char* argv[]) return 0; } -int reconfigure(const Settings& settings, int argc, char* argv[]) +int reconfigure(const ctor::settings& global_settings, int argc, char* argv[]) { + ctor::settings settings{global_settings}; + bool no_rerun{false}; std::vector<std::string> args; @@ -559,7 +888,7 @@ int reconfigure(const Settings& settings, int argc, char* argv[]) args.push_back(argv[i]); } - const auto& cfg = configuration(); + const auto& cfg = ctor::get_configuration(); std::cout << "Re-running configure:\n"; for(const auto& e : cfg.env) @@ -573,7 +902,7 @@ int reconfigure(const Settings& settings, int argc, char* argv[]) } std::cout << "\n"; - auto ret = regenerateCache(settings, cfg.args, cfg.env); + auto ret = regenerateCache(settings, argv[0], cfg.args, cfg.env); if(ret != 0) { return ret; |