1 use std
::collections
::{BTreeSet, HashMap, HashSet}
;
4 use std
::path
::PathBuf
;
8 use super::BuildContext
;
9 use crate::core
::{Edition, Package, PackageId, Target}
;
10 use crate::util
::{self, join_paths, process, CargoResult, CfgExpr, Config, ProcessBuilder}
;
13 /// The package being doc-tested.
15 /// The target being tested (currently always the package's lib).
17 /// Extern dependencies needed by `rustdoc`. The path is the location of
19 pub deps
: Vec
<(String
, PathBuf
)>,
22 /// A structure returning the result of a compilation.
23 pub struct Compilation
<'cfg
> {
24 /// An array of all tests created during this compilation.
25 /// `(package, target, path_to_test_exe)`
26 pub tests
: Vec
<(Package
, Target
, PathBuf
)>,
28 /// An array of all binaries created.
29 pub binaries
: Vec
<PathBuf
>,
31 /// All directories for the output of native build commands.
33 /// This is currently used to drive some entries which are added to the
34 /// LD_LIBRARY_PATH as appropriate.
36 /// The order should be deterministic.
37 pub native_dirs
: BTreeSet
<PathBuf
>,
39 /// Root output directory (for the local package's artifacts)
40 pub root_output
: PathBuf
,
42 /// Output directory for rust dependencies.
43 /// May be for the host or for a specific target.
44 pub deps_output
: PathBuf
,
46 /// Output directory for the rust host dependencies.
47 pub host_deps_output
: PathBuf
,
49 /// The path to rustc's own libstd
50 pub host_dylib_path
: PathBuf
,
52 /// The path to libstd for the target
53 pub target_dylib_path
: PathBuf
,
55 /// Extra environment variables that were passed to compilations and should
56 /// be passed to future invocations of programs.
57 pub extra_env
: HashMap
<PackageId
, Vec
<(String
, String
)>>,
59 /// Libraries to test with rustdoc.
60 pub to_doc_test
: Vec
<Doctest
>,
62 /// Features per package enabled during this compilation.
63 pub cfgs
: HashMap
<PackageId
, HashSet
<String
>>,
65 /// Flags to pass to rustdoc when invoked from cargo test, per package.
66 pub rustdocflags
: HashMap
<PackageId
, Vec
<String
>>,
72 rustc_process
: ProcessBuilder
,
73 primary_unit_rustc_process
: Option
<ProcessBuilder
>,
75 target_runner
: Option
<(PathBuf
, Vec
<String
>)>,
78 impl<'cfg
> Compilation
<'cfg
> {
79 pub fn new
<'a
>(bcx
: &BuildContext
<'a
, 'cfg
>) -> CargoResult
<Compilation
<'cfg
>> {
80 let mut rustc
= bcx
.rustc
.process();
82 let mut primary_unit_rustc_process
= bcx
.build_config
.primary_unit_rustc
.clone();
84 if bcx
.config
.extra_verbose() {
85 rustc
.display_env_vars();
87 if let Some(rustc
) = primary_unit_rustc_process
.as_mut() {
88 rustc
.display_env_vars();
93 // TODO: deprecated; remove.
94 native_dirs
: BTreeSet
::new(),
95 root_output
: PathBuf
::from("/"),
96 deps_output
: PathBuf
::from("/"),
97 host_deps_output
: PathBuf
::from("/"),
98 host_dylib_path
: bcx
.host_info
.sysroot_libdir
.clone(),
99 target_dylib_path
: bcx
.target_info
.sysroot_libdir
.clone(),
101 binaries
: Vec
::new(),
102 extra_env
: HashMap
::new(),
103 to_doc_test
: Vec
::new(),
104 cfgs
: HashMap
::new(),
105 rustdocflags
: HashMap
::new(),
107 rustc_process
: rustc
,
108 primary_unit_rustc_process
,
109 host
: bcx
.host_triple().to_string(),
110 target
: bcx
.target_triple().to_string(),
111 target_runner
: target_runner(bcx
)?
,
116 pub fn rustc_process(
121 ) -> CargoResult
<ProcessBuilder
> {
122 let rustc
= if is_primary
{
123 self.primary_unit_rustc_process
125 .unwrap_or_else(|| self.rustc_process
.clone())
127 self.rustc_process
.clone()
130 let mut p
= self.fill_env(rustc
, pkg
, true)?
;
131 if target
.edition() != Edition
::Edition2015
{
132 p
.arg(format
!("--edition={}", target
.edition()));
138 pub fn rustdoc_process(&self, pkg
: &Package
, target
: &Target
) -> CargoResult
<ProcessBuilder
> {
139 let mut p
= self.fill_env(process(&*self.config
.rustdoc()?
), pkg
, false)?
;
140 if target
.edition() != Edition
::Edition2015
{
141 p
.arg(format
!("--edition={}", target
.edition()));
147 pub fn host_process
<T
: AsRef
<OsStr
>>(
151 ) -> CargoResult
<ProcessBuilder
> {
152 self.fill_env(process(cmd
), pkg
, true)
155 fn target_runner(&self) -> &Option
<(PathBuf
, Vec
<String
>)> {
160 pub fn target_process
<T
: AsRef
<OsStr
>>(
164 ) -> CargoResult
<ProcessBuilder
> {
165 let builder
= if let Some((ref runner
, ref args
)) = *self.target_runner() {
166 let mut builder
= process(runner
);
173 self.fill_env(builder
, pkg
, false)
176 /// Prepares a new process with an appropriate environment to run against
177 /// the artifacts produced by the build process.
179 /// The package argument is also used to configure environment variables as
180 /// well as the working directory of the child process.
183 mut cmd
: ProcessBuilder
,
186 ) -> CargoResult
<ProcessBuilder
> {
187 let mut search_path
= if is_host
{
188 let mut search_path
= vec
![self.host_deps_output
.clone()];
189 search_path
.push(self.host_dylib_path
.clone());
192 let mut search_path
=
193 super::filter_dynamic_search_path(self.native_dirs
.iter(), &self.root_output
);
194 search_path
.push(self.deps_output
.clone());
195 search_path
.push(self.root_output
.clone());
196 search_path
.push(self.target_dylib_path
.clone());
200 let dylib_path
= util
::dylib_path();
201 let dylib_path_is_empty
= dylib_path
.is_empty();
202 search_path
.extend(dylib_path
.into_iter());
203 if cfg
!(target_os
= "macos") && dylib_path_is_empty
{
204 // These are the defaults when DYLD_FALLBACK_LIBRARY_PATH isn't
205 // set or set to an empty string. Since Cargo is explicitly setting
206 // the value, make sure the defaults still work.
207 if let Some(home
) = env
::var_os("HOME") {
208 search_path
.push(PathBuf
::from(home
).join("lib"));
210 search_path
.push(PathBuf
::from("/usr/local/lib"));
211 search_path
.push(PathBuf
::from("/usr/lib"));
213 let search_path
= join_paths(&search_path
, util
::dylib_path_envvar())?
;
215 cmd
.env(util
::dylib_path_envvar(), &search_path
);
216 if let Some(env
) = self.extra_env
.get(&pkg
.package_id()) {
217 for &(ref k
, ref v
) in env
{
222 let metadata
= pkg
.manifest().metadata();
224 let cargo_exe
= self.config
.cargo_exe()?
;
225 cmd
.env(crate::CARGO_ENV
, cargo_exe
);
227 // When adding new environment variables depending on
228 // crate properties which might require rebuild upon change
229 // consider adding the corresponding properties to the hash
230 // in BuildContext::target_metadata()
231 cmd
.env("CARGO_MANIFEST_DIR", pkg
.root())
232 .env("CARGO_PKG_VERSION_MAJOR", &pkg
.version().major
.to_string())
233 .env("CARGO_PKG_VERSION_MINOR", &pkg
.version().minor
.to_string())
234 .env("CARGO_PKG_VERSION_PATCH", &pkg
.version().patch
.to_string())
236 "CARGO_PKG_VERSION_PRE",
237 &pre_version_component(pkg
.version()),
239 .env("CARGO_PKG_VERSION", &pkg
.version().to_string())
240 .env("CARGO_PKG_NAME", &*pkg
.name())
242 "CARGO_PKG_DESCRIPTION",
243 metadata
.description
.as_ref().unwrap_or(&String
::new()),
246 "CARGO_PKG_HOMEPAGE",
247 metadata
.homepage
.as_ref().unwrap_or(&String
::new()),
250 "CARGO_PKG_REPOSITORY",
251 metadata
.repository
.as_ref().unwrap_or(&String
::new()),
253 .env("CARGO_PKG_AUTHORS", &pkg
.authors().join(":"))
259 fn pre_version_component(v
: &Version
) -> String
{
260 if v
.pre
.is_empty() {
261 return String
::new();
264 let mut ret
= String
::new();
266 for (i
, x
) in v
.pre
.iter().enumerate() {
270 ret
.push_str(&x
.to_string());
276 fn target_runner(bcx
: &BuildContext
<'_
, '_
>) -> CargoResult
<Option
<(PathBuf
, Vec
<String
>)>> {
277 let target
= bcx
.target_triple();
279 // try target.{}.runner
280 let key
= format
!("target.{}.runner", target
);
281 if let Some(v
) = bcx
.config
.get_path_and_args(&key
)?
{
282 return Ok(Some(v
.val
));
285 // try target.'cfg(...)'.runner
286 if let Some(table
) = bcx
.config
.get_table("target")?
{
287 let mut matching_runner
= None
;
289 for key
in table
.val
.keys() {
290 if CfgExpr
::matches_key(key
, bcx
.target_info
.cfg()) {
291 let key
= format
!("target.{}.runner", key
);
292 if let Some(runner
) = bcx
.config
.get_path_and_args(&key
)?
{
293 // more than one match, error out
294 if matching_runner
.is_some() {
296 "several matching instances of `target.'cfg(..)'.runner` \
301 matching_runner
= Some(runner
.val
);
306 return Ok(matching_runner
);