Skip to content

Commit

Permalink
auto merge of #10367 : alexcrichton/rust/system-abi, r=nikomatsakis
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bors committed Nov 9, 2013
2 parents 8379890 + 2fcc70e commit 3851f90
Show file tree
Hide file tree
Showing 14 changed files with 151 additions and 109 deletions.
23 changes: 20 additions & 3 deletions doc/tutorial-ffi.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

~~~~
#[cfg(target_os = "win32")]
#[cfg(target_os = "win32", target_arch = "x86")]
#[link_name = "kernel32"]
extern "stdcall" {
fn SetEnvironmentVariableA(n: *u8, v: *u8) -> int;
}
~~~~

This applies to the entire `extern` block, and must be either `"cdecl"` or
`"stdcall"`. The compiler may eventually support other calling conventions.
This applies to the entire `extern` block. The list of supported ABI constraints
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

Expand Down
14 changes: 7 additions & 7 deletions src/librustc/back/arm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,49 +10,49 @@

use back::target_strs;
use driver::session::sess_os_to_meta_os;
use driver::session;
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 {
module_asm: ~"",

meta_sect_name: meta_section_name(sess_os_to_meta_os(target_os)).to_owned(),

data_layout: match target_os {
session::OsMacos => {
abi::OsMacos => {
~"e-p:32:32:32" +
"-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:64:128" +
"-a0:0:64-n32"
}

session::OsWin32 => {
abi::OsWin32 => {
~"e-p:32:32:32" +
"-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:64:128" +
"-a0:0:64-n32"
}

session::OsLinux => {
abi::OsLinux => {
~"e-p:32:32:32" +
"-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:64:128" +
"-a0:0:64-n32"
}

session::OsAndroid => {
abi::OsAndroid => {
~"e-p:32:32:32" +
"-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:64:128" +
"-a0:0:64-n32"
}

session::OsFreebsd => {
abi::OsFreebsd => {
~"e-p:32:32:32" +
"-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" +
"-f32:32:32-f64:64:64" +
Expand Down
31 changes: 16 additions & 15 deletions src/librustc/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ use std::run;
use std::str;
use std::vec;
use std::rt::io::fs;
use syntax::abi;
use syntax::ast;
use syntax::ast_map::{path, path_mod, path_name, path_pretty_name};
use syntax::attr;
Expand Down Expand Up @@ -877,13 +878,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 {
session::OsWin32 => (win32::DLL_PREFIX, win32::DLL_SUFFIX),
session::OsMacos => (macos::DLL_PREFIX, macos::DLL_SUFFIX),
session::OsLinux => (linux::DLL_PREFIX, linux::DLL_SUFFIX),
session::OsAndroid => (android::DLL_PREFIX, android::DLL_SUFFIX),
session::OsFreebsd => (freebsd::DLL_PREFIX, freebsd::DLL_SUFFIX),
abi::OsWin32 => (win32::DLL_PREFIX, win32::DLL_SUFFIX),
abi::OsMacos => (macos::DLL_PREFIX, macos::DLL_SUFFIX),
abi::OsLinux => (linux::DLL_PREFIX, linux::DLL_SUFFIX),
abi::OsAndroid => (android::DLL_PREFIX, android::DLL_SUFFIX),
abi::OsFreebsd => (freebsd::DLL_PREFIX, freebsd::DLL_SUFFIX),
};
format!("{}{}-{}-{}{}", dll_prefix, lm.name, lm.extras_hash, lm.vers, dll_suffix)
}
Expand All @@ -898,7 +899,7 @@ pub fn get_cc_prog(sess: Session) -> ~str {
match sess.opts.linker {
Some(ref linker) => linker.to_str(),
None => match sess.targ_cfg.os {
session::OsAndroid =>
abi::OsAndroid =>
match &sess.opts.android_cross_path {
&Some(ref path) => {
format!("{}/bin/arm-linux-androideabi-gcc", *path)
Expand All @@ -908,7 +909,7 @@ pub fn get_cc_prog(sess: Session) -> ~str {
(--android-cross-path)")
}
},
session::OsWin32 => ~"g++",
abi::OsWin32 => ~"g++",
_ => ~"cc"
}
}
Expand Down Expand Up @@ -956,7 +957,7 @@ pub fn link_binary(sess: Session,
}

// 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
run::process_status("dsymutil", [output.as_str().unwrap().to_owned()]);
}
Expand Down Expand Up @@ -985,7 +986,7 @@ pub fn link_args(sess: Session,
// Converts a library file-stem into a cc -l argument
fn unlib(config: @session::config, stem: ~str) -> ~str {
if stem.starts_with("lib") &&
config.os != session::OsWin32 {
config.os != abi::OsWin32 {
stem.slice(3, stem.len()).to_owned()
} else {
stem
Expand Down Expand Up @@ -1029,7 +1030,7 @@ pub fn link_args(sess: Session,
obj_filename.as_str().unwrap().to_owned()]);

let lib_cmd = match sess.targ_cfg.os {
session::OsMacos => ~"-dynamiclib",
abi::OsMacos => ~"-dynamiclib",
_ => ~"-shared"
};

Expand Down Expand Up @@ -1080,7 +1081,7 @@ pub fn link_args(sess: Session,

// On mac we need to tell the linker to let this library
// 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
args.push("-Wl,-install_name,@rpath/"
+ output.filename_str().unwrap());
Expand All @@ -1089,20 +1090,20 @@ pub fn link_args(sess: Session,

// On linux librt and libdl are an indirect dependencies via rustrt,
// 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"]);

// LLVM implements the `frem` instruction as a call to `fmod`,
// which lives in libm. Similar to above, on some linuxes we
// have to be explicit about linking to it. See #2510
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(~"-lm");
}

if sess.targ_cfg.os == session::OsFreebsd {
if sess.targ_cfg.os == abi::OsFreebsd {
args.push_all([~"-pthread", ~"-lrt",
~"-L/usr/local/lib", ~"-lexecinfo",
~"-L/usr/local/lib/gcc46",
Expand Down
14 changes: 7 additions & 7 deletions src/librustc/back/mips.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,50 +9,50 @@
// except according to those terms.

use back::target_strs;
use driver::session;
use driver::session::sess_os_to_meta_os;
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 {
module_asm: ~"",

meta_sect_name: meta_section_name(sess_os_to_meta_os(target_os)).to_owned(),

data_layout: match target_os {
session::OsMacos => {
abi::OsMacos => {
~"e-p:32:32:32" +
"-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:64:128" +
"-a0:0:64-n32"
}

session::OsWin32 => {
abi::OsWin32 => {
~"e-p:32:32:32" +
"-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:64:128" +
"-a0:0:64-n32"
}

session::OsLinux => {
abi::OsLinux => {
~"e-p:32:32:32" +
"-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:64:128" +
"-a0:0:64-n32"
}

session::OsAndroid => {
abi::OsAndroid => {
~"e-p:32:32:32" +
"-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:64:128" +
"-a0:0:64-n32"
}

session::OsFreebsd => {
abi::OsFreebsd => {
~"e-p:32:32:32" +
"-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" +
"-f32:32:32-f64:64:64" +
Expand Down
30 changes: 14 additions & 16 deletions src/librustc/back/rpath.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,18 @@ use metadata::filesearch;

use std::hashmap::HashSet;
use std::{os, vec};
use syntax::abi;

fn not_win32(os: session::Os) -> bool {
os != session::OsWin32
fn not_win32(os: abi::Os) -> bool {
os != abi::OsWin32
}

pub fn get_rpath_flags(sess: session::Session, out_filename: &Path)
-> ~[~str] {
let os = sess.targ_cfg.os;

// No rpath on windows
if os == session::OsWin32 {
if os == abi::OsWin32 {
return ~[];
}

Expand Down Expand Up @@ -55,7 +56,7 @@ pub fn rpaths_to_flags(rpaths: &[~str]) -> ~[~str] {
rpaths.iter().map(|rpath| format!("-Wl,-rpath,{}",*rpath)).collect()
}

fn get_rpaths(os: session::Os,
fn get_rpaths(os: abi::Os,
sysroot: &Path,
output: &Path,
libs: &[Path],
Expand Down Expand Up @@ -100,13 +101,13 @@ fn get_rpaths(os: session::Os,
return rpaths;
}

fn get_rpaths_relative_to_output(os: session::Os,
fn get_rpaths_relative_to_output(os: abi::Os,
output: &Path,
libs: &[Path]) -> ~[~str] {
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,
lib: &Path)
-> ~str {
Expand All @@ -116,10 +117,10 @@ pub fn get_rpath_relative_to_output(os: session::Os,

// Mac doesn't appear to support $ORIGIN
let prefix = match os {
session::OsAndroid | session::OsLinux | session::OsFreebsd
abi::OsAndroid | abi::OsLinux | abi::OsFreebsd
=> "$ORIGIN",
session::OsMacos => "@loader_path",
session::OsWin32 => unreachable!()
abi::OsMacos => "@loader_path",
abi::OsWin32 => unreachable!()
};

let mut lib = os::make_absolute(lib);
Expand Down Expand Up @@ -169,13 +170,10 @@ pub fn minimize_rpaths(rpaths: &[~str]) -> ~[~str] {
mod test {
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::{minimize_rpaths, rpaths_to_flags, get_rpath_relative_to_output};
use driver::session;
use syntax::abi;

#[test]
fn test_rpaths_to_flags() {
Expand Down Expand Up @@ -219,7 +217,7 @@ mod test {
#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
fn test_rpath_relative() {
let o = session::OsLinux;
let o = abi::OsLinux;
let res = get_rpath_relative_to_output(o,
&Path::new("bin/rustc"), &Path::new("lib/libstd.so"));
assert_eq!(res.as_slice(), "$ORIGIN/../lib");
Expand All @@ -228,7 +226,7 @@ mod test {
#[test]
#[cfg(target_os = "freebsd")]
fn test_rpath_relative() {
let o = session::OsFreebsd;
let o = abi::OsFreebsd;
let res = get_rpath_relative_to_output(o,
&Path::new("bin/rustc"), &Path::new("lib/libstd.so"));
assert_eq!(res.as_slice(), "$ORIGIN/../lib");
Expand All @@ -237,7 +235,7 @@ mod test {
#[test]
#[cfg(target_os = "macos")]
fn test_rpath_relative() {
let o = session::OsMacos;
let o = abi::OsMacos;
let res = get_rpath_relative_to_output(o,
&Path::new("bin/rustc"),
&Path::new("lib/libstd.so"));
Expand Down
Loading

0 comments on commit 3851f90

Please sign in to comment.