Skip to content

Commit 8495548

Browse files
committed
Implement platform-specific dependencies
1 parent 57684d0 commit 8495548

File tree

10 files changed

+240
-52
lines changed

10 files changed

+240
-52
lines changed

src/cargo/core/dependency.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ pub struct Dependency {
1616
optional: bool,
1717
default_features: bool,
1818
features: Vec<String>,
19+
20+
// This dependency should be used only for this platform.
21+
// `None` means *all platforms*.
22+
only_for_platform: Option<String>,
1923
}
2024

2125
impl Dependency {
@@ -57,6 +61,7 @@ impl Dependency {
5761
features: Vec::new(),
5862
default_features: true,
5963
specified_req: None,
64+
only_for_platform: None,
6065
}
6166
}
6267

@@ -121,6 +126,11 @@ impl Dependency {
121126
.source_id(id.get_source_id().clone())
122127
}
123128

129+
pub fn only_for_platform(mut self, platform: Option<String>) -> Dependency {
130+
self.only_for_platform = platform;
131+
self
132+
}
133+
124134
/// Returns false if the dependency is only used to build the local package.
125135
pub fn is_transitive(&self) -> bool { self.transitive }
126136
pub fn is_optional(&self) -> bool { self.optional }
@@ -140,6 +150,15 @@ impl Dependency {
140150
(self.only_match_name || (self.req.matches(id.get_version()) &&
141151
&self.source_id == id.get_source_id()))
142152
}
153+
154+
/// Returns true if the dependency should be built for this platform.
155+
pub fn is_active_for_platform(&self, platform: &str) -> bool {
156+
match self.only_for_platform {
157+
None => true,
158+
Some(ref p) if p.as_slice() == platform => true,
159+
_ => false
160+
}
161+
}
143162
}
144163

145164
#[deriving(PartialEq,Clone,Encodable)]

src/cargo/core/resolver/mod.rs

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ pub enum ResolveMethod<'a> {
3232
ResolveEverything,
3333
ResolveRequired(/* dev_deps = */ bool,
3434
/* features = */ &'a [String],
35-
/* uses_default_features = */ bool),
35+
/* uses_default_features = */ bool,
36+
/* target_platform = */ Option<&'a str>),
3637
}
3738

3839
impl Resolve {
@@ -150,6 +151,12 @@ fn activate<R: Registry>(mut cx: Context,
150151
parent: &Summary,
151152
method: ResolveMethod)
152153
-> CargoResult<CargoResult<Context>> {
154+
// Extracting the platform request.
155+
let platform = match method {
156+
ResolveRequired(_, _, _, platform) => platform,
157+
ResolveEverything => None,
158+
};
159+
153160
// First, figure out our set of dependencies based on the requsted set of
154161
// features. This also calculates what features we're going to enable for
155162
// our own dependencies.
@@ -176,18 +183,19 @@ fn activate<R: Registry>(mut cx: Context,
176183
a.len().cmp(&b.len())
177184
});
178185

179-
activate_deps(cx, registry, parent, deps.as_slice(), 0)
186+
activate_deps(cx, registry, parent, platform, deps.as_slice(), 0)
180187
}
181188

182-
fn activate_deps<R: Registry>(cx: Context,
183-
registry: &mut R,
184-
parent: &Summary,
185-
deps: &[(&Dependency, Vec<Rc<Summary>>, Vec<String>)],
186-
cur: uint) -> CargoResult<CargoResult<Context>> {
189+
fn activate_deps<'a, R: Registry>(cx: Context,
190+
registry: &mut R,
191+
parent: &Summary,
192+
platform: Option<&'a str>,
193+
deps: &'a [(&Dependency, Vec<Rc<Summary>>, Vec<String>)],
194+
cur: uint) -> CargoResult<CargoResult<Context>> {
187195
if cur == deps.len() { return Ok(Ok(cx)) }
188196
let (dep, ref candidates, ref features) = deps[cur];
189197
let method = ResolveRequired(false, features.as_slice(),
190-
dep.uses_default_features());
198+
dep.uses_default_features(), platform);
191199

192200
let key = (dep.get_name().to_string(), dep.get_source_id().clone());
193201
let prev_active = cx.activations.find(&key)
@@ -269,7 +277,7 @@ fn activate_deps<R: Registry>(cx: Context,
269277
Err(e) => { last_err = Some(e); continue }
270278
}
271279
};
272-
match try!(activate_deps(my_cx, registry, parent, deps, cur + 1)) {
280+
match try!(activate_deps(my_cx, registry, parent, platform, deps, cur + 1)) {
273281
Ok(cx) => return Ok(Ok(cx)),
274282
Err(e) => { last_err = Some(e); }
275283
}
@@ -341,12 +349,22 @@ fn resolve_features<'a>(cx: &mut Context, parent: &'a Summary,
341349
(&'a Dependency, Vec<String>)>> {
342350
let dev_deps = match method {
343351
ResolveEverything => true,
344-
ResolveRequired(dev_deps, _, _) => dev_deps,
352+
ResolveRequired(dev_deps, _, _, _) => dev_deps,
345353
};
346354

347355
// First, filter by dev-dependencies
348356
let deps = parent.get_dependencies();
349-
let mut deps = deps.iter().filter(|d| d.is_transitive() || dev_deps);
357+
let deps = deps.iter().filter(|d| d.is_transitive() || dev_deps);
358+
359+
// Second, ignoring dependencies that should not be compiled for this platform
360+
let mut deps = deps.filter(|d| {
361+
match method {
362+
ResolveRequired(_, _, _, Some(ref platform)) => {
363+
d.is_active_for_platform(platform.as_slice())
364+
},
365+
_ => true
366+
}
367+
});
350368

351369
let (mut feature_deps, used_features) = try!(build_features(parent, method));
352370
let mut ret = HashMap::new();
@@ -419,15 +437,15 @@ fn build_features(s: &Summary, method: ResolveMethod)
419437
&mut visited));
420438
}
421439
}
422-
ResolveRequired(_, requested_features, _) => {
440+
ResolveRequired(_, requested_features, _, _) => {
423441
for feat in requested_features.iter() {
424442
try!(add_feature(s, feat.as_slice(), &mut deps, &mut used,
425443
&mut visited));
426444
}
427445
}
428446
}
429447
match method {
430-
ResolveEverything | ResolveRequired(_, _, true) => {
448+
ResolveEverything | ResolveRequired(_, _, true, _) => {
431449
if s.get_features().find_equiv(&"default").is_some() &&
432450
!visited.contains_equiv(&"default") {
433451
try!(add_feature(s, "default", &mut deps, &mut used,

src/cargo/ops/cargo_compile.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ pub fn compile_pkg(package: &Package, options: &mut CompileOptions)
8686

8787
let (packages, resolve_with_overrides, sources) = {
8888
let mut config = try!(Config::new(*shell, jobs, target.clone()));
89+
let rustc_host = config.rustc_host().to_string();
8990
let mut registry = PackageRegistry::new(&mut config);
9091

9192
// First, resolve the package's *listed* dependencies, as well as
@@ -98,8 +99,11 @@ pub fn compile_pkg(package: &Package, options: &mut CompileOptions)
9899
let _p = profile::start("resolving w/ overrides...");
99100

100101
try!(registry.add_overrides(override_ids));
102+
103+
let platform = target.as_ref().map(|e| e.as_slice()).or(Some(rustc_host.as_slice()));
101104
let method = resolver::ResolveRequired(dev_deps, features.as_slice(),
102-
!no_default_features);
105+
!no_default_features,
106+
platform);
103107
let resolved_with_overrides =
104108
try!(ops::resolve_with_previous(&mut registry, package, method,
105109
Some(&resolve), None));

src/cargo/ops/cargo_rustc/context.rs

Lines changed: 4 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::collections::hashmap::{Occupied, Vacant};
33
use std::str;
44

55
use core::{SourceMap, Package, PackageId, PackageSet, Resolve, Target};
6-
use util::{mod, CargoResult, ChainError, internal, Config, profile, Require};
6+
use util::{mod, CargoResult, ChainError, internal, Config, profile};
77
use util::human;
88

99
use super::{Kind, KindPlugin, KindTarget, Compilation};
@@ -17,7 +17,6 @@ pub enum PlatformRequirement {
1717
}
1818

1919
pub struct Context<'a, 'b> {
20-
pub rustc_version: String,
2120
pub config: &'b mut Config<'b>,
2221
pub resolve: &'a Resolve,
2322
pub sources: &'a SourceMap<'b>,
@@ -27,7 +26,6 @@ pub struct Context<'a, 'b> {
2726
host: Layout,
2827
target: Option<Layout>,
2928
target_triple: String,
30-
host_triple: String,
3129
host_dylib: Option<(String, String)>,
3230
package_set: &'a PackageSet,
3331
target_dylib: Option<(String, String)>,
@@ -49,13 +47,10 @@ impl<'a, 'b> Context<'a, 'b> {
4947
let (dylib, _) = try!(Context::filename_parts(None));
5048
dylib
5149
};
52-
let (rustc_version, rustc_host) = try!(Context::rustc_version());
5350
let target_triple = config.target().map(|s| s.to_string());
54-
let target_triple = target_triple.unwrap_or(rustc_host.clone());
51+
let target_triple = target_triple.unwrap_or(config.rustc_host().to_string());
5552
Ok(Context {
56-
rustc_version: rustc_version,
5753
target_triple: target_triple,
58-
host_triple: rustc_host,
5954
env: env,
6055
host: host,
6156
target: target,
@@ -71,28 +66,6 @@ impl<'a, 'b> Context<'a, 'b> {
7166
})
7267
}
7368

74-
/// Run `rustc` to figure out what its current version string is.
75-
///
76-
/// The second element of the tuple returned is the target triple that rustc
77-
/// is a host for.
78-
fn rustc_version() -> CargoResult<(String, String)> {
79-
let output = try!(util::process("rustc").arg("-v").arg("verbose")
80-
.exec_with_output());
81-
let output = try!(String::from_utf8(output.output).map_err(|_| {
82-
internal("rustc -v didn't return utf8 output")
83-
}));
84-
let triple = {
85-
let triple = output.as_slice().lines().filter(|l| {
86-
l.starts_with("host: ")
87-
}).map(|l| l.slice_from(6)).next();
88-
let triple = try!(triple.require(|| {
89-
internal("rustc -v didn't have a line for `host:`")
90-
}));
91-
triple.to_string()
92-
};
93-
Ok((output, triple))
94-
}
95-
9669
/// Run `rustc` to discover the dylib prefix/suffix for the target
9770
/// specified as well as the exe suffix
9871
fn filename_parts(target: Option<&str>)
@@ -204,9 +177,9 @@ impl<'a, 'b> Context<'a, 'b> {
204177
/// otherwise it corresponds to the target platform.
205178
fn dylib(&self, kind: Kind) -> CargoResult<(&str, &str)> {
206179
let (triple, pair) = if kind == KindPlugin {
207-
(&self.host_triple, &self.host_dylib)
180+
(self.config.rustc_host(), &self.host_dylib)
208181
} else {
209-
(&self.target_triple, &self.target_dylib)
182+
(self.target_triple.as_slice(), &self.target_dylib)
210183
};
211184
match *pair {
212185
None => return Err(human(format!("dylib outputs are not supported \

src/cargo/ops/cargo_rustc/fingerprint.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ fn is_fresh(loc: &Path, new_fingerprint: &str) -> CargoResult<bool> {
229229
/// fingerprint.
230230
fn mk_fingerprint<T: Hash>(cx: &Context, data: &T) -> String {
231231
let hasher = SipHasher::new_with_keys(0,0);
232-
util::to_hex(hasher.hash(&(&cx.rustc_version, data)))
232+
util::to_hex(hasher.hash(&(cx.config.rustc_version(), data)))
233233
}
234234

235235
fn calculate_target_fresh(pkg: &Package, dep_info: &Path) -> CargoResult<bool> {

src/cargo/ops/cargo_rustc/mod.rs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ use std::io::fs::PathExtensions;
55
use std::os;
66

77
use core::{SourceMap, Package, PackageId, PackageSet, Target, Resolve};
8-
use util::{CargoResult, ProcessBuilder, CargoError, human, caused_human};
9-
use util::{Config, internal, ChainError, Fresh, profile};
8+
use util::{mod, CargoResult, ProcessBuilder, CargoError, human, caused_human};
9+
use util::{Require, Config, internal, ChainError, Fresh, profile};
1010

1111
use self::job::{Job, Work};
1212
use self::job_queue as jq;
@@ -28,6 +28,28 @@ mod layout;
2828
#[deriving(PartialEq, Eq)]
2929
pub enum Kind { KindPlugin, KindTarget }
3030

31+
/// Run `rustc` to figure out what its current version string is.
32+
///
33+
/// The second element of the tuple returned is the target triple that rustc
34+
/// is a host for.
35+
pub fn rustc_version() -> CargoResult<(String, String)> {
36+
let output = try!(util::process("rustc").arg("-v").arg("verbose")
37+
.exec_with_output());
38+
let output = try!(String::from_utf8(output.output).map_err(|_| {
39+
internal("rustc -v didn't return utf8 output")
40+
}));
41+
let triple = {
42+
let triple = output.as_slice().lines().filter(|l| {
43+
l.starts_with("host: ")
44+
}).map(|l| l.slice_from(6)).next();
45+
let triple = try!(triple.require(|| {
46+
internal("rustc -v didn't have a line for `host:`")
47+
}));
48+
triple.to_string()
49+
};
50+
Ok((output, triple))
51+
}
52+
3153
// This is a temporary assert that ensures the consistency of the arguments
3254
// given the current limitations of Cargo. The long term fix is to have each
3355
// Target know the absolute path to the build location.

src/cargo/ops/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
pub use self::cargo_clean::{clean, CleanOptions};
22
pub use self::cargo_compile::{compile, compile_pkg, CompileOptions};
33
pub use self::cargo_read_manifest::{read_manifest,read_package,read_packages};
4-
pub use self::cargo_rustc::{compile_targets, Compilation, Layout, Kind};
4+
pub use self::cargo_rustc::{compile_targets, Compilation, Layout, Kind, rustc_version};
55
pub use self::cargo_rustc::{KindTarget, KindPlugin, Context, LayoutProxy};
66
pub use self::cargo_rustc::{PlatformRequirement, PlatformTarget};
77
pub use self::cargo_rustc::{PlatformPlugin, PlatformPluginAndTarget};

src/cargo/util/config.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use std::string;
77
use serialize::{Encodable,Encoder};
88
use toml;
99
use core::MultiShell;
10+
use ops;
1011
use util::{CargoResult, ChainError, Require, internal, human};
1112

1213
use util::toml as cargo_toml;
@@ -18,6 +19,9 @@ pub struct Config<'a> {
1819
target: Option<string::String>,
1920
linker: Option<string::String>,
2021
ar: Option<string::String>,
22+
rustc_version: string::String,
23+
/// The current host and default target of rustc
24+
rustc_host: string::String,
2125
}
2226

2327
impl<'a> Config<'a> {
@@ -27,6 +31,9 @@ impl<'a> Config<'a> {
2731
if jobs == Some(0) {
2832
return Err(human("jobs must be at least 1"))
2933
}
34+
35+
let (rustc_version, rustc_host) = try!(ops::rustc_version());
36+
3037
Ok(Config {
3138
home_path: try!(os::homedir().require(|| {
3239
human("Cargo couldn't find your home directory. \
@@ -37,6 +44,8 @@ impl<'a> Config<'a> {
3744
target: target,
3845
ar: None,
3946
linker: None,
47+
rustc_version: rustc_version,
48+
rustc_host: rustc_host,
4049
})
4150
}
4251

@@ -84,6 +93,16 @@ impl<'a> Config<'a> {
8493
pub fn ar(&self) -> Option<&str> {
8594
self.ar.as_ref().map(|t| t.as_slice())
8695
}
96+
97+
/// Return the output of `rustc -v verbose`
98+
pub fn rustc_version(&self) -> &str {
99+
self.rustc_version.as_slice()
100+
}
101+
102+
/// Return the host platform and default target of rustc
103+
pub fn rustc_host(&self) -> &str {
104+
self.rustc_host.as_slice()
105+
}
87106
}
88107

89108
#[deriving(Eq,PartialEq,Clone,Encodable,Decodable)]

0 commit comments

Comments
 (0)