1 //! Tests for cfg() expressions.
2
3 use cargo_test_support::registry::Package;
4 use cargo_test_support::rustc_host;
5 use cargo_test_support::{basic_manifest, project};
6
7 #[cargo_test]
cfg_easy()8 fn cfg_easy() {
9 let p = project()
10 .file(
11 "Cargo.toml",
12 r#"
13 [package]
14 name = "a"
15 version = "0.0.1"
16 authors = []
17
18 [target.'cfg(unix)'.dependencies]
19 b = { path = 'b' }
20 [target."cfg(windows)".dependencies]
21 b = { path = 'b' }
22 "#,
23 )
24 .file("src/lib.rs", "extern crate b;")
25 .file("b/Cargo.toml", &basic_manifest("b", "0.0.1"))
26 .file("b/src/lib.rs", "")
27 .build();
28 p.cargo("build -v").run();
29 }
30
31 #[cargo_test]
dont_include()32 fn dont_include() {
33 let other_family = if cfg!(unix) { "windows" } else { "unix" };
34 let p = project()
35 .file(
36 "Cargo.toml",
37 &format!(
38 r#"
39 [package]
40 name = "a"
41 version = "0.0.1"
42 authors = []
43
44 [target.'cfg({})'.dependencies]
45 b = {{ path = 'b' }}
46 "#,
47 other_family
48 ),
49 )
50 .file("src/lib.rs", "")
51 .file("b/Cargo.toml", &basic_manifest("b", "0.0.1"))
52 .file("b/src/lib.rs", "")
53 .build();
54 p.cargo("build")
55 .with_stderr(
56 "\
57 [COMPILING] a v0.0.1 ([..])
58 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
59 ",
60 )
61 .run();
62 }
63
64 #[cargo_test]
works_through_the_registry()65 fn works_through_the_registry() {
66 Package::new("baz", "0.1.0").publish();
67 Package::new("bar", "0.1.0")
68 .target_dep("baz", "0.1.0", "cfg(unix)")
69 .target_dep("baz", "0.1.0", "cfg(windows)")
70 .publish();
71
72 let p = project()
73 .file(
74 "Cargo.toml",
75 r#"
76 [package]
77 name = "foo"
78 version = "0.0.1"
79 authors = []
80
81 [dependencies]
82 bar = "0.1.0"
83 "#,
84 )
85 .file(
86 "src/lib.rs",
87 "#[allow(unused_extern_crates)] extern crate bar;",
88 )
89 .build();
90
91 p.cargo("build")
92 .with_stderr(
93 "\
94 [UPDATING] [..] index
95 [DOWNLOADING] crates ...
96 [DOWNLOADED] [..]
97 [DOWNLOADED] [..]
98 [COMPILING] baz v0.1.0
99 [COMPILING] bar v0.1.0
100 [COMPILING] foo v0.0.1 ([..])
101 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
102 ",
103 )
104 .run();
105 }
106
107 #[cargo_test]
ignore_version_from_other_platform()108 fn ignore_version_from_other_platform() {
109 let this_family = if cfg!(unix) { "unix" } else { "windows" };
110 let other_family = if cfg!(unix) { "windows" } else { "unix" };
111 Package::new("bar", "0.1.0").publish();
112 Package::new("bar", "0.2.0").publish();
113
114 let p = project()
115 .file(
116 "Cargo.toml",
117 &format!(
118 r#"
119 [package]
120 name = "foo"
121 version = "0.0.1"
122 authors = []
123
124 [target.'cfg({})'.dependencies]
125 bar = "0.1.0"
126
127 [target.'cfg({})'.dependencies]
128 bar = "0.2.0"
129 "#,
130 this_family, other_family
131 ),
132 )
133 .file(
134 "src/lib.rs",
135 "#[allow(unused_extern_crates)] extern crate bar;",
136 )
137 .build();
138
139 p.cargo("build")
140 .with_stderr(
141 "\
142 [UPDATING] [..] index
143 [DOWNLOADING] crates ...
144 [DOWNLOADED] [..]
145 [COMPILING] bar v0.1.0
146 [COMPILING] foo v0.0.1 ([..])
147 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
148 ",
149 )
150 .run();
151 }
152
153 #[cargo_test]
bad_target_spec()154 fn bad_target_spec() {
155 let p = project()
156 .file(
157 "Cargo.toml",
158 r#"
159 [package]
160 name = "foo"
161 version = "0.0.1"
162 authors = []
163
164 [target.'cfg(4)'.dependencies]
165 bar = "0.1.0"
166 "#,
167 )
168 .file("src/lib.rs", "")
169 .build();
170
171 p.cargo("build")
172 .with_status(101)
173 .with_stderr(
174 "\
175 [ERROR] failed to parse manifest at `[..]`
176
177 Caused by:
178 failed to parse `4` as a cfg expression: unexpected character `4` in cfg, [..]
179 ",
180 )
181 .run();
182 }
183
184 #[cargo_test]
bad_target_spec2()185 fn bad_target_spec2() {
186 let p = project()
187 .file(
188 "Cargo.toml",
189 r#"
190 [package]
191 name = "foo"
192 version = "0.0.1"
193 authors = []
194
195 [target.'cfg(bar =)'.dependencies]
196 baz = "0.1.0"
197 "#,
198 )
199 .file("src/lib.rs", "")
200 .build();
201
202 p.cargo("build")
203 .with_status(101)
204 .with_stderr(
205 "\
206 [ERROR] failed to parse manifest at `[..]`
207
208 Caused by:
209 failed to parse `bar =` as a cfg expression: expected a string, but cfg expression ended
210 ",
211 )
212 .run();
213 }
214
215 #[cargo_test]
multiple_match_ok()216 fn multiple_match_ok() {
217 let p = project()
218 .file(
219 "Cargo.toml",
220 &format!(
221 r#"
222 [package]
223 name = "a"
224 version = "0.0.1"
225 authors = []
226
227 [target.'cfg(unix)'.dependencies]
228 b = {{ path = 'b' }}
229 [target.'cfg(target_family = "unix")'.dependencies]
230 b = {{ path = 'b' }}
231 [target."cfg(windows)".dependencies]
232 b = {{ path = 'b' }}
233 [target.'cfg(target_family = "windows")'.dependencies]
234 b = {{ path = 'b' }}
235 [target."cfg(any(windows, unix))".dependencies]
236 b = {{ path = 'b' }}
237
238 [target.{}.dependencies]
239 b = {{ path = 'b' }}
240 "#,
241 rustc_host()
242 ),
243 )
244 .file("src/lib.rs", "extern crate b;")
245 .file("b/Cargo.toml", &basic_manifest("b", "0.0.1"))
246 .file("b/src/lib.rs", "")
247 .build();
248 p.cargo("build -v").run();
249 }
250
251 #[cargo_test]
any_ok()252 fn any_ok() {
253 let p = project()
254 .file(
255 "Cargo.toml",
256 r#"
257 [package]
258 name = "a"
259 version = "0.0.1"
260 authors = []
261
262 [target."cfg(any(windows, unix))".dependencies]
263 b = { path = 'b' }
264 "#,
265 )
266 .file("src/lib.rs", "extern crate b;")
267 .file("b/Cargo.toml", &basic_manifest("b", "0.0.1"))
268 .file("b/src/lib.rs", "")
269 .build();
270 p.cargo("build -v").run();
271 }
272
273 // https://github.com/rust-lang/cargo/issues/5313
274 #[cargo_test]
275 #[cfg(all(target_arch = "x86_64", target_os = "linux", target_env = "gnu"))]
cfg_looks_at_rustflags_for_target()276 fn cfg_looks_at_rustflags_for_target() {
277 let p = project()
278 .file(
279 "Cargo.toml",
280 r#"
281 [package]
282 name = "a"
283 version = "0.0.1"
284 authors = []
285
286 [target.'cfg(with_b)'.dependencies]
287 b = { path = 'b' }
288 "#,
289 )
290 .file(
291 "src/main.rs",
292 r#"
293 #[cfg(with_b)]
294 extern crate b;
295
296 fn main() { b::foo(); }
297 "#,
298 )
299 .file("b/Cargo.toml", &basic_manifest("b", "0.0.1"))
300 .file("b/src/lib.rs", "pub fn foo() {}")
301 .build();
302
303 p.cargo("build --target x86_64-unknown-linux-gnu")
304 .env("RUSTFLAGS", "--cfg with_b")
305 .run();
306 }
307
308 #[cargo_test]
bad_cfg_discovery()309 fn bad_cfg_discovery() {
310 // Check error messages when `rustc -v` and `rustc --print=*` parsing fails.
311 //
312 // This is a `rustc` replacement which behaves differently based on an
313 // environment variable.
314 let p = project()
315 .at("compiler")
316 .file("Cargo.toml", &basic_manifest("compiler", "0.1.0"))
317 .file(
318 "src/main.rs",
319 r#"
320 fn run_rustc() -> String {
321 let mut cmd = std::process::Command::new("rustc");
322 for arg in std::env::args_os().skip(1) {
323 cmd.arg(arg);
324 }
325 String::from_utf8(cmd.output().unwrap().stdout).unwrap()
326 }
327
328 fn main() {
329 let mode = std::env::var("FUNKY_MODE").unwrap();
330 if mode == "bad-version" {
331 println!("foo");
332 return;
333 }
334 if std::env::args_os().any(|a| a == "-vV") {
335 print!("{}", run_rustc());
336 return;
337 }
338 if mode == "no-crate-types" {
339 return;
340 }
341 if mode == "bad-crate-type" {
342 println!("foo");
343 return;
344 }
345 let output = run_rustc();
346 let mut lines = output.lines();
347 let sysroot = loop {
348 let line = lines.next().unwrap();
349 if line.contains("___") {
350 println!("{}", line);
351 } else {
352 break line;
353 }
354 };
355 if mode == "no-sysroot" {
356 return;
357 }
358 println!("{}", sysroot);
359 if mode != "bad-cfg" {
360 panic!("unexpected");
361 }
362 println!("123");
363 }
364 "#,
365 )
366 .build();
367 p.cargo("build").run();
368 let funky_rustc = p.bin("compiler");
369
370 let p = project().file("src/lib.rs", "").build();
371
372 p.cargo("build")
373 .env("RUSTC", &funky_rustc)
374 .env("FUNKY_MODE", "bad-version")
375 .with_status(101)
376 .with_stderr(
377 "\
378 [ERROR] `rustc -vV` didn't have a line for `host:`, got:
379 foo
380
381 ",
382 )
383 .run();
384
385 p.cargo("build")
386 .env("RUSTC", &funky_rustc)
387 .env("FUNKY_MODE", "no-crate-types")
388 .with_status(101)
389 .with_stderr(
390 "\
391 [ERROR] malformed output when learning about crate-type bin information
392 command was: `[..]compiler[..] --crate-name ___ [..]`
393 (no output received)
394 ",
395 )
396 .run();
397
398 p.cargo("build")
399 .env("RUSTC", &funky_rustc)
400 .env("FUNKY_MODE", "no-sysroot")
401 .with_status(101)
402 .with_stderr(
403 "\
404 [ERROR] output of --print=sysroot missing when learning about target-specific information from rustc
405 command was: `[..]compiler[..]--crate-type [..]`
406
407 --- stdout
408 [..]___[..]
409 [..]___[..]
410 [..]___[..]
411 [..]___[..]
412 [..]___[..]
413 [..]___[..]
414
415 ",
416 )
417 .run();
418
419 p.cargo("build")
420 .env("RUSTC", &funky_rustc)
421 .env("FUNKY_MODE", "bad-cfg")
422 .with_status(101)
423 .with_stderr(
424 "\
425 [ERROR] failed to parse the cfg from `rustc --print=cfg`, got:
426 [..]___[..]
427 [..]___[..]
428 [..]___[..]
429 [..]___[..]
430 [..]___[..]
431 [..]___[..]
432 [..]
433 123
434
435
436 Caused by:
437 failed to parse `123` as a cfg expression: unexpected character `1` in cfg, \
438 expected parens, a comma, an identifier, or a string
439 ",
440 )
441 .run();
442 }
443
444 #[cargo_test]
exclusive_dep_kinds()445 fn exclusive_dep_kinds() {
446 // Checks for a bug where the same package with different cfg expressions
447 // was not being filtered correctly.
448 Package::new("bar", "1.0.0").publish();
449 let p = project()
450 .file(
451 "Cargo.toml",
452 r#"
453 [package]
454 name = "foo"
455 version = "0.1.0"
456
457 [target.'cfg(abc)'.dependencies]
458 bar = "1.0"
459
460 [target.'cfg(not(abc))'.build-dependencies]
461 bar = "1.0"
462 "#,
463 )
464 .file("src/lib.rs", "")
465 .file("build.rs", "extern crate bar; fn main() {}")
466 .build();
467
468 p.cargo("check").run();
469 p.change_file("src/lib.rs", "extern crate bar;");
470 p.cargo("check")
471 .with_status(101)
472 // can't find crate for `bar`
473 .with_stderr_contains("[..]E0463[..]")
474 .run();
475 }
476