diff --git a/src/bindgen/cargo_expand.rs b/src/bindgen/cargo_expand.rs
new file mode 100644
index 0000000000000000000000000000000000000000..93ac20b9184b2f9f38774881ba6986fadef4105b
--- /dev/null
+++ b/src/bindgen/cargo_expand.rs
@@ -0,0 +1,21 @@
+use std::env;
+use std::path::Path;
+use std::process::Command;
+use std::str::from_utf8;
+
+pub fn expand(manifest_path: &Path, crate_name: &str) -> String {
+    let cargo = env::var("CARGO").unwrap_or_else(|_| String::from("cargo"));
+    let mut cmd = Command::new(cargo);
+    cmd.arg("rustc");
+    cmd.arg("--manifest-path");
+    cmd.arg(manifest_path);
+    cmd.arg("--all-features");
+    cmd.arg("-p");
+    cmd.arg(crate_name);
+    cmd.arg("--");
+    cmd.arg("-Z");
+    cmd.arg("unstable-options");
+    cmd.arg("--pretty=expanded");
+    let output = cmd.output().unwrap();
+    from_utf8(&output.stdout).unwrap().to_owned()
+}
diff --git a/src/bindgen/cargo_metadata.rs b/src/bindgen/cargo_metadata.rs
index 8b30eec2b75fb5df265d339fd6fd9bae22be4346..40bd39893db039144af23c6b341bd836c8f62cf8 100644
--- a/src/bindgen/cargo_metadata.rs
+++ b/src/bindgen/cargo_metadata.rs
@@ -110,10 +110,12 @@ impl From<serde_json::Error> for Error {
 pub fn metadata(manifest_path_arg: Option<&str>) -> Result<Metadata, Error> {
     let cargo = env::var("CARGO").unwrap_or_else(|_| String::from("cargo"));
     let mut cmd = Command::new(cargo);
-    cmd.arg("metadata").arg("--all-features");
+    cmd.arg("metadata");
+    cmd.arg("--all-features");
     cmd.arg("--format-version").arg("1");
     if let Some(mani) = manifest_path_arg {
-        cmd.arg("--manifest-path").arg(mani);
+        cmd.arg("--manifest-path");
+        cmd.arg(mani);
     }
     let output = cmd.output()?;
     let stdout = from_utf8(&output.stdout)?;
diff --git a/src/bindgen/mod.rs b/src/bindgen/mod.rs
index 3dabb7a43bd13a971d419eae91ee79d4a44eb15b..b24c514ecde48ea0c03ccf4f154adfaf9533136e 100644
--- a/src/bindgen/mod.rs
+++ b/src/bindgen/mod.rs
@@ -27,6 +27,7 @@ macro_rules! deserialize_enum_str {
     }
 }
 
+mod cargo_expand;
 mod cargo_metadata;
 mod cdecl;
 mod config;
diff --git a/src/bindgen/rust_lib.rs b/src/bindgen/rust_lib.rs
index 4337af4c0ff4fa20eb1d03d6dcaf497d6888ef89..02fa0e59324c64d3b00c73d710857d2c712f34a3 100644
--- a/src/bindgen/rust_lib.rs
+++ b/src/bindgen/rust_lib.rs
@@ -3,6 +3,7 @@ use std::fs::File;
 use std::io::Read;
 use std::path::{Path, PathBuf};
 
+use bindgen::cargo_expand;
 use bindgen::cargo_metadata;
 use syn;
 
@@ -39,53 +40,103 @@ pub fn parse_lib<F>(crate_path: &Path,
         }
     };
 
-    let mut items_cache = HashMap::new();
-    parse_crate(binding_crate_name,
-                &metadata,
-                items_callback,
-                &mut items_cache);
+    let mut context = ParseLibContext {
+      manifest_path: manifest_path,
+      metadata: metadata,
+      cache_src: HashMap::new(),
+      cache_expanded_crate: HashMap::new(),
+      items_callback: items_callback,
+    };
+
+    parse_crate(binding_crate_name, &mut context);
 }
 
-fn find_crate_src(package_name: &str, metadata: &cargo_metadata::Metadata) -> Option<PathBuf> {
-    let kind_lib = String::from("lib");
-    for package in &metadata.packages {
-        if package.name == package_name {
-            for target in &package.targets {
-                if target.kind.contains(&kind_lib) {
-                    return Some(PathBuf::from(&target.src_path));
-                }
-            }
-            break;
-        }
-    }
-    None
+struct ParseLibContext<F>
+  where F: FnMut(&str, &Vec<syn::Item>)
+{
+  manifest_path: PathBuf,
+  metadata: cargo_metadata::Metadata,
+  cache_src: HashMap<PathBuf, Vec<syn::Item>>,
+  cache_expanded_crate: HashMap<String, Vec<syn::Item>>,
+
+  items_callback: F,
+}
+
+impl<F> ParseLibContext<F>
+  where F: FnMut(&str, &Vec<syn::Item>)
+{
+  fn find_crate_src(&self, package_name: &str) -> Option<PathBuf> {
+      let kind_lib = String::from("lib");
+      for package in &self.metadata.packages {
+          if package.name == package_name {
+              for target in &package.targets {
+                  if target.kind.contains(&kind_lib) {
+                      return Some(PathBuf::from(&target.src_path));
+                  }
+              }
+              break;
+          }
+      }
+      None
+  }
 }
 
-fn parse_crate<F>(crate_name: &str,
-                  metadata: &cargo_metadata::Metadata,
-                  items_callback: &mut F,
-                  items_cache: &mut HashMap<PathBuf, Vec<syn::Item>>)
+fn parse_crate<F>(crate_name: &str, context: &mut ParseLibContext<F>)
     where F: FnMut(&str, &Vec<syn::Item>)
 {
-    let crate_src = find_crate_src(crate_name, metadata);
+    let crate_src = context.find_crate_src(crate_name);
 
     match crate_src {
         Some(crate_src) => {
-            parse_mod(crate_src.as_path(),
-                      crate_name,
-                      metadata,
-                      items_callback,
-                      items_cache);
+            parse_mod(crate_name,
+                      crate_src.as_path(),
+                      context);
         }
         None => info!("can't find crate {}", crate_name),
     }
 }
 
-fn parse_mod<F>(mod_path: &Path,
-                crate_name: &str,
-                metadata: &cargo_metadata::Metadata,
-                items_callback: &mut F,
-                items_cache: &mut HashMap<PathBuf, Vec<syn::Item>>)
+fn parse_expand_crate<F>(crate_name: &str, context: &mut ParseLibContext<F>)
+    where F: FnMut(&str, &Vec<syn::Item>)
+{
+    let mod_parsed = {
+        let owned_crate_name = crate_name.to_owned();
+
+        if !context.cache_expanded_crate.contains_key(&owned_crate_name) {
+            let s = cargo_expand::expand(&context.manifest_path,
+                                         crate_name);
+            let i = syn::parse_crate(&s).unwrap();
+            context.cache_expanded_crate.insert(owned_crate_name.clone(), i.items);
+        }
+        context.cache_expanded_crate.get(&owned_crate_name).unwrap().clone()
+    };
+
+    (context.items_callback)(crate_name,
+                             &mod_parsed);
+
+    for item in &mod_parsed {
+        match item.node {
+            syn::ItemKind::Mod(ref inline_items) => {
+                if let &Some(ref inline_items) = inline_items {
+                    (context.items_callback)(crate_name,
+                                             &inline_items);
+                    continue;
+                }
+
+                warn!("external mod found in expanded source");
+            }
+            syn::ItemKind::ExternCrate(_) => {
+                parse_expand_crate(&item.ident.to_string(),
+                                   context);
+            }
+            _ => {}
+        }
+    }
+}
+
+fn parse_mod<F>(crate_name: &str,
+                mod_path: &Path,
+                context: &mut ParseLibContext<F>)
     where F: FnMut(&str, &Vec<syn::Item>)
 {
     let mod_dir = mod_path.parent().unwrap().to_path_buf();
@@ -93,18 +144,18 @@ fn parse_mod<F>(mod_path: &Path,
     let mod_parsed = {
         let owned_mod_path = mod_path.to_path_buf();
 
-        if !items_cache.contains_key(&owned_mod_path) {
+        if !context.cache_src.contains_key(&owned_mod_path) {
             let mut s = String::new();
             let mut f = File::open(mod_path).unwrap();
             f.read_to_string(&mut s).unwrap();
             let i = syn::parse_crate(&s).unwrap();
-            items_cache.insert(owned_mod_path.clone(), i.items);
+            context.cache_src.insert(owned_mod_path.clone(), i.items);
         }
-        items_cache.get(&owned_mod_path).unwrap().clone()
+        context.cache_src.get(&owned_mod_path).unwrap().clone()
     };
 
-    items_callback(crate_name,
-                   &mod_parsed);
+    (context.items_callback)(crate_name,
+                             &mod_parsed);
 
     for item in &mod_parsed {
         match item.node {
@@ -112,8 +163,8 @@ fn parse_mod<F>(mod_path: &Path,
                 let next_mod_name = item.ident.to_string();
 
                 if let &Some(ref inline_items) = inline_items {
-                    items_callback(crate_name,
-                                   &inline_items);
+                    (context.items_callback)(crate_name,
+                                             &inline_items);
                     continue;
                 }
 
@@ -121,26 +172,20 @@ fn parse_mod<F>(mod_path: &Path,
                 let next_mod_path2 = mod_dir.join(next_mod_name.clone()).join("mod.rs");
 
                 if next_mod_path1.exists() {
-                    parse_mod(next_mod_path1.as_path(),
-                              crate_name,
-                              metadata,
-                              items_callback,
-                              items_cache);
+                    parse_mod(crate_name,
+                              next_mod_path1.as_path(),
+                              context);
                 } else if next_mod_path2.exists() {
-                    parse_mod(next_mod_path2.as_path(),
-                              crate_name,
-                              metadata,
-                              items_callback,
-                              items_cache);
+                    parse_mod(crate_name,
+                              next_mod_path2.as_path(),
+                              context);
                 } else {
                     info!("can't find mod {} in crate {}", next_mod_name, crate_name);
                 }
             }
             syn::ItemKind::ExternCrate(_) => {
-                parse_crate(&item.ident.to_string(),
-                            metadata,
-                            items_callback,
-                            items_cache);
+                parse_expand_crate(&item.ident.to_string(),
+                                   context);
             }
             _ => {}
         }