From 3cbadb8f5c55020ece96fab0fc8f4f51da01888e Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Thu, 19 Jan 2023 14:22:51 +0100 Subject: Make extension deduction architecture-aware. --- ctor.cc | 1 - src/configure.cc | 69 +++++++++++++---- src/ctor.h | 12 +++ src/task_ar.cc | 2 +- src/task_cc.cc | 2 +- src/task_ld.cc | 2 +- src/task_so.cc | 2 +- src/tools.cc | 231 +++++++++++++++++++++++++++++++++++++++++++++++-------- src/tools.h | 3 + 9 files changed, 272 insertions(+), 52 deletions(-) diff --git a/ctor.cc b/ctor.cc index c9faa5e..b2513af 100644 --- a/ctor.cc +++ b/ctor.cc @@ -10,7 +10,6 @@ ctor::build_configurations ctorConfigs(const ctor::settings& settings) return { { - .type = ctor::target_type::static_library, .target = "libctor.a", .sources = { "src/build.cc", diff --git a/src/configure.cc b/src/configure.cc index a2bb8bc..10f3056 100644 --- a/src/configure.cc +++ b/src/configure.cc @@ -193,6 +193,26 @@ std::ostream& operator<<(std::ostream& stream, const ctor::toolchain& toolchain) 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)) @@ -243,9 +263,9 @@ int regenerateCache(ctor::settings& settings, 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++"; @@ -302,7 +322,7 @@ int regenerateCache(ctor::settings& settings, opt.add("build", required_argument, key++, "Configure for building on specified architecture.", [&]() { - build_arch = optarg; + build_arch_prefix = optarg; return 0; }); @@ -316,7 +336,7 @@ int regenerateCache(ctor::settings& 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; }); @@ -399,9 +419,9 @@ int regenerateCache(ctor::settings& 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); @@ -455,14 +475,29 @@ int regenerateCache(ctor::settings& 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); + // Host detection + auto host_cc = locate(host_arch_prefix, cc_prog); + auto host_cxx = locate(host_arch_prefix, cxx_prog); + auto host_ar = locate(host_arch_prefix, ar_prog); + auto host_ld = locate(host_arch_prefix, ld_prog); + + auto host_toolchain = getToolChain(host_cxx); + auto host_arch_str = get_arch(ctor::output_system::host); + auto host_arch = get_arch(ctor::output_system::host, host_arch_str); + + std::cout << "** Host architecture '" << host_arch_str << "': " << host_arch << std::endl; + + // Build detection + auto build_cc = locate(build_arch_prefix, cc_prog); + auto build_cxx = locate(build_arch_prefix, cxx_prog); + auto build_ar = locate(build_arch_prefix, ar_prog); + auto build_ld = locate(build_arch_prefix, ld_prog); + + auto build_toolchain = getToolChain(build_cxx); + auto build_arch_str = get_arch(ctor::output_system::build); + auto build_arch = get_arch(ctor::output_system::build, build_arch_str); + + std::cout << "** Build architecture '" << build_arch_str << "': " << build_arch << std::endl; if(!host_cxx.empty()) { @@ -494,8 +529,10 @@ int regenerateCache(ctor::settings& settings, istr << "{\n"; istr << " static ctor::configuration cfg =\n"; istr << " {\n"; - istr << " .host_toolchain = " << getToolChain(host_cxx) << ",\n"; - istr << " .build_toolchain = " << getToolChain(build_cxx) << ",\n"; + istr << " .host_toolchain = " << host_toolchain << ",\n"; + istr << " .host_arch = " << host_arch << ",\n"; + istr << " .build_toolchain = " << build_toolchain << ",\n"; + istr << " .build_arch = " << build_arch << ",\n"; istr << " .args = {"; for(const auto& arg : args) { diff --git a/src/ctor.h b/src/ctor.h index 4e0a247..ab486a5 100644 --- a/src/ctor.h +++ b/src/ctor.h @@ -43,6 +43,15 @@ enum class output_system build, // Internal tool during cross-compilation }; +enum class arch +{ + unix, //!< Target platform architecture is unix-based (ie. linux, bsd, etc) + apple, //!< Target platform architecture is macos + windows, //!< Target platform architecture is windows + + unknown, //!< Target platform architecture has not yet detected or was not possible to detect +}; + struct source { source(const char* file) : file(file) {} @@ -256,7 +265,10 @@ struct configuration const std::string& get(const std::string& key, const std::string& default_value = {}) const; ctor::toolchain host_toolchain{ctor::toolchain::none}; + ctor::arch host_arch{ctor::arch::unknown}; + ctor::toolchain build_toolchain{ctor::toolchain::none}; + ctor::arch build_arch{ctor::arch::unknown}; std::vector args; // vector of arguments used when last calling configure std::map env; // env used when last calling configure diff --git a/src/task_ar.cc b/src/task_ar.cc index b73c6ac..605ab17 100644 --- a/src/task_ar.cc +++ b/src/task_ar.cc @@ -26,7 +26,7 @@ TaskAR::TaskAR(const ctor::build_configuration& config, target_type = ctor::target_type::static_library; _targetFile = target; auto toolchain = getToolChain(config.system); - _targetFile = extension(toolchain, target_type, _targetFile); + _targetFile = extension(toolchain, target_type, config.system, _targetFile); for(const auto& object : objects) { std::filesystem::path objectFile = object; diff --git a/src/task_cc.cc b/src/task_cc.cc index f16a07f..46662ad 100644 --- a/src/task_cc.cc +++ b/src/task_cc.cc @@ -62,7 +62,7 @@ TaskCC::TaskCC(const ctor::build_configuration& config, const ctor::settings& se _targetFile = source.output; } auto toolchain = getToolChain(config.system); - _targetFile = extension(toolchain, target_type, _targetFile); + _targetFile = extension(toolchain, target_type, config.system, _targetFile); depsFile = targetFile().parent_path() / targetFile().stem(); depsFile += ".d"; diff --git a/src/task_ld.cc b/src/task_ld.cc index e619dfd..908b641 100644 --- a/src/task_ld.cc +++ b/src/task_ld.cc @@ -31,7 +31,7 @@ TaskLD::TaskLD(const ctor::build_configuration& config, _targetFile = target; auto toolchain = getToolChain(config.system); - _targetFile = extension(toolchain, target_type, _targetFile); + _targetFile = extension(toolchain, target_type, config.system, _targetFile); for(const auto& object : objects) { std::filesystem::path objectFile = object; diff --git a/src/task_so.cc b/src/task_so.cc index 9aae7ff..522f6f2 100644 --- a/src/task_so.cc +++ b/src/task_so.cc @@ -27,7 +27,7 @@ TaskSO::TaskSO(const ctor::build_configuration& config, target_type = ctor::target_type::dynamic_library; _targetFile = base / target; auto toolchain = getToolChain(config.system); - _targetFile = extension(toolchain, target_type, _targetFile); + _targetFile = extension(toolchain, target_type, config.system, _targetFile); for(const auto& object : objects) { std::filesystem::path objectFile = object; diff --git a/src/tools.cc b/src/tools.cc index a83f115..be94794 100644 --- a/src/tools.cc +++ b/src/tools.cc @@ -8,6 +8,7 @@ #include #include +#include #include "util.h" @@ -115,7 +116,8 @@ ctor::toolchain getToolChain(const std::string& compiler) return ctor::toolchain::clang; } else if(cc_cmd.find("g++") != std::string::npos || - cc_cmd.find("gcc") != std::string::npos) + cc_cmd.find("gcc") != std::string::npos || + cc_cmd.find("mingw") != std::string::npos) { return ctor::toolchain::gcc; } @@ -146,9 +148,95 @@ ctor::toolchain getToolChain(ctor::output_system system) } namespace gcc { +std::string get_arch(ctor::output_system system) +{ + std::string cmd; + + const auto& c = ctor::get_configuration(); + switch(system) + { + case ctor::output_system::host: + cmd = c.get(ctor::cfg::host_cxx, "/usr/bin/g++"); + break; + case ctor::output_system::build: + cmd = c.get(ctor::cfg::build_cxx, "/usr/bin/g++"); + break; + } + + cmd += " -v"; + cmd += " 2>&1"; + auto pipe = popen(cmd.data(), "r"); + if(!pipe) + { + std::cerr << "Could not run compiler " << cmd << "\n"; + return {};//ctor::arch::unknown; + } + + std::string arch; + while(!feof(pipe)) + { + char buf[1024]; + if(fgets(buf, sizeof(buf), pipe) != nullptr) + { + arch = buf; + if(arch.starts_with("Target:")) + { + break; + } + } + } + + pclose(pipe); + + // Remove trailing newline + if(arch.ends_with("\n")) + { + arch = arch.substr(0, arch.length() - 1); + } + + // Remove 'Target: ' prefix + arch = arch.substr(8); + return arch; +} + +ctor::arch get_arch(const std::string& str) +{ + // gcc -v 2>&1 | grep Target + // Target: x86_64-apple-darwin19.6.0 + // Target: x86_64-pc-linux-gnu + // Target: arm-linux-gnueabihf + // Target: x86_64-linux-gnu + // Target: x86_64-unknown-freebsd13.1 + // # x86_64-w64-mingw32-c++-win32 -v 2>&1 | grep Target + // Target: x86_64-w64-mingw32 + // # i686-w64-mingw32-c++-win32 -v 2>&1 | grep Target + // Target: i686-w64-mingw32 + + if(str.find("apple") != std::string::npos || + str.find("darwin") != std::string::npos) + { + return ctor::arch::apple; + } + + if(str.find("linux") != std::string::npos || + str.find("bsd") != std::string::npos) + { + return ctor::arch::unix; + } + + if(str.find("mingw") != std::string::npos) + { + return ctor::arch::windows; + } + + std::cerr << "Could not deduce gcc arch from '" << str << "'" << std::endl; + + return ctor::arch::unknown; +} + ctor::c_flag c_option(const std::string& flag) { - if(flag.substr(0, 2) == "-I") + if(flag.starts_with("-I")) { std::string path = flag.substr(2); path.erase(0, path.find_first_not_of(' ')); @@ -160,7 +248,7 @@ ctor::c_flag c_option(const std::string& flag) ctor::cxx_flag cxx_option(const std::string& flag) { - if(flag.substr(0, 2) == "-I") + if(flag.starts_with("-I")) { std::string path = flag.substr(2); path.erase(0, path.find_first_not_of(' ')); @@ -172,7 +260,7 @@ ctor::cxx_flag cxx_option(const std::string& flag) ctor::ld_flag ld_option(const std::string& flag) { - if(flag.substr(0, 2) == "-L") + if(flag.starts_with("-L")) { std::string path = flag.substr(2); path.erase(0, path.find_first_not_of(' ')); @@ -320,34 +408,37 @@ std::vector asm_option(ctor::asm_opt opt, const std::string& arg) std::cerr << "Unsupported compiler option.\n"; return {}; } +} // gcc:: -std::string extension(ctor::target_type target_type) +std::string get_arch(ctor::output_system system) { - switch(target_type) + auto toolchain = getToolChain(system); + switch(toolchain) { - case ctor::target_type::automatic: - break; - case ctor::target_type::executable: - return ""; - case ctor::target_type::static_library: - return ".a"; - case ctor::target_type::dynamic_library: - return ".so"; - case ctor::target_type::object: - return ".o"; - case ctor::target_type::unit_test: - return ""; - case ctor::target_type::unit_test_library: - return ".a"; - case ctor::target_type::function: - break; - case ctor::target_type::unknown: + case ctor::toolchain::clang: + case ctor::toolchain::gcc: + return gcc::get_arch(system); + case ctor::toolchain::any: + case ctor::toolchain::none: break; } return {}; } -} // gcc:: +ctor::arch get_arch(ctor::output_system system, const std::string& str) +{ + auto toolchain = getToolChain(system); + switch(toolchain) + { + case ctor::toolchain::clang: + case ctor::toolchain::gcc: + return gcc::get_arch(str); + case ctor::toolchain::any: + case ctor::toolchain::none: + break; + } + return ctor::arch::unknown; +} std::vector c_option(ctor::toolchain toolchain, ctor::c_opt opt, @@ -746,6 +837,7 @@ ctor::target_type target_type_from_extension(ctor::toolchain toolchain, std::filesystem::path extension(ctor::toolchain toolchain, ctor::target_type target_type, + ctor::output_system system, const std::filesystem::path& file) { auto type = target_type_from_extension(toolchain, file); @@ -755,16 +847,93 @@ std::filesystem::path extension(ctor::toolchain toolchain, return file; } + const auto& c = ctor::get_configuration(); + ctor::arch arch{}; + switch(system) + { + case ctor::output_system::host: + arch = c.host_arch; + break; + case ctor::output_system::build: + arch = c.build_arch; + break; + } + + // This might be before configure - so detection is needed for boostrap + if(arch == ctor::arch::unknown) + { + arch = get_arch(system, get_arch(system)); + } + std::string ext{file.extension().string()}; - switch(toolchain) + switch(target_type) { - case ctor::toolchain::gcc: - case ctor::toolchain::clang: - ext = gcc::extension(target_type); + case ctor::target_type::automatic: + break; + case ctor::target_type::executable: + case ctor::target_type::unit_test: + switch(arch) + { + case ctor::arch::unix: + case ctor::arch::apple: + ext = ""; + break; + case ctor::arch::windows: + ext = ".exe"; + break; + case ctor::arch::unknown: + break; + } + break; + case ctor::target_type::static_library: + case ctor::target_type::unit_test_library: + switch(arch) + { + case ctor::arch::unix: + case ctor::arch::apple: + ext = ".a"; + break; + case ctor::arch::windows: + ext = ".lib"; + break; + case ctor::arch::unknown: + break; + } + break; + case ctor::target_type::dynamic_library: + switch(arch) + { + case ctor::arch::unix: + ext = ".so"; + break; + case ctor::arch::apple: + ext = ".dylib"; + break; + case ctor::arch::windows: + ext = ".dll"; + break; + case ctor::arch::unknown: + break; + } + break; + case ctor::target_type::object: + switch(arch) + { + case ctor::arch::unix: + case ctor::arch::apple: + ext = ".o"; + break; + case ctor::arch::windows: + ext = ".obj"; + break; + case ctor::arch::unknown: + break; + } + break; + case ctor::target_type::function: + break; + case ctor::target_type::unknown: break; - case ctor::toolchain::any: - case ctor::toolchain::none: - return file; } auto output{file}; diff --git a/src/tools.h b/src/tools.h index 4fb6302..188d49f 100644 --- a/src/tools.h +++ b/src/tools.h @@ -17,6 +17,8 @@ std::ostream& operator<<(std::ostream& stream, const ctor::ld_opt& opt); std::ostream& operator<<(std::ostream& stream, const ctor::ar_opt& opt); std::ostream& operator<<(std::ostream& stream, const ctor::asm_opt& opt); +std::string get_arch(ctor::output_system system); +ctor::arch get_arch(ctor::output_system system, const std::string& str); //! Get tool-chain type from compiler path string ctor::toolchain getToolChain(const std::string& compiler); @@ -118,4 +120,5 @@ ctor::target_type target_type_from_extension(ctor::toolchain toolchain, // mingw .exe .lib .dll std::filesystem::path extension(ctor::toolchain toolchain, ctor::target_type target_type, + ctor::output_system system, const std::filesystem::path& file); -- cgit v1.2.3