Extract target info
authorAleksey Kladov <aleksey.kladov@gmail.com>
Mon, 2 Apr 2018 20:39:42 +0000 (23:39 +0300)
committerAleksey Kladov <aleksey.kladov@gmail.com>
Mon, 2 Apr 2018 20:39:42 +0000 (23:39 +0300)
src/cargo/ops/cargo_rustc/context/compilation_files.rs
src/cargo/ops/cargo_rustc/context/mod.rs
src/cargo/ops/cargo_rustc/context/target_info.rs [new file with mode: 0644]

index 98217d260d8a8803883db81a6739c3564ad53902..b1cfa97c6f0eaed75dea01846d653549c63fce17 100644 (file)
@@ -1,4 +1,4 @@
-use std::collections::hash_map::{Entry, HashMap};
+use std::collections::HashMap;
 use std::env;
 use std::fmt;
 use std::hash::{Hash, Hasher, SipHasher};
@@ -241,25 +241,16 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> {
                     } else {
                         crate_type
                     };
-                    let mut crate_types = info.crate_types.borrow_mut();
-                    let entry = crate_types.entry(crate_type.to_string());
-                    let crate_type_info = match entry {
-                        Entry::Occupied(o) => &*o.into_mut(),
-                        Entry::Vacant(v) => {
-                            let value = info.discover_crate_type(v.key())?;
-                            &*v.insert(value)
-                        }
-                    };
-                    match *crate_type_info {
-                        Some((ref prefix, ref suffix)) => {
-                            let suffixes = add_target_specific_suffixes(
-                                cx.target_triple(),
-                                crate_type,
-                                unit.target.kind(),
-                                suffix,
-                                file_type,
-                            );
-                            for file_type in suffixes {
+                    let file_types = info.file_types(
+                        crate_type,
+                        file_type,
+                        unit.target.kind(),
+                        cx.target_triple(),
+                    )?;
+
+                    match file_types {
+                        Some(types) => {
+                            for file_type in types {
                                 // wasm bin target will generate two files in deps such as
                                 // "web-stuff.js" and "web_stuff.wasm". Note the different usages of
                                 // "-" and "_". should_replace_hyphens is a flag to indicate that
@@ -274,23 +265,27 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> {
                                 };
                                 let filename = out_dir.join(format!(
                                     "{}{}{}",
-                                    prefix,
+                                    file_type.prefix,
                                     conv(file_stem.clone()),
                                     file_type.suffix,
                                 ));
                                 let link_dst = link_stem.clone().map(|(ld, ls)| {
-                                    ld.join(format!("{}{}{}", prefix, conv(ls), file_type.suffix))
+                                    ld.join(format!(
+                                        "{}{}{}",
+                                        file_type.prefix,
+                                        conv(ls),
+                                        file_type.suffix
+                                    ))
                                 });
                                 ret.push((filename, link_dst, file_type.target_file_type));
                             }
-                            Ok(())
                         }
                         // not supported, don't worry about it
                         None => {
                             unsupported.push(crate_type.to_string());
-                            Ok(())
                         }
                     }
+                    Ok(())
                 };
                 //info!("{:?}", unit);
                 match *unit.target.kind() {
@@ -450,73 +445,3 @@ fn compute_metadata<'a, 'cfg>(
     }
     Some(Metadata(hasher.finish()))
 }
-
-struct FileType {
-    suffix: String,
-    target_file_type: TargetFileType,
-    should_replace_hyphens: bool,
-}
-
-// (not a rustdoc)
-// Return a list of 3-tuples (suffix, file_type, should_replace_hyphens).
-//
-// should_replace_hyphens will be used by the caller to replace "-" with "_"
-// in a bin_stem. See the caller side (calc_target_filenames()) for details.
-fn add_target_specific_suffixes(
-    target_triple: &str,
-    crate_type: &str,
-    target_kind: &TargetKind,
-    suffix: &str,
-    file_type: TargetFileType,
-) -> Vec<FileType> {
-    let mut ret = vec![
-        FileType {
-            suffix: suffix.to_string(),
-            target_file_type: file_type,
-            should_replace_hyphens: false,
-        },
-    ];
-
-    // rust-lang/cargo#4500
-    if target_triple.ends_with("pc-windows-msvc") && crate_type.ends_with("dylib")
-        && suffix == ".dll"
-    {
-        ret.push(FileType {
-            suffix: ".dll.lib".to_string(),
-            target_file_type: TargetFileType::Normal,
-            should_replace_hyphens: false,
-        })
-    }
-
-    // rust-lang/cargo#4535
-    if target_triple.starts_with("wasm32-") && crate_type == "bin" && suffix == ".js" {
-        ret.push(FileType {
-            suffix: ".wasm".to_string(),
-            target_file_type: TargetFileType::Normal,
-            should_replace_hyphens: true,
-        })
-    }
-
-    // rust-lang/cargo#4490, rust-lang/cargo#4960
-    //  - only uplift debuginfo for binaries.
-    //    tests are run directly from target/debug/deps/
-    //    and examples are inside target/debug/examples/ which already have symbols next to them
-    //    so no need to do anything.
-    if *target_kind == TargetKind::Bin {
-        if target_triple.contains("-apple-") {
-            ret.push(FileType {
-                suffix: ".dSYM".to_string(),
-                target_file_type: TargetFileType::DebugInfo,
-                should_replace_hyphens: false,
-            })
-        } else if target_triple.ends_with("-msvc") {
-            ret.push(FileType {
-                suffix: ".pdb".to_string(),
-                target_file_type: TargetFileType::DebugInfo,
-                should_replace_hyphens: false,
-            })
-        }
-    }
-
-    ret
-}
index 482d80cb65ea8f9c0e164534c002844f19c173f9..f54b8015f0c7f1d3585f2d7552bacba176850172 100644 (file)
@@ -5,13 +5,12 @@ use std::env;
 use std::path::{Path, PathBuf};
 use std::str::{self, FromStr};
 use std::sync::Arc;
-use std::cell::RefCell;
 
 use jobserver::Client;
 
 use core::{Package, PackageId, PackageSet, Profile, Resolve, Target};
 use core::{Dependency, Profiles, Workspace};
-use util::{internal, profile, Cfg, CfgExpr, Config, ProcessBuilder};
+use util::{internal, profile, Cfg, CfgExpr, Config};
 use util::errors::{CargoResult, CargoResultExt};
 
 use super::TargetConfig;
@@ -28,6 +27,10 @@ mod compilation_files;
 use self::compilation_files::CompilationFiles;
 pub use self::compilation_files::Metadata;
 
+mod target_info;
+pub use self::target_info::TargetFileType;
+use self::target_info::TargetInfo;
+
 /// All information needed to define a Unit.
 ///
 /// A unit is an object that has enough information so that cargo knows how to build it.
@@ -63,17 +66,6 @@ pub struct Unit<'a> {
     pub kind: Kind,
 }
 
-/// Type of each file generated by a Unit.
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub enum TargetFileType {
-    /// Not a special file type.
-    Normal,
-    /// It is something you can link against (e.g. a library)
-    Linkable,
-    /// It is a piece of external debug information (e.g. *.dSYM and *.pdb)
-    DebugInfo,
-}
-
 /// The build context, containing all information about a build task
 pub struct Context<'a, 'cfg: 'a> {
     /// The workspace the build is for
@@ -105,34 +97,6 @@ pub struct Context<'a, 'cfg: 'a> {
     files: Option<CompilationFiles<'a, 'cfg>>,
 }
 
-#[derive(Clone, Default)]
-struct TargetInfo {
-    crate_type_process: Option<ProcessBuilder>,
-    crate_types: RefCell<HashMap<String, Option<(String, String)>>>,
-    cfg: Option<Vec<Cfg>>,
-    sysroot_libdir: Option<PathBuf>,
-}
-
-impl TargetInfo {
-    fn discover_crate_type(&self, crate_type: &str) -> CargoResult<Option<(String, String)>> {
-        let mut process = self.crate_type_process.clone().unwrap();
-
-        process.arg("--crate-type").arg(crate_type);
-
-        let output = process.exec_with_output().chain_err(|| {
-            format!(
-                "failed to run `rustc` to learn about \
-                 crate-type {} information",
-                crate_type
-            )
-        })?;
-
-        let error = str::from_utf8(&output.stderr).unwrap();
-        let output = str::from_utf8(&output.stdout).unwrap();
-        Ok(parse_crate_type(crate_type, error, &mut output.lines())?)
-    }
-}
-
 impl<'a, 'cfg> Context<'a, 'cfg> {
     pub fn new(
         ws: &'a Workspace<'cfg>,
@@ -238,109 +202,17 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
             _ => true,
         };
 
-        if host_target_same {
-            let info = self.probe_target_info_kind(Kind::Target)?;
-            self.host_info = info.clone();
-            self.target_info = info;
+        self.host_info = TargetInfo::new(self, Kind::Host)?;
+        self.target_info = if host_target_same {
+            self.host_info.clone()
         } else {
-            self.host_info = self.probe_target_info_kind(Kind::Host)?;
-            self.target_info = self.probe_target_info_kind(Kind::Target)?;
-        }
+            TargetInfo::new(self, Kind::Target)?
+        };
         self.compilation.host_dylib_path = self.host_info.sysroot_libdir.clone();
         self.compilation.target_dylib_path = self.target_info.sysroot_libdir.clone();
         Ok(())
     }
 
-    fn probe_target_info_kind(&self, kind: Kind) -> CargoResult<TargetInfo> {
-        let rustflags = env_args(
-            self.config,
-            &self.build_config,
-            self.info(&kind),
-            kind,
-            "RUSTFLAGS",
-        )?;
-        let mut process = self.config.rustc()?.process();
-        process
-            .arg("-")
-            .arg("--crate-name")
-            .arg("___")
-            .arg("--print=file-names")
-            .args(&rustflags)
-            .env_remove("RUST_LOG");
-
-        if kind == Kind::Target {
-            process.arg("--target").arg(&self.target_triple());
-        }
-
-        let crate_type_process = process.clone();
-        const KNOWN_CRATE_TYPES: &[&str] =
-            &["bin", "rlib", "dylib", "cdylib", "staticlib", "proc-macro"];
-        for crate_type in KNOWN_CRATE_TYPES.iter() {
-            process.arg("--crate-type").arg(crate_type);
-        }
-
-        let mut with_cfg = process.clone();
-        with_cfg.arg("--print=sysroot");
-        with_cfg.arg("--print=cfg");
-
-        let mut has_cfg_and_sysroot = true;
-        let output = with_cfg
-            .exec_with_output()
-            .or_else(|_| {
-                has_cfg_and_sysroot = false;
-                process.exec_with_output()
-            })
-            .chain_err(|| "failed to run `rustc` to learn about target-specific information")?;
-
-        let error = str::from_utf8(&output.stderr).unwrap();
-        let output = str::from_utf8(&output.stdout).unwrap();
-        let mut lines = output.lines();
-        let mut map = HashMap::new();
-        for crate_type in KNOWN_CRATE_TYPES {
-            let out = parse_crate_type(crate_type, error, &mut lines)?;
-            map.insert(crate_type.to_string(), out);
-        }
-
-        let mut sysroot_libdir = None;
-        if has_cfg_and_sysroot {
-            let line = match lines.next() {
-                Some(line) => line,
-                None => bail!(
-                    "output of --print=sysroot missing when learning about \
-                     target-specific information from rustc"
-                ),
-            };
-            let mut rustlib = PathBuf::from(line);
-            if kind == Kind::Host {
-                if cfg!(windows) {
-                    rustlib.push("bin");
-                } else {
-                    rustlib.push("lib");
-                }
-                sysroot_libdir = Some(rustlib);
-            } else {
-                rustlib.push("lib");
-                rustlib.push("rustlib");
-                rustlib.push(self.target_triple());
-                rustlib.push("lib");
-                sysroot_libdir = Some(rustlib);
-            }
-        }
-
-        let cfg = if has_cfg_and_sysroot {
-            Some(lines.map(Cfg::from_str).collect::<CargoResult<_>>()?)
-        } else {
-            None
-        };
-
-        Ok(TargetInfo {
-            crate_type_process: Some(crate_type_process),
-            crate_types: RefCell::new(map),
-            cfg,
-            sysroot_libdir,
-        })
-    }
-
     /// Builds up the `used_in_plugin` internal to this context from the list of
     /// top-level units.
     ///
@@ -708,44 +580,3 @@ fn env_args(
 
     Ok(Vec::new())
 }
-
-/// Takes rustc output (using specialized command line args), and calculates the file prefix and
-/// suffix for the given crate type, or returns None if the type is not supported. (e.g. for a
-/// rust library like libcargo.rlib, prefix = "lib", suffix = "rlib").
-///
-/// The caller needs to ensure that the lines object is at the correct line for the given crate
-/// type: this is not checked.
-// This function can not handle more than 1 file per type (with wasm32-unknown-emscripten, there
-// are 2 files for bin (.wasm and .js))
-fn parse_crate_type(
-    crate_type: &str,
-    error: &str,
-    lines: &mut str::Lines,
-) -> CargoResult<Option<(String, String)>> {
-    let not_supported = error.lines().any(|line| {
-        (line.contains("unsupported crate type") || line.contains("unknown crate type"))
-            && line.contains(crate_type)
-    });
-    if not_supported {
-        return Ok(None);
-    }
-    let line = match lines.next() {
-        Some(line) => line,
-        None => bail!(
-            "malformed output when learning about \
-             crate-type {} information",
-            crate_type
-        ),
-    };
-    let mut parts = line.trim().split("___");
-    let prefix = parts.next().unwrap();
-    let suffix = match parts.next() {
-        Some(part) => part,
-        None => bail!(
-            "output of --print=file-names has changed in \
-             the compiler, cannot parse"
-        ),
-    };
-
-    Ok(Some((prefix.to_string(), suffix.to_string())))
-}
diff --git a/src/cargo/ops/cargo_rustc/context/target_info.rs b/src/cargo/ops/cargo_rustc/context/target_info.rs
new file mode 100644 (file)
index 0000000..17f3ac7
--- /dev/null
@@ -0,0 +1,263 @@
+use std::cell::RefCell;
+use std::collections::hash_map::{Entry, HashMap};
+use std::path::PathBuf;
+use std::str::{self, FromStr};
+
+use super::{env_args, Context};
+use util::{CargoResult, CargoResultExt, Cfg, ProcessBuilder};
+use core::TargetKind;
+use ops::Kind;
+
+#[derive(Clone, Default)]
+pub struct TargetInfo {
+    crate_type_process: Option<ProcessBuilder>,
+    crate_types: RefCell<HashMap<String, Option<(String, String)>>>,
+    pub(super) cfg: Option<Vec<Cfg>>,
+    pub(super) sysroot_libdir: Option<PathBuf>,
+}
+
+/// Type of each file generated by a Unit.
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub enum TargetFileType {
+    /// Not a special file type.
+    Normal,
+    /// It is something you can link against (e.g. a library)
+    Linkable,
+    /// It is a piece of external debug information (e.g. *.dSYM and *.pdb)
+    DebugInfo,
+}
+
+pub struct FileType {
+    pub suffix: String,
+    pub prefix: String,
+    pub target_file_type: TargetFileType,
+    pub should_replace_hyphens: bool,
+}
+
+impl TargetInfo {
+    pub fn new(cx: &Context, kind: Kind) -> CargoResult<TargetInfo> {
+        let rustflags = env_args(
+            cx.config,
+            &cx.build_config,
+            cx.info(&kind),
+            kind,
+            "RUSTFLAGS",
+        )?;
+        let mut process = cx.config.rustc()?.process();
+        process
+            .arg("-")
+            .arg("--crate-name")
+            .arg("___")
+            .arg("--print=file-names")
+            .args(&rustflags)
+            .env_remove("RUST_LOG");
+
+        if kind == Kind::Target {
+            process.arg("--target").arg(&cx.target_triple());
+        }
+
+        let crate_type_process = process.clone();
+        const KNOWN_CRATE_TYPES: &[&str] =
+            &["bin", "rlib", "dylib", "cdylib", "staticlib", "proc-macro"];
+        for crate_type in KNOWN_CRATE_TYPES.iter() {
+            process.arg("--crate-type").arg(crate_type);
+        }
+
+        let mut with_cfg = process.clone();
+        with_cfg.arg("--print=sysroot");
+        with_cfg.arg("--print=cfg");
+
+        let mut has_cfg_and_sysroot = true;
+        let output = with_cfg
+            .exec_with_output()
+            .or_else(|_| {
+                has_cfg_and_sysroot = false;
+                process.exec_with_output()
+            })
+            .chain_err(|| "failed to run `rustc` to learn about target-specific information")?;
+
+        let error = str::from_utf8(&output.stderr).unwrap();
+        let output = str::from_utf8(&output.stdout).unwrap();
+        let mut lines = output.lines();
+        let mut map = HashMap::new();
+        for crate_type in KNOWN_CRATE_TYPES {
+            let out = parse_crate_type(crate_type, error, &mut lines)?;
+            map.insert(crate_type.to_string(), out);
+        }
+
+        let mut sysroot_libdir = None;
+        if has_cfg_and_sysroot {
+            let line = match lines.next() {
+                Some(line) => line,
+                None => bail!(
+                    "output of --print=sysroot missing when learning about \
+                     target-specific information from rustc"
+                ),
+            };
+            let mut rustlib = PathBuf::from(line);
+            if kind == Kind::Host {
+                if cfg!(windows) {
+                    rustlib.push("bin");
+                } else {
+                    rustlib.push("lib");
+                }
+                sysroot_libdir = Some(rustlib);
+            } else {
+                rustlib.push("lib");
+                rustlib.push("rustlib");
+                rustlib.push(cx.target_triple());
+                rustlib.push("lib");
+                sysroot_libdir = Some(rustlib);
+            }
+        }
+
+        let cfg = if has_cfg_and_sysroot {
+            Some(lines.map(Cfg::from_str).collect::<CargoResult<_>>()?)
+        } else {
+            None
+        };
+
+        Ok(TargetInfo {
+            crate_type_process: Some(crate_type_process),
+            crate_types: RefCell::new(map),
+            cfg,
+            sysroot_libdir,
+        })
+    }
+
+    pub fn file_types(
+        &self,
+        crate_type: &str,
+        file_type: TargetFileType,
+        kind: &TargetKind,
+        target_triple: &str,
+    ) -> CargoResult<Option<Vec<FileType>>> {
+        let mut crate_types = self.crate_types.borrow_mut();
+        let entry = crate_types.entry(crate_type.to_string());
+        let crate_type_info = match entry {
+            Entry::Occupied(o) => &*o.into_mut(),
+            Entry::Vacant(v) => {
+                let value = self.discover_crate_type(v.key())?;
+                &*v.insert(value)
+            }
+        };
+        let (prefix, suffix) = match *crate_type_info {
+            Some((ref prefix, ref suffix)) => (prefix, suffix),
+            None => return Ok(None),
+        };
+        let mut ret = vec![
+            FileType {
+                suffix: suffix.to_string(),
+                prefix: prefix.clone(),
+                target_file_type: file_type,
+                should_replace_hyphens: false,
+            },
+        ];
+
+        // rust-lang/cargo#4500
+        if target_triple.ends_with("pc-windows-msvc") && crate_type.ends_with("dylib")
+            && suffix == ".dll"
+        {
+            ret.push(FileType {
+                suffix: ".dll.lib".to_string(),
+                prefix: prefix.clone(),
+                target_file_type: TargetFileType::Normal,
+                should_replace_hyphens: false,
+            })
+        }
+
+        // rust-lang/cargo#4535
+        if target_triple.starts_with("wasm32-") && crate_type == "bin" && suffix == ".js" {
+            ret.push(FileType {
+                suffix: ".wasm".to_string(),
+                prefix: prefix.clone(),
+                target_file_type: TargetFileType::Normal,
+                should_replace_hyphens: true,
+            })
+        }
+
+        // rust-lang/cargo#4490, rust-lang/cargo#4960
+        //  - only uplift debuginfo for binaries.
+        //    tests are run directly from target/debug/deps/
+        //    and examples are inside target/debug/examples/ which already have symbols next to them
+        //    so no need to do anything.
+        if *kind == TargetKind::Bin {
+            if target_triple.contains("-apple-") {
+                ret.push(FileType {
+                    suffix: ".dSYM".to_string(),
+                    prefix: prefix.clone(),
+                    target_file_type: TargetFileType::DebugInfo,
+                    should_replace_hyphens: false,
+                })
+            } else if target_triple.ends_with("-msvc") {
+                ret.push(FileType {
+                    suffix: ".pdb".to_string(),
+                    prefix: prefix.clone(),
+                    target_file_type: TargetFileType::DebugInfo,
+                    should_replace_hyphens: false,
+                })
+            }
+        }
+
+        Ok(Some(ret))
+    }
+
+    fn discover_crate_type(&self, crate_type: &str) -> CargoResult<Option<(String, String)>> {
+        let mut process = self.crate_type_process.clone().unwrap();
+
+        process.arg("--crate-type").arg(crate_type);
+
+        let output = process.exec_with_output().chain_err(|| {
+            format!(
+                "failed to run `rustc` to learn about \
+                 crate-type {} information",
+                crate_type
+            )
+        })?;
+
+        let error = str::from_utf8(&output.stderr).unwrap();
+        let output = str::from_utf8(&output.stdout).unwrap();
+        Ok(parse_crate_type(crate_type, error, &mut output.lines())?)
+    }
+}
+
+/// Takes rustc output (using specialized command line args), and calculates the file prefix and
+/// suffix for the given crate type, or returns None if the type is not supported. (e.g. for a
+/// rust library like libcargo.rlib, prefix = "lib", suffix = "rlib").
+///
+/// The caller needs to ensure that the lines object is at the correct line for the given crate
+/// type: this is not checked.
+// This function can not handle more than 1 file per type (with wasm32-unknown-emscripten, there
+// are 2 files for bin (.wasm and .js))
+fn parse_crate_type(
+    crate_type: &str,
+    error: &str,
+    lines: &mut str::Lines,
+) -> CargoResult<Option<(String, String)>> {
+    let not_supported = error.lines().any(|line| {
+        (line.contains("unsupported crate type") || line.contains("unknown crate type"))
+            && line.contains(crate_type)
+    });
+    if not_supported {
+        return Ok(None);
+    }
+    let line = match lines.next() {
+        Some(line) => line,
+        None => bail!(
+            "malformed output when learning about \
+             crate-type {} information",
+            crate_type
+        ),
+    };
+    let mut parts = line.trim().split("___");
+    let prefix = parts.next().unwrap();
+    let suffix = match parts.next() {
+        Some(part) => part,
+        None => bail!(
+            "output of --print=file-names has changed in \
+             the compiler, cannot parse"
+        ),
+    };
+
+    Ok(Some((prefix.to_string(), suffix.to_string())))
+}