about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2013-11-30 11:39:55 -0800
committerAlex Crichton <alex@alexcrichton.com>2013-11-30 15:47:43 -0800
commitf9d6fd20a515d677e923686f2fbf4e9f2307aab1 (patch)
treea72a14d12c945d655d45da715cf172fb0439f62d
parent4252a24ae1236207a99c1d313d4b1b1eda3ebb58 (diff)
downloadrust-f9d6fd20a515d677e923686f2fbf4e9f2307aab1.tar.gz
rust-f9d6fd20a515d677e923686f2fbf4e9f2307aab1.zip
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
-rw-r--r--src/librustc/back/link.rs36
-rw-r--r--src/librustc/metadata/common.rs2
-rw-r--r--src/librustc/metadata/creader.rs22
-rw-r--r--src/librustc/metadata/csearch.rs3
-rw-r--r--src/librustc/metadata/cstore.rs7
-rw-r--r--src/librustc/metadata/decoder.rs9
-rw-r--r--src/librustc/metadata/encoder.rs10
-rw-r--r--src/test/compile-fail/bad-extern-link-attrs.rs16
-rw-r--r--src/test/compile-fail/osx-frameworks.rs18
-rw-r--r--src/test/run-pass/osx-frameworks.rs25
10 files changed, 130 insertions, 18 deletions
diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs
index 8119618da57..5cf912a929f 100644
--- a/src/librustc/back/link.rs
+++ b/src/librustc/back/link.rs
@@ -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());
+            }
+        }
     }
 }
diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs
index 5ed1eac746c..f6eadfcc916 100644
--- a/src/librustc/metadata/common.rs
+++ b/src/librustc/metadata/common.rs
@@ -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,
diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs
index 9d28a5abed2..b425f1449f5 100644
--- a/src/librustc/metadata/creader.rs
+++ b/src/librustc/metadata/creader.rs
@@ -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);
diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs
index 96250fd5ec8..c1c56e94f27 100644
--- a/src/librustc/metadata/csearch.rs
+++ b/src/librustc/metadata/csearch.rs
@@ -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)
 }
diff --git a/src/librustc/metadata/cstore.rs b/src/librustc/metadata/cstore.rs
index 50da84d3895..c2f6443ed54 100644
--- a/src/librustc/metadata/cstore.rs
+++ b/src/librustc/metadata/cstore.rs
@@ -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
diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs
index 441f1620e4d..b5746cec58d 100644
--- a/src/librustc/metadata/decoder.rs
+++ b/src/librustc/metadata/decoder.rs
@@ -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;
diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs
index 269054c6fd2..ea4f4b0f3cf 100644
--- a/src/librustc/metadata/encoder.rs
+++ b/src/librustc/metadata/encoder.rs
@@ -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();
             }
         }
     }
diff --git a/src/test/compile-fail/bad-extern-link-attrs.rs b/src/test/compile-fail/bad-extern-link-attrs.rs
new file mode 100644
index 00000000000..0616da26602
--- /dev/null
+++ b/src/test/compile-fail/bad-extern-link-attrs.rs
@@ -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() {}
diff --git a/src/test/compile-fail/osx-frameworks.rs b/src/test/compile-fail/osx-frameworks.rs
new file mode 100644
index 00000000000..61593629656
--- /dev/null
+++ b/src/test/compile-fail/osx-frameworks.rs
@@ -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() {
+}
diff --git a/src/test/run-pass/osx-frameworks.rs b/src/test/run-pass/osx-frameworks.rs
new file mode 100644
index 00000000000..cfb7a8e43be
--- /dev/null
+++ b/src/test/run-pass/osx-frameworks.rs
@@ -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() {}