1
Fork 0

Add a "system" ABI

This adds an other ABI option which allows a custom selection over the target
architecture and OS. The only current candidate for this change is that kernel32
on win32 uses stdcall, but on win64 it uses the cdecl calling convention.
Otherwise everywhere else this is defined as using the Cdecl calling convention.

cc #10049
Closes #8774
This commit is contained in:
Alex Crichton 2013-11-08 11:06:57 -08:00
parent 9d8dc004a0
commit 2fcc70ec9d
14 changed files with 151 additions and 109 deletions

View file

@ -418,15 +418,32 @@ calling foreign functions. Some foreign functions, most notably the Windows API,
conventions. Rust provides a way to tell the compiler which convention to use: conventions. Rust provides a way to tell the compiler which convention to use:
~~~~ ~~~~
#[cfg(target_os = "win32")] #[cfg(target_os = "win32", target_arch = "x86")]
#[link_name = "kernel32"] #[link_name = "kernel32"]
extern "stdcall" { extern "stdcall" {
fn SetEnvironmentVariableA(n: *u8, v: *u8) -> int; fn SetEnvironmentVariableA(n: *u8, v: *u8) -> int;
} }
~~~~ ~~~~
This applies to the entire `extern` block, and must be either `"cdecl"` or This applies to the entire `extern` block. The list of supported ABI constraints
`"stdcall"`. The compiler may eventually support other calling conventions. are:
* `stdcall`
* `aapcs`
* `cdecl`
* `fastcall`
* `Rust`
* `rust-intrinsic`
* `system`
* `C`
Most of the abis in this list are self-explanatory, but the `system` abi may
seem a little odd. This constraint selects whatever the appropriate ABI is for
interoperating with the target's libraries. For example, on win32 with a x86
architecture, this means that the abi used would be `stdcall`. On x86_64,
however, windows uses the `C` calling convention, so `C` would be used. This
means that in our previous example, we could have used `extern "system" { ... }`
to define a block for all windows systems, not just x86 ones.
# Interoperability with foreign code # Interoperability with foreign code

View file

@ -10,17 +10,17 @@
use back::target_strs; use back::target_strs;
use driver::session::sess_os_to_meta_os; use driver::session::sess_os_to_meta_os;
use driver::session;
use metadata::loader::meta_section_name; use metadata::loader::meta_section_name;
use syntax::abi;
pub fn get_target_strs(target_triple: ~str, target_os: session::Os) -> target_strs::t { pub fn get_target_strs(target_triple: ~str, target_os: abi::Os) -> target_strs::t {
return target_strs::t { return target_strs::t {
module_asm: ~"", module_asm: ~"",
meta_sect_name: meta_section_name(sess_os_to_meta_os(target_os)).to_owned(), meta_sect_name: meta_section_name(sess_os_to_meta_os(target_os)).to_owned(),
data_layout: match target_os { data_layout: match target_os {
session::OsMacos => { abi::OsMacos => {
~"e-p:32:32:32" + ~"e-p:32:32:32" +
"-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" + "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" +
"-f32:32:32-f64:64:64" + "-f32:32:32-f64:64:64" +
@ -28,7 +28,7 @@ pub fn get_target_strs(target_triple: ~str, target_os: session::Os) -> target_st
"-a0:0:64-n32" "-a0:0:64-n32"
} }
session::OsWin32 => { abi::OsWin32 => {
~"e-p:32:32:32" + ~"e-p:32:32:32" +
"-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" + "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" +
"-f32:32:32-f64:64:64" + "-f32:32:32-f64:64:64" +
@ -36,7 +36,7 @@ pub fn get_target_strs(target_triple: ~str, target_os: session::Os) -> target_st
"-a0:0:64-n32" "-a0:0:64-n32"
} }
session::OsLinux => { abi::OsLinux => {
~"e-p:32:32:32" + ~"e-p:32:32:32" +
"-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" + "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" +
"-f32:32:32-f64:64:64" + "-f32:32:32-f64:64:64" +
@ -44,7 +44,7 @@ pub fn get_target_strs(target_triple: ~str, target_os: session::Os) -> target_st
"-a0:0:64-n32" "-a0:0:64-n32"
} }
session::OsAndroid => { abi::OsAndroid => {
~"e-p:32:32:32" + ~"e-p:32:32:32" +
"-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" + "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" +
"-f32:32:32-f64:64:64" + "-f32:32:32-f64:64:64" +
@ -52,7 +52,7 @@ pub fn get_target_strs(target_triple: ~str, target_os: session::Os) -> target_st
"-a0:0:64-n32" "-a0:0:64-n32"
} }
session::OsFreebsd => { abi::OsFreebsd => {
~"e-p:32:32:32" + ~"e-p:32:32:32" +
"-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" + "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" +
"-f32:32:32-f64:64:64" + "-f32:32:32-f64:64:64" +

View file

@ -32,6 +32,7 @@ use std::run;
use std::str; use std::str;
use std::vec; use std::vec;
use std::rt::io::fs; use std::rt::io::fs;
use syntax::abi;
use syntax::ast; use syntax::ast;
use syntax::ast_map::{path, path_mod, path_name, path_pretty_name}; use syntax::ast_map::{path, path_mod, path_name, path_pretty_name};
use syntax::attr; use syntax::attr;
@ -864,13 +865,13 @@ pub fn mangle_internal_name_by_path(ccx: &mut CrateContext, path: path) -> ~str
} }
pub fn output_dll_filename(os: session::Os, lm: LinkMeta) -> ~str { pub fn output_dll_filename(os: abi::Os, lm: LinkMeta) -> ~str {
let (dll_prefix, dll_suffix) = match os { let (dll_prefix, dll_suffix) = match os {
session::OsWin32 => (win32::DLL_PREFIX, win32::DLL_SUFFIX), abi::OsWin32 => (win32::DLL_PREFIX, win32::DLL_SUFFIX),
session::OsMacos => (macos::DLL_PREFIX, macos::DLL_SUFFIX), abi::OsMacos => (macos::DLL_PREFIX, macos::DLL_SUFFIX),
session::OsLinux => (linux::DLL_PREFIX, linux::DLL_SUFFIX), abi::OsLinux => (linux::DLL_PREFIX, linux::DLL_SUFFIX),
session::OsAndroid => (android::DLL_PREFIX, android::DLL_SUFFIX), abi::OsAndroid => (android::DLL_PREFIX, android::DLL_SUFFIX),
session::OsFreebsd => (freebsd::DLL_PREFIX, freebsd::DLL_SUFFIX), abi::OsFreebsd => (freebsd::DLL_PREFIX, freebsd::DLL_SUFFIX),
}; };
format!("{}{}-{}-{}{}", dll_prefix, lm.name, lm.extras_hash, lm.vers, dll_suffix) format!("{}{}-{}-{}{}", dll_prefix, lm.name, lm.extras_hash, lm.vers, dll_suffix)
} }
@ -885,7 +886,7 @@ pub fn get_cc_prog(sess: Session) -> ~str {
match sess.opts.linker { match sess.opts.linker {
Some(ref linker) => linker.to_str(), Some(ref linker) => linker.to_str(),
None => match sess.targ_cfg.os { None => match sess.targ_cfg.os {
session::OsAndroid => abi::OsAndroid =>
match &sess.opts.android_cross_path { match &sess.opts.android_cross_path {
&Some(ref path) => { &Some(ref path) => {
format!("{}/bin/arm-linux-androideabi-gcc", *path) format!("{}/bin/arm-linux-androideabi-gcc", *path)
@ -895,7 +896,7 @@ pub fn get_cc_prog(sess: Session) -> ~str {
(--android-cross-path)") (--android-cross-path)")
} }
}, },
session::OsWin32 => ~"g++", abi::OsWin32 => ~"g++",
_ => ~"cc" _ => ~"cc"
} }
} }
@ -943,7 +944,7 @@ pub fn link_binary(sess: Session,
} }
// Clean up on Darwin // Clean up on Darwin
if sess.targ_cfg.os == session::OsMacos { if sess.targ_cfg.os == abi::OsMacos {
// FIXME (#9639): This needs to handle non-utf8 paths // FIXME (#9639): This needs to handle non-utf8 paths
run::process_status("dsymutil", [output.as_str().unwrap().to_owned()]); run::process_status("dsymutil", [output.as_str().unwrap().to_owned()]);
} }
@ -972,7 +973,7 @@ pub fn link_args(sess: Session,
// Converts a library file-stem into a cc -l argument // Converts a library file-stem into a cc -l argument
fn unlib(config: @session::config, stem: ~str) -> ~str { fn unlib(config: @session::config, stem: ~str) -> ~str {
if stem.starts_with("lib") && if stem.starts_with("lib") &&
config.os != session::OsWin32 { config.os != abi::OsWin32 {
stem.slice(3, stem.len()).to_owned() stem.slice(3, stem.len()).to_owned()
} else { } else {
stem stem
@ -1016,7 +1017,7 @@ pub fn link_args(sess: Session,
obj_filename.as_str().unwrap().to_owned()]); obj_filename.as_str().unwrap().to_owned()]);
let lib_cmd = match sess.targ_cfg.os { let lib_cmd = match sess.targ_cfg.os {
session::OsMacos => ~"-dynamiclib", abi::OsMacos => ~"-dynamiclib",
_ => ~"-shared" _ => ~"-shared"
}; };
@ -1067,7 +1068,7 @@ pub fn link_args(sess: Session,
// On mac we need to tell the linker to let this library // On mac we need to tell the linker to let this library
// be rpathed // be rpathed
if sess.targ_cfg.os == session::OsMacos { if sess.targ_cfg.os == abi::OsMacos {
// FIXME (#9639): This needs to handle non-utf8 paths // FIXME (#9639): This needs to handle non-utf8 paths
args.push("-Wl,-install_name,@rpath/" args.push("-Wl,-install_name,@rpath/"
+ output.filename_str().unwrap()); + output.filename_str().unwrap());
@ -1076,7 +1077,7 @@ pub fn link_args(sess: Session,
// On linux librt and libdl are an indirect dependencies via rustrt, // On linux librt and libdl are an indirect dependencies via rustrt,
// and binutils 2.22+ won't add them automatically // and binutils 2.22+ won't add them automatically
if sess.targ_cfg.os == session::OsLinux { if sess.targ_cfg.os == abi::OsLinux {
args.push_all([~"-lrt", ~"-ldl"]); args.push_all([~"-lrt", ~"-ldl"]);
// LLVM implements the `frem` instruction as a call to `fmod`, // LLVM implements the `frem` instruction as a call to `fmod`,
@ -1084,12 +1085,12 @@ pub fn link_args(sess: Session,
// have to be explicit about linking to it. See #2510 // have to be explicit about linking to it. See #2510
args.push(~"-lm"); args.push(~"-lm");
} }
else if sess.targ_cfg.os == session::OsAndroid { else if sess.targ_cfg.os == abi::OsAndroid {
args.push_all([~"-ldl", ~"-llog", ~"-lsupc++", ~"-lgnustl_shared"]); args.push_all([~"-ldl", ~"-llog", ~"-lsupc++", ~"-lgnustl_shared"]);
args.push(~"-lm"); args.push(~"-lm");
} }
if sess.targ_cfg.os == session::OsFreebsd { if sess.targ_cfg.os == abi::OsFreebsd {
args.push_all([~"-pthread", ~"-lrt", args.push_all([~"-pthread", ~"-lrt",
~"-L/usr/local/lib", ~"-lexecinfo", ~"-L/usr/local/lib", ~"-lexecinfo",
~"-L/usr/local/lib/gcc46", ~"-L/usr/local/lib/gcc46",

View file

@ -9,18 +9,18 @@
// except according to those terms. // except according to those terms.
use back::target_strs; use back::target_strs;
use driver::session;
use driver::session::sess_os_to_meta_os; use driver::session::sess_os_to_meta_os;
use metadata::loader::meta_section_name; use metadata::loader::meta_section_name;
use syntax::abi;
pub fn get_target_strs(target_triple: ~str, target_os: session::Os) -> target_strs::t { pub fn get_target_strs(target_triple: ~str, target_os: abi::Os) -> target_strs::t {
return target_strs::t { return target_strs::t {
module_asm: ~"", module_asm: ~"",
meta_sect_name: meta_section_name(sess_os_to_meta_os(target_os)).to_owned(), meta_sect_name: meta_section_name(sess_os_to_meta_os(target_os)).to_owned(),
data_layout: match target_os { data_layout: match target_os {
session::OsMacos => { abi::OsMacos => {
~"e-p:32:32:32" + ~"e-p:32:32:32" +
"-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" + "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" +
"-f32:32:32-f64:64:64" + "-f32:32:32-f64:64:64" +
@ -28,7 +28,7 @@ pub fn get_target_strs(target_triple: ~str, target_os: session::Os) -> target_st
"-a0:0:64-n32" "-a0:0:64-n32"
} }
session::OsWin32 => { abi::OsWin32 => {
~"e-p:32:32:32" + ~"e-p:32:32:32" +
"-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" + "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" +
"-f32:32:32-f64:64:64" + "-f32:32:32-f64:64:64" +
@ -36,7 +36,7 @@ pub fn get_target_strs(target_triple: ~str, target_os: session::Os) -> target_st
"-a0:0:64-n32" "-a0:0:64-n32"
} }
session::OsLinux => { abi::OsLinux => {
~"e-p:32:32:32" + ~"e-p:32:32:32" +
"-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" + "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" +
"-f32:32:32-f64:64:64" + "-f32:32:32-f64:64:64" +
@ -44,7 +44,7 @@ pub fn get_target_strs(target_triple: ~str, target_os: session::Os) -> target_st
"-a0:0:64-n32" "-a0:0:64-n32"
} }
session::OsAndroid => { abi::OsAndroid => {
~"e-p:32:32:32" + ~"e-p:32:32:32" +
"-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" + "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" +
"-f32:32:32-f64:64:64" + "-f32:32:32-f64:64:64" +
@ -52,7 +52,7 @@ pub fn get_target_strs(target_triple: ~str, target_os: session::Os) -> target_st
"-a0:0:64-n32" "-a0:0:64-n32"
} }
session::OsFreebsd => { abi::OsFreebsd => {
~"e-p:32:32:32" + ~"e-p:32:32:32" +
"-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" + "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" +
"-f32:32:32-f64:64:64" + "-f32:32:32-f64:64:64" +

View file

@ -15,9 +15,10 @@ use metadata::filesearch;
use std::hashmap::HashSet; use std::hashmap::HashSet;
use std::{os, vec}; use std::{os, vec};
use syntax::abi;
fn not_win32(os: session::Os) -> bool { fn not_win32(os: abi::Os) -> bool {
os != session::OsWin32 os != abi::OsWin32
} }
pub fn get_rpath_flags(sess: session::Session, out_filename: &Path) pub fn get_rpath_flags(sess: session::Session, out_filename: &Path)
@ -25,7 +26,7 @@ pub fn get_rpath_flags(sess: session::Session, out_filename: &Path)
let os = sess.targ_cfg.os; let os = sess.targ_cfg.os;
// No rpath on windows // No rpath on windows
if os == session::OsWin32 { if os == abi::OsWin32 {
return ~[]; return ~[];
} }
@ -55,7 +56,7 @@ pub fn rpaths_to_flags(rpaths: &[~str]) -> ~[~str] {
rpaths.iter().map(|rpath| format!("-Wl,-rpath,{}",*rpath)).collect() rpaths.iter().map(|rpath| format!("-Wl,-rpath,{}",*rpath)).collect()
} }
fn get_rpaths(os: session::Os, fn get_rpaths(os: abi::Os,
sysroot: &Path, sysroot: &Path,
output: &Path, output: &Path,
libs: &[Path], libs: &[Path],
@ -100,13 +101,13 @@ fn get_rpaths(os: session::Os,
return rpaths; return rpaths;
} }
fn get_rpaths_relative_to_output(os: session::Os, fn get_rpaths_relative_to_output(os: abi::Os,
output: &Path, output: &Path,
libs: &[Path]) -> ~[~str] { libs: &[Path]) -> ~[~str] {
libs.iter().map(|a| get_rpath_relative_to_output(os, output, a)).collect() libs.iter().map(|a| get_rpath_relative_to_output(os, output, a)).collect()
} }
pub fn get_rpath_relative_to_output(os: session::Os, pub fn get_rpath_relative_to_output(os: abi::Os,
output: &Path, output: &Path,
lib: &Path) lib: &Path)
-> ~str { -> ~str {
@ -116,10 +117,10 @@ pub fn get_rpath_relative_to_output(os: session::Os,
// Mac doesn't appear to support $ORIGIN // Mac doesn't appear to support $ORIGIN
let prefix = match os { let prefix = match os {
session::OsAndroid | session::OsLinux | session::OsFreebsd abi::OsAndroid | abi::OsLinux | abi::OsFreebsd
=> "$ORIGIN", => "$ORIGIN",
session::OsMacos => "@loader_path", abi::OsMacos => "@loader_path",
session::OsWin32 => unreachable!() abi::OsWin32 => unreachable!()
}; };
let mut lib = os::make_absolute(lib); let mut lib = os::make_absolute(lib);
@ -169,13 +170,10 @@ pub fn minimize_rpaths(rpaths: &[~str]) -> ~[~str] {
mod test { mod test {
use std::os; use std::os;
// FIXME(#2119): the outer attribute should be #[cfg(unix, test)], then
// these redundant #[cfg(test)] blocks can be removed
#[cfg(test)]
#[cfg(test)]
use back::rpath::{get_absolute_rpath, get_install_prefix_rpath}; use back::rpath::{get_absolute_rpath, get_install_prefix_rpath};
use back::rpath::{minimize_rpaths, rpaths_to_flags, get_rpath_relative_to_output}; use back::rpath::{minimize_rpaths, rpaths_to_flags, get_rpath_relative_to_output};
use driver::session; use driver::session;
use syntax::abi;
#[test] #[test]
fn test_rpaths_to_flags() { fn test_rpaths_to_flags() {
@ -219,7 +217,7 @@ mod test {
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
#[cfg(target_os = "android")] #[cfg(target_os = "android")]
fn test_rpath_relative() { fn test_rpath_relative() {
let o = session::OsLinux; let o = abi::OsLinux;
let res = get_rpath_relative_to_output(o, let res = get_rpath_relative_to_output(o,
&Path::new("bin/rustc"), &Path::new("lib/libstd.so")); &Path::new("bin/rustc"), &Path::new("lib/libstd.so"));
assert_eq!(res.as_slice(), "$ORIGIN/../lib"); assert_eq!(res.as_slice(), "$ORIGIN/../lib");
@ -228,7 +226,7 @@ mod test {
#[test] #[test]
#[cfg(target_os = "freebsd")] #[cfg(target_os = "freebsd")]
fn test_rpath_relative() { fn test_rpath_relative() {
let o = session::OsFreebsd; let o = abi::OsFreebsd;
let res = get_rpath_relative_to_output(o, let res = get_rpath_relative_to_output(o,
&Path::new("bin/rustc"), &Path::new("lib/libstd.so")); &Path::new("bin/rustc"), &Path::new("lib/libstd.so"));
assert_eq!(res.as_slice(), "$ORIGIN/../lib"); assert_eq!(res.as_slice(), "$ORIGIN/../lib");
@ -237,7 +235,7 @@ mod test {
#[test] #[test]
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
fn test_rpath_relative() { fn test_rpath_relative() {
let o = session::OsMacos; let o = abi::OsMacos;
let res = get_rpath_relative_to_output(o, let res = get_rpath_relative_to_output(o,
&Path::new("bin/rustc"), &Path::new("bin/rustc"),
&Path::new("lib/libstd.so")); &Path::new("lib/libstd.so"));

View file

@ -11,35 +11,35 @@
use back::target_strs; use back::target_strs;
use driver::session::sess_os_to_meta_os; use driver::session::sess_os_to_meta_os;
use driver::session;
use metadata::loader::meta_section_name; use metadata::loader::meta_section_name;
use syntax::abi;
pub fn get_target_strs(target_triple: ~str, target_os: session::Os) -> target_strs::t { pub fn get_target_strs(target_triple: ~str, target_os: abi::Os) -> target_strs::t {
return target_strs::t { return target_strs::t {
module_asm: ~"", module_asm: ~"",
meta_sect_name: meta_section_name(sess_os_to_meta_os(target_os)).to_owned(), meta_sect_name: meta_section_name(sess_os_to_meta_os(target_os)).to_owned(),
data_layout: match target_os { data_layout: match target_os {
session::OsMacos => { abi::OsMacos => {
~"e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16" + ~"e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16" +
"-i32:32:32-i64:32:64" + "-i32:32:32-i64:32:64" +
"-f32:32:32-f64:32:64-v64:64:64" + "-f32:32:32-f64:32:64-v64:64:64" +
"-v128:128:128-a0:0:64-f80:128:128" + "-n8:16:32" "-v128:128:128-a0:0:64-f80:128:128" + "-n8:16:32"
} }
session::OsWin32 => { abi::OsWin32 => {
~"e-p:32:32-f64:64:64-i64:64:64-f80:32:32-n8:16:32" ~"e-p:32:32-f64:64:64-i64:64:64-f80:32:32-n8:16:32"
} }
session::OsLinux => { abi::OsLinux => {
~"e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32" ~"e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32"
} }
session::OsAndroid => { abi::OsAndroid => {
~"e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32" ~"e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32"
} }
session::OsFreebsd => { abi::OsFreebsd => {
~"e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32" ~"e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32"
} }
}, },

View file

@ -11,41 +11,41 @@
use back::target_strs; use back::target_strs;
use driver::session::sess_os_to_meta_os; use driver::session::sess_os_to_meta_os;
use driver::session;
use metadata::loader::meta_section_name; use metadata::loader::meta_section_name;
use syntax::abi;
pub fn get_target_strs(target_triple: ~str, target_os: session::Os) -> target_strs::t { pub fn get_target_strs(target_triple: ~str, target_os: abi::Os) -> target_strs::t {
return target_strs::t { return target_strs::t {
module_asm: ~"", module_asm: ~"",
meta_sect_name: meta_section_name(sess_os_to_meta_os(target_os)).to_owned(), meta_sect_name: meta_section_name(sess_os_to_meta_os(target_os)).to_owned(),
data_layout: match target_os { data_layout: match target_os {
session::OsMacos => { abi::OsMacos => {
~"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-"+ ~"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-"+
"f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-"+ "f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-"+
"s0:64:64-f80:128:128-n8:16:32:64" "s0:64:64-f80:128:128-n8:16:32:64"
} }
session::OsWin32 => { abi::OsWin32 => {
// FIXME: Test this. Copied from linux (#2398) // FIXME: Test this. Copied from linux (#2398)
~"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-"+ ~"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-"+
"f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-"+ "f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-"+
"s0:64:64-f80:128:128-n8:16:32:64-S128" "s0:64:64-f80:128:128-n8:16:32:64-S128"
} }
session::OsLinux => { abi::OsLinux => {
~"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-"+ ~"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-"+
"f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-"+ "f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-"+
"s0:64:64-f80:128:128-n8:16:32:64-S128" "s0:64:64-f80:128:128-n8:16:32:64-S128"
} }
session::OsAndroid => { abi::OsAndroid => {
~"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-"+ ~"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-"+
"f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-"+ "f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-"+
"s0:64:64-f80:128:128-n8:16:32:64-S128" "s0:64:64-f80:128:128-n8:16:32:64-S128"
} }
session::OsFreebsd => { abi::OsFreebsd => {
~"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-"+ ~"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-"+
"f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-"+ "f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-"+
"s0:64:64-f80:128:128-n8:16:32:64-S128" "s0:64:64-f80:128:128-n8:16:32:64-S128"

View file

@ -69,11 +69,11 @@ pub fn source_name(input: &input) -> @str {
pub fn default_configuration(sess: Session) -> pub fn default_configuration(sess: Session) ->
ast::CrateConfig { ast::CrateConfig {
let tos = match sess.targ_cfg.os { let tos = match sess.targ_cfg.os {
session::OsWin32 => @"win32", abi::OsWin32 => @"win32",
session::OsMacos => @"macos", abi::OsMacos => @"macos",
session::OsLinux => @"linux", abi::OsLinux => @"linux",
session::OsAndroid => @"android", abi::OsAndroid => @"android",
session::OsFreebsd => @"freebsd" abi::OsFreebsd => @"freebsd"
}; };
// ARM is bi-endian, however using NDK seems to default // ARM is bi-endian, however using NDK seems to default
@ -353,7 +353,7 @@ pub fn phase_5_run_llvm_passes(sess: Session,
// segmented stacks are enabled. However, unwind info directives in assembly // segmented stacks are enabled. However, unwind info directives in assembly
// output are OK, so we generate assembly first and then run it through // output are OK, so we generate assembly first and then run it through
// an external assembler. // an external assembler.
if sess.targ_cfg.os == session::OsWin32 && if sess.targ_cfg.os == abi::OsWin32 &&
(sess.opts.output_type == link::output_type_object || (sess.opts.output_type == link::output_type_object ||
sess.opts.output_type == link::output_type_exe) { sess.opts.output_type == link::output_type_exe) {
let output_type = link::output_type_assembly; let output_type = link::output_type_assembly;
@ -567,19 +567,19 @@ pub fn pretty_print_input(sess: Session,
is_expanded); is_expanded);
} }
pub fn get_os(triple: &str) -> Option<session::Os> { pub fn get_os(triple: &str) -> Option<abi::Os> {
for &(name, os) in os_names.iter() { for &(name, os) in os_names.iter() {
if triple.contains(name) { return Some(os) } if triple.contains(name) { return Some(os) }
} }
None None
} }
static os_names : &'static [(&'static str, session::Os)] = &'static [ static os_names : &'static [(&'static str, abi::Os)] = &'static [
("mingw32", session::OsWin32), ("mingw32", abi::OsWin32),
("win32", session::OsWin32), ("win32", abi::OsWin32),
("darwin", session::OsMacos), ("darwin", abi::OsMacos),
("android", session::OsAndroid), ("android", abi::OsAndroid),
("linux", session::OsLinux), ("linux", abi::OsLinux),
("freebsd", session::OsFreebsd)]; ("freebsd", abi::OsFreebsd)];
pub fn get_arch(triple: &str) -> Option<abi::Architecture> { pub fn get_arch(triple: &str) -> Option<abi::Architecture> {
for &(arch, abi) in architecture_abis.iter() { for &(arch, abi) in architecture_abis.iter() {

View file

@ -31,9 +31,6 @@ use syntax;
use std::int; use std::int;
use std::hashmap::{HashMap,HashSet}; use std::hashmap::{HashMap,HashSet};
#[deriving(Eq)]
pub enum Os { OsWin32, OsMacos, OsLinux, OsAndroid, OsFreebsd, }
#[deriving(Clone)] #[deriving(Clone)]
pub enum crate_type { pub enum crate_type {
bin_crate, bin_crate,
@ -42,7 +39,7 @@ pub enum crate_type {
} }
pub struct config { pub struct config {
os: Os, os: abi::Os,
arch: abi::Architecture, arch: abi::Architecture,
target_strs: target_strs::t, target_strs: target_strs::t,
int_type: int_ty, int_type: int_ty,
@ -410,15 +407,15 @@ pub fn building_library(req_crate_type: crate_type,
} }
} }
pub fn sess_os_to_meta_os(os: Os) -> metadata::loader::Os { pub fn sess_os_to_meta_os(os: abi::Os) -> metadata::loader::Os {
use metadata::loader; use metadata::loader;
match os { match os {
OsWin32 => loader::OsWin32, abi::OsWin32 => loader::OsWin32,
OsLinux => loader::OsLinux, abi::OsLinux => loader::OsLinux,
OsAndroid => loader::OsAndroid, abi::OsAndroid => loader::OsAndroid,
OsMacos => loader::OsMacos, abi::OsMacos => loader::OsMacos,
OsFreebsd => loader::OsFreebsd abi::OsFreebsd => loader::OsFreebsd
} }
} }

View file

@ -11,6 +11,7 @@
use driver::session; use driver::session;
use driver::session::Session; use driver::session::Session;
use syntax::abi;
use syntax::ast::{Crate, NodeId, item, item_fn}; use syntax::ast::{Crate, NodeId, item, item_fn};
use syntax::ast_map; use syntax::ast_map;
use syntax::attr; use syntax::attr;
@ -48,7 +49,7 @@ pub fn find_entry_point(session: Session, crate: &Crate, ast_map: ast_map::map)
// FIXME #4404 android JNI hacks // FIXME #4404 android JNI hacks
if *session.building_library && if *session.building_library &&
session.targ_cfg.os != session::OsAndroid { session.targ_cfg.os != abi::OsAndroid {
// No need to find a main function // No need to find a main function
return; return;
} }
@ -151,7 +152,7 @@ fn configure_main(this: &mut EntryContext) {
} else { } else {
// If we *are* building a library, then we're on android where we still might // If we *are* building a library, then we're on android where we still might
// optionally want to translate main $4404 // optionally want to translate main $4404
assert_eq!(this.session.targ_cfg.os, session::OsAndroid); assert_eq!(this.session.targ_cfg.os, abi::OsAndroid);
} }
} }
} }

View file

@ -85,7 +85,7 @@ use syntax::parse::token;
use syntax::parse::token::{special_idents}; use syntax::parse::token::{special_idents};
use syntax::print::pprust::stmt_to_str; use syntax::print::pprust::stmt_to_str;
use syntax::{ast, ast_util, codemap, ast_map}; use syntax::{ast, ast_util, codemap, ast_map};
use syntax::abi::{X86, X86_64, Arm, Mips, Rust, RustIntrinsic}; use syntax::abi::{X86, X86_64, Arm, Mips, Rust, RustIntrinsic, OsWin32, OsAndroid};
use syntax::visit; use syntax::visit;
use syntax::visit::Visitor; use syntax::visit::Visitor;
@ -853,7 +853,8 @@ pub fn trans_external_path(ccx: &mut CrateContext, did: ast::DefId, t: ty::t) ->
let name = csearch::get_symbol(ccx.sess.cstore, did); let name = csearch::get_symbol(ccx.sess.cstore, did);
match ty::get(t).sty { match ty::get(t).sty {
ty::ty_bare_fn(ref fn_ty) => { ty::ty_bare_fn(ref fn_ty) => {
match fn_ty.abis.for_arch(ccx.sess.targ_cfg.arch) { match fn_ty.abis.for_target(ccx.sess.targ_cfg.os,
ccx.sess.targ_cfg.arch) {
Some(Rust) | Some(RustIntrinsic) => { Some(Rust) | Some(RustIntrinsic) => {
get_extern_rust_fn(ccx, fn_ty.sig.inputs, fn_ty.sig.output, name, did) get_extern_rust_fn(ccx, fn_ty.sig.inputs, fn_ty.sig.output, name, did)
} }
@ -2312,7 +2313,7 @@ fn finish_register_fn(ccx: @mut CrateContext, sp: Span, sym: ~str, node_id: ast:
// FIXME #4404 android JNI hacks // FIXME #4404 android JNI hacks
let is_entry = is_entry_fn(&ccx.sess, node_id) && (!*ccx.sess.building_library || let is_entry = is_entry_fn(&ccx.sess, node_id) && (!*ccx.sess.building_library ||
(*ccx.sess.building_library && (*ccx.sess.building_library &&
ccx.sess.targ_cfg.os == session::OsAndroid)); ccx.sess.targ_cfg.os == OsAndroid));
if is_entry { if is_entry {
create_entry_wrapper(ccx, sp, llfn); create_entry_wrapper(ccx, sp, llfn);
} }
@ -2981,7 +2982,7 @@ pub fn decl_crate_map(sess: session::Session, mapmeta: LinkMeta,
}; };
// On windows we'd like to export the toplevel cratemap // On windows we'd like to export the toplevel cratemap
// such that we can find it from libstd. // such that we can find it from libstd.
if targ_cfg.os == session::OsWin32 && "toplevel" == mapname { if targ_cfg.os == OsWin32 && "toplevel" == mapname {
lib::llvm::SetLinkage(map, lib::llvm::DLLExportLinkage); lib::llvm::SetLinkage(map, lib::llvm::DLLExportLinkage);
} else { } else {
lib::llvm::SetLinkage(map, lib::llvm::ExternalLinkage); lib::llvm::SetLinkage(map, lib::llvm::ExternalLinkage);
@ -3157,7 +3158,7 @@ pub fn trans_crate(sess: session::Session,
// __rust_crate_map_toplevel symbol (extra underscore) which it will // __rust_crate_map_toplevel symbol (extra underscore) which it will
// subsequently fail to find. So to mitigate that we just introduce // subsequently fail to find. So to mitigate that we just introduce
// an alias from the symbol it expects to the one that actually exists. // an alias from the symbol it expects to the one that actually exists.
if ccx.sess.targ_cfg.os == session::OsWin32 && if ccx.sess.targ_cfg.os == OsWin32 &&
!*ccx.sess.building_library { !*ccx.sess.building_library {
let maptype = val_ty(ccx.crate_map).to_ref(); let maptype = val_ty(ccx.crate_map).to_ref();

View file

@ -9,7 +9,7 @@
// except according to those terms. // except according to those terms.
use driver::session::{OsWin32, OsMacos}; use syntax::abi::{OsWin32, OsMacos};
use lib::llvm::*; use lib::llvm::*;
use super::cabi::*; use super::cabi::*;
use super::common::*; use super::common::*;

View file

@ -32,7 +32,7 @@ use syntax::codemap::Span;
use syntax::{ast}; use syntax::{ast};
use syntax::{attr, ast_map}; use syntax::{attr, ast_map};
use syntax::parse::token::special_idents; use syntax::parse::token::special_idents;
use syntax::abi::{RustIntrinsic, Rust, Stdcall, Fastcall, use syntax::abi::{RustIntrinsic, Rust, Stdcall, Fastcall, System,
Cdecl, Aapcs, C, AbiSet}; Cdecl, Aapcs, C, AbiSet};
use util::ppaux::{Repr, UserString}; use util::ppaux::{Repr, UserString};
use middle::trans::type_::Type; use middle::trans::type_::Type;
@ -75,8 +75,9 @@ struct LlvmSignature {
pub fn llvm_calling_convention(ccx: &mut CrateContext, pub fn llvm_calling_convention(ccx: &mut CrateContext,
abis: AbiSet) -> Option<CallConv> { abis: AbiSet) -> Option<CallConv> {
let os = ccx.sess.targ_cfg.os;
let arch = ccx.sess.targ_cfg.arch; let arch = ccx.sess.targ_cfg.arch;
abis.for_arch(arch).map(|abi| { abis.for_target(os, arch).map(|abi| {
match abi { match abi {
RustIntrinsic => { RustIntrinsic => {
// Intrinsics are emitted by monomorphic fn // Intrinsics are emitted by monomorphic fn
@ -89,6 +90,9 @@ pub fn llvm_calling_convention(ccx: &mut CrateContext,
format!("Foreign functions with Rust ABI")); format!("Foreign functions with Rust ABI"));
} }
// It's the ABI's job to select this, not us.
System => ccx.sess.bug("System abi should be selected elsewhere"),
Stdcall => lib::llvm::X86StdcallCallConv, Stdcall => lib::llvm::X86StdcallCallConv,
Fastcall => lib::llvm::X86FastcallCallConv, Fastcall => lib::llvm::X86FastcallCallConv,
C => lib::llvm::CCallConv, C => lib::llvm::CCallConv,

View file

@ -10,6 +10,9 @@
use std::to_bytes; use std::to_bytes;
#[deriving(Eq)]
pub enum Os { OsWin32, OsMacos, OsLinux, OsAndroid, OsFreebsd, }
#[deriving(Eq)] #[deriving(Eq)]
pub enum Abi { pub enum Abi {
// NB: This ordering MUST match the AbiDatas array below. // NB: This ordering MUST match the AbiDatas array below.
@ -24,6 +27,7 @@ pub enum Abi {
// Multiplatform ABIs second // Multiplatform ABIs second
Rust, Rust,
C, C,
System,
RustIntrinsic, RustIntrinsic,
} }
@ -76,6 +80,7 @@ static AbiDatas: &'static [AbiData] = &[
// adjusting the indices below. // adjusting the indices below.
AbiData {abi: Rust, name: "Rust", abi_arch: RustArch}, AbiData {abi: Rust, name: "Rust", abi_arch: RustArch},
AbiData {abi: C, name: "C", abi_arch: AllArch}, AbiData {abi: C, name: "C", abi_arch: AllArch},
AbiData {abi: System, name: "system", abi_arch: AllArch},
AbiData {abi: RustIntrinsic, name: "rust-intrinsic", abi_arch: RustArch}, AbiData {abi: RustIntrinsic, name: "rust-intrinsic", abi_arch: RustArch},
]; ];
@ -125,6 +130,14 @@ impl Abi {
pub fn name(&self) -> &'static str { pub fn name(&self) -> &'static str {
self.data().name self.data().name
} }
pub fn for_target(&self, os: Os, arch: Architecture) -> Abi {
match (*self, os, arch) {
(System, OsWin32, X86) => Stdcall,
(System, _, _) => C,
(me, _, _) => me,
}
}
} }
impl Architecture { impl Architecture {
@ -196,7 +209,7 @@ impl AbiSet {
self.bits == 0 self.bits == 0
} }
pub fn for_arch(&self, arch: Architecture) -> Option<Abi> { pub fn for_target(&self, os: Os, arch: Architecture) -> Option<Abi> {
// NB---Single platform ABIs come first // NB---Single platform ABIs come first
let mut res = None; let mut res = None;
@ -210,7 +223,7 @@ impl AbiSet {
} }
}; };
res res.map(|r| r.for_target(os, arch))
} }
pub fn check_valid(&self) -> Option<(Abi, Abi)> { pub fn check_valid(&self) -> Option<(Abi, Abi)> {
@ -344,6 +357,11 @@ fn cannot_combine_rust_intrinsic_and_cdecl() {
cannot_combine(RustIntrinsic, Cdecl); cannot_combine(RustIntrinsic, Cdecl);
} }
#[test]
fn can_combine_system_and_cdecl() {
can_combine(System, Cdecl);
}
#[test] #[test]
fn can_combine_c_and_stdcall() { fn can_combine_c_and_stdcall() {
can_combine(C, Stdcall); can_combine(C, Stdcall);
@ -382,36 +400,41 @@ fn abi_to_str_rust() {
#[test] #[test]
fn indices_are_correct() { fn indices_are_correct() {
for (i, abi_data) in AbiDatas.iter().enumerate() { for (i, abi_data) in AbiDatas.iter().enumerate() {
assert!(i == abi_data.abi.index()); assert_eq!(i, abi_data.abi.index());
} }
let bits = 1 << (X86 as u32); let bits = 1 << (X86 as u32);
let bits = bits | 1 << (X86_64 as u32); let bits = bits | 1 << (X86_64 as u32);
assert!(IntelBits == bits); assert_eq!(IntelBits, bits);
let bits = 1 << (Arm as u32); let bits = 1 << (Arm as u32);
assert!(ArmBits == bits); assert_eq!(ArmBits, bits);
} }
#[cfg(test)] #[cfg(test)]
fn check_arch(abis: &[Abi], arch: Architecture, expect: Option<Abi>) { fn get_arch(abis: &[Abi], os: Os, arch: Architecture) -> Option<Abi> {
let mut set = AbiSet::empty(); let mut set = AbiSet::empty();
for &abi in abis.iter() { for &abi in abis.iter() {
set.add(abi); set.add(abi);
} }
let r = set.for_arch(arch); set.for_target(os, arch)
assert!(r == expect);
} }
#[test] #[test]
fn pick_multiplatform() { fn pick_multiplatform() {
check_arch([C, Cdecl], X86, Some(Cdecl)); assert_eq!(get_arch([C, Cdecl], OsLinux, X86), Some(Cdecl));
check_arch([C, Cdecl], X86_64, Some(Cdecl)); assert_eq!(get_arch([C, Cdecl], OsLinux, X86_64), Some(Cdecl));
check_arch([C, Cdecl], Arm, Some(C)); assert_eq!(get_arch([C, Cdecl], OsLinux, Arm), Some(C));
} }
#[test] #[test]
fn pick_uniplatform() { fn pick_uniplatform() {
check_arch([Stdcall], X86, Some(Stdcall)); assert_eq!(get_arch([Stdcall], OsLinux, X86), Some(Stdcall));
check_arch([Stdcall], Arm, None); assert_eq!(get_arch([Stdcall], OsLinux, Arm), None);
assert_eq!(get_arch([System], OsLinux, X86), Some(C));
assert_eq!(get_arch([System], OsWin32, X86), Some(Stdcall));
assert_eq!(get_arch([System], OsWin32, X86_64), Some(C));
assert_eq!(get_arch([System], OsWin32, Arm), Some(C));
assert_eq!(get_arch([Stdcall], OsWin32, X86), Some(Stdcall));
assert_eq!(get_arch([Stdcall], OsWin32, X86_64), Some(Stdcall));
} }