Skip to content

Commit f9d6fd2

Browse files
committed
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
1 parent 4252a24 commit f9d6fd2

File tree

10 files changed

+130
-18
lines changed

10 files changed

+130
-18
lines changed

src/librustc/back/link.rs

+29-7
Original file line numberDiff line numberDiff line change
@@ -1015,7 +1015,7 @@ fn link_rlib(sess: Session, obj_filename: &Path,
10151015
cstore::NativeStatic => {
10161016
a.add_native_library(l.as_slice());
10171017
}
1018-
cstore::NativeUnknown => {}
1018+
cstore::NativeFramework | cstore::NativeUnknown => {}
10191019
}
10201020
}
10211021
return a;
@@ -1044,8 +1044,13 @@ fn link_staticlib(sess: Session, obj_filename: &Path, out_filename: &Path) {
10441044
};
10451045
a.add_rlib(&p);
10461046
let native_libs = csearch::get_native_libraries(sess.cstore, cnum);
1047-
for lib in native_libs.iter() {
1048-
sess.warn(format!("unlinked native library: {}", *lib));
1047+
for &(kind, ref lib) in native_libs.iter() {
1048+
let name = match kind {
1049+
cstore::NativeStatic => "static library",
1050+
cstore::NativeUnknown => "library",
1051+
cstore::NativeFramework => "framework",
1052+
};
1053+
sess.warn(format!("unlinked native {}: {}", name, *lib));
10491054
}
10501055
}
10511056
}
@@ -1204,8 +1209,17 @@ fn add_upstream_rust_crates(args: &mut ~[~str], sess: Session,
12041209
args.push(cratepath.as_str().unwrap().to_owned());
12051210

12061211
let libs = csearch::get_native_libraries(sess.cstore, cnum);
1207-
for lib in libs.iter() {
1208-
args.push("-l" + *lib);
1212+
for &(kind, ref lib) in libs.iter() {
1213+
match kind {
1214+
cstore::NativeUnknown => args.push("-l" + *lib),
1215+
cstore::NativeFramework => {
1216+
args.push(~"-framework");
1217+
args.push(lib.to_owned());
1218+
}
1219+
cstore::NativeStatic => {
1220+
sess.bug("statics shouldn't be propagated");
1221+
}
1222+
}
12091223
}
12101224
}
12111225
return;
@@ -1262,7 +1276,15 @@ fn add_local_native_libraries(args: &mut ~[~str], sess: Session) {
12621276
args.push("-L" + path.as_str().unwrap().to_owned());
12631277
}
12641278

1265-
for &(ref l, _) in cstore::get_used_libraries(sess.cstore).iter() {
1266-
args.push(~"-l" + *l);
1279+
for &(ref l, kind) in cstore::get_used_libraries(sess.cstore).iter() {
1280+
match kind {
1281+
cstore::NativeUnknown | cstore::NativeStatic => {
1282+
args.push("-l" + *l);
1283+
}
1284+
cstore::NativeFramework => {
1285+
args.push(~"-framework");
1286+
args.push(l.to_owned());
1287+
}
1288+
}
12671289
}
12681290
}

src/librustc/metadata/common.rs

+2
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,8 @@ pub static tag_region_param_def_def_id: uint = 0x102;
199199

200200
pub static tag_native_libraries: uint = 0x103;
201201
pub static tag_native_libraries_lib: uint = 0x104;
202+
pub static tag_native_libraries_name: uint = 0x105;
203+
pub static tag_native_libraries_kind: uint = 0x106;
202204

203205
pub struct LinkMeta {
204206
name: @str,

src/librustc/metadata/creader.rs

+18-4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use metadata::loader;
1818
use std::hashmap::HashMap;
1919
use syntax::ast;
2020
use std::vec;
21+
use syntax::abi;
2122
use syntax::attr;
2223
use syntax::attr::AttrMetaMethods;
2324
use syntax::codemap::{Span, dummy_sp};
@@ -191,10 +192,22 @@ fn visit_item(e: &Env, i: @ast::item) {
191192
"kind" == k.name()
192193
}).and_then(|a| a.value_str());
193194
let kind = match kind {
194-
Some(k) if "static" == k => cstore::NativeStatic,
195195
Some(k) => {
196-
e.sess.span_fatal(i.span,
197-
format!("unknown kind: `{}`", k));
196+
if "static" == k {
197+
cstore::NativeStatic
198+
} else if e.sess.targ_cfg.os == abi::OsMacos &&
199+
"framework" == k {
200+
cstore::NativeFramework
201+
} else if "framework" == k {
202+
e.sess.span_err(m.span,
203+
"native frameworks are only available \
204+
on OSX targets");
205+
cstore::NativeUnknown
206+
} else {
207+
e.sess.span_err(m.span,
208+
format!("unknown kind: `{}`", k));
209+
cstore::NativeUnknown
210+
}
198211
}
199212
None => cstore::NativeUnknown
200213
};
@@ -204,9 +217,10 @@ fn visit_item(e: &Env, i: @ast::item) {
204217
let n = match n {
205218
Some(n) => n,
206219
None => {
207-
e.sess.span_fatal(i.span,
220+
e.sess.span_err(m.span,
208221
"#[link(...)] specified without \
209222
`name = \"foo\"`");
223+
@"foo"
210224
}
211225
};
212226
cstore::add_used_library(cstore, n.to_owned(), kind);

src/librustc/metadata/csearch.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,8 @@ pub fn get_item_visibility(cstore: @mut cstore::CStore,
263263
}
264264

265265
pub fn get_native_libraries(cstore: @mut cstore::CStore,
266-
crate_num: ast::CrateNum) -> ~[~str] {
266+
crate_num: ast::CrateNum)
267+
-> ~[(cstore::NativeLibaryKind, ~str)] {
267268
let cdata = cstore::get_crate_data(cstore, crate_num);
268269
decoder::get_native_libraries(cdata)
269270
}

src/librustc/metadata/cstore.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,11 @@ pub enum LinkagePreference {
4040
RequireStatic,
4141
}
4242

43-
#[deriving(Eq)]
43+
#[deriving(Eq, FromPrimitive)]
4444
pub enum NativeLibaryKind {
45-
NativeStatic,
46-
NativeUnknown,
45+
NativeStatic, // native static library (.a archive)
46+
NativeFramework, // OSX-specific
47+
NativeUnknown, // default way to specify a dynamic library
4748
}
4849

4950
// Where a crate came from on the local filesystem. One of these two options

src/librustc/metadata/decoder.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -1530,11 +1530,16 @@ pub fn get_trait_of_method(cdata: Cmd, id: ast::NodeId, tcx: ty::ctxt)
15301530
}
15311531

15321532

1533-
pub fn get_native_libraries(cdata: Cmd) -> ~[~str] {
1533+
pub fn get_native_libraries(cdata: Cmd) -> ~[(cstore::NativeLibaryKind, ~str)] {
15341534
let libraries = reader::get_doc(reader::Doc(cdata.data), tag_native_libraries);
15351535
let mut result = ~[];
15361536
reader::tagged_docs(libraries, tag_native_libraries_lib, |lib_doc| {
1537-
result.push(lib_doc.as_str());
1537+
let kind_doc = reader::get_doc(lib_doc, tag_native_libraries_kind);
1538+
let name_doc = reader::get_doc(lib_doc, tag_native_libraries_name);
1539+
let kind: cstore::NativeLibaryKind =
1540+
FromPrimitive::from_u32(reader::doc_as_u32(kind_doc)).unwrap();
1541+
let name = name_doc.as_str();
1542+
result.push((kind, name));
15381543
true
15391544
});
15401545
return result;

src/librustc/metadata/encoder.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -1640,10 +1640,18 @@ fn encode_native_libraries(ecx: &EncodeContext, ebml_w: &mut writer::Encoder) {
16401640
for &(ref lib, kind) in cstore::get_used_libraries(ecx.cstore).iter() {
16411641
match kind {
16421642
cstore::NativeStatic => {} // these libraries are not propagated
1643-
cstore::NativeUnknown => {
1643+
cstore::NativeFramework | cstore::NativeUnknown => {
16441644
ebml_w.start_tag(tag_native_libraries_lib);
1645+
1646+
ebml_w.start_tag(tag_native_libraries_kind);
1647+
ebml_w.writer.write_be_u32(kind as u32);
1648+
ebml_w.end_tag();
1649+
1650+
ebml_w.start_tag(tag_native_libraries_name);
16451651
ebml_w.writer.write(lib.as_bytes());
16461652
ebml_w.end_tag();
1653+
1654+
ebml_w.end_tag();
16471655
}
16481656
}
16491657
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#[link()] //~ ERROR: specified without `name =
12+
#[link(name = "foo")]
13+
#[link(name = "foo", kind = "bar")] //~ ERROR: unknown kind
14+
extern {}
15+
16+
fn main() {}
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// xfail-macos this is supposed to succeed on osx
12+
13+
#[link(name = "foo", kind = "framework")]
14+
extern {}
15+
//~^^ ERROR: native frameworks are only available on OSX
16+
17+
fn main() {
18+
}

src/test/run-pass/osx-frameworks.rs

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use std::libc;
12+
13+
#[cfg(target_os = "macos")]
14+
#[link(name = "CoreFoundation", kind = "framework")]
15+
extern {
16+
fn CFRunLoopGetTypeID() -> libc::c_ulong;
17+
}
18+
19+
#[cfg(target_os = "macos")]
20+
fn main() {
21+
unsafe { CFRunLoopGetTypeID(); }
22+
}
23+
24+
#[cfg(not(target_os = "macos"))]
25+
pub fn main() {}

0 commit comments

Comments
 (0)