diff --git a/src/libextra/extra.rs b/src/libextra/extra.rs
index 796dd9c7c7e..74787e66fec 100644
--- a/src/libextra/extra.rs
+++ b/src/libextra/extra.rs
@@ -26,7 +26,8 @@ Rust extras are part of the standard Rust distribution.
        url = "https://github.com/mozilla/rust/tree/master/src/libextra")];
 
 #[doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
-      html_favicon_url = "http://www.rust-lang.org/favicon.ico")];
+      html_favicon_url = "http://www.rust-lang.org/favicon.ico",
+      html_root_url = "http://static.rust-lang.org/doc/master")];
 
 #[comment = "Rust extras"];
 #[license = "MIT/ASL2"];
diff --git a/src/librustdoc/clean.rs b/src/librustdoc/clean.rs
index b0f2ba286e6..b9100d6e365 100644
--- a/src/librustdoc/clean.rs
+++ b/src/librustdoc/clean.rs
@@ -15,11 +15,18 @@ use its = syntax::parse::token::ident_to_str;
 
 use syntax;
 use syntax::ast;
+use syntax::ast_map;
 use syntax::ast_util;
 use syntax::attr;
 use syntax::attr::AttributeMethods;
 
+use rustc::metadata::cstore;
+use rustc::metadata::csearch;
+use rustc::metadata::decoder;
+
 use std;
+use std::hashmap::HashMap;
+
 use doctree;
 use visit_ast;
 use std::local_data;
@@ -61,19 +68,44 @@ impl<T: Clean<U>, U> Clean<~[U]> for syntax::opt_vec::OptVec<T> {
 pub struct Crate {
     name: ~str,
     module: Option<Item>,
+    externs: HashMap<ast::CrateNum, ExternalCrate>,
 }
 
 impl Clean<Crate> for visit_ast::RustdocVisitor {
     fn clean(&self) -> Crate {
         use syntax::attr::{find_linkage_metas, last_meta_item_value_str_by_name};
-        let maybe_meta = last_meta_item_value_str_by_name(find_linkage_metas(self.attrs), "name");
+        let maybe_meta = last_meta_item_value_str_by_name(
+                                find_linkage_metas(self.attrs), "name");
+        let cx = local_data::get(super::ctxtkey, |x| *x.unwrap());
+
+        let mut externs = HashMap::new();
+        do cstore::iter_crate_data(cx.sess.cstore) |n, meta| {
+            externs.insert(n, meta.clean());
+        }
 
         Crate {
             name: match maybe_meta {
                 Some(x) => x.to_owned(),
-                None => fail2!("rustdoc_ng requires a \\#[link(name=\"foo\")] crate attribute"),
+                None => fail2!("rustdoc requires a \\#[link(name=\"foo\")] \
+                                crate attribute"),
             },
             module: Some(self.module.clean()),
+            externs: externs,
+        }
+    }
+}
+
+#[deriving(Clone, Encodable, Decodable)]
+pub struct ExternalCrate {
+    name: ~str,
+    attrs: ~[Attribute],
+}
+
+impl Clean<ExternalCrate> for cstore::crate_metadata {
+    fn clean(&self) -> ExternalCrate {
+        ExternalCrate {
+            name: self.name.to_owned(),
+            attrs: decoder::get_crate_attributes(self.data).clean()
         }
     }
 }
@@ -542,7 +574,15 @@ pub enum Type {
     ResolvedPath {
         path: Path,
         typarams: Option<~[TyParamBound]>,
-        did: ast::DefId
+        id: ast::NodeId,
+    },
+    /// Same as above, but only external variants
+    ExternalPath {
+        path: Path,
+        typarams: Option<~[TyParamBound]>,
+        fqn: ~[~str],
+        kind: TypeKind,
+        crate: ast::CrateNum,
     },
     // I have no idea how to usefully use this.
     TyParamBinder(ast::NodeId),
@@ -572,6 +612,14 @@ pub enum Type {
     // region, raw, other boxes, mutable
 }
 
+#[deriving(Clone, Encodable, Decodable)]
+pub enum TypeKind {
+    TypeStruct,
+    TypeEnum,
+    TypeTrait,
+    TypeFunction,
+}
+
 impl Clean<Type> for ast::Ty {
     fn clean(&self) -> Type {
         use syntax::ast::*;
@@ -1099,26 +1147,12 @@ fn name_from_pat(p: &ast::Pat) -> ~str {
     }
 }
 
-fn remove_comment_tags(s: &str) -> ~str {
-    if s.starts_with("/") {
-        match s.slice(0,3) {
-            &"///" => return s.slice(3, s.len()).trim().to_owned(),
-            &"/**" | &"/*!" => return s.slice(3, s.len() - 2).trim().to_owned(),
-            _ => return s.trim().to_owned()
-        }
-    } else {
-        return s.to_owned();
-    }
-}
-
 /// Given a Type, resolve it using the def_map
 fn resolve_type(path: Path, tpbs: Option<~[TyParamBound]>,
                 id: ast::NodeId) -> Type {
-    use syntax::ast::*;
-
-    let dm = local_data::get(super::ctxtkey, |x| *x.unwrap()).tycx.def_map;
+    let cx = local_data::get(super::ctxtkey, |x| *x.unwrap());
     debug2!("searching for {:?} in defmap", id);
-    let d = match dm.find(&id) {
+    let d = match cx.tycx.def_map.find(&id) {
         Some(k) => k,
         None => {
             let ctxt = local_data::get(super::ctxtkey, |x| *x.unwrap());
@@ -1128,28 +1162,41 @@ fn resolve_type(path: Path, tpbs: Option<~[TyParamBound]>,
         }
     };
 
-    let def_id = match *d {
-        DefFn(i, _) => i,
-        DefSelf(i) | DefSelfTy(i) => return Self(i),
-        DefTy(i) => i,
-        DefTrait(i) => {
+    let (def_id, kind) = match *d {
+        ast::DefFn(i, _) => (i, TypeFunction),
+        ast::DefSelf(i) | ast::DefSelfTy(i) => return Self(i),
+        ast::DefTy(i) => (i, TypeEnum),
+        ast::DefTrait(i) => {
             debug2!("saw DefTrait in def_to_id");
-            i
+            (i, TypeTrait)
         },
-        DefPrimTy(p) => match p {
-            ty_str => return String,
-            ty_bool => return Bool,
+        ast::DefPrimTy(p) => match p {
+            ast::ty_str => return String,
+            ast::ty_bool => return Bool,
             _ => return Primitive(p)
         },
-        DefTyParam(i, _) => return Generic(i.node),
-        DefStruct(i) => i,
-        DefTyParamBinder(i) => {
+        ast::DefTyParam(i, _) => return Generic(i.node),
+        ast::DefStruct(i) => (i, TypeStruct),
+        ast::DefTyParamBinder(i) => {
             debug2!("found a typaram_binder, what is it? {}", i);
             return TyParamBinder(i);
         },
         x => fail2!("resolved type maps to a weird def {:?}", x),
     };
-    ResolvedPath{ path: path, typarams: tpbs, did: def_id }
+    if ast_util::is_local(def_id) {
+        ResolvedPath{ path: path, typarams: tpbs, id: def_id.node }
+    } else {
+        let fqn = csearch::get_item_path(cx.tycx, def_id);
+        let fqn = fqn.move_iter().map(|i| {
+            match i {
+                ast_map::path_mod(id) |
+                ast_map::path_name(id) |
+                ast_map::path_pretty_name(id, _) => id.clean()
+            }
+        }).to_owned_vec();
+        ExternalPath{ path: path, typarams: tpbs, fqn: fqn, kind: kind,
+                      crate: def_id.crate }
+    }
 }
 
 fn resolve_use_source(path: Path, id: ast::NodeId) -> ImportSource {
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index acbed7f4120..c5f6d7c44fd 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -16,6 +16,7 @@ use syntax::ast;
 use syntax::ast_util;
 
 use clean;
+use html::render;
 use html::render::{cache_key, current_location_key};
 
 pub struct VisSpace(Option<ast::visibility>);
@@ -97,8 +98,46 @@ impl fmt::Default for clean::Path {
     }
 }
 
-fn resolved_path(w: &mut io::Writer, did: ast::DefId,
-                 path: &clean::Path, print_all: bool) {
+fn resolved_path(w: &mut io::Writer, id: ast::NodeId, p: &clean::Path,
+                 print_all: bool) {
+    path(w, p, print_all,
+        |_cache, loc| {
+            match p.segments[0].name.as_slice() {
+                "super" => Some("../".repeat(loc.len() - 1)),
+                _ => Some("../".repeat(loc.len())),
+            }
+        },
+        |cache| {
+            match cache.paths.find(&id) {
+                None => None,
+                Some(&(ref fqp, shortty)) => Some((fqp.clone(), shortty))
+            }
+        });
+}
+
+fn external_path(w: &mut io::Writer, p: &clean::Path, print_all: bool,
+                 fqn: &[~str], kind: clean::TypeKind, crate: ast::CrateNum) {
+    path(w, p, print_all,
+        |cache, loc| {
+            match *cache.extern_locations.get(&crate) {
+                render::Remote(ref s) => Some(s.clone()),
+                render::Local => Some("../".repeat(loc.len())),
+                render::Unknown => None,
+            }
+        },
+        |_cache| {
+            Some((fqn.to_owned(), match kind {
+                clean::TypeStruct => "struct",
+                clean::TypeEnum => "enum",
+                clean::TypeFunction => "fn",
+                clean::TypeTrait => "trait",
+            }))
+        })
+}
+
+fn path(w: &mut io::Writer, path: &clean::Path, print_all: bool,
+        root: &fn(&render::Cache, &[~str]) -> Option<~str>,
+        info: &fn(&render::Cache) -> Option<(~[~str], &'static str)>) {
     // The generics will get written to both the title and link
     let mut generics = ~"";
     let last = path.segments.last();
@@ -121,51 +160,49 @@ fn resolved_path(w: &mut io::Writer, did: ast::DefId,
     do local_data::get(current_location_key) |loc| {
         let loc = loc.unwrap();
 
-        if print_all {
-            let mut root = match path.segments[0].name.as_slice() {
-                "super" => ~"../",
-                "self" => ~"",
-                _ => "../".repeat(loc.len() - 1),
-            };
-            let amt = path.segments.len() - 1;
-            for seg in path.segments.slice_to(amt).iter() {
-                if "super" == seg.name || "self" == seg.name {
-                    write!(w, "{}::", seg.name);
-                } else {
-                    root.push_str(seg.name);
-                    root.push_str("/");
-                    write!(w, "<a class='mod'
-                                  href='{}index.html'>{}</a>::",
-                           root,
-                           seg.name);
-                }
-            }
-        }
-
         do local_data::get(cache_key) |cache| {
             do cache.unwrap().read |cache| {
-                match cache.paths.find(&did.node) {
-                    // This is a documented path, link to it!
-                    // FIXME(#9539): this is_local check should not exist
-                    Some(&(ref fqp, shortty)) if ast_util::is_local(did) => {
-                        let fqn = fqp.connect("::");
-                        let same = loc.iter().zip(fqp.iter())
-                                      .take_while(|&(a, b)| *a == *b).len();
+                let abs_root = root(cache, loc.as_slice());
+                let rel_root = match path.segments[0].name.as_slice() {
+                    "self" => Some(~"./"),
+                    _ => None,
+                };
 
-                        let mut url = ~"";
-                        if "super" == path.segments[0].name {
-                            url.push_str("../");
-                        } else if "self" != path.segments[0].name {
-                            url.push_str("../".repeat(loc.len() - same));
-                        }
-                        if same < fqp.len() {
-                            let remaining = fqp.slice_from(same);
-                            let to_link = remaining.slice_to(remaining.len() - 1);
-                            for component in to_link.iter() {
-                                url.push_str(*component);
-                                url.push_str("/");
+                if print_all {
+                    let amt = path.segments.len() - 1;
+                    match rel_root {
+                        Some(root) => {
+                            let mut root = root;
+                            for seg in path.segments.slice_to(amt).iter() {
+                                if "super" == seg.name || "self" == seg.name {
+                                    write!(w, "{}::", seg.name);
+                                } else {
+                                    root.push_str(seg.name);
+                                    root.push_str("/");
+                                    write!(w, "<a class='mod'
+                                                  href='{}index.html'>{}</a>::",
+                                           root,
+                                           seg.name);
+                                }
                             }
                         }
+                        None => {
+                            for seg in path.segments.slice_to(amt).iter() {
+                                write!(w, "{}::", seg.name);
+                            }
+                        }
+                    }
+                }
+
+                match info(cache) {
+                    // This is a documented path, link to it!
+                    Some((ref fqp, shortty)) if abs_root.is_some() => {
+                        let mut url = abs_root.unwrap();
+                        let to_link = fqp.slice_to(fqp.len() - 1);
+                        for component in to_link.iter() {
+                            url.push_str(*component);
+                            url.push_str("/");
+                        }
                         match shortty {
                             "mod" => {
                                 url.push_str(*fqp.last());
@@ -178,24 +215,35 @@ fn resolved_path(w: &mut io::Writer, did: ast::DefId,
                                 url.push_str(".html");
                             }
                         }
-                        write!(w, "<a class='{}' href='{}' title='{}'>{}</a>{}",
-                               shortty, url, fqn, last.name, generics);
+
+                        write!(w, "<a class='{}' href='{}' title='{}'>{}</a>",
+                               shortty, url, fqp.connect("::"), last.name);
                     }
+
                     _ => {
-                        if print_all {
-                            let amt = path.segments.len() - 1;
-                            for seg in path.segments.iter().take(amt) {
-                                write!(w, "{}::", seg.name);
-                            }
-                        }
-                        write!(w, "{}{}", last.name, generics);
+                        write!(w, "{}", last.name);
                     }
-                };
+                }
+                write!(w, "{}", generics);
             }
         }
     }
 }
 
+fn typarams(w: &mut io::Writer, typarams: &Option<~[clean::TyParamBound]>) {
+    match *typarams {
+        Some(ref params) => {
+            write!(w, "&lt;");
+            for (i, param) in params.iter().enumerate() {
+                if i > 0 { write!(w, ", "); }
+                write!(w, "{}", *param);
+            }
+            write!(w, "&gt;");
+        }
+        None => {}
+    }
+}
+
 impl fmt::Default for clean::Type {
     fn fmt(g: &clean::Type, f: &mut fmt::Formatter) {
         match *g {
@@ -206,19 +254,14 @@ impl fmt::Default for clean::Type {
                     }
                 }
             }
-            clean::ResolvedPath{did, typarams: ref typarams, path: ref path} => {
-                resolved_path(f.buf, did, path, false);
-                match *typarams {
-                    Some(ref params) => {
-                        f.buf.write("&lt;".as_bytes());
-                        for (i, param) in params.iter().enumerate() {
-                            if i > 0 { f.buf.write(", ".as_bytes()) }
-                            write!(f.buf, "{}", *param);
-                        }
-                        f.buf.write("&gt;".as_bytes());
-                    }
-                    None => {}
-                }
+            clean::ResolvedPath{id, typarams: ref tp, path: ref path} => {
+                resolved_path(f.buf, id, path, false);
+                typarams(f.buf, tp);
+            }
+            clean::ExternalPath{path: ref path, typarams: ref tp,
+                                fqn: ref fqn, kind, crate} => {
+                external_path(f.buf, path, false, fqn.as_slice(), kind, crate);
+                typarams(f.buf, tp);
             }
             clean::Self(*) => f.buf.write("Self".as_bytes()),
             clean::Primitive(prim) => {
@@ -417,8 +460,9 @@ impl fmt::Default for clean::ViewPath {
 impl fmt::Default for clean::ImportSource {
     fn fmt(v: &clean::ImportSource, f: &mut fmt::Formatter) {
         match v.did {
-            Some(did) => {
-                resolved_path(f.buf, did, &v.path, true);
+            // XXX: shouldn't be restricted to just local imports
+            Some(did) if ast_util::is_local(did) => {
+                resolved_path(f.buf, did.node, &v.path, true);
             }
             _ => {
                 for (i, seg) in v.path.segments.iter().enumerate() {
@@ -433,7 +477,8 @@ impl fmt::Default for clean::ImportSource {
 impl fmt::Default for clean::ViewListIdent {
     fn fmt(v: &clean::ViewListIdent, f: &mut fmt::Formatter) {
         match v.source {
-            Some(did) => {
+            // XXX: shouldn't be limited to just local imports
+            Some(did) if ast_util::is_local(did) => {
                 let path = clean::Path {
                     global: false,
                     segments: ~[clean::PathSegment {
@@ -442,7 +487,7 @@ impl fmt::Default for clean::ViewListIdent {
                         types: ~[],
                     }]
                 };
-                resolved_path(f.buf, did, &path, false);
+                resolved_path(f.buf, did.node, &path, false);
             }
             _ => write!(f.buf, "{}", v.name),
         }
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index b39a2bcbfb5..6f3595ac2d9 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -28,10 +28,8 @@ use std::vec;
 use extra::arc::RWArc;
 use extra::json::ToJson;
 use extra::sort;
-use extra::time;
 
 use syntax::ast;
-use syntax::ast_util::is_local;
 use syntax::attr;
 
 use clean;
@@ -52,6 +50,12 @@ pub struct Context {
     include_sources: bool,
 }
 
+pub enum ExternalLocation {
+    Remote(~str),   // remote url root of the documentation
+    Local,          // inside local folder
+    Unknown,        // unknown where the documentation is
+}
+
 enum Implementor {
     PathType(clean::Type),
     OtherType(clean::Generics, /* trait */ clean::Type, /* for */ clean::Type),
@@ -68,6 +72,8 @@ struct Cache {
     traits: HashMap<ast::NodeId, HashMap<~str, ~str>>,
     // trait id => implementors of the trait
     implementors: HashMap<ast::NodeId, ~[Implementor]>,
+    // crate number => where is the crate's dox located at
+    extern_locations: HashMap<ast::CrateNum, ExternalLocation>,
 
     priv stack: ~[~str],
     priv parent_stack: ~[ast::NodeId],
@@ -142,6 +148,7 @@ pub fn run(mut crate: clean::Crate, dst: Path) {
         stack: ~[],
         parent_stack: ~[],
         search_index: ~[],
+        extern_locations: HashMap::new(),
     };
     cache.stack.push(crate.name.clone());
     crate = cache.fold_crate(crate);
@@ -154,6 +161,7 @@ pub fn run(mut crate: clean::Crate, dst: Path) {
     write(dst.push("main.css"), include_str!("static/main.css"));
     write(dst.push("normalize.css"), include_str!("static/normalize.css"));
 
+    // Publish the search index
     {
         let dst = dst.push("search-index.js");
         let mut w = BufferedWriter::new(dst.open_writer(io::CreateOrTruncate));
@@ -180,9 +188,9 @@ pub fn run(mut crate: clean::Crate, dst: Path) {
         w.flush();
     }
 
-    info2!("emitting source files");
-    let started = time::precise_time_ns();
+    // Render all source files (this may turn into a giant no-op)
     {
+        info2!("emitting source files");
         let dst = cx.dst.push("src");
         mkdir(&dst);
         let dst = dst.push(crate.name);
@@ -194,14 +202,13 @@ pub fn run(mut crate: clean::Crate, dst: Path) {
         };
         crate = folder.fold_crate(crate);
     }
-    let ended = time::precise_time_ns();
-    info2!("Took {:.03f}s", (ended as f64 - started as f64) / 1e9f64);
 
-    info2!("rendering the whole crate");
-    let started = time::precise_time_ns();
+    for (&n, e) in crate.externs.iter() {
+        cache.extern_locations.insert(n, extern_location(e, &cx.dst));
+    }
+
+    // And finally render the whole crate's documentation
     cx.crate(crate, cache);
-    let ended = time::precise_time_ns();
-    info2!("Took {:.03f}s", (ended as f64 - started as f64) / 1e9f64);
 }
 
 fn write(dst: Path, contents: &str) {
@@ -235,6 +242,38 @@ fn clean_srcpath(src: &str, f: &fn(&str)) {
     }
 }
 
+fn extern_location(e: &clean::ExternalCrate, dst: &Path) -> ExternalLocation {
+    // See if there's documentation generated into the local directory
+    let local_location = dst.push(e.name);
+    if local_location.is_dir() {
+        return Local;
+    }
+
+    // Failing that, see if there's an attribute specifying where to find this
+    // external crate
+    for attr in e.attrs.iter() {
+        match *attr {
+            clean::List(~"doc", ref list) => {
+                for attr in list.iter() {
+                    match *attr {
+                        clean::NameValue(~"html_root_url", ref s) => {
+                            if s.ends_with("/") {
+                                return Remote(s.to_owned());
+                            }
+                            return Remote(*s + "/");
+                        }
+                        _ => {}
+                    }
+                }
+            }
+            _ => {}
+        }
+    }
+
+    // Well, at least we tried.
+    return Unknown;
+}
+
 impl<'self> DocFolder for SourceCollector<'self> {
     fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
         if self.cx.include_sources && !self.seen.contains(&item.source.filename) {
@@ -353,8 +392,7 @@ impl DocFolder for Cache {
         match item.inner {
             clean::ImplItem(ref i) => {
                 match i.trait_ {
-                    Some(clean::ResolvedPath{ did, _ }) if is_local(did) => {
-                        let id = did.node;
+                    Some(clean::ResolvedPath{ id, _ }) => {
                         let v = do self.implementors.find_or_insert_with(id) |_|{
                             ~[]
                         };
@@ -441,8 +479,8 @@ impl DocFolder for Cache {
             }
             clean::ImplItem(ref i) => {
                 match i.for_ {
-                    clean::ResolvedPath{ did, _ } if is_local(did) => {
-                        self.parent_stack.push(did.node); true
+                    clean::ResolvedPath{ id, _ } => {
+                        self.parent_stack.push(id); true
                     }
                     _ => false
                 }
@@ -457,8 +495,7 @@ impl DocFolder for Cache {
                 match item {
                     clean::Item{ attrs, inner: clean::ImplItem(i), _ } => {
                         match i.for_ {
-                            clean::ResolvedPath { did, _ } if is_local(did) => {
-                                let id = did.node;
+                            clean::ResolvedPath { id, _ } => {
                                 let v = do self.impls.find_or_insert_with(id) |_| {
                                     ~[]
                                 };
@@ -1258,7 +1295,7 @@ fn render_impl(w: &mut io::Writer, i: &clean::Impl, dox: &Option<~str>) {
         Some(ref ty) => {
             write!(w, "{} for ", *ty);
             match *ty {
-                clean::ResolvedPath { did, _ } => Some(did),
+                clean::ResolvedPath { id, _ } => Some(id),
                 _ => None,
             }
         }
@@ -1289,8 +1326,7 @@ fn render_impl(w: &mut io::Writer, i: &clean::Impl, dox: &Option<~str>) {
         // No documentation? Attempt to slurp in the trait's documentation
         let trait_id = match trait_id {
             None => continue,
-            Some(id) if is_local(id) => continue,
-            Some(id) => id.node,
+            Some(id) => id,
         };
         do local_data::get(cache_key) |cache| {
             do cache.unwrap().read |cache| {
diff --git a/src/librustdoc/passes.rs b/src/librustdoc/passes.rs
index 8f1955fb423..e7b4ce9e056 100644
--- a/src/librustdoc/passes.rs
+++ b/src/librustdoc/passes.rs
@@ -13,7 +13,6 @@ use std::uint;
 use std::hashmap::HashSet;
 
 use syntax::ast;
-use syntax::ast_util::is_local;
 
 use clean;
 use clean::Item;
@@ -131,8 +130,8 @@ pub fn strip_private(mut crate: clean::Crate) -> plugins::PluginResult {
             match i.inner {
                 clean::ImplItem(ref imp) => {
                     match imp.trait_ {
-                        Some(clean::ResolvedPath{ did, _ }) => {
-                            if is_local(did) && !self.contains(&did.node) {
+                        Some(clean::ResolvedPath{ id, _ }) => {
+                            if !self.contains(&id) {
                                 return None;
                             }
                         }
diff --git a/src/libstd/std.rs b/src/libstd/std.rs
index ece623fab24..5501cdfdcd5 100644
--- a/src/libstd/std.rs
+++ b/src/libstd/std.rs
@@ -58,7 +58,8 @@ they contained the following prologue:
 #[crate_type = "lib"];
 
 #[doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
-      html_favicon_url = "http://www.rust-lang.org/favicon.ico")];
+      html_favicon_url = "http://www.rust-lang.org/favicon.ico",
+      html_root_url = "http://static.rust-lang.org/doc/master")];
 
 // Don't link to std. We are std.
 #[no_std];