e648c96c5f
Rust's current compilation model makes it impossible on Windows to generate one object file with a complete and final set of dllexport annotations. This is because when an object is generated the compiler doesn't actually know if it will later be included in a dynamic library or not. The compiler works around this today by flagging *everything* as dllexport, but this has the drawback of exposing too much. Thankfully there are alternate methods of specifying the exported surface area of a dll on Windows, one of which is passing a `*.def` file to the linker which lists all public symbols of the dynamic library. This commit removes all locations that add `dllexport` to LLVM variables and instead dynamically generates a `*.def` file which is passed to the linker. This file will include all the public symbols of the current object file as well as all upstream libraries, and the crucial aspect is that it's only used when generating a dynamic library. When generating an executable this file isn't generated, so all the symbols aren't exported from an executable. To ensure that statically included native libraries are reexported correctly, the previously added support for the `#[linked_from]` attribute is used to determine the set of FFI symbols that are exported from a dynamic library, and this is required to get the compiler to link correctly.
68 lines
2.2 KiB
Rust
68 lines
2.2 KiB
Rust
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
// file at the top-level directory of this distribution and at
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
// option. This file may not be copied, modified, or distributed
|
|
// except according to those terms.
|
|
|
|
// ignore-msvc -- sprintf isn't a symbol in msvcrt? maybe a #define?
|
|
|
|
#![feature(libc, std_misc)]
|
|
|
|
extern crate libc;
|
|
|
|
use std::ffi::{CStr, CString};
|
|
use libc::{c_char, c_int};
|
|
|
|
|
|
extern {
|
|
fn sprintf(s: *mut c_char, format: *const c_char, ...) -> c_int;
|
|
}
|
|
|
|
unsafe fn check<T, F>(expected: &str, f: F) where F: FnOnce(*mut c_char) -> T {
|
|
let mut x = [0 as c_char; 50];
|
|
f(&mut x[0] as *mut c_char);
|
|
assert_eq!(expected.as_bytes(), CStr::from_ptr(x.as_ptr()).to_bytes());
|
|
}
|
|
|
|
pub fn main() {
|
|
|
|
unsafe {
|
|
// Call with just the named parameter
|
|
let c = CString::new(&b"Hello World\n"[..]).unwrap();
|
|
check("Hello World\n", |s| sprintf(s, c.as_ptr()));
|
|
|
|
// Call with variable number of arguments
|
|
let c = CString::new(&b"%d %f %c %s\n"[..]).unwrap();
|
|
check("42 42.500000 a %d %f %c %s\n\n", |s| {
|
|
sprintf(s, c.as_ptr(), 42, 42.5f64, 'a' as c_int, c.as_ptr());
|
|
});
|
|
|
|
// Make a function pointer
|
|
let x: unsafe extern fn(*mut c_char, *const c_char, ...) -> c_int = sprintf;
|
|
|
|
// A function that takes a function pointer
|
|
unsafe fn call(p: unsafe extern fn(*mut c_char, *const c_char, ...) -> c_int) {
|
|
// Call with just the named parameter
|
|
let c = CString::new(&b"Hello World\n"[..]).unwrap();
|
|
check("Hello World\n", |s| sprintf(s, c.as_ptr()));
|
|
|
|
// Call with variable number of arguments
|
|
let c = CString::new(&b"%d %f %c %s\n"[..]).unwrap();
|
|
check("42 42.500000 a %d %f %c %s\n\n", |s| {
|
|
sprintf(s, c.as_ptr(), 42, 42.5f64, 'a' as c_int, c.as_ptr());
|
|
});
|
|
}
|
|
|
|
// Pass sprintf directly
|
|
call(sprintf);
|
|
|
|
// Pass sprintf indirectly
|
|
call(x);
|
|
}
|
|
|
|
}
|