Support OSX frameworks

This adds support to link to OSX frameworks via the new link attribute when
using `kind = "framework"`. It is a compiler error to request linkage to a
framework when the target is not macos because other platforms don't support
frameworks.

Closes #2023
This commit is contained in:
Alex Crichton 2013-11-30 11:39:55 -08:00
parent 4252a24ae1
commit f9d6fd20a5
10 changed files with 130 additions and 18 deletions

View File

@ -1015,7 +1015,7 @@ fn link_rlib(sess: Session, obj_filename: &Path,
cstore::NativeStatic => {
a.add_native_library(l.as_slice());
}
cstore::NativeUnknown => {}
cstore::NativeFramework | cstore::NativeUnknown => {}
}
}
return a;
@ -1044,8 +1044,13 @@ fn link_staticlib(sess: Session, obj_filename: &Path, out_filename: &Path) {
};
a.add_rlib(&p);
let native_libs = csearch::get_native_libraries(sess.cstore, cnum);
for lib in native_libs.iter() {
sess.warn(format!("unlinked native library: {}", *lib));
for &(kind, ref lib) in native_libs.iter() {
let name = match kind {
cstore::NativeStatic => "static library",
cstore::NativeUnknown => "library",
cstore::NativeFramework => "framework",
};
sess.warn(format!("unlinked native {}: {}", name, *lib));
}
}
}
@ -1204,8 +1209,17 @@ fn add_upstream_rust_crates(args: &mut ~[~str], sess: Session,
args.push(cratepath.as_str().unwrap().to_owned());
let libs = csearch::get_native_libraries(sess.cstore, cnum);
for lib in libs.iter() {
args.push("-l" + *lib);
for &(kind, ref lib) in libs.iter() {
match kind {
cstore::NativeUnknown => args.push("-l" + *lib),
cstore::NativeFramework => {
args.push(~"-framework");
args.push(lib.to_owned());
}
cstore::NativeStatic => {
sess.bug("statics shouldn't be propagated");
}
}
}
}
return;
@ -1262,7 +1276,15 @@ fn add_local_native_libraries(args: &mut ~[~str], sess: Session) {
args.push("-L" + path.as_str().unwrap().to_owned());
}
for &(ref l, _) in cstore::get_used_libraries(sess.cstore).iter() {
args.push(~"-l" + *l);
for &(ref l, kind) in cstore::get_used_libraries(sess.cstore).iter() {
match kind {
cstore::NativeUnknown | cstore::NativeStatic => {
args.push("-l" + *l);
}
cstore::NativeFramework => {
args.push(~"-framework");
args.push(l.to_owned());
}
}
}
}

View File

@ -199,6 +199,8 @@ pub static tag_region_param_def_def_id: uint = 0x102;
pub static tag_native_libraries: uint = 0x103;
pub static tag_native_libraries_lib: uint = 0x104;
pub static tag_native_libraries_name: uint = 0x105;
pub static tag_native_libraries_kind: uint = 0x106;
pub struct LinkMeta {
name: @str,

View File

@ -18,6 +18,7 @@ use metadata::loader;
use std::hashmap::HashMap;
use syntax::ast;
use std::vec;
use syntax::abi;
use syntax::attr;
use syntax::attr::AttrMetaMethods;
use syntax::codemap::{Span, dummy_sp};
@ -191,10 +192,22 @@ fn visit_item(e: &Env, i: @ast::item) {
"kind" == k.name()
}).and_then(|a| a.value_str());
let kind = match kind {
Some(k) if "static" == k => cstore::NativeStatic,
Some(k) => {
e.sess.span_fatal(i.span,
format!("unknown kind: `{}`", k));
if "static" == k {
cstore::NativeStatic
} else if e.sess.targ_cfg.os == abi::OsMacos &&
"framework" == k {
cstore::NativeFramework
} else if "framework" == k {
e.sess.span_err(m.span,
"native frameworks are only available \
on OSX targets");
cstore::NativeUnknown
} else {
e.sess.span_err(m.span,
format!("unknown kind: `{}`", k));
cstore::NativeUnknown
}
}
None => cstore::NativeUnknown
};
@ -204,9 +217,10 @@ fn visit_item(e: &Env, i: @ast::item) {
let n = match n {
Some(n) => n,
None => {
e.sess.span_fatal(i.span,
e.sess.span_err(m.span,
"#[link(...)] specified without \
`name = \"foo\"`");
@"foo"
}
};
cstore::add_used_library(cstore, n.to_owned(), kind);

View File

@ -263,7 +263,8 @@ pub fn get_item_visibility(cstore: @mut cstore::CStore,
}
pub fn get_native_libraries(cstore: @mut cstore::CStore,
crate_num: ast::CrateNum) -> ~[~str] {
crate_num: ast::CrateNum)
-> ~[(cstore::NativeLibaryKind, ~str)] {
let cdata = cstore::get_crate_data(cstore, crate_num);
decoder::get_native_libraries(cdata)
}

View File

@ -40,10 +40,11 @@ pub enum LinkagePreference {
RequireStatic,
}
#[deriving(Eq)]
#[deriving(Eq, FromPrimitive)]
pub enum NativeLibaryKind {
NativeStatic,
NativeUnknown,
NativeStatic, // native static library (.a archive)
NativeFramework, // OSX-specific
NativeUnknown, // default way to specify a dynamic library
}
// Where a crate came from on the local filesystem. One of these two options

View File

@ -1530,11 +1530,16 @@ pub fn get_trait_of_method(cdata: Cmd, id: ast::NodeId, tcx: ty::ctxt)
}
pub fn get_native_libraries(cdata: Cmd) -> ~[~str] {
pub fn get_native_libraries(cdata: Cmd) -> ~[(cstore::NativeLibaryKind, ~str)] {
let libraries = reader::get_doc(reader::Doc(cdata.data), tag_native_libraries);
let mut result = ~[];
reader::tagged_docs(libraries, tag_native_libraries_lib, |lib_doc| {
result.push(lib_doc.as_str());
let kind_doc = reader::get_doc(lib_doc, tag_native_libraries_kind);
let name_doc = reader::get_doc(lib_doc, tag_native_libraries_name);
let kind: cstore::NativeLibaryKind =
FromPrimitive::from_u32(reader::doc_as_u32(kind_doc)).unwrap();
let name = name_doc.as_str();
result.push((kind, name));
true
});
return result;

View File

@ -1640,10 +1640,18 @@ fn encode_native_libraries(ecx: &EncodeContext, ebml_w: &mut writer::Encoder) {
for &(ref lib, kind) in cstore::get_used_libraries(ecx.cstore).iter() {
match kind {
cstore::NativeStatic => {} // these libraries are not propagated
cstore::NativeUnknown => {
cstore::NativeFramework | cstore::NativeUnknown => {
ebml_w.start_tag(tag_native_libraries_lib);
ebml_w.start_tag(tag_native_libraries_kind);
ebml_w.writer.write_be_u32(kind as u32);
ebml_w.end_tag();
ebml_w.start_tag(tag_native_libraries_name);
ebml_w.writer.write(lib.as_bytes());
ebml_w.end_tag();
ebml_w.end_tag();
}
}
}

View File

@ -0,0 +1,16 @@
// 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.
#[link()] //~ ERROR: specified without `name =
#[link(name = "foo")]
#[link(name = "foo", kind = "bar")] //~ ERROR: unknown kind
extern {}
fn main() {}

View File

@ -0,0 +1,18 @@
// 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.
// xfail-macos this is supposed to succeed on osx
#[link(name = "foo", kind = "framework")]
extern {}
//~^^ ERROR: native frameworks are only available on OSX
fn main() {
}

View File

@ -0,0 +1,25 @@
// 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.
use std::libc;
#[cfg(target_os = "macos")]
#[link(name = "CoreFoundation", kind = "framework")]
extern {
fn CFRunLoopGetTypeID() -> libc::c_ulong;
}
#[cfg(target_os = "macos")]
fn main() {
unsafe { CFRunLoopGetTypeID(); }
}
#[cfg(not(target_os = "macos"))]
pub fn main() {}