diff options
author | John Hodge <tpg@mutabah.net> | 2018-06-03 14:48:39 +0800 |
---|---|---|
committer | John Hodge <tpg@mutabah.net> | 2018-06-03 14:48:39 +0800 |
commit | 50ab851adfda92d2ccc3ff8d0f8c6a5bf37ed484 (patch) | |
tree | 5c52bb04e8a9efe60ae79e3c91deaebdb3953e6e | |
parent | 1d136695352a7e3059952f50e7b0bef5b8465205 (diff) | |
download | mrust-50ab851adfda92d2ccc3ff8d0f8c6a5bf37ed484.tar.gz |
Trans C - Add configuration for linker args
-rw-r--r-- | src/trans/codegen_c.cpp | 28 | ||||
-rw-r--r-- | src/trans/target.cpp | 104 | ||||
-rw-r--r-- | src/trans/target.hpp | 12 |
3 files changed, 114 insertions, 30 deletions
diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index a4b0387a..c30657bf 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -205,7 +205,7 @@ namespace { m_outfile_path_c(outfile + ".c"), m_of(m_outfile_path_c) { - switch(Target_GetCurSpec().m_codegen_mode) + switch(Target_GetCurSpec().m_backend_c.m_codegen_mode) { case CodegenMode::Gnu11: m_compiler = Compiler::Gcc; @@ -303,7 +303,7 @@ namespace { << "\treturn ((v&0xFFFFFFFF) == 0 ? __builtin_ctz(v>>32) + 32 : __builtin_ctz(v));\n" << "}\n" ; - break; + break; case Compiler::Msvc: m_of << "static inline uint64_t __builtin_popcount(uint64_t v) {\n" @@ -567,7 +567,7 @@ namespace { // - `gcc-${TRIPLE}` (if available) // - `gcc` as fallback { - ::std::string varname = "CC-" + Target_GetCurSpec().m_c_compiler; + ::std::string varname = "CC-" + Target_GetCurSpec().m_backend_c.m_c_compiler; if( getenv(varname.c_str()) ) { args.push_back( getenv(varname.c_str()) ); } @@ -576,12 +576,14 @@ namespace { } else { // TODO: Determine if the compiler can't be found, and fall back to `gcc` if that's the case - args.push_back( Target_GetCurSpec().m_c_compiler + "-gcc" ); + args.push_back( Target_GetCurSpec().m_backend_c.m_c_compiler + "-gcc" ); //args.push_back( "gcc" ); } } - args.push_back("-ffunction-sections"); - args.push_back("-pthread"); + for( const auto& a : Target_GetCurSpec().m_backend_c.m_compiler_opts ) + { + args.push_back( a.c_str() ); + } switch(opt.opt_level) { case 0: break; @@ -624,7 +626,10 @@ namespace { { args.push_back("-l"); args.push_back(path.c_str()); } - args.push_back("-Wl,--gc-sections"); + for( const auto& a : Target_GetCurSpec().m_backend_c.m_linker_opts ) + { + args.push_back( a.c_str() ); + } } else { @@ -633,8 +638,9 @@ namespace { break; case Compiler::Msvc: // TODO: Look up these paths in the registry and use CreateProcess instead of system + // - OR, run `vcvarsall` and get the required environment variables and PATH from it? args.push_back(detect_msvc().path_vcvarsall); - args.push_back( Target_GetCurSpec().m_c_compiler ); + args.push_back( Target_GetCurSpec().m_backend_c.m_c_compiler ); args.push_back("&"); args.push_back("cl.exe"); args.push_back("/nologo"); @@ -680,9 +686,9 @@ namespace { } args.push_back("kernel32.lib"); // Needed for Interlocked* - // Command-line specified linker search directories args.push_back("/link"); - //args.push_back("/verbose"); + + // Command-line specified linker search directories for(const auto& path : link_dirs ) { args.push_back(FMT("/LIBPATH:" << path)); @@ -3569,7 +3575,7 @@ namespace { #endif } - if( Target_GetCurSpec().m_c_compiler == "amd64" ) { + if( Target_GetCurSpec().m_backend_c.m_c_compiler == "amd64" ) { MIR_TODO(mir_res, "MSVC amd64 doesn't support inline assembly, need to have a transform for '" << e.tpl << "'"); } m_of << indent << "__asm {\n"; diff --git a/src/trans/target.cpp b/src/trans/target.cpp index 87b5aa1d..1727cdba 100644 --- a/src/trans/target.cpp +++ b/src/trans/target.cpp @@ -133,11 +133,11 @@ namespace check_path_length(key_val, 3); if( key_val.value.as_string() == "msvc" ) { - rv.m_codegen_mode = CodegenMode::Msvc; + rv.m_backend_c.m_codegen_mode = CodegenMode::Msvc; } else if( key_val.value.as_string() == "gnu" ) { - rv.m_codegen_mode = CodegenMode::Gnu11; + rv.m_backend_c.m_codegen_mode = CodegenMode::Gnu11; } else { @@ -148,7 +148,23 @@ namespace else if( key_val.path[2] == "target" ) { check_path_length(key_val, 3); - rv.m_c_compiler = key_val.value.as_string(); + rv.m_backend_c.m_c_compiler = key_val.value.as_string(); + } + else if( key_val.path[2] == "compiler-opts" ) + { + check_path_length(key_val, 3); + for(const auto& v : key_val.value.as_list()) + { + rv.m_backend_c.m_compiler_opts.push_back( v.as_string() ); + } + } + else if( key_val.path[2] == "linker-opts" ) + { + check_path_length(key_val, 3); + for(const auto& v : key_val.value.as_list()) + { + rv.m_backend_c.m_linker_opts.push_back( v.as_string() ); + } } else { @@ -233,8 +249,56 @@ namespace return rv; } + void save_spec_to_file(const ::std::string& filename, const TargetSpec& spec) + { + // TODO: Have a round-trip unit test + ::std::ofstream of(filename); + + struct H + { + static const char* tfstr(bool v) + { + return v ? "true" : "false"; + } + static const char* c_variant_name(const CodegenMode m) + { + switch(m) + { + case CodegenMode::Gnu11: return "gnu"; + case CodegenMode::Msvc: return "msvc"; + } + return ""; + } + }; + + of + << "[target]\n" + << "family = \"" << spec.m_family << "\"\n" + << "os-name = \"" << spec.m_os_name << "\"\n" + << "env-name = \"" << spec.m_env_name << "\"\n" + //<< "arch = \"" << spec.m_arch.m_name << "\"\n" + << "\n" + << "[backend.c]\n" + << "variant = \"" << H::c_variant_name(spec.m_backend_c.m_codegen_mode) << "\"\n" + << "target = \"" << spec.m_backend_c.m_c_compiler << "\"\n" + << "compiler-opts = [" << spec.m_backend_c.m_compiler_opts << "]\n" + << "linker-opts = [" << spec.m_backend_c.m_linker_opts << "]\n" + << "\n" + << "[arch]" + << "name = \"" << spec.m_arch.m_name << "\"\n" + << "pointer-bits = " << spec.m_arch.m_pointer_bits << "\n" + << "is-big-endian = " << H::tfstr(spec.m_arch.m_big_endian) << "\n" + << "has-atomic-u8 = " << H::tfstr(spec.m_arch.m_atomics.u8) << "\n" + << "has-atomic-u16 = " << H::tfstr(spec.m_arch.m_atomics.u16) << "\n" + << "has-atomic-u32 = " << H::tfstr(spec.m_arch.m_atomics.u32) << "\n" + << "has-atomic-u64 = " << H::tfstr(spec.m_arch.m_atomics.u64) << "\n" + << "has-atomic-ptr = " << H::tfstr(spec.m_arch.m_atomics.ptr) << "\n" + ; + } TargetSpec init_from_spec_name(const ::std::string& target_name) { + // Options for all the fully-GNU environments + #define BACKEND_C_OPTS_GNU {"-ffunction-sections", "-pthread"}, {"-Wl,--gc-sections"} // If there's a '/' or a '\' in the filename, open it as a path, otherwise assume it's a triple. if( target_name.find('/') != ::std::string::npos || target_name.find('\\') != ::std::string::npos ) { @@ -243,98 +307,100 @@ namespace else if(target_name == "i586-linux-gnu") { return TargetSpec { - "unix", "linux", "gnu", CodegenMode::Gnu11, "i586-linux-gnu", + "unix", "linux", "gnu", {CodegenMode::Gnu11, "i586-linux-gnu", BACKEND_C_OPTS_GNU}, ARCH_X86 }; } else if(target_name == "x86_64-linux-gnu") { return TargetSpec { - "unix", "linux", "gnu", CodegenMode::Gnu11, "x86_64-linux-gnu", + "unix", "linux", "gnu", {CodegenMode::Gnu11, "x86_64-linux-gnu", BACKEND_C_OPTS_GNU}, ARCH_X86_64 }; } else if(target_name == "arm-linux-gnu") { return TargetSpec { - "unix", "linux", "gnu", CodegenMode::Gnu11, "arm-elf-eabi", + "unix", "linux", "gnu", {CodegenMode::Gnu11, "arm-elf-eabi", BACKEND_C_OPTS_GNU}, ARCH_ARM32 }; } else if(target_name == "aarch64-linux-gnu") { return TargetSpec { - "unix", "linux", "gnu", CodegenMode::Gnu11, "aarch64-linux-gnu", + "unix", "linux", "gnu", {CodegenMode::Gnu11, "aarch64-linux-gnu", BACKEND_C_OPTS_GNU}, ARCH_ARM64 }; } else if(target_name == "i586-windows-gnu") { return TargetSpec { - "windows", "windows", "gnu", CodegenMode::Gnu11, "mingw32", + "windows", "windows", "gnu", {CodegenMode::Gnu11, "mingw32", BACKEND_C_OPTS_GNU}, ARCH_X86 }; } else if(target_name == "x86_64-windows-gnu") { return TargetSpec { - "windows", "windows", "gnu", CodegenMode::Gnu11, "x86_64-w64-mingw32", + "windows", "windows", "gnu", {CodegenMode::Gnu11, "x86_64-w64-mingw32", BACKEND_C_OPTS_GNU}, ARCH_X86_64 }; } else if (target_name == "x86-windows-msvc") { + // TODO: Should this include the "kernel32.lib" inclusion? return TargetSpec { - "windows", "windows", "msvc", CodegenMode::Msvc, "x86", + "windows", "windows", "msvc", {CodegenMode::Msvc, "x86", {}, {}}, ARCH_X86 }; } else if (target_name == "x86_64-windows-msvc") { return TargetSpec { - "windows", "windows", "msvc", CodegenMode::Msvc, "amd64", + "windows", "windows", "msvc", {CodegenMode::Msvc, "amd64", {}, {}}, ARCH_X86_64 }; } else if(target_name == "x86_64-unknown-netbsd") { return TargetSpec { - "unix", "netbsd", "gnu", CodegenMode::Gnu11, "x86_64-unknown-netbsd", + "unix", "netbsd", "gnu", {CodegenMode::Gnu11, "x86_64-unknown-netbsd", BACKEND_C_OPTS_GNU}, ARCH_X86_64 }; } else if(target_name == "i686-unknown-openbsd") { return TargetSpec { - "unix", "openbsd", "gnu", CodegenMode::Gnu11, "i686-unknown-openbsd", + "unix", "openbsd", "gnu", {CodegenMode::Gnu11, "i686-unknown-openbsd", BACKEND_C_OPTS_GNU}, ARCH_X86 }; } else if(target_name == "x86_64-unknown-openbsd") { return TargetSpec { - "unix", "openbsd", "gnu", CodegenMode::Gnu11, "x86_64-unknown-openbsd", + "unix", "openbsd", "gnu", {CodegenMode::Gnu11, "x86_64-unknown-openbsd", BACKEND_C_OPTS_GNU}, ARCH_X86_64 }; } else if(target_name == "arm-unknown-openbsd") { return TargetSpec { - "unix", "openbsd", "gnu", CodegenMode::Gnu11, "arm-unknown-openbsd", + "unix", "openbsd", "gnu", {CodegenMode::Gnu11, "arm-unknown-openbsd", BACKEND_C_OPTS_GNU}, ARCH_ARM32 }; } else if(target_name == "aarch64-unknown-openbsd") { return TargetSpec { - "unix", "openbsd", "gnu", CodegenMode::Gnu11, "aarch64-unknown-openbsd", + "unix", "openbsd", "gnu", {CodegenMode::Gnu11, "aarch64-unknown-openbsd", BACKEND_C_OPTS_GNU}, ARCH_ARM64 }; } else if(target_name == "x86_64-apple-macosx") { + // NOTE: OSX uses clang and lld, which don't fully support the defaults used for GNU targets return TargetSpec { - "unix", "macos", "gnu", CodegenMode::Gnu11, "x86_64-apple-darwin", + "unix", "macos", "gnu", {CodegenMode::Gnu11, "x86_64-apple-darwin", {}, {}}, ARCH_X86_64 }; } @@ -351,6 +417,10 @@ const TargetSpec& Target_GetCurSpec() { return g_target; } +void Target_ExportCurSpec(const ::std::string& filename) +{ + save_spec_to_file(filename, g_target); +} void Target_SetCfg(const ::std::string& target_name) { g_target = init_from_spec_name(target_name); diff --git a/src/trans/target.hpp b/src/trans/target.hpp index 81205831..b1ed9456 100644 --- a/src/trans/target.hpp +++ b/src/trans/target.hpp @@ -31,14 +31,20 @@ struct TargetArch bool ptr; } m_atomics; }; +struct BackendOptsC +{ + CodegenMode m_codegen_mode; + ::std::string m_c_compiler; // MSVC arch / GNU triplet + ::std::vector< ::std::string> m_compiler_opts; + ::std::vector< ::std::string> m_linker_opts; +}; struct TargetSpec { ::std::string m_family; ::std::string m_os_name; ::std::string m_env_name; - CodegenMode m_codegen_mode; - ::std::string m_c_compiler; // MSVC arch / GNU triplet + BackendOptsC m_backend_c; TargetArch m_arch; }; @@ -96,6 +102,8 @@ struct TypeRepr extern const TargetSpec& Target_GetCurSpec(); extern void Target_SetCfg(const ::std::string& target_name); +extern void Target_ExportCurSpec(const ::std::string& filename); + extern bool Target_GetSizeOf(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty, size_t& out_size); extern bool Target_GetAlignOf(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty, size_t& out_align); extern bool Target_GetSizeAndAlignOf(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty, size_t& out_size, size_t& out_align); |