diff options
Diffstat (limited to 'src/tools.cc')
-rw-r--r-- | src/tools.cc | 926 |
1 files changed, 866 insertions, 60 deletions
diff --git a/src/tools.cc b/src/tools.cc index 7e8ac78..be94794 100644 --- a/src/tools.cc +++ b/src/tools.cc @@ -5,132 +5,938 @@ #include <filesystem> #include <iostream> +#include <sstream> #include <cassert> +#include <cstdio> -ToolChain getToolChain(OutputSystem system) +#include "util.h" + +std::ostream& operator<<(std::ostream& stream, const ctor::c_opt& opt) { - std::string compiler; - switch(system) + // Adding to this enum should also imply adding to the unit-tests below + switch(opt) { - case OutputSystem::Host: - compiler = getConfiguration(cfg::host_cxx, "g++"); - break; - case OutputSystem::Build: - compiler = getConfiguration(cfg::build_cxx, "g++"); - break; + case ctor::c_opt::output: stream << "ctor::c_opt::output"; break; + case ctor::c_opt::debug: stream << "ctor::c_opt::debug"; break; + case ctor::c_opt::warn_all: stream << "ctor::c_opt::warn_all"; break; + case ctor::c_opt::warnings_as_errors: stream << "ctor::c_opt::warnings_as_errors"; break; + case ctor::c_opt::generate_dep_tree: stream << "ctor::c_opt::generate_dep_tree"; break; + case ctor::c_opt::no_link: stream << "ctor::c_opt::no_link"; break; + case ctor::c_opt::include_path: stream << "ctor::c_opt::include_path"; break; + case ctor::c_opt::c_std: stream << "ctor::c_opt::c_std"; break; + case ctor::c_opt::optimization: stream << "ctor::c_opt::optimization"; break; + case ctor::c_opt::position_independent_code: stream << "ctor::c_opt::position_independent_code"; break; + case ctor::c_opt::position_independent_executable: stream << "ctor::c_opt::position_independent_executable"; break; + case ctor::c_opt::custom: stream << "ctor::c_opt::custom"; break; + } + + return stream; +} + +std::ostream& operator<<(std::ostream& stream, const ctor::cxx_opt& opt) +{ + // Adding to this enum should also imply adding to the unit-tests below + switch(opt) + { + case ctor::cxx_opt::output: stream << "ctor::cxx_opt::output"; break; + case ctor::cxx_opt::debug: stream << "ctor::cxx_opt::debug"; break; + case ctor::cxx_opt::warn_all: stream << "ctor::cxx_opt::warn_all"; break; + case ctor::cxx_opt::warnings_as_errors: stream << "ctor::cxx_opt::warnings_as_errors"; break; + case ctor::cxx_opt::generate_dep_tree: stream << "ctor::cxx_opt::generate_dep_tree"; break; + case ctor::cxx_opt::no_link: stream << "ctor::cxx_opt::no_link"; break; + case ctor::cxx_opt::include_path: stream << "ctor::cxx_opt::include_path"; break; + case ctor::cxx_opt::cpp_std: stream << "ctor::cxx_opt::cpp_std"; break; + case ctor::cxx_opt::optimization: stream << "ctor::cxx_opt::optimization"; break; + case ctor::cxx_opt::position_independent_code: stream << "ctor::cxx_opt::position_independent_code"; break; + case ctor::cxx_opt::position_independent_executable: stream << "ctor::cxx_opt::position_independent_executable"; break; + case ctor::cxx_opt::custom: stream << "ctor::cxx_opt::custom"; break; + } + + return stream; +} + +std::ostream& operator<<(std::ostream& stream, const ctor::ld_opt& opt) +{ + // Adding to this enum should also imply adding to the unit-tests below + switch(opt) + { + case ctor::ld_opt::output: stream << "ctor::ld_opt::output"; break; + case ctor::ld_opt::strip: stream << "ctor::ld_opt::strip"; break; + case ctor::ld_opt::warn_all: stream << "ctor::ld_opt::warn_all"; break; + case ctor::ld_opt::warnings_as_errors: stream << "ctor::ld_opt::warnings_as_errors"; break; + case ctor::ld_opt::library_path: stream << "ctor::ld_opt::library_path"; break; + case ctor::ld_opt::link: stream << "ctor::ld_opt::link"; break; + case ctor::ld_opt::cpp_std: stream << "ctor::ld_opt::cpp_std"; break; + case ctor::ld_opt::build_shared: stream << "ctor::ld_opt::build_shared"; break; + case ctor::ld_opt::threads: stream << "ctor::ld_opt::threads"; break; + case ctor::ld_opt::position_independent_code: stream << "ctor::ld_opt::position_independent_code"; break; + case ctor::ld_opt::position_independent_executable: stream << "ctor::ld_opt::position_independent_executable"; break; + case ctor::ld_opt::custom: stream << "ctor::ld_opt::custom"; break; + } + + return stream; +} + +std::ostream& operator<<(std::ostream& stream, const ctor::ar_opt& opt) +{ + // Adding to this enum should also imply adding to the unit-tests below + switch(opt) + { + case ctor::ar_opt::replace: stream << "ctor::ar_opt::replace"; break; + case ctor::ar_opt::add_index: stream << "ctor::ar_opt::add_index"; break; + case ctor::ar_opt::create: stream << "ctor::ar_opt::create"; break; + case ctor::ar_opt::output: stream << "ctor::ar_opt::output"; break; + case ctor::ar_opt::custom: stream << "ctor::ar_opt::custom"; break; } + return stream; +} + +std::ostream& operator<<(std::ostream& stream, const ctor::asm_opt& opt) +{ + // Adding to this enum should also imply adding to the unit-tests below + switch(opt) + { + case ctor::asm_opt::custom: stream << "ctor::asm_opt::custom"; break; + } + + return stream; +} + +ctor::toolchain getToolChain(const std::string& compiler) +{ std::filesystem::path cc(compiler); auto cc_cmd = cc.stem().string(); // Note: "g++" is a substring of "clang++" so "clang++" must be tested first. - if(cc_cmd.find("clang++") != std::string::npos) + if(cc_cmd.find("clang++") != std::string::npos || + cc_cmd.find("clang") != std::string::npos) { - return ToolChain::clang; + return ctor::toolchain::clang; } - else if(cc_cmd.find("g++") != std::string::npos) + else if(cc_cmd.find("g++") != std::string::npos || + cc_cmd.find("gcc") != std::string::npos || + cc_cmd.find("mingw") != std::string::npos) { - return ToolChain::gcc; + return ctor::toolchain::gcc; } std::cerr << "Unsupported output system.\n"; - return ToolChain::gcc; + return ctor::toolchain::gcc; +} + +ctor::toolchain getToolChain(ctor::output_system system) +{ + const auto& cfg = ctor::get_configuration(); + if(system == ctor::output_system::host) + { + if(cfg.host_toolchain != ctor::toolchain::none) + { + return cfg.host_toolchain; + } + return getToolChain(cfg.get(ctor::cfg::host_cxx, "g++")); + } + else + { + if(cfg.build_toolchain != ctor::toolchain::none) + { + return cfg.build_toolchain; + } + return getToolChain(cfg.get(ctor::cfg::build_cxx, "g++")); + } +} + +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.starts_with("-I")) + { + std::string path = flag.substr(2); + path.erase(0, path.find_first_not_of(' ')); + return { ctor::c_opt::include_path, path }; + } + + return { ctor::c_opt::custom, flag }; +} + +ctor::cxx_flag cxx_option(const std::string& flag) +{ + if(flag.starts_with("-I")) + { + std::string path = flag.substr(2); + path.erase(0, path.find_first_not_of(' ')); + return { ctor::cxx_opt::include_path, path }; + } + + return { ctor::cxx_opt::custom, flag }; } -namespace +ctor::ld_flag ld_option(const std::string& flag) { -std::vector<std::string> getOptionGcc(opt option, const std::string& arg) + if(flag.starts_with("-L")) + { + std::string path = flag.substr(2); + path.erase(0, path.find_first_not_of(' ')); + return { ctor::ld_opt::library_path, path }; + } + + return { ctor::ld_opt::custom, flag }; +} + +ctor::ar_flag ar_option(const std::string& flag) { - switch(option) + return { ctor::ar_opt::custom, flag }; +} + +std::vector<std::string> cxx_option(ctor::cxx_opt opt, const std::string& arg) +{ + switch(opt) { - case opt::output: + case ctor::cxx_opt::output: return {"-o", arg}; - case opt::debug: + case ctor::cxx_opt::debug: return {"-g"}; - case opt::strip: - return {"-s"}; - case opt::warn_all: + case ctor::cxx_opt::warn_all: + return {"-Wall"}; + case ctor::cxx_opt::warnings_as_errors: + return {"-Werror"}; + case ctor::cxx_opt::generate_dep_tree: + return {"-MMD"}; + case ctor::cxx_opt::no_link: + return {"-c"}; + case ctor::cxx_opt::include_path: + return {"-I" + arg}; + case ctor::cxx_opt::cpp_std: + return {"-std=" + arg}; + case ctor::cxx_opt::optimization: + return {"-O" + arg}; + case ctor::cxx_opt::position_independent_code: + return {"-fPIC"}; + case ctor::cxx_opt::position_independent_executable: + return {"-fPIE"}; + case ctor::cxx_opt::custom: + return {arg}; + } + + std::cerr << "Unsupported compiler option.\n"; + return {}; +} + +std::vector<std::string> c_option(ctor::c_opt opt, const std::string& arg) +{ + switch(opt) + { + case ctor::c_opt::output: + return {"-o", arg}; + case ctor::c_opt::debug: + return {"-g"}; + case ctor::c_opt::warn_all: return {"-Wall"}; - case opt::warnings_as_errors: + case ctor::c_opt::warnings_as_errors: return {"-Werror"}; - case opt::generate_dep_tree: + case ctor::c_opt::generate_dep_tree: return {"-MMD"}; - case opt::no_link: + case ctor::c_opt::no_link: return {"-c"}; - case opt::include_path: + case ctor::c_opt::include_path: return {"-I" + arg}; - case opt::library_path: + case ctor::c_opt::c_std: + return {"-std=" + arg}; + case ctor::c_opt::optimization: + return {"-O" + arg}; + case ctor::c_opt::position_independent_code: + return {"-fPIC"}; + case ctor::c_opt::position_independent_executable: + return {"-fPIE"}; + case ctor::c_opt::custom: + return {arg}; + } + + std::cerr << "Unsupported compiler option.\n"; + return {}; +} + +std::vector<std::string> ld_option(ctor::ld_opt opt, const std::string& arg) +{ + switch(opt) + { + case ctor::ld_opt::output: + return {"-o", arg}; + case ctor::ld_opt::strip: + return {"-s"}; + case ctor::ld_opt::warn_all: + return {"-Wall"}; + case ctor::ld_opt::warnings_as_errors: + return {"-Werror"}; + case ctor::ld_opt::library_path: return {"-L" + arg}; - case opt::link: + case ctor::ld_opt::link: return {"-l" + arg}; - case opt::cpp_std: + case ctor::ld_opt::cpp_std: return {"-std=" + arg}; - case opt::build_shared: + case ctor::ld_opt::build_shared: return {"-shared"}; - case opt::threads: + case ctor::ld_opt::threads: return {"-pthread"}; - case opt::optimization: - return {"-O" + arg}; - case opt::position_independent_code: + case ctor::ld_opt::position_independent_code: return {"-fPIC"}; - case opt::position_independent_executable: + case ctor::ld_opt::position_independent_executable: return {"-fPIE"}; - case opt::custom: + case ctor::ld_opt::custom: + return {arg}; + } + + std::cerr << "Unsupported compiler option.\n"; + return {}; +} + +std::vector<std::string> ar_option(ctor::ar_opt opt, const std::string& arg) +{ + switch(opt) + { + case ctor::ar_opt::replace: + return {"-r"}; + case ctor::ar_opt::add_index: + return {"-s"}; + case ctor::ar_opt::create: + return {"-c"}; + case ctor::ar_opt::output: + return {arg}; + case ctor::ar_opt::custom: + return {arg}; + } + + std::cerr << "Unsupported compiler option.\n"; + return {}; +} + +std::vector<std::string> asm_option(ctor::asm_opt opt, const std::string& arg) +{ + switch(opt) + { + case ctor::asm_opt::custom: return {arg}; } std::cerr << "Unsupported compiler option.\n"; return {}; } +} // gcc:: + +std::string get_arch(ctor::output_system system) +{ + auto toolchain = getToolChain(system); + switch(toolchain) + { + case ctor::toolchain::clang: + case ctor::toolchain::gcc: + return gcc::get_arch(system); + case ctor::toolchain::any: + case ctor::toolchain::none: + break; + } + return {}; +} + +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<std::string> c_option(ctor::toolchain toolchain, + ctor::c_opt opt, + const std::string& arg) +{ + switch(toolchain) + { + case ctor::toolchain::gcc: + case ctor::toolchain::clang: + return gcc::c_option(opt, arg); + case ctor::toolchain::any: + { + std::ostringstream ss; + ss << "{" << opt; + if(!arg.empty()) + { + ss << ", \"" << arg << "\""; + } + ss << "}"; + return { ss.str() }; + } + case ctor::toolchain::none: + break; + } + + std::cerr << "Unsupported tool-chain.\n"; + return {}; +} + +std::vector<std::string> cxx_option(ctor::toolchain toolchain, + ctor::cxx_opt opt, + const std::string& arg) +{ + switch(toolchain) + { + case ctor::toolchain::gcc: + case ctor::toolchain::clang: + return gcc::cxx_option(opt, arg); + case ctor::toolchain::any: + { + std::ostringstream ss; + ss << "{" << opt; + if(!arg.empty()) + { + ss << ", \"" << arg << "\""; + } + ss << "}"; + return { ss.str() }; + } + case ctor::toolchain::none: + break; + } + + std::cerr << "Unsupported tool-chain.\n"; + return {}; +} + +std::vector<std::string> ld_option(ctor::toolchain toolchain, + ctor::ld_opt opt, + const std::string& arg) +{ + switch(toolchain) + { + case ctor::toolchain::gcc: + case ctor::toolchain::clang: + return gcc::ld_option(opt, arg); + case ctor::toolchain::any: + { + std::ostringstream ss; + ss << "{" << opt; + if(!arg.empty()) + { + ss << ", \"" << arg << "\""; + } + ss << "}"; + return { ss.str() }; + } + case ctor::toolchain::none: + break; + } + + std::cerr << "Unsupported tool-chain.\n"; + return {}; } -std::vector<std::string> getOption(ToolChain tool_chain, - opt option, +std::vector<std::string> ar_option(ctor::toolchain toolchain, + ctor::ar_opt opt, const std::string& arg) { - switch(tool_chain) + switch(toolchain) { - case ToolChain::gcc: - case ToolChain::clang: - return getOptionGcc(option, arg); + case ctor::toolchain::gcc: + case ctor::toolchain::clang: + return gcc::ar_option(opt, arg); + case ctor::toolchain::any: + { + std::ostringstream ss; + ss << "{" << opt; + if(!arg.empty()) + { + ss << ", \"" << arg << "\""; + } + ss << "}"; + return { ss.str() }; + } + case ctor::toolchain::none: + break; } std::cerr << "Unsupported tool-chain.\n"; return {}; } +std::vector<std::string> asm_option(ctor::toolchain toolchain, + ctor::asm_opt opt, + const std::string& arg) +{ + switch(toolchain) + { + case ctor::toolchain::gcc: + case ctor::toolchain::clang: + return gcc::asm_option(opt, arg); + case ctor::toolchain::any: + { + std::ostringstream ss; + ss << "{" << opt; + if(!arg.empty()) + { + ss << ", \"" << arg << "\""; + } + ss << "}"; + return { ss.str() }; + } + case ctor::toolchain::none: + break; + } + + std::cerr << "Unsupported tool-chain.\n"; + return {}; +} + + +ctor::c_flag c_option(const std::string& flag, ctor::toolchain toolchain) +{ + switch(toolchain) + { + case ctor::toolchain::gcc: + case ctor::toolchain::clang: + return gcc::c_option(flag); + case ctor::toolchain::any: + case ctor::toolchain::none: + break; + } + + return { ctor::c_opt::custom, flag }; +} + +ctor::cxx_flag cxx_option(const std::string& flag, ctor::toolchain toolchain) +{ + switch(toolchain) + { + case ctor::toolchain::gcc: + case ctor::toolchain::clang: + return gcc::cxx_option(flag); + case ctor::toolchain::any: + case ctor::toolchain::none: + break; + } + + return { ctor::cxx_opt::custom, flag }; +} + +ctor::ld_flag ld_option(const std::string& flag, ctor::toolchain toolchain) +{ + switch(toolchain) + { + case ctor::toolchain::gcc: + case ctor::toolchain::clang: + return gcc::ld_option(flag); + case ctor::toolchain::any: + case ctor::toolchain::none: + break; + } + + return { ctor::ld_opt::custom, flag }; +} + +ctor::ar_flag ar_option(const std::string& flag, ctor::toolchain toolchain) +{ + switch(toolchain) + { + case ctor::toolchain::gcc: + case ctor::toolchain::clang: + return gcc::ar_option(flag); + case ctor::toolchain::any: + case ctor::toolchain::none: + break; + } + + return { ctor::ar_opt::custom, flag }; +} + +ctor::asm_flag asm_option(const std::string& flag, ctor::toolchain toolchain) +{ + switch(toolchain) + { + case ctor::toolchain::gcc: + case ctor::toolchain::clang: + case ctor::toolchain::any: + case ctor::toolchain::none: + break; + } + + return { ctor::asm_opt::custom, flag }; +} + +// Flag to string coversions + +std::vector<std::string> to_strings(ctor::toolchain toolchain, + const ctor::c_flag& flag) +{ + if(flag.toolchain == ctor::toolchain::any || + flag.toolchain == toolchain) + { + return c_option(toolchain, flag.opt, flag.arg); + } + + return {}; +} + +std::vector<std::string> to_strings(ctor::toolchain toolchain, + const ctor::cxx_flag& flag) +{ + if(flag.toolchain == ctor::toolchain::any || + flag.toolchain == toolchain) + { + return cxx_option(toolchain, flag.opt, flag.arg); + } + + return {}; +} + +std::vector<std::string> to_strings(ctor::toolchain toolchain, + const ctor::ld_flag& flag) +{ + if(flag.toolchain == ctor::toolchain::any || + flag.toolchain == toolchain) + { + return ld_option(toolchain, flag.opt, flag.arg); + } + + return {}; +} + +std::vector<std::string> to_strings(ctor::toolchain toolchain, + const ctor::ar_flag& flag) +{ + if(flag.toolchain == ctor::toolchain::any || + flag.toolchain == toolchain) + { + return ar_option(toolchain, flag.opt, flag.arg); + } + + return {}; +} + +std::vector<std::string> to_strings(ctor::toolchain toolchain, + const ctor::asm_flag& flag) +{ + if(flag.toolchain == ctor::toolchain::any || + flag.toolchain == toolchain) + { + return asm_option(toolchain, flag.opt, flag.arg); + } + + return {}; +} + namespace { -std::pair<opt, std::string> getOptionGcc(const std::string& flag) +ctor::toolchain guess_toolchain(const std::string& opt) { - if(flag.substr(0, 2) == "-I") + if(opt.empty()) { - std::string path = flag.substr(2); - path.erase(0, path.find_first_not_of(' ')); - return { opt::include_path, path }; + return ctor::toolchain::any; } - if(flag.substr(0, 2) == "-L") + if(opt[0] == '-') { - std::string path = flag.substr(2); - path.erase(0, path.find_first_not_of(' ')); - return { opt::library_path, path }; + return ctor::toolchain::gcc; } - return { opt::custom, flag }; + //if(opt[0] == '/') + //{ + // return ctor::toolchain::msvc; + //} + return ctor::toolchain::any; +} +} + +template<> +ctor::flag<ctor::c_opt>::flag(const char* str) +{ + *this = c_option(str, guess_toolchain(str)); +} + +template<> +ctor::flag<ctor::cxx_opt>::flag(const char* str) +{ + *this = cxx_option(str, guess_toolchain(str)); +} + +template<> +ctor::flag<ctor::ld_opt>::flag(const char* str) +{ + *this = ld_option(str, guess_toolchain(str)); +} + +template<> +ctor::flag<ctor::ar_opt>::flag(const char* str) +{ + *this = ar_option(str, guess_toolchain(str)); } + +template<> +ctor::flag<ctor::asm_opt>::flag(const char* str) +{ + *this = asm_option(str, guess_toolchain(str)); } -std::pair<opt, std::string> getOption(const std::string& flag, - ToolChain tool_chain) + +ctor::target_type target_type_from_extension(ctor::toolchain toolchain, + const std::filesystem::path& file) { - switch(tool_chain) + auto ext = to_lower(file.extension().string()); + // Loosely based on: + // https://en.wikipedia.org/wiki/List_of_file_formats#Object_code,_executable_files,_shared_and_dynamically_linked_libraries + if(toolchain == ctor::toolchain::any || + toolchain == ctor::toolchain::gcc || + toolchain == ctor::toolchain::clang) { - case ToolChain::gcc: - case ToolChain::clang: - return getOptionGcc(flag); + if(ext == ".a") + { + return ctor::target_type::static_library; + } + + if(ext == ".so" || + ext == ".dylib") + { + return ctor::target_type::dynamic_library; + } + + if(ext == ".o") + { + return ctor::target_type::object; + } + + if(ext == "" || + ext == ".bin" || + ext == ".run" || + ext == ".out") + { + return ctor::target_type::executable; + } } - std::cerr << "Unsupported tool-chain.\n"; - return { opt::custom, flag }; + if(toolchain == ctor::toolchain::any// || + //toolchain == ctor::toolchain::msvc || + //toolchain == ctor::toolchain::mingw || + ) + { + if(ext == ".lib") + { + return ctor::target_type::static_library; + } + + if(ext == ".dll") + { + return ctor::target_type::dynamic_library; + } + + if(ext == ".obj") + { + return ctor::target_type::object; + } + + if(ext == ".exe" || + ext == ".com") + { + return ctor::target_type::executable; + } + } + + return ctor::target_type::unknown; +} + + +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); + if(type == target_type) + { + // File already has the correct extension + 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(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; + } + + auto output{file}; + output.replace_extension(ext); + return output; } |