]> git.proxmox.com Git - rustc.git/blame - src/tools/cargo/tests/testsuite/build_script.rs
New upstream version 1.72.1+dfsg1
[rustc.git] / src / tools / cargo / tests / testsuite / build_script.rs
CommitLineData
0a29b90c
FG
1//! Tests for build.rs scripts.
2
3use cargo_test_support::compare::assert_match_exact;
4use cargo_test_support::install::cargo_home;
5use cargo_test_support::paths::CargoPathExt;
6use cargo_test_support::registry::Package;
7use cargo_test_support::tools;
8use cargo_test_support::{
9 basic_manifest, cargo_exe, cross_compile, is_coarse_mtime, project, project_in,
10};
11use cargo_test_support::{rustc_host, sleep_ms, slow_cpu_multiplier, symlink_supported};
12use cargo_util::paths::{self, remove_dir_all};
13use std::env;
14use std::fs;
15use std::io;
16use std::thread;
17
18#[cargo_test]
19fn custom_build_script_failed() {
20 let p = project()
21 .file(
22 "Cargo.toml",
23 r#"
24 [package]
25
26 name = "foo"
27 version = "0.5.0"
28 authors = ["wycats@example.com"]
29 build = "build.rs"
30 "#,
31 )
32 .file("src/main.rs", "fn main() {}")
33 .file("build.rs", "fn main() { std::process::exit(101); }")
34 .build();
35 p.cargo("build -v")
36 .with_status(101)
37 .with_stderr(
38 "\
39[COMPILING] foo v0.5.0 ([CWD])
40[RUNNING] `rustc --crate-name build_script_build build.rs [..]--crate-type bin [..]`
41[RUNNING] `[..]/build-script-build`
42[ERROR] failed to run custom build command for `foo v0.5.0 ([CWD])`
43
44Caused by:
45 process didn't exit successfully: `[..]/build-script-build` (exit [..]: 101)",
46 )
47 .run();
48}
49
50#[cargo_test]
51fn custom_build_script_failed_backtraces_message() {
52 // In this situation (no dependency sharing), debuginfo is turned off in
53 // `dev.build-override`. However, if an error occurs running e.g. a build
54 // script, and backtraces are opted into: a message explaining how to
55 // improve backtraces is also displayed.
56 let p = project()
57 .file(
58 "Cargo.toml",
59 r#"
60 [package]
61
62 name = "foo"
63 version = "0.5.0"
64 authors = ["wycats@example.com"]
65 build = "build.rs"
66 "#,
67 )
68 .file("src/main.rs", "fn main() {}")
69 .file("build.rs", "fn main() { std::process::exit(101); }")
70 .build();
71 p.cargo("build -v")
72 .env("RUST_BACKTRACE", "1")
73 .with_status(101)
74 .with_stderr(
75 "\
76[COMPILING] foo v0.5.0 ([CWD])
77[RUNNING] `rustc --crate-name build_script_build build.rs [..]--crate-type bin [..]`
78[RUNNING] `[..]/build-script-build`
79[ERROR] failed to run custom build command for `foo v0.5.0 ([CWD])`
80note: To improve backtraces for build dependencies, set the \
81CARGO_PROFILE_DEV_BUILD_OVERRIDE_DEBUG=true environment variable [..]
82
83Caused by:
84 process didn't exit successfully: `[..]/build-script-build` (exit [..]: 101)",
85 )
86 .run();
87
88 p.cargo("check -v")
89 .env("RUST_BACKTRACE", "1")
90 .with_status(101)
91 .with_stderr(
92 "\
93[COMPILING] foo v0.5.0 ([CWD])
94[RUNNING] `[..]/build-script-build`
95[ERROR] failed to run custom build command for `foo v0.5.0 ([CWD])`
96note: To improve backtraces for build dependencies, set the \
97CARGO_PROFILE_DEV_BUILD_OVERRIDE_DEBUG=true environment variable [..]
98
99Caused by:
100 process didn't exit successfully: `[..]/build-script-build` (exit [..]: 101)",
101 )
102 .run();
103}
104
105#[cargo_test]
106fn custom_build_script_failed_backtraces_message_with_debuginfo() {
107 // This is the same test as `custom_build_script_failed_backtraces_message` above, this time
108 // ensuring that the message dedicated to improving backtraces by requesting debuginfo is not
109 // shown when debuginfo is already turned on.
110 let p = project()
111 .file(
112 "Cargo.toml",
113 r#"
114 [package]
115
116 name = "foo"
117 version = "0.5.0"
118 authors = ["wycats@example.com"]
119 build = "build.rs"
120 "#,
121 )
122 .file("src/main.rs", "fn main() {}")
123 .file("build.rs", "fn main() { std::process::exit(101); }")
124 .build();
125 p.cargo("build -v")
126 .env("RUST_BACKTRACE", "1")
127 .env("CARGO_PROFILE_DEV_BUILD_OVERRIDE_DEBUG", "true")
128 .with_status(101)
129 .with_stderr(
130 "\
131[COMPILING] foo v0.5.0 ([CWD])
132[RUNNING] `rustc --crate-name build_script_build build.rs [..]--crate-type bin [..]`
133[RUNNING] `[..]/build-script-build`
134[ERROR] failed to run custom build command for `foo v0.5.0 ([CWD])`
135
136Caused by:
137 process didn't exit successfully: `[..]/build-script-build` (exit [..]: 101)",
138 )
139 .run();
140}
141
142#[cargo_test]
143fn custom_build_env_vars() {
144 let p = project()
145 .file(
146 "Cargo.toml",
147 r#"
148 [package]
149
150 name = "foo"
151 version = "0.5.0"
152 authors = ["wycats@example.com"]
153
154 [features]
155 bar_feat = ["bar/foo"]
156
157 [dependencies.bar]
158 path = "bar"
159 "#,
160 )
161 .file("src/main.rs", "fn main() {}")
162 .file(
163 "bar/Cargo.toml",
164 r#"
165 [package]
166
167 name = "bar"
168 version = "0.5.0"
169 authors = ["wycats@example.com"]
170 build = "build.rs"
171
172 [features]
173 foo = []
174 "#,
175 )
176 .file("bar/src/lib.rs", "pub fn hello() {}");
177
178 let cargo = cargo_exe().canonicalize().unwrap();
179 let cargo = cargo.to_str().unwrap();
180 let rustc = paths::resolve_executable("rustc".as_ref())
181 .unwrap()
182 .canonicalize()
183 .unwrap();
184 let rustc = rustc.to_str().unwrap();
185 let file_content = format!(
186 r##"
187 use std::env;
188 use std::path::Path;
189
190 fn main() {{
191 let _target = env::var("TARGET").unwrap();
192 let _ncpus = env::var("NUM_JOBS").unwrap();
193 let _dir = env::var("CARGO_MANIFEST_DIR").unwrap();
194
195 let opt = env::var("OPT_LEVEL").unwrap();
196 assert_eq!(opt, "0");
197
198 let opt = env::var("PROFILE").unwrap();
199 assert_eq!(opt, "debug");
200
201 let debug = env::var("DEBUG").unwrap();
202 assert_eq!(debug, "true");
203
204 let out = env::var("OUT_DIR").unwrap();
205 assert!(out.starts_with(r"{0}"));
206 assert!(Path::new(&out).is_dir());
207
208 let _host = env::var("HOST").unwrap();
209
210 let _feat = env::var("CARGO_FEATURE_FOO").unwrap();
211
212 let cargo = env::var("CARGO").unwrap();
213 if env::var_os("CHECK_CARGO_IS_RUSTC").is_some() {{
214 assert_eq!(cargo, r#"{rustc}"#);
215 }} else {{
216 assert_eq!(cargo, r#"{cargo}"#);
217 }}
218
219 let rustc = env::var("RUSTC").unwrap();
220 assert_eq!(rustc, "rustc");
221
222 let rustdoc = env::var("RUSTDOC").unwrap();
223 assert_eq!(rustdoc, "rustdoc");
224
225 assert!(env::var("RUSTC_WRAPPER").is_err());
226 assert!(env::var("RUSTC_WORKSPACE_WRAPPER").is_err());
227
228 assert!(env::var("RUSTC_LINKER").is_err());
229
230 assert!(env::var("RUSTFLAGS").is_err());
231 let rustflags = env::var("CARGO_ENCODED_RUSTFLAGS").unwrap();
232 assert_eq!(rustflags, "");
233 }}
234 "##,
235 p.root()
236 .join("target")
237 .join("debug")
238 .join("build")
239 .display(),
240 );
241
242 let p = p.file("bar/build.rs", &file_content).build();
243
244 p.cargo("build --features bar_feat").run();
245 p.cargo("build --features bar_feat")
246 // we use rustc since $CARGO is only used if it points to a path that exists
247 .env("CHECK_CARGO_IS_RUSTC", "1")
248 .env(cargo::CARGO_ENV, rustc)
249 .run();
250}
251
252#[cargo_test]
253fn custom_build_env_var_rustflags() {
254 let rustflags = "--cfg=special";
255 let rustflags_alt = "--cfg=notspecial";
256 let p = project()
257 .file(
258 ".cargo/config",
259 &format!(
260 r#"
261 [build]
262 rustflags = ["{}"]
263 "#,
264 rustflags
265 ),
266 )
267 .file(
268 "build.rs",
269 &format!(
270 r#"
271 use std::env;
272
273 fn main() {{
274 // Static assertion that exactly one of the cfg paths is always taken.
275 assert!(env::var("RUSTFLAGS").is_err());
276 let x;
277 #[cfg(special)]
278 {{ assert_eq!(env::var("CARGO_ENCODED_RUSTFLAGS").unwrap(), "{}"); x = String::new(); }}
279 #[cfg(notspecial)]
280 {{ assert_eq!(env::var("CARGO_ENCODED_RUSTFLAGS").unwrap(), "{}"); x = String::new(); }}
281 let _ = x;
282 }}
283 "#,
284 rustflags, rustflags_alt,
285 ),
286 )
287 .file("src/lib.rs", "")
288 .build();
289
290 p.cargo("check").run();
291
292 // RUSTFLAGS overrides build.rustflags, so --cfg=special shouldn't be passed
293 p.cargo("check").env("RUSTFLAGS", rustflags_alt).run();
294}
295
296#[cargo_test]
297fn custom_build_env_var_encoded_rustflags() {
298 // NOTE: We use "-Clink-arg=-B nope" here rather than, say, "-A missing_docs", since for the
299 // latter it won't matter if the whitespace accidentally gets split, as rustc will do the right
300 // thing either way.
301 let p = project()
302 .file(
303 ".cargo/config",
304 r#"
305 [build]
306 rustflags = ["-Clink-arg=-B nope", "--cfg=foo"]
307 "#,
308 )
309 .file(
310 "build.rs",
311 r#"
312 use std::env;
313
314 fn main() {{
315 assert_eq!(env::var("CARGO_ENCODED_RUSTFLAGS").unwrap(), "-Clink-arg=-B nope\x1f--cfg=foo");
316 }}
317 "#,
318 )
319 .file("src/lib.rs", "")
320 .build();
321
322 p.cargo("check").run();
323}
324
325#[cargo_test]
326fn custom_build_env_var_rustc_wrapper() {
327 let wrapper = tools::echo_wrapper();
328 let p = project()
329 .file(
330 "build.rs",
331 r#"
332 use std::env;
333
334 fn main() {{
335 assert_eq!(
336 env::var("RUSTC_WRAPPER").unwrap(),
337 env::var("CARGO_RUSTC_WRAPPER_CHECK").unwrap()
338 );
339 }}
340 "#,
341 )
342 .file("src/lib.rs", "")
343 .build();
344
345 p.cargo("check")
346 .env("CARGO_BUILD_RUSTC_WRAPPER", &wrapper)
347 .env("CARGO_RUSTC_WRAPPER_CHECK", &wrapper)
348 .run();
349}
350
351#[cargo_test]
352fn custom_build_env_var_rustc_workspace_wrapper() {
353 let wrapper = tools::echo_wrapper();
354
355 // Workspace wrapper should be set for any crate we're operating directly on.
356 let p = project()
357 .file(
358 "build.rs",
359 r#"
360 use std::env;
361
362 fn main() {{
363 assert_eq!(
364 env::var("RUSTC_WORKSPACE_WRAPPER").unwrap(),
365 env::var("CARGO_RUSTC_WORKSPACE_WRAPPER_CHECK").unwrap()
366 );
367 }}
368 "#,
369 )
370 .file("src/lib.rs", "")
371 .build();
372
373 p.cargo("check")
374 .env("CARGO_BUILD_RUSTC_WORKSPACE_WRAPPER", &wrapper)
375 .env("CARGO_RUSTC_WORKSPACE_WRAPPER_CHECK", &wrapper)
376 .run();
377
378 // But should not be set for a crate from the registry, as then it's not in a workspace.
379 Package::new("bar", "0.1.0")
380 .file(
381 "Cargo.toml",
382 r#"
383 [package]
384 name = "bar"
385 version = "0.1.0"
386 links = "a"
387 "#,
388 )
389 .file(
390 "build.rs",
391 r#"
392 use std::env;
393
394 fn main() {{
395 assert!(env::var("RUSTC_WORKSPACE_WRAPPER").is_err());
396 }}
397 "#,
398 )
399 .file("src/lib.rs", "")
400 .publish();
401 let p = project()
402 .file(
403 "Cargo.toml",
404 r#"
405 [package]
406 name = "foo"
407 version = "0.1.0"
408
409 [dependencies]
410 bar = "0.1"
411 "#,
412 )
413 .file("src/lib.rs", "")
414 .build();
415
416 p.cargo("check")
417 .env("CARGO_BUILD_RUSTC_WORKSPACE_WRAPPER", &wrapper)
418 .run();
419}
420
421#[cargo_test]
422fn custom_build_env_var_rustc_linker() {
423 if cross_compile::disabled() {
424 return;
425 }
426 let target = cross_compile::alternate();
427 let p = project()
428 .file(
429 ".cargo/config",
430 &format!(
431 r#"
432 [target.{}]
433 linker = "/path/to/linker"
434 "#,
435 target
436 ),
437 )
438 .file(
439 "build.rs",
440 r#"
441 use std::env;
442
443 fn main() {
444 assert!(env::var("RUSTC_LINKER").unwrap().ends_with("/path/to/linker"));
445 }
446 "#,
447 )
448 .file("src/lib.rs", "")
449 .build();
450
451 // no crate type set => linker never called => build succeeds if and
452 // only if build.rs succeeds, despite linker binary not existing.
453 p.cargo("build --target").arg(&target).run();
454}
455
456#[cargo_test]
457fn custom_build_env_var_rustc_linker_bad_host_target() {
458 let target = rustc_host();
459 let p = project()
460 .file(
461 ".cargo/config",
462 &format!(
463 r#"
464 [target.{}]
465 linker = "/path/to/linker"
466 "#,
467 target
468 ),
469 )
470 .file("build.rs", "fn main() {}")
471 .file("src/lib.rs", "")
472 .build();
473
474 // build.rs should fail since host == target when no target is set
475 p.cargo("build --verbose")
476 .with_status(101)
477 .with_stderr_contains(
478 "\
479[COMPILING] foo v0.0.1 ([CWD])
480[RUNNING] `rustc --crate-name build_script_build build.rs [..]--crate-type bin [..]-C linker=[..]/path/to/linker [..]`
481[ERROR] linker `[..]/path/to/linker` not found
482"
483 )
484 .run();
485}
486
487#[cargo_test]
488fn custom_build_env_var_rustc_linker_host_target() {
489 let target = rustc_host();
490 let p = project()
491 .file(
492 ".cargo/config",
493 &format!(
494 r#"
495 target-applies-to-host = false
496 [target.{}]
497 linker = "/path/to/linker"
498 "#,
499 target
500 ),
501 )
502 .file(
503 "build.rs",
504 r#"
505 use std::env;
506
507 fn main() {
508 assert!(env::var("RUSTC_LINKER").unwrap().ends_with("/path/to/linker"));
509 }
510 "#,
511 )
512 .file("src/lib.rs", "")
513 .build();
514
515 // no crate type set => linker never called => build succeeds if and
516 // only if build.rs succeeds, despite linker binary not existing.
517 p.cargo("build -Z target-applies-to-host --target")
518 .arg(&target)
519 .masquerade_as_nightly_cargo(&["target-applies-to-host"])
520 .run();
521}
522
523#[cargo_test]
524fn custom_build_env_var_rustc_linker_host_target_env() {
525 let target = rustc_host();
526 let p = project()
527 .file(
528 ".cargo/config",
529 &format!(
530 r#"
531 [target.{}]
532 linker = "/path/to/linker"
533 "#,
534 target
535 ),
536 )
537 .file(
538 "build.rs",
539 r#"
540 use std::env;
541
542 fn main() {
543 assert!(env::var("RUSTC_LINKER").unwrap().ends_with("/path/to/linker"));
544 }
545 "#,
546 )
547 .file("src/lib.rs", "")
548 .build();
549
550 // no crate type set => linker never called => build succeeds if and
551 // only if build.rs succeeds, despite linker binary not existing.
552 p.cargo("build -Z target-applies-to-host --target")
553 .env("CARGO_TARGET_APPLIES_TO_HOST", "false")
554 .arg(&target)
555 .masquerade_as_nightly_cargo(&["target-applies-to-host"])
556 .run();
557}
558
559#[cargo_test]
560fn custom_build_invalid_host_config_feature_flag() {
561 let target = rustc_host();
562 let p = project()
563 .file(
564 ".cargo/config",
565 &format!(
566 r#"
567 [target.{}]
568 linker = "/path/to/linker"
569 "#,
570 target
571 ),
572 )
573 .file("build.rs", "fn main() {}")
574 .file("src/lib.rs", "")
575 .build();
576
577 // build.rs should fail due to -Zhost-config being set without -Ztarget-applies-to-host
578 p.cargo("build -Z host-config --target")
579 .arg(&target)
580 .masquerade_as_nightly_cargo(&["host-config"])
581 .with_status(101)
582 .with_stderr_contains(
583 "\
584error: the -Zhost-config flag requires the -Ztarget-applies-to-host flag to be set
585",
586 )
587 .run();
588}
589
590#[cargo_test]
591fn custom_build_linker_host_target_with_bad_host_config() {
592 let target = rustc_host();
593 let p = project()
594 .file(
595 ".cargo/config",
596 &format!(
597 r#"
598 [host]
599 linker = "/path/to/host/linker"
600 [target.{}]
601 linker = "/path/to/target/linker"
602 "#,
603 target
604 ),
605 )
606 .file("build.rs", "fn main() {}")
607 .file("src/lib.rs", "")
608 .build();
609
610 // build.rs should fail due to bad host linker being set
611 p.cargo("build -Z target-applies-to-host -Z host-config --verbose --target")
612 .arg(&target)
613 .masquerade_as_nightly_cargo(&["target-applies-to-host", "host-config"])
614 .with_status(101)
615 .with_stderr_contains(
616 "\
617[COMPILING] foo v0.0.1 ([CWD])
618[RUNNING] `rustc --crate-name build_script_build build.rs [..]--crate-type bin [..]-C linker=[..]/path/to/host/linker [..]`
619[ERROR] linker `[..]/path/to/host/linker` not found
620"
621 )
622 .run();
623}
624
625#[cargo_test]
626fn custom_build_linker_bad_host() {
627 let target = rustc_host();
628 let p = project()
629 .file(
630 ".cargo/config",
631 &format!(
632 r#"
633 [host]
634 linker = "/path/to/host/linker"
635 [target.{}]
636 linker = "/path/to/target/linker"
637 "#,
638 target
639 ),
640 )
641 .file("build.rs", "fn main() {}")
642 .file("src/lib.rs", "")
643 .build();
644
645 // build.rs should fail due to bad host linker being set
646 p.cargo("build -Z target-applies-to-host -Z host-config --verbose --target")
647 .arg(&target)
648 .masquerade_as_nightly_cargo(&["target-applies-to-host", "host-config"])
649 .with_status(101)
650 .with_stderr_contains(
651 "\
652[COMPILING] foo v0.0.1 ([CWD])
653[RUNNING] `rustc --crate-name build_script_build build.rs [..]--crate-type bin [..]-C linker=[..]/path/to/host/linker [..]`
654[ERROR] linker `[..]/path/to/host/linker` not found
655"
656 )
657 .run();
658}
659
660#[cargo_test]
661fn custom_build_linker_bad_host_with_arch() {
662 let target = rustc_host();
663 let p = project()
664 .file(
665 ".cargo/config",
666 &format!(
667 r#"
668 [host]
669 linker = "/path/to/host/linker"
670 [host.{}]
671 linker = "/path/to/host/arch/linker"
672 [target.{}]
673 linker = "/path/to/target/linker"
674 "#,
675 target, target
676 ),
677 )
678 .file("build.rs", "fn main() {}")
679 .file("src/lib.rs", "")
680 .build();
681
682 // build.rs should fail due to bad host linker being set
683 p.cargo("build -Z target-applies-to-host -Z host-config --verbose --target")
684 .arg(&target)
685 .masquerade_as_nightly_cargo(&["target-applies-to-host", "host-config"])
686 .with_status(101)
687 .with_stderr_contains(
688 "\
689[COMPILING] foo v0.0.1 ([CWD])
690[RUNNING] `rustc --crate-name build_script_build build.rs [..]--crate-type bin [..]-C linker=[..]/path/to/host/arch/linker [..]`
691[ERROR] linker `[..]/path/to/host/arch/linker` not found
692"
693 )
694 .run();
695}
696
697#[cargo_test]
698fn custom_build_env_var_rustc_linker_cross_arch_host() {
699 let target = rustc_host();
700 let cross_target = cross_compile::alternate();
701 let p = project()
702 .file(
703 ".cargo/config",
704 &format!(
705 r#"
706 [host.{}]
707 linker = "/path/to/host/arch/linker"
708 [target.{}]
709 linker = "/path/to/target/linker"
710 "#,
711 cross_target, target
712 ),
713 )
714 .file(
715 "build.rs",
716 r#"
717 use std::env;
718
719 fn main() {
720 assert!(env::var("RUSTC_LINKER").unwrap().ends_with("/path/to/target/linker"));
721 }
722 "#,
723 )
724 .file("src/lib.rs", "")
725 .build();
726
727 // build.rs should be built fine since cross target != host target.
728 // assertion should succeed since it's still passed the target linker
729 p.cargo("build -Z target-applies-to-host -Z host-config --verbose --target")
730 .arg(&target)
731 .masquerade_as_nightly_cargo(&["target-applies-to-host", "host-config"])
732 .run();
733}
734
735#[cargo_test]
736fn custom_build_linker_bad_cross_arch_host() {
737 let target = rustc_host();
738 let cross_target = cross_compile::alternate();
739 let p = project()
740 .file(
741 ".cargo/config",
742 &format!(
743 r#"
744 [host]
745 linker = "/path/to/host/linker"
746 [host.{}]
747 linker = "/path/to/host/arch/linker"
748 [target.{}]
749 linker = "/path/to/target/linker"
750 "#,
751 cross_target, target
752 ),
753 )
754 .file("build.rs", "fn main() {}")
755 .file("src/lib.rs", "")
756 .build();
757
758 // build.rs should fail due to bad host linker being set
759 p.cargo("build -Z target-applies-to-host -Z host-config --verbose --target")
760 .arg(&target)
761 .masquerade_as_nightly_cargo(&["target-applies-to-host", "host-config"])
762 .with_status(101)
763 .with_stderr_contains(
764 "\
765[COMPILING] foo v0.0.1 ([CWD])
766[RUNNING] `rustc --crate-name build_script_build build.rs [..]--crate-type bin [..]-C linker=[..]/path/to/host/linker [..]`
767[ERROR] linker `[..]/path/to/host/linker` not found
768"
769 )
770 .run();
771}
772
773#[cargo_test]
774fn custom_build_script_wrong_rustc_flags() {
775 let p = project()
776 .file(
777 "Cargo.toml",
778 r#"
779 [package]
780
781 name = "foo"
782 version = "0.5.0"
783 authors = ["wycats@example.com"]
784 build = "build.rs"
785 "#,
786 )
787 .file("src/main.rs", "fn main() {}")
788 .file(
789 "build.rs",
790 r#"fn main() { println!("cargo:rustc-flags=-aaa -bbb"); }"#,
791 )
792 .build();
793
794 p.cargo("build")
795 .with_status(101)
796 .with_stderr_contains(
797 "[ERROR] Only `-l` and `-L` flags are allowed in build script of `foo v0.5.0 ([CWD])`: \
798 `-aaa -bbb`",
799 )
800 .run();
801}
802
803#[cargo_test]
804fn custom_build_script_rustc_flags() {
805 let p = project()
806 .file(
807 "Cargo.toml",
808 r#"
809 [package]
810
811 name = "bar"
812 version = "0.5.0"
813 authors = ["wycats@example.com"]
814
815 [dependencies.foo]
816 path = "foo"
817 "#,
818 )
819 .file("src/main.rs", "fn main() {}")
820 .file(
821 "foo/Cargo.toml",
822 r#"
823 [package]
824
825 name = "foo"
826 version = "0.5.0"
827 authors = ["wycats@example.com"]
828 build = "build.rs"
829 "#,
830 )
831 .file("foo/src/lib.rs", "")
832 .file(
833 "foo/build.rs",
834 r#"
835 fn main() {
836 println!("cargo:rustc-flags=-l nonexistinglib -L /dummy/path1 -L /dummy/path2");
837 }
838 "#,
839 )
840 .build();
841
842 p.cargo("build --verbose")
843 .with_stderr(
844 "\
845[COMPILING] foo [..]
846[RUNNING] `rustc --crate-name build_script_build foo/build.rs [..]
847[RUNNING] `[..]build-script-build`
848[RUNNING] `rustc --crate-name foo foo/src/lib.rs [..]\
849 -L dependency=[CWD]/target/debug/deps \
850 -L /dummy/path1 -L /dummy/path2 -l nonexistinglib`
851[COMPILING] bar [..]
852[RUNNING] `rustc --crate-name bar src/main.rs [..]\
853 -L dependency=[CWD]/target/debug/deps \
854 --extern foo=[..]libfoo-[..] \
855 -L /dummy/path1 -L /dummy/path2`
856[FINISHED] dev [..]
857",
858 )
859 .run();
860}
861
862#[cargo_test]
863fn custom_build_script_rustc_flags_no_space() {
864 let p = project()
865 .file(
866 "Cargo.toml",
867 r#"
868 [package]
869
870 name = "bar"
871 version = "0.5.0"
872 authors = ["wycats@example.com"]
873
874 [dependencies.foo]
875 path = "foo"
876 "#,
877 )
878 .file("src/main.rs", "fn main() {}")
879 .file(
880 "foo/Cargo.toml",
881 r#"
882 [package]
883
884 name = "foo"
885 version = "0.5.0"
886 authors = ["wycats@example.com"]
887 build = "build.rs"
888 "#,
889 )
890 .file("foo/src/lib.rs", "")
891 .file(
892 "foo/build.rs",
893 r#"
894 fn main() {
895 println!("cargo:rustc-flags=-lnonexistinglib -L/dummy/path1 -L/dummy/path2");
896 }
897 "#,
898 )
899 .build();
900
901 p.cargo("build --verbose")
902 .with_stderr(
903 "\
904[COMPILING] foo [..]
905[RUNNING] `rustc --crate-name build_script_build foo/build.rs [..]
906[RUNNING] `[..]build-script-build`
907[RUNNING] `rustc --crate-name foo foo/src/lib.rs [..]\
908 -L dependency=[CWD]/target/debug/deps \
909 -L /dummy/path1 -L /dummy/path2 -l nonexistinglib`
910[COMPILING] bar [..]
911[RUNNING] `rustc --crate-name bar src/main.rs [..]\
912 -L dependency=[CWD]/target/debug/deps \
913 --extern foo=[..]libfoo-[..] \
914 -L /dummy/path1 -L /dummy/path2`
915[FINISHED] dev [..]
916",
917 )
918 .run();
919}
920
921#[cargo_test]
922fn links_no_build_cmd() {
923 let p = project()
924 .file(
925 "Cargo.toml",
926 r#"
927 [package]
928 name = "foo"
929 version = "0.5.0"
930 authors = []
931 links = "a"
932 "#,
933 )
934 .file("src/lib.rs", "")
935 .build();
936
937 p.cargo("build")
938 .with_status(101)
939 .with_stderr(
940 "\
941[ERROR] failed to parse manifest at `[..]/foo/Cargo.toml`
942
943Caused by:
944 package `foo v0.5.0 ([CWD])` specifies that it links to `a` but does \
945not have a custom build script
946",
947 )
948 .run();
949}
950
951#[cargo_test]
952fn links_duplicates() {
953 // this tests that the links_duplicates are caught at resolver time
954 let p = project()
955 .file(
956 "Cargo.toml",
957 r#"
958 [package]
959 name = "foo"
960 version = "0.5.0"
961 authors = []
962 links = "a"
963 build = "build.rs"
964
965 [dependencies.a-sys]
966 path = "a-sys"
967 "#,
968 )
969 .file("src/lib.rs", "")
970 .file("build.rs", "")
971 .file(
972 "a-sys/Cargo.toml",
973 r#"
974 [package]
975 name = "a-sys"
976 version = "0.5.0"
977 authors = []
978 links = "a"
979 build = "build.rs"
980 "#,
981 )
982 .file("a-sys/src/lib.rs", "")
983 .file("a-sys/build.rs", "")
984 .build();
985
986 p.cargo("build").with_status(101)
987 .with_stderr("\
988error: failed to select a version for `a-sys`.
989 ... required by package `foo v0.5.0 ([..])`
990versions that meet the requirements `*` are: 0.5.0
991
992the package `a-sys` links to the native library `a`, but it conflicts with a previous package which links to `a` as well:
993package `foo v0.5.0 ([..])`
994Only one package in the dependency graph may specify the same links value. This helps ensure that only one copy of a native library is linked in the final binary. Try to adjust your dependencies so that only one package uses the links ='a-sys' value. For more information, see https://doc.rust-lang.org/cargo/reference/resolver.html#links.
995
996failed to select a version for `a-sys` which could resolve this conflict
997").run();
998}
999
1000#[cargo_test]
1001fn links_duplicates_old_registry() {
1002 // Test old links validator. See `validate_links`.
1003 Package::new("bar", "0.1.0")
1004 .file(
1005 "Cargo.toml",
1006 r#"
1007 [package]
1008 name = "bar"
1009 version = "0.1.0"
1010 links = "a"
1011 "#,
1012 )
1013 .file("build.rs", "fn main() {}")
1014 .file("src/lib.rs", "")
1015 .publish();
1016
1017 let p = project()
1018 .file(
1019 "Cargo.toml",
1020 r#"
1021 [package]
1022 name = "foo"
1023 version = "0.1.0"
1024 links = "a"
1025
1026 [dependencies]
1027 bar = "0.1"
1028 "#,
1029 )
1030 .file("build.rs", "fn main() {}")
1031 .file("src/lib.rs", "")
1032 .build();
1033
1034 p.cargo("build")
1035 .with_status(101)
1036 .with_stderr(
1037 "\
1038[UPDATING] `[..]` index
1039[DOWNLOADING] crates ...
1040[DOWNLOADED] bar v0.1.0 ([..])
1041[ERROR] multiple packages link to native library `a`, \
1042 but a native library can be linked only once
1043
1044package `bar v0.1.0`
1045 ... which satisfies dependency `bar = \"^0.1\"` (locked to 0.1.0) of package `foo v0.1.0 ([..]foo)`
1046links to native library `a`
1047
1048package `foo v0.1.0 ([..]foo)`
1049also links to native library `a`
1050",
1051 )
1052 .run();
1053}
1054
1055#[cargo_test]
1056fn links_duplicates_deep_dependency() {
1057 // this tests that the links_duplicates are caught at resolver time
1058 let p = project()
1059 .file(
1060 "Cargo.toml",
1061 r#"
1062 [package]
1063 name = "foo"
1064 version = "0.5.0"
1065 authors = []
1066 links = "a"
1067 build = "build.rs"
1068
1069 [dependencies.a]
1070 path = "a"
1071 "#,
1072 )
1073 .file("src/lib.rs", "")
1074 .file("build.rs", "")
1075 .file(
1076 "a/Cargo.toml",
1077 r#"
1078 [package]
1079 name = "a"
1080 version = "0.5.0"
1081 authors = []
1082 build = "build.rs"
1083
1084 [dependencies.a-sys]
1085 path = "a-sys"
1086 "#,
1087 )
1088 .file("a/src/lib.rs", "")
1089 .file("a/build.rs", "")
1090 .file(
1091 "a/a-sys/Cargo.toml",
1092 r#"
1093 [package]
1094 name = "a-sys"
1095 version = "0.5.0"
1096 authors = []
1097 links = "a"
1098 build = "build.rs"
1099 "#,
1100 )
1101 .file("a/a-sys/src/lib.rs", "")
1102 .file("a/a-sys/build.rs", "")
1103 .build();
1104
1105 p.cargo("build").with_status(101)
1106 .with_stderr("\
1107error: failed to select a version for `a-sys`.
1108 ... required by package `a v0.5.0 ([..])`
1109 ... which satisfies path dependency `a` of package `foo v0.5.0 ([..])`
1110versions that meet the requirements `*` are: 0.5.0
1111
1112the package `a-sys` links to the native library `a`, but it conflicts with a previous package which links to `a` as well:
1113package `foo v0.5.0 ([..])`
1114Only one package in the dependency graph may specify the same links value. This helps ensure that only one copy of a native library is linked in the final binary. Try to adjust your dependencies so that only one package uses the links ='a-sys' value. For more information, see https://doc.rust-lang.org/cargo/reference/resolver.html#links.
1115
1116failed to select a version for `a-sys` which could resolve this conflict
1117").run();
1118}
1119
1120#[cargo_test]
1121fn overrides_and_links() {
1122 let target = rustc_host();
1123
1124 let p = project()
1125 .file(
1126 "Cargo.toml",
1127 r#"
1128 [package]
1129 name = "foo"
1130 version = "0.5.0"
1131 authors = []
1132 build = "build.rs"
1133
1134 [dependencies.a]
1135 path = "a"
1136 "#,
1137 )
1138 .file("src/lib.rs", "")
1139 .file(
1140 "build.rs",
1141 r#"
1142 use std::env;
1143 fn main() {
1144 assert_eq!(env::var("DEP_FOO_FOO").ok().expect("FOO missing"),
1145 "bar");
1146 assert_eq!(env::var("DEP_FOO_BAR").ok().expect("BAR missing"),
1147 "baz");
1148 }
1149 "#,
1150 )
1151 .file(
1152 ".cargo/config",
1153 &format!(
1154 r#"
1155 [target.{}.foo]
1156 rustc-flags = "-L foo -L bar"
1157 foo = "bar"
1158 bar = "baz"
1159 "#,
1160 target
1161 ),
1162 )
1163 .file(
1164 "a/Cargo.toml",
1165 r#"
1166 [package]
1167 name = "a"
1168 version = "0.5.0"
1169 authors = []
1170 links = "foo"
1171 build = "build.rs"
1172 "#,
1173 )
1174 .file("a/src/lib.rs", "")
1175 .file("a/build.rs", "not valid rust code")
1176 .build();
1177
1178 p.cargo("build -v")
1179 .with_stderr(
1180 "\
1181[..]
1182[..]
1183[..]
1184[..]
1185[..]
1186[RUNNING] `rustc --crate-name foo [..] -L foo -L bar`
1187[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
1188",
1189 )
1190 .run();
1191}
1192
1193#[cargo_test]
1194fn unused_overrides() {
1195 let target = rustc_host();
1196
1197 let p = project()
1198 .file(
1199 "Cargo.toml",
1200 r#"
1201 [package]
1202 name = "foo"
1203 version = "0.5.0"
1204 authors = []
1205 build = "build.rs"
1206 "#,
1207 )
1208 .file("src/lib.rs", "")
1209 .file("build.rs", "fn main() {}")
1210 .file(
1211 ".cargo/config",
1212 &format!(
1213 r#"
1214 [target.{}.foo]
1215 rustc-flags = "-L foo -L bar"
1216 foo = "bar"
1217 bar = "baz"
1218 "#,
1219 target
1220 ),
1221 )
1222 .build();
1223
1224 p.cargo("build -v").run();
1225}
1226
1227#[cargo_test]
1228fn links_passes_env_vars() {
1229 let p = project()
1230 .file(
1231 "Cargo.toml",
1232 r#"
1233 [package]
1234 name = "foo"
1235 version = "0.5.0"
1236 authors = []
1237 build = "build.rs"
1238
1239 [dependencies.a]
1240 path = "a"
1241 "#,
1242 )
1243 .file("src/lib.rs", "")
1244 .file(
1245 "build.rs",
1246 r#"
1247 use std::env;
1248 fn main() {
1249 assert_eq!(env::var("DEP_FOO_FOO").unwrap(), "bar");
1250 assert_eq!(env::var("DEP_FOO_BAR").unwrap(), "baz");
1251 }
1252 "#,
1253 )
1254 .file(
1255 "a/Cargo.toml",
1256 r#"
1257 [package]
1258 name = "a"
1259 version = "0.5.0"
1260 authors = []
1261 links = "foo"
1262 build = "build.rs"
1263 "#,
1264 )
1265 .file("a/src/lib.rs", "")
1266 .file(
1267 "a/build.rs",
1268 r#"
1269 use std::env;
1270 fn main() {
1271 let lib = env::var("CARGO_MANIFEST_LINKS").unwrap();
1272 assert_eq!(lib, "foo");
1273
1274 println!("cargo:foo=bar");
1275 println!("cargo:bar=baz");
1276 }
1277 "#,
1278 )
1279 .build();
1280
1281 p.cargo("build -v").run();
1282}
1283
1284#[cargo_test]
1285fn only_rerun_build_script() {
1286 let p = project()
1287 .file(
1288 "Cargo.toml",
1289 r#"
1290 [package]
1291 name = "foo"
1292 version = "0.5.0"
1293 authors = []
1294 build = "build.rs"
1295 "#,
1296 )
1297 .file("src/lib.rs", "")
1298 .file("build.rs", "fn main() {}")
1299 .build();
1300
1301 p.cargo("build -v").run();
1302 p.root().move_into_the_past();
1303
1304 p.change_file("some-new-file", "");
1305 p.root().move_into_the_past();
1306
1307 p.cargo("build -v")
1308 .with_stderr(
1309 "\
1310[DIRTY] foo v0.5.0 ([CWD]): the precalculated components changed
1311[COMPILING] foo v0.5.0 ([CWD])
1312[RUNNING] `[..]/build-script-build`
1313[RUNNING] `rustc --crate-name foo [..]`
1314[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
1315",
1316 )
1317 .run();
1318}
1319
1320#[cargo_test]
1321fn rebuild_continues_to_pass_env_vars() {
1322 let a = project()
1323 .at("a")
1324 .file(
1325 "Cargo.toml",
1326 r#"
1327 [package]
1328 name = "a"
1329 version = "0.5.0"
1330 authors = []
1331 links = "foo"
1332 build = "build.rs"
1333 "#,
1334 )
1335 .file("src/lib.rs", "")
1336 .file(
1337 "build.rs",
1338 r#"
1339 use std::time::Duration;
1340 fn main() {
1341 println!("cargo:foo=bar");
1342 println!("cargo:bar=baz");
1343 std::thread::sleep(Duration::from_millis(500));
1344 }
1345 "#,
1346 )
1347 .build();
1348 a.root().move_into_the_past();
1349
1350 let p = project()
1351 .file(
1352 "Cargo.toml",
1353 &format!(
1354 r#"
1355 [package]
1356 name = "foo"
1357 version = "0.5.0"
1358 authors = []
1359 build = "build.rs"
1360
1361 [dependencies.a]
1362 path = '{}'
1363 "#,
1364 a.root().display()
1365 ),
1366 )
1367 .file("src/lib.rs", "")
1368 .file(
1369 "build.rs",
1370 r#"
1371 use std::env;
1372 fn main() {
1373 assert_eq!(env::var("DEP_FOO_FOO").unwrap(), "bar");
1374 assert_eq!(env::var("DEP_FOO_BAR").unwrap(), "baz");
1375 }
1376 "#,
1377 )
1378 .build();
1379
1380 p.cargo("build -v").run();
1381 p.root().move_into_the_past();
1382
1383 p.change_file("some-new-file", "");
1384 p.root().move_into_the_past();
1385
1386 p.cargo("build -v").run();
1387}
1388
1389#[cargo_test]
1390fn testing_and_such() {
1391 let p = project()
1392 .file(
1393 "Cargo.toml",
1394 r#"
1395 [package]
1396 name = "foo"
1397 version = "0.5.0"
1398 authors = []
1399 build = "build.rs"
1400 "#,
1401 )
1402 .file("src/lib.rs", "")
1403 .file("build.rs", "fn main() {}")
1404 .build();
1405
1406 println!("build");
1407 p.cargo("build -v").run();
1408 p.root().move_into_the_past();
1409
1410 p.change_file("src/lib.rs", "");
1411 p.root().move_into_the_past();
1412
1413 println!("test");
1414 p.cargo("test -vj1")
1415 .with_stderr(
1416 "\
1417[DIRTY] foo v0.5.0 ([CWD]): the precalculated components changed
1418[COMPILING] foo v0.5.0 ([CWD])
1419[RUNNING] `[..]/build-script-build`
1420[RUNNING] `rustc --crate-name foo [..]`
1421[RUNNING] `rustc --crate-name foo [..]`
1422[FINISHED] test [unoptimized + debuginfo] target(s) in [..]
1423[RUNNING] `[..]/foo-[..][EXE]`
1424[DOCTEST] foo
1425[RUNNING] `rustdoc [..]--test [..]`",
1426 )
1427 .with_stdout_contains_n("running 0 tests", 2)
1428 .run();
1429
1430 println!("doc");
1431 p.cargo("doc -v")
1432 .with_stderr(
1433 "\
1434[DOCUMENTING] foo v0.5.0 ([CWD])
1435[RUNNING] `rustdoc [..]`
1436[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
1437",
1438 )
1439 .run();
1440
1441 p.change_file("src/main.rs", "fn main() {}");
1442 println!("run");
1443 p.cargo("run")
1444 .with_stderr(
1445 "\
1446[COMPILING] foo v0.5.0 ([CWD])
1447[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
1448[RUNNING] `target/debug/foo[EXE]`
1449",
1450 )
1451 .run();
1452}
1453
1454#[cargo_test]
1455fn propagation_of_l_flags() {
1456 let target = rustc_host();
1457 let p = project()
1458 .file(
1459 "Cargo.toml",
1460 r#"
1461 [package]
1462 name = "foo"
1463 version = "0.5.0"
1464 authors = []
1465 [dependencies.a]
1466 path = "a"
1467 "#,
1468 )
1469 .file("src/lib.rs", "")
1470 .file(
1471 "a/Cargo.toml",
1472 r#"
1473 [package]
1474 name = "a"
1475 version = "0.5.0"
1476 authors = []
1477 links = "bar"
1478 build = "build.rs"
1479
1480 [dependencies.b]
1481 path = "../b"
1482 "#,
1483 )
1484 .file("a/src/lib.rs", "")
1485 .file(
1486 "a/build.rs",
1487 r#"fn main() { println!("cargo:rustc-flags=-L bar"); }"#,
1488 )
1489 .file(
1490 "b/Cargo.toml",
1491 r#"
1492 [package]
1493 name = "b"
1494 version = "0.5.0"
1495 authors = []
1496 links = "foo"
1497 build = "build.rs"
1498 "#,
1499 )
1500 .file("b/src/lib.rs", "")
1501 .file("b/build.rs", "bad file")
1502 .file(
1503 ".cargo/config",
1504 &format!(
1505 r#"
1506 [target.{}.foo]
1507 rustc-flags = "-L foo"
1508 "#,
1509 target
1510 ),
1511 )
1512 .build();
1513
1514 p.cargo("build -v -j1")
1515 .with_stderr_contains(
1516 "\
1517[RUNNING] `rustc --crate-name a [..] -L bar[..]-L foo[..]`
1518[COMPILING] foo v0.5.0 ([CWD])
1519[RUNNING] `rustc --crate-name foo [..] -L bar -L foo`
1520",
1521 )
1522 .run();
1523}
1524
1525#[cargo_test]
1526fn propagation_of_l_flags_new() {
1527 let target = rustc_host();
1528 let p = project()
1529 .file(
1530 "Cargo.toml",
1531 r#"
1532 [package]
1533 name = "foo"
1534 version = "0.5.0"
1535 authors = []
1536 [dependencies.a]
1537 path = "a"
1538 "#,
1539 )
1540 .file("src/lib.rs", "")
1541 .file(
1542 "a/Cargo.toml",
1543 r#"
1544 [package]
1545 name = "a"
1546 version = "0.5.0"
1547 authors = []
1548 links = "bar"
1549 build = "build.rs"
1550
1551 [dependencies.b]
1552 path = "../b"
1553 "#,
1554 )
1555 .file("a/src/lib.rs", "")
1556 .file(
1557 "a/build.rs",
1558 r#"
1559 fn main() {
1560 println!("cargo:rustc-link-search=bar");
1561 }
1562 "#,
1563 )
1564 .file(
1565 "b/Cargo.toml",
1566 r#"
1567 [package]
1568 name = "b"
1569 version = "0.5.0"
1570 authors = []
1571 links = "foo"
1572 build = "build.rs"
1573 "#,
1574 )
1575 .file("b/src/lib.rs", "")
1576 .file("b/build.rs", "bad file")
1577 .file(
1578 ".cargo/config",
1579 &format!(
1580 r#"
1581 [target.{}.foo]
1582 rustc-link-search = ["foo"]
1583 "#,
1584 target
1585 ),
1586 )
1587 .build();
1588
1589 p.cargo("build -v -j1")
1590 .with_stderr_contains(
1591 "\
1592[RUNNING] `rustc --crate-name a [..] -L bar[..]-L foo[..]`
1593[COMPILING] foo v0.5.0 ([CWD])
1594[RUNNING] `rustc --crate-name foo [..] -L bar -L foo`
1595",
1596 )
1597 .run();
1598}
1599
1600#[cargo_test]
1601fn build_deps_simple() {
1602 let p = project()
1603 .file(
1604 "Cargo.toml",
1605 r#"
1606 [package]
1607 name = "foo"
1608 version = "0.5.0"
1609 authors = []
1610 build = "build.rs"
1611 [build-dependencies.a]
1612 path = "a"
1613 "#,
1614 )
1615 .file("src/lib.rs", "")
1616 .file(
1617 "build.rs",
1618 "
1619 #[allow(unused_extern_crates)]
1620 extern crate a;
1621 fn main() {}
1622 ",
1623 )
1624 .file("a/Cargo.toml", &basic_manifest("a", "0.5.0"))
1625 .file("a/src/lib.rs", "")
1626 .build();
1627
1628 p.cargo("build -v")
1629 .with_stderr(
1630 "\
1631[COMPILING] a v0.5.0 ([CWD]/a)
1632[RUNNING] `rustc --crate-name a [..]`
1633[COMPILING] foo v0.5.0 ([CWD])
1634[RUNNING] `rustc [..] build.rs [..] --extern a=[..]`
1635[RUNNING] `[..]/foo-[..]/build-script-build`
1636[RUNNING] `rustc --crate-name foo [..]`
1637[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
1638",
1639 )
1640 .run();
1641}
1642
1643#[cargo_test]
1644fn build_deps_not_for_normal() {
1645 let target = rustc_host();
1646 let p = project()
1647 .file(
1648 "Cargo.toml",
1649 r#"
1650 [package]
1651 name = "foo"
1652 version = "0.5.0"
1653 authors = []
1654 build = "build.rs"
1655 [build-dependencies.aaaaa]
1656 path = "a"
1657 "#,
1658 )
1659 .file(
1660 "src/lib.rs",
1661 "#[allow(unused_extern_crates)] extern crate aaaaa;",
1662 )
1663 .file(
1664 "build.rs",
1665 "
1666 #[allow(unused_extern_crates)]
1667 extern crate aaaaa;
1668 fn main() {}
1669 ",
1670 )
1671 .file("a/Cargo.toml", &basic_manifest("aaaaa", "0.5.0"))
1672 .file("a/src/lib.rs", "")
1673 .build();
1674
1675 p.cargo("build -v --target")
1676 .arg(&target)
1677 .with_status(101)
1678 .with_stderr_contains("[..]can't find crate for `aaaaa`[..]")
1679 .with_stderr_contains(
1680 "\
1681[ERROR] could not compile `foo` (lib) due to previous error
1682
1683Caused by:
1684 process didn't exit successfully: [..]
1685",
1686 )
1687 .run();
1688}
1689
1690#[cargo_test]
1691fn build_cmd_with_a_build_cmd() {
1692 let p = project()
1693 .file(
1694 "Cargo.toml",
1695 r#"
1696 [package]
1697 name = "foo"
1698 version = "0.5.0"
1699 authors = []
1700 build = "build.rs"
1701
1702 [build-dependencies.a]
1703 path = "a"
1704 "#,
1705 )
1706 .file("src/lib.rs", "")
1707 .file(
1708 "build.rs",
1709 "
1710 #[allow(unused_extern_crates)]
1711 extern crate a;
1712 fn main() {}
1713 ",
1714 )
1715 .file(
1716 "a/Cargo.toml",
1717 r#"
1718 [package]
1719 name = "a"
1720 version = "0.5.0"
1721 authors = []
1722 build = "build.rs"
1723
1724 [build-dependencies.b]
1725 path = "../b"
1726 "#,
1727 )
1728 .file("a/src/lib.rs", "")
1729 .file(
1730 "a/build.rs",
1731 "#[allow(unused_extern_crates)] extern crate b; fn main() {}",
1732 )
1733 .file("b/Cargo.toml", &basic_manifest("b", "0.5.0"))
1734 .file("b/src/lib.rs", "")
1735 .build();
1736
1737 p.cargo("build -v")
1738 .with_stderr(
1739 "\
1740[COMPILING] b v0.5.0 ([CWD]/b)
1741[RUNNING] `rustc --crate-name b [..]`
1742[COMPILING] a v0.5.0 ([CWD]/a)
1743[RUNNING] `rustc [..] a/build.rs [..] --extern b=[..]`
1744[RUNNING] `[..]/a-[..]/build-script-build`
1745[RUNNING] `rustc --crate-name a [..]lib.rs [..]--crate-type lib \
1746 --emit=[..]link[..] \
1747 -C metadata=[..] \
1748 --out-dir [..]target/debug/deps \
1749 -L [..]target/debug/deps`
1750[COMPILING] foo v0.5.0 ([CWD])
1751[RUNNING] `rustc --crate-name build_script_build build.rs [..]--crate-type bin \
1752 --emit=[..]link[..]\
1753 -C metadata=[..] --out-dir [..] \
1754 -L [..]target/debug/deps \
1755 --extern a=[..]liba[..].rlib`
1756[RUNNING] `[..]/foo-[..]/build-script-build`
1757[RUNNING] `rustc --crate-name foo [..]lib.rs [..]--crate-type lib \
fe692bf9 1758 --emit=[..]link[..]-C debuginfo=2 [..]\
0a29b90c
FG
1759 -C metadata=[..] \
1760 --out-dir [..] \
1761 -L [..]target/debug/deps`
1762[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
1763",
1764 )
1765 .run();
1766}
1767
1768#[cargo_test]
1769fn out_dir_is_preserved() {
1770 let p = project()
1771 .file(
1772 "Cargo.toml",
1773 r#"
1774 [package]
1775 name = "foo"
1776 version = "0.5.0"
1777 authors = []
1778 build = "build.rs"
1779 "#,
1780 )
1781 .file("src/lib.rs", "")
1782 .file(
1783 "build.rs",
1784 r#"
1785 use std::env;
1786 use std::fs::File;
1787 use std::path::Path;
1788 fn main() {
1789 let out = env::var("OUT_DIR").unwrap();
1790 File::create(Path::new(&out).join("foo")).unwrap();
1791 }
1792 "#,
1793 )
1794 .build();
1795
1796 // Make the file
1797 p.cargo("build -v").run();
1798
1799 // Change to asserting that it's there
1800 p.change_file(
1801 "build.rs",
1802 r#"
1803 use std::env;
1804 use std::fs::File;
1805 use std::path::Path;
1806 fn main() {
1807 let out = env::var("OUT_DIR").unwrap();
1808 File::open(&Path::new(&out).join("foo")).unwrap();
1809 }
1810 "#,
1811 );
1812 p.cargo("build -v")
1813 .with_stderr(
1814 "\
1815[DIRTY] foo [..]: the file `build.rs` has changed ([..])
1816[COMPILING] foo [..]
1817[RUNNING] `rustc --crate-name build_script_build [..]
1818[RUNNING] `[..]/build-script-build`
1819[RUNNING] `rustc --crate-name foo [..]
1820[FINISHED] [..]
1821",
1822 )
1823 .run();
1824
1825 // Run a fresh build where file should be preserved
1826 p.cargo("build -v")
1827 .with_stderr(
1828 "\
1829[FRESH] foo [..]
1830[FINISHED] [..]
1831",
1832 )
1833 .run();
1834
1835 // One last time to make sure it's still there.
1836 p.change_file("foo", "");
1837 p.cargo("build -v")
1838 .with_stderr(
1839 "\
1840[DIRTY] foo [..]: the precalculated components changed
1841[COMPILING] foo [..]
1842[RUNNING] `[..]build-script-build`
1843[RUNNING] `rustc --crate-name foo [..]
1844[FINISHED] [..]
1845",
1846 )
1847 .run();
1848}
1849
1850#[cargo_test]
1851fn output_separate_lines() {
1852 let p = project()
1853 .file(
1854 "Cargo.toml",
1855 r#"
1856 [package]
1857 name = "foo"
1858 version = "0.5.0"
1859 authors = []
1860 build = "build.rs"
1861 "#,
1862 )
1863 .file("src/lib.rs", "")
1864 .file(
1865 "build.rs",
1866 r#"
1867 fn main() {
1868 println!("cargo:rustc-flags=-L foo");
1869 println!("cargo:rustc-flags=-l static=foo");
1870 }
1871 "#,
1872 )
1873 .build();
1874 p.cargo("build -v")
1875 .with_status(101)
1876 .with_stderr_contains(
1877 "\
1878[COMPILING] foo v0.5.0 ([CWD])
1879[RUNNING] `rustc [..] build.rs [..]`
1880[RUNNING] `[..]/foo-[..]/build-script-build`
1881[RUNNING] `rustc --crate-name foo [..] -L foo -l static=foo`
1882[ERROR] could not find native static library [..]
1883",
1884 )
1885 .run();
1886}
1887
1888#[cargo_test]
1889fn output_separate_lines_new() {
1890 let p = project()
1891 .file(
1892 "Cargo.toml",
1893 r#"
1894 [package]
1895 name = "foo"
1896 version = "0.5.0"
1897 authors = []
1898 build = "build.rs"
1899 "#,
1900 )
1901 .file("src/lib.rs", "")
1902 .file(
1903 "build.rs",
1904 r#"
1905 fn main() {
1906 println!("cargo:rustc-link-search=foo");
1907 println!("cargo:rustc-link-lib=static=foo");
1908 println!("cargo:rustc-link-lib=bar");
1909 println!("cargo:rustc-link-search=bar");
1910 }
1911 "#,
1912 )
1913 .build();
1914 // The order of the arguments passed to rustc is important.
1915 p.cargo("build -v")
1916 .with_status(101)
1917 .with_stderr_contains(
1918 "\
1919[COMPILING] foo v0.5.0 ([CWD])
1920[RUNNING] `rustc [..] build.rs [..]`
1921[RUNNING] `[..]/foo-[..]/build-script-build`
1922[RUNNING] `rustc --crate-name foo [..] -L foo -L bar -l static=foo -l bar`
1923[ERROR] could not find native static library [..]
1924",
1925 )
1926 .run();
1927}
1928
0a29b90c
FG
1929#[cargo_test]
1930fn code_generation() {
1931 let p = project()
1932 .file(
1933 "Cargo.toml",
1934 r#"
1935 [package]
1936 name = "foo"
1937 version = "0.5.0"
1938 authors = []
1939 build = "build.rs"
1940 "#,
1941 )
1942 .file(
1943 "src/main.rs",
1944 r#"
1945 include!(concat!(env!("OUT_DIR"), "/hello.rs"));
1946
1947 fn main() {
1948 println!("{}", message());
1949 }
1950 "#,
1951 )
1952 .file(
1953 "build.rs",
1954 r#"
1955 use std::env;
1956 use std::fs;
1957 use std::path::PathBuf;
1958
1959 fn main() {
1960 let dst = PathBuf::from(env::var("OUT_DIR").unwrap());
1961 fs::write(dst.join("hello.rs"),
1962 "
1963 pub fn message() -> &'static str {
1964 \"Hello, World!\"
1965 }
1966 ")
1967 .unwrap();
1968 }
1969 "#,
1970 )
1971 .build();
1972
1973 p.cargo("run")
1974 .with_stderr(
1975 "\
1976[COMPILING] foo v0.5.0 ([CWD])
1977[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
fe692bf9 1978[RUNNING] `target/debug/foo[EXE]`",
0a29b90c
FG
1979 )
1980 .with_stdout("Hello, World!")
1981 .run();
1982
1983 p.cargo("test").run();
1984}
1985
1986#[cargo_test]
1987fn release_with_build_script() {
1988 let p = project()
1989 .file(
1990 "Cargo.toml",
1991 r#"
1992 [package]
1993 name = "foo"
1994 version = "0.5.0"
1995 authors = []
1996 build = "build.rs"
1997 "#,
1998 )
1999 .file("src/lib.rs", "")
2000 .file(
2001 "build.rs",
2002 r#"
2003 fn main() {}
2004 "#,
2005 )
2006 .build();
2007
2008 p.cargo("build -v --release").run();
2009}
2010
2011#[cargo_test]
2012fn build_script_only() {
2013 let p = project()
2014 .file(
2015 "Cargo.toml",
2016 r#"
2017 [package]
2018 name = "foo"
2019 version = "0.0.0"
2020 authors = []
2021 build = "build.rs"
2022 "#,
2023 )
2024 .file("build.rs", r#"fn main() {}"#)
2025 .build();
2026 p.cargo("build -v")
2027 .with_status(101)
2028 .with_stderr(
2029 "\
2030[ERROR] failed to parse manifest at `[..]`
2031
2032Caused by:
2033 no targets specified in the manifest
2034 either src/lib.rs, src/main.rs, a [lib] section, or [[bin]] section must be present",
2035 )
2036 .run();
2037}
2038
2039#[cargo_test]
2040fn shared_dep_with_a_build_script() {
2041 let p = project()
2042 .file(
2043 "Cargo.toml",
2044 r#"
2045 [package]
2046 name = "foo"
2047 version = "0.5.0"
2048 authors = []
2049 build = "build.rs"
2050
2051 [dependencies.a]
2052 path = "a"
2053
2054 [build-dependencies.b]
2055 path = "b"
2056 "#,
2057 )
2058 .file("src/lib.rs", "")
2059 .file("build.rs", "fn main() {}")
2060 .file(
2061 "a/Cargo.toml",
2062 r#"
2063 [package]
2064 name = "a"
2065 version = "0.5.0"
2066 authors = []
2067 build = "build.rs"
2068 "#,
2069 )
2070 .file("a/build.rs", "fn main() {}")
2071 .file("a/src/lib.rs", "")
2072 .file(
2073 "b/Cargo.toml",
2074 r#"
2075 [package]
2076 name = "b"
2077 version = "0.5.0"
2078 authors = []
2079
2080 [dependencies.a]
2081 path = "../a"
2082 "#,
2083 )
2084 .file("b/src/lib.rs", "")
2085 .build();
2086 p.cargo("build -v").run();
2087}
2088
2089#[cargo_test]
2090fn transitive_dep_host() {
2091 let p = project()
2092 .file(
2093 "Cargo.toml",
2094 r#"
2095 [package]
2096 name = "foo"
2097 version = "0.5.0"
2098 authors = []
2099 build = "build.rs"
2100
2101 [build-dependencies.b]
2102 path = "b"
2103 "#,
2104 )
2105 .file("src/lib.rs", "")
2106 .file("build.rs", "fn main() {}")
2107 .file(
2108 "a/Cargo.toml",
2109 r#"
2110 [package]
2111 name = "a"
2112 version = "0.5.0"
2113 authors = []
2114 links = "foo"
2115 build = "build.rs"
2116 "#,
2117 )
2118 .file("a/build.rs", "fn main() {}")
2119 .file("a/src/lib.rs", "")
2120 .file(
2121 "b/Cargo.toml",
2122 r#"
2123 [package]
2124 name = "b"
2125 version = "0.5.0"
2126 authors = []
2127
2128 [lib]
2129 name = "b"
2130 plugin = true
2131
2132 [dependencies.a]
2133 path = "../a"
2134 "#,
2135 )
2136 .file("b/src/lib.rs", "")
2137 .build();
2138 p.cargo("build").run();
2139}
2140
2141#[cargo_test]
2142fn test_a_lib_with_a_build_command() {
2143 let p = project()
2144 .file(
2145 "Cargo.toml",
2146 r#"
2147 [package]
2148 name = "foo"
2149 version = "0.5.0"
2150 authors = []
2151 build = "build.rs"
2152 "#,
2153 )
2154 .file(
2155 "src/lib.rs",
2156 r#"
2157 include!(concat!(env!("OUT_DIR"), "/foo.rs"));
2158
2159 /// ```
2160 /// foo::bar();
2161 /// ```
2162 pub fn bar() {
2163 assert_eq!(foo(), 1);
2164 }
2165 "#,
2166 )
2167 .file(
2168 "build.rs",
2169 r#"
2170 use std::env;
2171 use std::fs;
2172 use std::path::PathBuf;
2173
2174 fn main() {
2175 let out = PathBuf::from(env::var("OUT_DIR").unwrap());
2176 fs::write(out.join("foo.rs"), "fn foo() -> i32 { 1 }").unwrap();
2177 }
2178 "#,
2179 )
2180 .build();
2181 p.cargo("test").run();
2182}
2183
2184#[cargo_test]
2185fn test_dev_dep_build_script() {
2186 let p = project()
2187 .file(
2188 "Cargo.toml",
2189 r#"
2190 [package]
2191 name = "foo"
2192 version = "0.5.0"
2193 authors = []
2194
2195 [dev-dependencies.a]
2196 path = "a"
2197 "#,
2198 )
2199 .file("src/lib.rs", "")
2200 .file(
2201 "a/Cargo.toml",
2202 r#"
2203 [package]
2204 name = "a"
2205 version = "0.5.0"
2206 authors = []
2207 build = "build.rs"
2208 "#,
2209 )
2210 .file("a/build.rs", "fn main() {}")
2211 .file("a/src/lib.rs", "")
2212 .build();
2213
2214 p.cargo("test").run();
2215}
2216
2217#[cargo_test]
2218fn build_script_with_dynamic_native_dependency() {
2219 let build = project()
2220 .at("builder")
2221 .file(
2222 "Cargo.toml",
2223 r#"
2224 [package]
2225 name = "builder"
2226 version = "0.0.1"
2227 authors = []
2228
2229 [lib]
2230 name = "builder"
2231 crate-type = ["dylib"]
2232 "#,
2233 )
2234 .file("src/lib.rs", "#[no_mangle] pub extern fn foo() {}")
2235 .build();
2236
2237 let foo = project()
2238 .file(
2239 "Cargo.toml",
2240 r#"
2241 [package]
2242 name = "foo"
2243 version = "0.0.1"
2244 authors = []
2245 build = "build.rs"
2246
2247 [build-dependencies.bar]
2248 path = "bar"
2249 "#,
2250 )
2251 .file("build.rs", "extern crate bar; fn main() { bar::bar() }")
2252 .file("src/lib.rs", "")
2253 .file(
2254 "bar/Cargo.toml",
2255 r#"
2256 [package]
2257 name = "bar"
2258 version = "0.0.1"
2259 authors = []
2260 build = "build.rs"
2261 "#,
2262 )
2263 .file(
2264 "bar/build.rs",
2265 r#"
2266 use std::env;
2267 use std::fs;
2268 use std::path::PathBuf;
2269
2270 fn main() {
2271 let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
2272 let root = PathBuf::from(env::var("BUILDER_ROOT").unwrap());
2273 let file = format!("{}builder{}",
2274 env::consts::DLL_PREFIX,
2275 env::consts::DLL_SUFFIX);
2276 let src = root.join(&file);
2277 let dst = out_dir.join(&file);
2278 fs::copy(src, dst).unwrap();
2279 if cfg!(target_env = "msvc") {
2280 fs::copy(root.join("builder.dll.lib"),
2281 out_dir.join("builder.dll.lib")).unwrap();
2282 }
2283 println!("cargo:rustc-link-search=native={}", out_dir.display());
2284 }
2285 "#,
2286 )
2287 .file(
2288 "bar/src/lib.rs",
2289 r#"
2290 pub fn bar() {
2291 #[cfg_attr(not(target_env = "msvc"), link(name = "builder"))]
2292 #[cfg_attr(target_env = "msvc", link(name = "builder.dll"))]
2293 extern { fn foo(); }
2294 unsafe { foo() }
2295 }
2296 "#,
2297 )
2298 .build();
2299
2300 build
2301 .cargo("build -v")
2302 .env("CARGO_LOG", "cargo::ops::cargo_rustc")
2303 .run();
2304
2305 let root = build.root().join("target").join("debug");
2306 foo.cargo("build -v")
2307 .env("BUILDER_ROOT", root)
2308 .env("CARGO_LOG", "cargo::ops::cargo_rustc")
2309 .run();
2310}
2311
2312#[cargo_test]
2313fn profile_and_opt_level_set_correctly() {
2314 let p = project()
2315 .file(
2316 "Cargo.toml",
2317 r#"
2318 [package]
2319 name = "foo"
2320 version = "0.0.1"
2321 authors = []
2322 build = "build.rs"
2323 "#,
2324 )
2325 .file("src/lib.rs", "")
2326 .file(
2327 "build.rs",
2328 r#"
2329 use std::env;
2330
2331 fn main() {
2332 assert_eq!(env::var("OPT_LEVEL").unwrap(), "3");
2333 assert_eq!(env::var("PROFILE").unwrap(), "release");
2334 assert_eq!(env::var("DEBUG").unwrap(), "false");
2335 }
2336 "#,
2337 )
2338 .build();
2339 p.cargo("bench").run();
2340}
2341
2342#[cargo_test]
2343fn profile_debug_0() {
2344 let p = project()
2345 .file(
2346 "Cargo.toml",
2347 r#"
2348 [package]
2349 name = "foo"
2350 version = "0.0.1"
2351
2352 [profile.dev]
2353 debug = 0
2354 "#,
2355 )
2356 .file("src/lib.rs", "")
2357 .file(
2358 "build.rs",
2359 r#"
2360 use std::env;
2361
2362 fn main() {
2363 assert_eq!(env::var("OPT_LEVEL").unwrap(), "0");
2364 assert_eq!(env::var("PROFILE").unwrap(), "debug");
2365 assert_eq!(env::var("DEBUG").unwrap(), "false");
2366 }
2367 "#,
2368 )
2369 .build();
2370 p.cargo("build").run();
2371}
2372
2373#[cargo_test]
2374fn build_script_with_lto() {
2375 let p = project()
2376 .file(
2377 "Cargo.toml",
2378 r#"
2379 [package]
2380 name = "foo"
2381 version = "0.0.1"
2382 authors = []
2383 build = "build.rs"
2384
2385 [profile.dev]
2386 lto = true
2387 "#,
2388 )
2389 .file("src/lib.rs", "")
2390 .file("build.rs", "fn main() {}")
2391 .build();
2392 p.cargo("build").run();
2393}
2394
2395#[cargo_test]
2396fn test_duplicate_deps() {
2397 let p = project()
2398 .file(
2399 "Cargo.toml",
2400 r#"
2401 [package]
2402 name = "foo"
2403 version = "0.1.0"
2404 authors = []
2405 build = "build.rs"
2406
2407 [dependencies.bar]
2408 path = "bar"
2409
2410 [build-dependencies.bar]
2411 path = "bar"
2412 "#,
2413 )
2414 .file(
2415 "src/main.rs",
2416 r#"
2417 extern crate bar;
2418 fn main() { bar::do_nothing() }
2419 "#,
2420 )
2421 .file(
2422 "build.rs",
2423 r#"
2424 extern crate bar;
2425 fn main() { bar::do_nothing() }
2426 "#,
2427 )
2428 .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
2429 .file("bar/src/lib.rs", "pub fn do_nothing() {}")
2430 .build();
2431
2432 p.cargo("build").run();
2433}
2434
2435#[cargo_test]
2436fn cfg_feedback() {
2437 let p = project()
2438 .file(
2439 "Cargo.toml",
2440 r#"
2441 [package]
2442 name = "foo"
2443 version = "0.0.1"
2444 authors = []
2445 build = "build.rs"
2446 "#,
2447 )
2448 .file("src/main.rs", "#[cfg(foo)] fn main() {}")
2449 .file(
2450 "build.rs",
2451 r#"fn main() { println!("cargo:rustc-cfg=foo"); }"#,
2452 )
2453 .build();
2454 p.cargo("build -v").run();
2455}
2456
2457#[cargo_test]
2458fn cfg_override() {
2459 let target = rustc_host();
2460
2461 let p = project()
2462 .file(
2463 "Cargo.toml",
2464 r#"
2465 [package]
2466 name = "foo"
2467 version = "0.5.0"
2468 authors = []
2469 links = "a"
2470 build = "build.rs"
2471 "#,
2472 )
2473 .file("src/main.rs", "#[cfg(foo)] fn main() {}")
2474 .file("build.rs", "")
2475 .file(
2476 ".cargo/config",
2477 &format!(
2478 r#"
2479 [target.{}.a]
2480 rustc-cfg = ["foo"]
2481 "#,
2482 target
2483 ),
2484 )
2485 .build();
2486
2487 p.cargo("build -v").run();
2488}
2489
2490#[cargo_test]
2491fn cfg_test() {
2492 let p = project()
2493 .file(
2494 "Cargo.toml",
2495 r#"
2496 [package]
2497 name = "foo"
2498 version = "0.0.1"
2499 authors = []
2500 build = "build.rs"
2501 "#,
2502 )
2503 .file(
2504 "build.rs",
2505 r#"fn main() { println!("cargo:rustc-cfg=foo"); }"#,
2506 )
2507 .file(
2508 "src/lib.rs",
2509 r#"
2510 ///
2511 /// ```
2512 /// extern crate foo;
2513 ///
2514 /// fn main() {
2515 /// foo::foo()
2516 /// }
2517 /// ```
2518 ///
2519 #[cfg(foo)]
2520 pub fn foo() {}
2521
2522 #[cfg(foo)]
2523 #[test]
2524 fn test_foo() {
2525 foo()
2526 }
2527 "#,
2528 )
2529 .file("tests/test.rs", "#[cfg(foo)] #[test] fn test_bar() {}")
2530 .build();
2531 p.cargo("test -v")
2532 .with_stderr(
2533 "\
2534[COMPILING] foo v0.0.1 ([CWD])
2535[RUNNING] [..] build.rs [..]
2536[RUNNING] `[..]/build-script-build`
2537[RUNNING] [..] --cfg foo[..]
2538[RUNNING] [..] --cfg foo[..]
2539[RUNNING] [..] --cfg foo[..]
2540[FINISHED] test [unoptimized + debuginfo] target(s) in [..]
2541[RUNNING] `[..]/foo-[..][EXE]`
2542[RUNNING] `[..]/test-[..][EXE]`
2543[DOCTEST] foo
2544[RUNNING] [..] --cfg foo[..]",
2545 )
2546 .with_stdout_contains("test test_foo ... ok")
2547 .with_stdout_contains("test test_bar ... ok")
2548 .with_stdout_contains_n("test [..] ... ok", 3)
2549 .run();
2550}
2551
2552#[cargo_test]
2553fn cfg_doc() {
2554 let p = project()
2555 .file(
2556 "Cargo.toml",
2557 r#"
2558 [package]
2559 name = "foo"
2560 version = "0.0.1"
2561 authors = []
2562 build = "build.rs"
2563
2564 [dependencies.bar]
2565 path = "bar"
2566 "#,
2567 )
2568 .file(
2569 "build.rs",
2570 r#"fn main() { println!("cargo:rustc-cfg=foo"); }"#,
2571 )
2572 .file("src/lib.rs", "#[cfg(foo)] pub fn foo() {}")
2573 .file(
2574 "bar/Cargo.toml",
2575 r#"
2576 [package]
2577 name = "bar"
2578 version = "0.0.1"
2579 authors = []
2580 build = "build.rs"
2581 "#,
2582 )
2583 .file(
2584 "bar/build.rs",
2585 r#"fn main() { println!("cargo:rustc-cfg=bar"); }"#,
2586 )
2587 .file("bar/src/lib.rs", "#[cfg(bar)] pub fn bar() {}")
2588 .build();
2589 p.cargo("doc").run();
2590 assert!(p.root().join("target/doc").is_dir());
2591 assert!(p.root().join("target/doc/foo/fn.foo.html").is_file());
2592 assert!(p.root().join("target/doc/bar/fn.bar.html").is_file());
2593}
2594
2595#[cargo_test]
2596fn cfg_override_test() {
2597 let p = project()
2598 .file(
2599 "Cargo.toml",
2600 r#"
2601 [package]
2602 name = "foo"
2603 version = "0.0.1"
2604 authors = []
2605 build = "build.rs"
2606 links = "a"
2607 "#,
2608 )
2609 .file("build.rs", "")
2610 .file(
2611 ".cargo/config",
2612 &format!(
2613 r#"
2614 [target.{}.a]
2615 rustc-cfg = ["foo"]
2616 "#,
2617 rustc_host()
2618 ),
2619 )
2620 .file(
2621 "src/lib.rs",
2622 r#"
2623 ///
2624 /// ```
2625 /// extern crate foo;
2626 ///
2627 /// fn main() {
2628 /// foo::foo()
2629 /// }
2630 /// ```
2631 ///
2632 #[cfg(foo)]
2633 pub fn foo() {}
2634
2635 #[cfg(foo)]
2636 #[test]
2637 fn test_foo() {
2638 foo()
2639 }
2640 "#,
2641 )
2642 .file("tests/test.rs", "#[cfg(foo)] #[test] fn test_bar() {}")
2643 .build();
2644 p.cargo("test -v")
2645 .with_stderr(
2646 "\
2647[COMPILING] foo v0.0.1 ([CWD])
2648[RUNNING] `[..]`
2649[RUNNING] `[..]`
2650[RUNNING] `[..]`
2651[FINISHED] test [unoptimized + debuginfo] target(s) in [..]
2652[RUNNING] `[..]/foo-[..][EXE]`
2653[RUNNING] `[..]/test-[..][EXE]`
2654[DOCTEST] foo
2655[RUNNING] [..] --cfg foo[..]",
2656 )
2657 .with_stdout_contains("test test_foo ... ok")
2658 .with_stdout_contains("test test_bar ... ok")
2659 .with_stdout_contains_n("test [..] ... ok", 3)
2660 .run();
2661}
2662
2663#[cargo_test]
2664fn cfg_override_doc() {
2665 let p = project()
2666 .file(
2667 "Cargo.toml",
2668 r#"
2669 [package]
2670 name = "foo"
2671 version = "0.0.1"
2672 authors = []
2673 build = "build.rs"
2674 links = "a"
2675
2676 [dependencies.bar]
2677 path = "bar"
2678 "#,
2679 )
2680 .file(
2681 ".cargo/config",
2682 &format!(
2683 r#"
2684 [target.{target}.a]
2685 rustc-cfg = ["foo"]
2686 [target.{target}.b]
2687 rustc-cfg = ["bar"]
2688 "#,
2689 target = rustc_host()
2690 ),
2691 )
2692 .file("build.rs", "")
2693 .file("src/lib.rs", "#[cfg(foo)] pub fn foo() {}")
2694 .file(
2695 "bar/Cargo.toml",
2696 r#"
2697 [package]
2698 name = "bar"
2699 version = "0.0.1"
2700 authors = []
2701 build = "build.rs"
2702 links = "b"
2703 "#,
2704 )
2705 .file("bar/build.rs", "")
2706 .file("bar/src/lib.rs", "#[cfg(bar)] pub fn bar() {}")
2707 .build();
2708 p.cargo("doc").run();
2709 assert!(p.root().join("target/doc").is_dir());
2710 assert!(p.root().join("target/doc/foo/fn.foo.html").is_file());
2711 assert!(p.root().join("target/doc/bar/fn.bar.html").is_file());
2712}
2713
2714#[cargo_test]
2715fn env_build() {
2716 let p = project()
2717 .file(
2718 "Cargo.toml",
2719 r#"
2720 [package]
2721 name = "foo"
2722 version = "0.0.1"
2723 authors = []
2724 build = "build.rs"
2725 "#,
2726 )
2727 .file(
2728 "src/main.rs",
2729 r#"
2730 const FOO: &'static str = env!("FOO");
2731 fn main() {
2732 println!("{}", FOO);
2733 }
2734 "#,
2735 )
2736 .file(
2737 "build.rs",
2738 r#"fn main() { println!("cargo:rustc-env=FOO=foo"); }"#,
2739 )
2740 .build();
2741 p.cargo("build -v").run();
2742 p.cargo("run -v").with_stdout("foo\n").run();
2743}
2744
2745#[cargo_test]
2746fn env_test() {
2747 let p = project()
2748 .file(
2749 "Cargo.toml",
2750 r#"
2751 [package]
2752 name = "foo"
2753 version = "0.0.1"
2754 authors = []
2755 build = "build.rs"
2756 "#,
2757 )
2758 .file(
2759 "build.rs",
2760 r#"fn main() { println!("cargo:rustc-env=FOO=foo"); }"#,
2761 )
2762 .file(
2763 "src/lib.rs",
2764 r#"pub const FOO: &'static str = env!("FOO"); "#,
2765 )
2766 .file(
2767 "tests/test.rs",
2768 r#"
2769 extern crate foo;
2770
2771 #[test]
2772 fn test_foo() {
2773 assert_eq!("foo", foo::FOO);
2774 }
2775 "#,
2776 )
2777 .build();
2778 p.cargo("test -v")
2779 .with_stderr(
2780 "\
2781[COMPILING] foo v0.0.1 ([CWD])
2782[RUNNING] [..] build.rs [..]
2783[RUNNING] `[..]/build-script-build`
2784[RUNNING] [..] --crate-name foo[..]
2785[RUNNING] [..] --crate-name foo[..]
2786[RUNNING] [..] --crate-name test[..]
2787[FINISHED] test [unoptimized + debuginfo] target(s) in [..]
2788[RUNNING] `[..]/foo-[..][EXE]`
2789[RUNNING] `[..]/test-[..][EXE]`
2790[DOCTEST] foo
2791[RUNNING] [..] --crate-name foo[..]",
2792 )
2793 .with_stdout_contains_n("running 0 tests", 2)
2794 .with_stdout_contains("test test_foo ... ok")
2795 .run();
2796}
2797
2798#[cargo_test]
2799fn env_doc() {
2800 let p = project()
2801 .file(
2802 "Cargo.toml",
2803 r#"
2804 [package]
2805 name = "foo"
2806 version = "0.0.1"
2807 authors = []
2808 build = "build.rs"
2809 "#,
2810 )
2811 .file(
2812 "src/main.rs",
2813 r#"
2814 const FOO: &'static str = env!("FOO");
2815 fn main() {}
2816 "#,
2817 )
2818 .file(
2819 "build.rs",
2820 r#"fn main() { println!("cargo:rustc-env=FOO=foo"); }"#,
2821 )
2822 .build();
2823 p.cargo("doc -v").run();
2824}
2825
2826#[cargo_test]
2827fn flags_go_into_tests() {
2828 let p = project()
2829 .file(
2830 "Cargo.toml",
2831 r#"
2832 [package]
2833 name = "foo"
2834 version = "0.5.0"
2835 authors = []
2836
2837 [dependencies]
2838 b = { path = "b" }
2839 "#,
2840 )
2841 .file("src/lib.rs", "")
2842 .file("tests/foo.rs", "")
2843 .file(
2844 "b/Cargo.toml",
2845 r#"
2846 [package]
2847 name = "b"
2848 version = "0.5.0"
2849 authors = []
2850 [dependencies]
2851 a = { path = "../a" }
2852 "#,
2853 )
2854 .file("b/src/lib.rs", "")
2855 .file(
2856 "a/Cargo.toml",
2857 r#"
2858 [package]
2859 name = "a"
2860 version = "0.5.0"
2861 authors = []
2862 build = "build.rs"
2863 "#,
2864 )
2865 .file("a/src/lib.rs", "")
2866 .file(
2867 "a/build.rs",
2868 r#"
2869 fn main() {
2870 println!("cargo:rustc-link-search=test");
2871 }
2872 "#,
2873 )
2874 .build();
2875
2876 p.cargo("test -v --test=foo")
2877 .with_stderr(
2878 "\
2879[COMPILING] a v0.5.0 ([..]
2880[RUNNING] `rustc [..] a/build.rs [..]`
2881[RUNNING] `[..]/build-script-build`
2882[RUNNING] `rustc [..] a/src/lib.rs [..] -L test[..]`
2883[COMPILING] b v0.5.0 ([..]
2884[RUNNING] `rustc [..] b/src/lib.rs [..] -L test[..]`
2885[COMPILING] foo v0.5.0 ([..]
2886[RUNNING] `rustc [..] src/lib.rs [..] -L test[..]`
2887[RUNNING] `rustc [..] tests/foo.rs [..] -L test[..]`
2888[FINISHED] test [unoptimized + debuginfo] target(s) in [..]
2889[RUNNING] `[..]/foo-[..][EXE]`",
2890 )
2891 .with_stdout_contains("running 0 tests")
2892 .run();
2893
2894 p.cargo("test -v -pb --lib")
2895 .with_stderr(
2896 "\
2897[FRESH] a v0.5.0 ([..]
2898[COMPILING] b v0.5.0 ([..]
2899[RUNNING] `rustc [..] b/src/lib.rs [..] -L test[..]`
2900[FINISHED] test [unoptimized + debuginfo] target(s) in [..]
2901[RUNNING] `[..]/b-[..][EXE]`",
2902 )
2903 .with_stdout_contains("running 0 tests")
2904 .run();
2905}
2906
2907#[cargo_test]
2908fn diamond_passes_args_only_once() {
2909 let p = project()
2910 .file(
2911 "Cargo.toml",
2912 r#"
2913 [package]
2914 name = "foo"
2915 version = "0.5.0"
2916 authors = []
2917
2918 [dependencies]
2919 a = { path = "a" }
2920 b = { path = "b" }
2921 "#,
2922 )
2923 .file("src/lib.rs", "")
2924 .file("tests/foo.rs", "")
2925 .file(
2926 "a/Cargo.toml",
2927 r#"
2928 [package]
2929 name = "a"
2930 version = "0.5.0"
2931 authors = []
2932 [dependencies]
2933 b = { path = "../b" }
2934 c = { path = "../c" }
2935 "#,
2936 )
2937 .file("a/src/lib.rs", "")
2938 .file(
2939 "b/Cargo.toml",
2940 r#"
2941 [package]
2942 name = "b"
2943 version = "0.5.0"
2944 authors = []
2945 [dependencies]
2946 c = { path = "../c" }
2947 "#,
2948 )
2949 .file("b/src/lib.rs", "")
2950 .file(
2951 "c/Cargo.toml",
2952 r#"
2953 [package]
2954 name = "c"
2955 version = "0.5.0"
2956 authors = []
2957 build = "build.rs"
2958 "#,
2959 )
2960 .file(
2961 "c/build.rs",
2962 r#"
2963 fn main() {
2964 println!("cargo:rustc-link-search=native=test");
2965 }
2966 "#,
2967 )
2968 .file("c/src/lib.rs", "")
2969 .build();
2970
2971 p.cargo("build -v")
2972 .with_stderr(
2973 "\
2974[COMPILING] c v0.5.0 ([..]
2975[RUNNING] `rustc [..]`
2976[RUNNING] `[..]`
2977[RUNNING] `rustc [..]`
2978[COMPILING] b v0.5.0 ([..]
2979[RUNNING] `rustc [..]`
2980[COMPILING] a v0.5.0 ([..]
2981[RUNNING] `rustc [..]`
2982[COMPILING] foo v0.5.0 ([..]
2983[RUNNING] `[..]rmeta -L native=test`
2984[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
2985",
2986 )
2987 .run();
2988}
2989
2990#[cargo_test]
2991fn adding_an_override_invalidates() {
2992 let target = rustc_host();
2993 let p = project()
2994 .file(
2995 "Cargo.toml",
2996 r#"
2997 [package]
2998 name = "foo"
2999 version = "0.5.0"
3000 authors = []
3001 links = "foo"
3002 build = "build.rs"
3003 "#,
3004 )
3005 .file("src/lib.rs", "")
3006 .file(".cargo/config", "")
3007 .file(
3008 "build.rs",
3009 r#"
3010 fn main() {
3011 println!("cargo:rustc-link-search=native=foo");
3012 }
3013 "#,
3014 )
3015 .build();
3016
3017 p.cargo("build -v")
3018 .with_stderr(
3019 "\
3020[COMPILING] foo v0.5.0 ([..]
3021[RUNNING] `rustc [..]`
3022[RUNNING] `[..]`
3023[RUNNING] `rustc [..] -L native=foo`
3024[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
3025",
3026 )
3027 .run();
3028
3029 p.change_file(
3030 ".cargo/config",
3031 &format!(
3032 "
3033 [target.{}.foo]
3034 rustc-link-search = [\"native=bar\"]
3035 ",
3036 target
3037 ),
3038 );
3039
3040 p.cargo("build -v")
3041 .with_stderr(
3042 "\
3043[COMPILING] foo v0.5.0 ([..]
3044[RUNNING] `rustc [..] -L native=bar`
3045[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
3046",
3047 )
3048 .run();
3049}
3050
3051#[cargo_test]
3052fn changing_an_override_invalidates() {
3053 let target = rustc_host();
3054 let p = project()
3055 .file(
3056 "Cargo.toml",
3057 r#"
3058 [package]
3059 name = "foo"
3060 version = "0.5.0"
3061 authors = []
3062 links = "foo"
3063 build = "build.rs"
3064 "#,
3065 )
3066 .file("src/lib.rs", "")
3067 .file(
3068 ".cargo/config",
3069 &format!(
3070 "
3071 [target.{}.foo]
3072 rustc-link-search = [\"native=foo\"]
3073 ",
3074 target
3075 ),
3076 )
3077 .file("build.rs", "")
3078 .build();
3079
3080 p.cargo("build -v")
3081 .with_stderr(
3082 "\
3083[COMPILING] foo v0.5.0 ([..]
3084[RUNNING] `rustc [..] -L native=foo`
3085[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
3086",
3087 )
3088 .run();
3089
3090 p.change_file(
3091 ".cargo/config",
3092 &format!(
3093 "
3094 [target.{}.foo]
3095 rustc-link-search = [\"native=bar\"]
3096 ",
3097 target
3098 ),
3099 );
3100
3101 p.cargo("build -v")
3102 .with_stderr(
3103 "\
3104[DIRTY] foo v0.5.0 ([..]): the precalculated components changed
3105[COMPILING] foo v0.5.0 ([..]
3106[RUNNING] `rustc [..] -L native=bar`
3107[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
3108",
3109 )
3110 .run();
3111}
3112
3113#[cargo_test]
3114fn fresh_builds_possible_with_link_libs() {
3115 // The bug is non-deterministic. Sometimes you can get a fresh build
3116 let target = rustc_host();
3117 let p = project()
3118 .file(
3119 "Cargo.toml",
3120 r#"
3121 [package]
3122 name = "foo"
3123 version = "0.5.0"
3124 authors = []
3125 links = "nativefoo"
3126 build = "build.rs"
3127 "#,
3128 )
3129 .file("src/lib.rs", "")
3130 .file(
3131 ".cargo/config",
3132 &format!(
3133 "
3134 [target.{}.nativefoo]
3135 rustc-link-lib = [\"a\"]
3136 rustc-link-search = [\"./b\"]
3137 rustc-flags = \"-l z -L ./\"
3138 ",
3139 target
3140 ),
3141 )
3142 .file("build.rs", "")
3143 .build();
3144
3145 p.cargo("build -v")
3146 .with_stderr(
3147 "\
3148[COMPILING] foo v0.5.0 ([..]
3149[RUNNING] `rustc [..]`
3150[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
3151",
3152 )
3153 .run();
3154
3155 p.cargo("build -v")
3156 .with_stderr(
3157 "\
3158[FRESH] foo v0.5.0 ([..])
3159[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
3160",
3161 )
3162 .run();
3163}
3164
3165#[cargo_test]
3166fn fresh_builds_possible_with_multiple_metadata_overrides() {
3167 // The bug is non-deterministic. Sometimes you can get a fresh build
3168 let target = rustc_host();
3169 let p = project()
3170 .file(
3171 "Cargo.toml",
3172 r#"
3173 [package]
3174 name = "foo"
3175 version = "0.5.0"
3176 authors = []
3177 links = "foo"
3178 build = "build.rs"
3179 "#,
3180 )
3181 .file("src/lib.rs", "")
3182 .file(
3183 ".cargo/config",
3184 &format!(
3185 "
3186 [target.{}.foo]
3187 a = \"\"
3188 b = \"\"
3189 c = \"\"
3190 d = \"\"
3191 e = \"\"
3192 ",
3193 target
3194 ),
3195 )
3196 .file("build.rs", "")
3197 .build();
3198
3199 p.cargo("build -v")
3200 .with_stderr(
3201 "\
3202[COMPILING] foo v0.5.0 ([..]
3203[RUNNING] `rustc [..]`
3204[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
3205",
3206 )
3207 .run();
3208
3209 p.cargo("build -v")
3210 .env("CARGO_LOG", "cargo::ops::cargo_rustc::fingerprint=info")
3211 .with_stderr(
3212 "\
3213[FRESH] foo v0.5.0 ([..])
3214[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
3215",
3216 )
3217 .run();
3218}
3219
3220#[cargo_test]
3221fn generate_good_d_files() {
3222 // this is here to stop regression on an issue where build.rs rerun-if-changed paths aren't
3223 // made absolute properly, which in turn interacts poorly with the dep-info-basedir setting,
3224 // and the dep-info files have other-crate-relative paths spat out in them
3225 let p = project()
3226 .file(
3227 "awoo/Cargo.toml",
3228 r#"
3229 [package]
3230 name = "awoo"
3231 version = "0.5.0"
3232 build = "build.rs"
3233 "#,
3234 )
3235 .file("awoo/src/lib.rs", "")
3236 .file(
3237 "awoo/build.rs",
3238 r#"
3239 fn main() {
3240 println!("cargo:rerun-if-changed=build.rs");
3241 println!("cargo:rerun-if-changed=barkbarkbark");
3242 }
3243 "#,
3244 )
3245 .file(
3246 "Cargo.toml",
3247 r#"
3248 [package]
3249 name = "meow"
3250 version = "0.5.0"
3251 [dependencies]
3252 awoo = { path = "awoo" }
3253 "#,
3254 )
3255 .file("src/main.rs", "fn main() {}")
3256 .build();
3257
3258 p.cargo("build -v").run();
3259
3260 let dot_d_path = p.bin("meow").with_extension("d");
3261 println!("*meow at* {:?}", dot_d_path);
3262 let dot_d = fs::read_to_string(&dot_d_path).unwrap();
3263
3264 println!("*.d file content*: {}", &dot_d);
3265
3266 assert_match_exact(
3267 "[..]/target/debug/meow[EXE]: [..]/awoo/barkbarkbark [..]/awoo/build.rs[..]",
3268 &dot_d,
3269 );
3270
3271 // paths relative to dependency roots should not be allowed
3272 assert!(!dot_d
3273 .split_whitespace()
3274 .any(|v| v == "barkbarkbark" || v == "build.rs"));
3275
3276 p.change_file(
3277 ".cargo/config.toml",
3278 r#"
3279 [build]
3280 dep-info-basedir="."
3281 "#,
3282 );
3283 p.cargo("build -v").run();
3284
3285 let dot_d = fs::read_to_string(&dot_d_path).unwrap();
3286
3287 println!("*.d file content with dep-info-basedir*: {}", &dot_d);
3288
3289 assert_match_exact(
3290 "target/debug/meow[EXE]: awoo/barkbarkbark awoo/build.rs[..]",
3291 &dot_d,
3292 );
3293
3294 // paths relative to dependency roots should not be allowed
3295 assert!(!dot_d
3296 .split_whitespace()
3297 .any(|v| v == "barkbarkbark" || v == "build.rs"));
3298}
3299
3300#[cargo_test]
3301fn generate_good_d_files_for_external_tools() {
3302 // This tests having a relative paths going out of the
3303 // project root in config's dep-info-basedir
3304 let p = project_in("rust_things")
3305 .file(
3306 "awoo/Cargo.toml",
3307 r#"
3308 [package]
3309 name = "awoo"
3310 version = "0.5.0"
3311 build = "build.rs"
3312 "#,
3313 )
3314 .file("awoo/src/lib.rs", "")
3315 .file(
3316 "awoo/build.rs",
3317 r#"
3318 fn main() {
3319 println!("cargo:rerun-if-changed=build.rs");
3320 println!("cargo:rerun-if-changed=barkbarkbark");
3321 }
3322 "#,
3323 )
3324 .file(
3325 "Cargo.toml",
3326 r#"
3327 [package]
3328 name = "meow"
3329 version = "0.5.0"
3330 [dependencies]
3331 awoo = { path = "awoo" }
3332 "#,
3333 )
3334 .file("src/main.rs", "fn main() {}")
3335 .file(
3336 ".cargo/config.toml",
3337 r#"
3338 [build]
3339 dep-info-basedir="../.."
3340 "#,
3341 )
3342 .build();
3343
3344 p.cargo("build -v").run();
3345
3346 let dot_d_path = p.bin("meow").with_extension("d");
3347 let dot_d = fs::read_to_string(&dot_d_path).unwrap();
3348
3349 println!("*.d file content with dep-info-basedir*: {}", &dot_d);
3350
3351 assert_match_exact(
3352 concat!(
3353 "rust_things/foo/target/debug/meow[EXE]:",
3354 " rust_things/foo/awoo/barkbarkbark",
3355 " rust_things/foo/awoo/build.rs",
3356 " rust_things/foo/awoo/src/lib.rs",
3357 " rust_things/foo/src/main.rs",
3358 ),
3359 &dot_d,
3360 );
3361}
3362
3363#[cargo_test]
3364fn rebuild_only_on_explicit_paths() {
3365 let p = project()
3366 .file(
3367 "Cargo.toml",
3368 r#"
3369 [package]
3370 name = "foo"
3371 version = "0.5.0"
3372 authors = []
3373 build = "build.rs"
3374 "#,
3375 )
3376 .file("src/lib.rs", "")
3377 .file(
3378 "build.rs",
3379 r#"
3380 fn main() {
3381 println!("cargo:rerun-if-changed=foo");
3382 println!("cargo:rerun-if-changed=bar");
3383 }
3384 "#,
3385 )
3386 .build();
3387
3388 p.cargo("build -v").run();
3389
3390 // files don't exist, so should always rerun if they don't exist
3391 println!("run without");
3392 p.cargo("build -v")
3393 .with_stderr(
3394 "\
3395[DIRTY] foo v0.5.0 ([..]): the file `foo` is missing
3396[COMPILING] foo v0.5.0 ([..])
3397[RUNNING] `[..]/build-script-build`
3398[RUNNING] `rustc [..] src/lib.rs [..]`
3399[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
3400",
3401 )
3402 .run();
3403
3404 sleep_ms(1000);
3405 p.change_file("foo", "");
3406 p.change_file("bar", "");
3407 sleep_ms(1000); // make sure the to-be-created outfile has a timestamp distinct from the infiles
3408
3409 // now the exist, so run once, catch the mtime, then shouldn't run again
3410 println!("run with");
3411 p.cargo("build -v")
3412 .with_stderr(
3413 "\
3414[DIRTY] foo v0.5.0 ([..]): the file `foo` has changed ([..])
3415[COMPILING] foo v0.5.0 ([..])
3416[RUNNING] `[..]/build-script-build`
3417[RUNNING] `rustc [..] src/lib.rs [..]`
3418[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
3419",
3420 )
3421 .run();
3422
3423 println!("run with2");
3424 p.cargo("build -v")
3425 .with_stderr(
3426 "\
3427[FRESH] foo v0.5.0 ([..])
3428[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
3429",
3430 )
3431 .run();
3432
3433 sleep_ms(1000);
3434
3435 // random other files do not affect freshness
3436 println!("run baz");
3437 p.change_file("baz", "");
3438 p.cargo("build -v")
3439 .with_stderr(
3440 "\
3441[FRESH] foo v0.5.0 ([..])
3442[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
3443",
3444 )
3445 .run();
3446
3447 // but changing dependent files does
3448 println!("run foo change");
3449 p.change_file("foo", "");
3450 p.cargo("build -v")
3451 .with_stderr(
3452 "\
3453[DIRTY] foo v0.5.0 ([..]): the file `foo` has changed ([..])
3454[COMPILING] foo v0.5.0 ([..])
3455[RUNNING] `[..]/build-script-build`
3456[RUNNING] `rustc [..] src/lib.rs [..]`
3457[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
3458",
3459 )
3460 .run();
3461
3462 // .. as does deleting a file
3463 println!("run bar delete");
3464 fs::remove_file(p.root().join("bar")).unwrap();
3465 p.cargo("build -v")
3466 .with_stderr(
3467 "\
3468[DIRTY] foo v0.5.0 ([..]): the file `bar` is missing
3469[COMPILING] foo v0.5.0 ([..])
3470[RUNNING] `[..]/build-script-build`
3471[RUNNING] `rustc [..] src/lib.rs [..]`
3472[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
3473",
3474 )
3475 .run();
3476}
3477
3478#[cargo_test]
3479fn doctest_receives_build_link_args() {
3480 let p = project()
3481 .file(
3482 "Cargo.toml",
3483 r#"
3484 [package]
3485 name = "foo"
3486 version = "0.5.0"
3487 authors = []
3488 [dependencies.a]
3489 path = "a"
3490 "#,
3491 )
3492 .file("src/lib.rs", "")
3493 .file(
3494 "a/Cargo.toml",
3495 r#"
3496 [package]
3497 name = "a"
3498 version = "0.5.0"
3499 authors = []
3500 links = "bar"
3501 build = "build.rs"
3502 "#,
3503 )
3504 .file("a/src/lib.rs", "")
3505 .file(
3506 "a/build.rs",
3507 r#"
3508 fn main() {
3509 println!("cargo:rustc-link-search=native=bar");
3510 }
3511 "#,
3512 )
3513 .build();
3514
3515 p.cargo("test -v")
3516 .with_stderr_contains(
3517 "[RUNNING] `rustdoc [..]--crate-name foo --test [..]-L native=bar[..]`",
3518 )
3519 .run();
3520}
3521
3522#[cargo_test]
3523fn please_respect_the_dag() {
3524 let p = project()
3525 .file(
3526 "Cargo.toml",
3527 r#"
3528 [package]
3529 name = "foo"
3530 version = "0.5.0"
3531 authors = []
3532 build = "build.rs"
3533
3534 [dependencies]
3535 a = { path = 'a' }
3536 "#,
3537 )
3538 .file("src/lib.rs", "")
3539 .file(
3540 "build.rs",
3541 r#"
3542 fn main() {
3543 println!("cargo:rustc-link-search=native=foo");
3544 }
3545 "#,
3546 )
3547 .file(
3548 "a/Cargo.toml",
3549 r#"
3550 [package]
3551 name = "a"
3552 version = "0.5.0"
3553 authors = []
3554 links = "bar"
3555 build = "build.rs"
3556 "#,
3557 )
3558 .file("a/src/lib.rs", "")
3559 .file(
3560 "a/build.rs",
3561 r#"
3562 fn main() {
3563 println!("cargo:rustc-link-search=native=bar");
3564 }
3565 "#,
3566 )
3567 .build();
3568
3569 p.cargo("build -v")
3570 .with_stderr_contains("[RUNNING] `rustc [..] -L native=foo -L native=bar[..]`")
3571 .run();
3572}
3573
3574#[cargo_test]
3575fn non_utf8_output() {
3576 let p = project()
3577 .file(
3578 "Cargo.toml",
3579 r#"
3580 [package]
3581 name = "foo"
3582 version = "0.5.0"
3583 authors = []
3584 build = "build.rs"
3585 "#,
3586 )
3587 .file(
3588 "build.rs",
3589 r#"
3590 use std::io::prelude::*;
3591
3592 fn main() {
3593 let mut out = std::io::stdout();
3594 // print something that's not utf8
3595 out.write_all(b"\xff\xff\n").unwrap();
3596
3597 // now print some cargo metadata that's utf8
3598 println!("cargo:rustc-cfg=foo");
3599
3600 // now print more non-utf8
3601 out.write_all(b"\xff\xff\n").unwrap();
3602 }
3603 "#,
3604 )
3605 .file("src/main.rs", "#[cfg(foo)] fn main() {}")
3606 .build();
3607
3608 p.cargo("build -v").run();
3609}
3610
3611#[cargo_test]
3612fn custom_target_dir() {
3613 let p = project()
3614 .file(
3615 "Cargo.toml",
3616 r#"
3617 [package]
3618 name = "foo"
3619 version = "0.5.0"
3620 authors = []
3621
3622 [dependencies]
3623 a = { path = "a" }
3624 "#,
3625 )
3626 .file("src/lib.rs", "")
3627 .file(
3628 ".cargo/config",
3629 r#"
3630 [build]
3631 target-dir = 'test'
3632 "#,
3633 )
3634 .file(
3635 "a/Cargo.toml",
3636 r#"
3637 [package]
3638 name = "a"
3639 version = "0.5.0"
3640 authors = []
3641 build = "build.rs"
3642 "#,
3643 )
3644 .file("a/build.rs", "fn main() {}")
3645 .file("a/src/lib.rs", "")
3646 .build();
3647
3648 p.cargo("build -v").run();
3649}
3650
3651#[cargo_test]
3652fn panic_abort_with_build_scripts() {
3653 let p = project()
3654 .file(
3655 "Cargo.toml",
3656 r#"
3657 [package]
3658 name = "foo"
3659 version = "0.5.0"
3660 authors = []
3661
3662 [profile.release]
3663 panic = 'abort'
3664
3665 [dependencies]
3666 a = { path = "a" }
3667 "#,
3668 )
3669 .file(
3670 "src/lib.rs",
3671 "#[allow(unused_extern_crates)] extern crate a;",
3672 )
3673 .file("build.rs", "fn main() {}")
3674 .file(
3675 "a/Cargo.toml",
3676 r#"
3677 [package]
3678 name = "a"
3679 version = "0.5.0"
3680 authors = []
3681 build = "build.rs"
3682
3683 [build-dependencies]
3684 b = { path = "../b" }
3685 "#,
3686 )
3687 .file("a/src/lib.rs", "")
3688 .file(
3689 "a/build.rs",
3690 "#[allow(unused_extern_crates)] extern crate b; fn main() {}",
3691 )
3692 .file(
3693 "b/Cargo.toml",
3694 r#"
3695 [package]
3696 name = "b"
3697 version = "0.5.0"
3698 authors = []
3699 "#,
3700 )
3701 .file("b/src/lib.rs", "")
3702 .build();
3703
3704 p.cargo("build -v --release").run();
3705
3706 p.root().join("target").rm_rf();
3707
3708 p.cargo("test --release -v")
3709 .with_stderr_does_not_contain("[..]panic=abort[..]")
3710 .run();
3711}
3712
3713#[cargo_test]
3714fn warnings_emitted() {
3715 let p = project()
3716 .file(
3717 "Cargo.toml",
3718 r#"
3719 [package]
3720 name = "foo"
3721 version = "0.5.0"
3722 authors = []
3723 build = "build.rs"
3724 "#,
3725 )
3726 .file("src/lib.rs", "")
3727 .file(
3728 "build.rs",
3729 r#"
3730 fn main() {
3731 println!("cargo:warning=foo");
3732 println!("cargo:warning=bar");
3733 }
3734 "#,
3735 )
3736 .build();
3737
3738 p.cargo("build -v")
3739 .with_stderr(
3740 "\
3741[COMPILING] foo v0.5.0 ([..])
3742[RUNNING] `rustc [..]`
3743[RUNNING] `[..]`
3744warning: foo
3745warning: bar
3746[RUNNING] `rustc [..]`
3747[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
3748",
3749 )
3750 .run();
3751}
3752
3753#[cargo_test]
3754fn warnings_emitted_when_build_script_panics() {
3755 let p = project()
3756 .file(
3757 "Cargo.toml",
3758 r#"
3759 [package]
3760 name = "foo"
3761 version = "0.5.0"
3762 authors = []
3763 build = "build.rs"
3764 "#,
3765 )
3766 .file("src/lib.rs", "")
3767 .file(
3768 "build.rs",
3769 r#"
3770 fn main() {
3771 println!("cargo:warning=foo");
3772 println!("cargo:warning=bar");
3773 panic!();
3774 }
3775 "#,
3776 )
3777 .build();
3778
3779 p.cargo("build")
3780 .with_status(101)
3781 .with_stdout("")
3782 .with_stderr_contains("warning: foo\nwarning: bar")
3783 .run();
3784}
3785
3786#[cargo_test]
3787fn warnings_hidden_for_upstream() {
3788 Package::new("bar", "0.1.0")
3789 .file(
3790 "build.rs",
3791 r#"
3792 fn main() {
3793 println!("cargo:warning=foo");
3794 println!("cargo:warning=bar");
3795 }
3796 "#,
3797 )
3798 .file(
3799 "Cargo.toml",
3800 r#"
3801 [package]
3802 name = "bar"
3803 version = "0.1.0"
3804 authors = []
3805 build = "build.rs"
3806 "#,
3807 )
3808 .file("src/lib.rs", "")
3809 .publish();
3810
3811 let p = project()
3812 .file(
3813 "Cargo.toml",
3814 r#"
3815 [package]
3816 name = "foo"
3817 version = "0.5.0"
3818 authors = []
3819
3820 [dependencies]
3821 bar = "*"
3822 "#,
3823 )
3824 .file("src/lib.rs", "")
3825 .build();
3826
3827 p.cargo("build -v")
3828 .with_stderr(
3829 "\
3830[UPDATING] `[..]` index
3831[DOWNLOADING] crates ...
3832[DOWNLOADED] bar v0.1.0 ([..])
3833[COMPILING] bar v0.1.0
3834[RUNNING] `rustc [..]`
3835[RUNNING] `[..]`
3836[RUNNING] `rustc [..]`
3837[COMPILING] foo v0.5.0 ([..])
3838[RUNNING] `rustc [..]`
3839[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
3840",
3841 )
3842 .run();
3843}
3844
3845#[cargo_test]
3846fn warnings_printed_on_vv() {
3847 Package::new("bar", "0.1.0")
3848 .file(
3849 "build.rs",
3850 r#"
3851 fn main() {
3852 println!("cargo:warning=foo");
3853 println!("cargo:warning=bar");
3854 }
3855 "#,
3856 )
3857 .file(
3858 "Cargo.toml",
3859 r#"
3860 [package]
3861 name = "bar"
3862 version = "0.1.0"
3863 authors = []
3864 build = "build.rs"
3865 "#,
3866 )
3867 .file("src/lib.rs", "")
3868 .publish();
3869
3870 let p = project()
3871 .file(
3872 "Cargo.toml",
3873 r#"
3874 [package]
3875 name = "foo"
3876 version = "0.5.0"
3877 authors = []
3878
3879 [dependencies]
3880 bar = "*"
3881 "#,
3882 )
3883 .file("src/lib.rs", "")
3884 .build();
3885
3886 p.cargo("build -vv")
3887 .with_stderr(
3888 "\
3889[UPDATING] `[..]` index
3890[DOWNLOADING] crates ...
3891[DOWNLOADED] bar v0.1.0 ([..])
3892[COMPILING] bar v0.1.0
3893[RUNNING] `[..] rustc [..]`
3894[RUNNING] `[..]`
3895warning: foo
3896warning: bar
3897[RUNNING] `[..] rustc [..]`
3898[COMPILING] foo v0.5.0 ([..])
3899[RUNNING] `[..] rustc [..]`
3900[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
3901",
3902 )
3903 .run();
3904}
3905
3906#[cargo_test]
3907fn output_shows_on_vv() {
3908 let p = project()
3909 .file(
3910 "Cargo.toml",
3911 r#"
3912 [package]
3913 name = "foo"
3914 version = "0.5.0"
3915 authors = []
3916 build = "build.rs"
3917 "#,
3918 )
3919 .file("src/lib.rs", "")
3920 .file(
3921 "build.rs",
3922 r#"
3923 use std::io::prelude::*;
3924
3925 fn main() {
3926 std::io::stderr().write_all(b"stderr\n").unwrap();
3927 std::io::stdout().write_all(b"stdout\n").unwrap();
3928 }
3929 "#,
3930 )
3931 .build();
3932
3933 p.cargo("build -vv")
3934 .with_stdout("[foo 0.5.0] stdout")
3935 .with_stderr(
3936 "\
3937[COMPILING] foo v0.5.0 ([..])
3938[RUNNING] `[..] rustc [..]`
3939[RUNNING] `[..]`
3940[foo 0.5.0] stderr
3941[RUNNING] `[..] rustc [..]`
3942[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
3943",
3944 )
3945 .run();
3946}
3947
3948#[cargo_test]
3949fn links_with_dots() {
3950 let target = rustc_host();
3951
3952 let p = project()
3953 .file(
3954 "Cargo.toml",
3955 r#"
3956 [package]
3957 name = "foo"
3958 version = "0.5.0"
3959 authors = []
3960 build = "build.rs"
3961 links = "a.b"
3962 "#,
3963 )
3964 .file("src/lib.rs", "")
3965 .file(
3966 "build.rs",
3967 r#"
3968 fn main() {
3969 println!("cargo:rustc-link-search=bar")
3970 }
3971 "#,
3972 )
3973 .file(
3974 ".cargo/config",
3975 &format!(
3976 r#"
3977 [target.{}.'a.b']
3978 rustc-link-search = ["foo"]
3979 "#,
3980 target
3981 ),
3982 )
3983 .build();
3984
3985 p.cargo("build -v")
3986 .with_stderr_contains("[RUNNING] `rustc --crate-name foo [..] [..] -L foo[..]`")
3987 .run();
3988}
3989
3990#[cargo_test]
3991fn rustc_and_rustdoc_set_correctly() {
3992 let p = project()
3993 .file(
3994 "Cargo.toml",
3995 r#"
3996 [package]
3997 name = "foo"
3998 version = "0.0.1"
3999 authors = []
4000 build = "build.rs"
4001 "#,
4002 )
4003 .file("src/lib.rs", "")
4004 .file(
4005 "build.rs",
4006 r#"
4007 use std::env;
4008
4009 fn main() {
4010 assert_eq!(env::var("RUSTC").unwrap(), "rustc");
4011 assert_eq!(env::var("RUSTDOC").unwrap(), "rustdoc");
4012 }
4013 "#,
4014 )
4015 .build();
4016 p.cargo("bench").run();
4017}
4018
4019#[cargo_test]
4020fn cfg_env_vars_available() {
4021 let p = project()
4022 .file(
4023 "Cargo.toml",
4024 r#"
4025 [package]
4026 name = "foo"
4027 version = "0.0.1"
4028 authors = []
4029 build = "build.rs"
4030 "#,
4031 )
4032 .file("src/lib.rs", "")
4033 .file(
4034 "build.rs",
4035 r#"
4036 use std::env;
4037
4038 fn main() {
4039 let fam = env::var("CARGO_CFG_TARGET_FAMILY").unwrap();
4040 if cfg!(unix) {
4041 assert_eq!(fam, "unix");
4042 } else {
4043 assert_eq!(fam, "windows");
4044 }
4045 }
4046 "#,
4047 )
4048 .build();
4049 p.cargo("bench").run();
4050}
4051
4052#[cargo_test]
4053fn switch_features_rerun() {
4054 let p = project()
4055 .file(
4056 "Cargo.toml",
4057 r#"
4058 [package]
4059 name = "foo"
4060 version = "0.0.1"
4061 authors = []
4062 build = "build.rs"
4063
4064 [features]
4065 foo = []
4066 "#,
4067 )
4068 .file(
4069 "src/main.rs",
4070 r#"
4071 fn main() {
4072 println!(include_str!(concat!(env!("OUT_DIR"), "/output")));
4073 }
4074 "#,
4075 )
4076 .file(
4077 "build.rs",
4078 r#"
4079 use std::env;
4080 use std::fs;
4081 use std::path::Path;
4082
4083 fn main() {
4084 let out_dir = env::var_os("OUT_DIR").unwrap();
4085 let output = Path::new(&out_dir).join("output");
4086
4087 if env::var_os("CARGO_FEATURE_FOO").is_some() {
4088 fs::write(output, "foo").unwrap();
4089 } else {
4090 fs::write(output, "bar").unwrap();
4091 }
4092 }
4093 "#,
4094 )
4095 .build();
4096
4097 p.cargo("build -v --features=foo").run();
4098 p.rename_run("foo", "with_foo").with_stdout("foo\n").run();
4099 p.cargo("build -v").run();
4100 p.rename_run("foo", "without_foo")
4101 .with_stdout("bar\n")
4102 .run();
4103 p.cargo("build -v --features=foo").run();
4104 p.rename_run("foo", "with_foo2").with_stdout("foo\n").run();
4105}
4106
4107#[cargo_test]
4108fn assume_build_script_when_build_rs_present() {
4109 let p = project()
4110 .file(
4111 "src/main.rs",
4112 r#"
4113 fn main() {
4114 if ! cfg!(foo) {
4115 panic!("the build script was not run");
4116 }
4117 }
4118 "#,
4119 )
4120 .file(
4121 "build.rs",
4122 r#"
4123 fn main() {
4124 println!("cargo:rustc-cfg=foo");
4125 }
4126 "#,
4127 )
4128 .build();
4129
4130 p.cargo("run -v").run();
4131}
4132
4133#[cargo_test]
4134fn if_build_set_to_false_dont_treat_build_rs_as_build_script() {
4135 let p = project()
4136 .file(
4137 "Cargo.toml",
4138 r#"
4139 [package]
4140 name = "foo"
4141 version = "0.0.1"
4142 authors = []
4143 build = false
4144 "#,
4145 )
4146 .file(
4147 "src/main.rs",
4148 r#"
4149 fn main() {
4150 if cfg!(foo) {
4151 panic!("the build script was run");
4152 }
4153 }
4154 "#,
4155 )
4156 .file(
4157 "build.rs",
4158 r#"
4159 fn main() {
4160 println!("cargo:rustc-cfg=foo");
4161 }
4162 "#,
4163 )
4164 .build();
4165
4166 p.cargo("run -v").run();
4167}
4168
4169#[cargo_test]
4170fn deterministic_rustc_dependency_flags() {
4171 // This bug is non-deterministic hence the large number of dependencies
4172 // in the hopes it will have a much higher chance of triggering it.
4173
4174 Package::new("dep1", "0.1.0")
4175 .file(
4176 "Cargo.toml",
4177 r#"
4178 [package]
4179 name = "dep1"
4180 version = "0.1.0"
4181 authors = []
4182 build = "build.rs"
4183 "#,
4184 )
4185 .file(
4186 "build.rs",
4187 r#"
4188 fn main() {
4189 println!("cargo:rustc-flags=-L native=test1");
4190 }
4191 "#,
4192 )
4193 .file("src/lib.rs", "")
4194 .publish();
4195 Package::new("dep2", "0.1.0")
4196 .file(
4197 "Cargo.toml",
4198 r#"
4199 [package]
4200 name = "dep2"
4201 version = "0.1.0"
4202 authors = []
4203 build = "build.rs"
4204 "#,
4205 )
4206 .file(
4207 "build.rs",
4208 r#"
4209 fn main() {
4210 println!("cargo:rustc-flags=-L native=test2");
4211 }
4212 "#,
4213 )
4214 .file("src/lib.rs", "")
4215 .publish();
4216 Package::new("dep3", "0.1.0")
4217 .file(
4218 "Cargo.toml",
4219 r#"
4220 [package]
4221 name = "dep3"
4222 version = "0.1.0"
4223 authors = []
4224 build = "build.rs"
4225 "#,
4226 )
4227 .file(
4228 "build.rs",
4229 r#"
4230 fn main() {
4231 println!("cargo:rustc-flags=-L native=test3");
4232 }
4233 "#,
4234 )
4235 .file("src/lib.rs", "")
4236 .publish();
4237 Package::new("dep4", "0.1.0")
4238 .file(
4239 "Cargo.toml",
4240 r#"
4241 [package]
4242 name = "dep4"
4243 version = "0.1.0"
4244 authors = []
4245 build = "build.rs"
4246 "#,
4247 )
4248 .file(
4249 "build.rs",
4250 r#"
4251 fn main() {
4252 println!("cargo:rustc-flags=-L native=test4");
4253 }
4254 "#,
4255 )
4256 .file("src/lib.rs", "")
4257 .publish();
4258
4259 let p = project()
4260 .file(
4261 "Cargo.toml",
4262 r#"
4263 [package]
4264 name = "foo"
4265 version = "0.1.0"
4266 authors = []
4267
4268 [dependencies]
4269 dep1 = "*"
4270 dep2 = "*"
4271 dep3 = "*"
4272 dep4 = "*"
4273 "#,
4274 )
4275 .file("src/main.rs", "fn main() {}")
4276 .build();
4277
4278 p.cargo("build -v")
4279 .with_stderr_contains(
4280 "\
4281[RUNNING] `rustc --crate-name foo [..] -L native=test1 -L native=test2 \
4282-L native=test3 -L native=test4`
4283",
4284 )
4285 .run();
4286}
4287
4288#[cargo_test]
4289fn links_duplicates_with_cycle() {
4290 // this tests that the links_duplicates are caught at resolver time
4291 let p = project()
4292 .file(
4293 "Cargo.toml",
4294 r#"
4295 [package]
4296 name = "foo"
4297 version = "0.5.0"
4298 authors = []
4299 links = "a"
4300 build = "build.rs"
4301
4302 [dependencies.a]
4303 path = "a"
4304
4305 [dev-dependencies]
4306 b = { path = "b" }
4307 "#,
4308 )
4309 .file("src/lib.rs", "")
4310 .file("build.rs", "")
4311 .file(
4312 "a/Cargo.toml",
4313 r#"
4314 [package]
4315 name = "a"
4316 version = "0.5.0"
4317 authors = []
4318 links = "a"
4319 build = "build.rs"
4320 "#,
4321 )
4322 .file("a/src/lib.rs", "")
4323 .file("a/build.rs", "")
4324 .file(
4325 "b/Cargo.toml",
4326 r#"
4327 [package]
4328 name = "b"
4329 version = "0.5.0"
4330 authors = []
4331
4332 [dependencies]
4333 foo = { path = ".." }
4334 "#,
4335 )
4336 .file("b/src/lib.rs", "")
4337 .build();
4338
4339 p.cargo("build").with_status(101)
4340 .with_stderr("\
4341error: failed to select a version for `a`.
4342 ... required by package `foo v0.5.0 ([..])`
4343versions that meet the requirements `*` are: 0.5.0
4344
4345the package `a` links to the native library `a`, but it conflicts with a previous package which links to `a` as well:
4346package `foo v0.5.0 ([..])`
4347Only one package in the dependency graph may specify the same links value. This helps ensure that only one copy of a native library is linked in the final binary. Try to adjust your dependencies so that only one package uses the links ='a' value. For more information, see https://doc.rust-lang.org/cargo/reference/resolver.html#links.
4348
4349failed to select a version for `a` which could resolve this conflict
4350").run();
4351}
4352
4353#[cargo_test]
4354fn rename_with_link_search_path() {
4355 _rename_with_link_search_path(false);
4356}
4357
4358#[cargo_test]
4359#[cfg_attr(
4360 target_os = "macos",
4361 ignore = "don't have a cdylib cross target on macos"
4362)]
4363fn rename_with_link_search_path_cross() {
4364 if cross_compile::disabled() {
4365 return;
4366 }
4367
4368 _rename_with_link_search_path(true);
4369}
4370
4371fn _rename_with_link_search_path(cross: bool) {
4372 let target_arg = if cross {
4373 format!(" --target={}", cross_compile::alternate())
4374 } else {
4375 "".to_string()
4376 };
4377 let p = project()
4378 .file(
4379 "Cargo.toml",
4380 r#"
4381 [package]
4382 name = "foo"
4383 version = "0.5.0"
4384 authors = []
4385
4386 [lib]
4387 crate-type = ["cdylib"]
4388 "#,
4389 )
4390 .file(
4391 "src/lib.rs",
4392 "#[no_mangle] pub extern fn cargo_test_foo() {}",
4393 );
4394 let p = p.build();
4395
4396 p.cargo(&format!("build{}", target_arg)).run();
4397
4398 let p2 = project()
4399 .at("bar")
4400 .file("Cargo.toml", &basic_manifest("bar", "0.5.0"))
4401 .file(
4402 "build.rs",
4403 r#"
4404 use std::env;
4405 use std::fs;
4406 use std::path::PathBuf;
4407
4408 fn main() {
4409 // Move the `libfoo.so` from the root of our project into the
4410 // build directory. This way Cargo should automatically manage
4411 // `LD_LIBRARY_PATH` and such.
4412 let root = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap());
4413 let file = format!("{}foo{}", env::consts::DLL_PREFIX, env::consts::DLL_SUFFIX);
4414 let src = root.join(&file);
4415
4416 let dst_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
4417 let dst = dst_dir.join(&file);
4418
4419 fs::copy(&src, &dst).unwrap();
4420 // handle windows, like below
4421 drop(fs::copy(root.join("foo.dll.lib"), dst_dir.join("foo.dll.lib")));
4422
4423 println!("cargo:rerun-if-changed=build.rs");
4424 if cfg!(target_env = "msvc") {
4425 println!("cargo:rustc-link-lib=foo.dll");
4426 } else {
4427 println!("cargo:rustc-link-lib=foo");
4428 }
4429 println!("cargo:rustc-link-search=all={}",
4430 dst.parent().unwrap().display());
4431 }
4432 "#,
4433 )
4434 .file(
4435 "src/main.rs",
4436 r#"
4437 extern {
4438 #[link_name = "cargo_test_foo"]
4439 fn foo();
4440 }
4441
4442 fn main() {
4443 unsafe { foo(); }
4444 }
4445 "#,
4446 );
4447 let p2 = p2.build();
4448
4449 // Move the output `libfoo.so` into the directory of `p2`, and then delete
4450 // the `p` project. On macOS, the `libfoo.dylib` artifact references the
4451 // original path in `p` so we want to make sure that it can't find it (hence
4452 // the deletion).
4453 let root = if cross {
4454 p.root()
4455 .join("target")
4456 .join(cross_compile::alternate())
4457 .join("debug")
4458 .join("deps")
4459 } else {
4460 p.root().join("target").join("debug").join("deps")
4461 };
4462 let file = format!("{}foo{}", env::consts::DLL_PREFIX, env::consts::DLL_SUFFIX);
4463 let src = root.join(&file);
4464
4465 let dst = p2.root().join(&file);
4466
4467 fs::copy(&src, &dst).unwrap();
4468 // copy the import library for windows, if it exists
4469 drop(fs::copy(
4470 &root.join("foo.dll.lib"),
4471 p2.root().join("foo.dll.lib"),
4472 ));
4473 remove_dir_all(p.root()).unwrap();
4474
4475 // Everything should work the first time
4476 p2.cargo(&format!("run{}", target_arg)).run();
4477
4478 // Now rename the root directory and rerun `cargo run`. Not only should we
4479 // not build anything but we also shouldn't crash.
4480 let mut new = p2.root();
4481 new.pop();
4482 new.push("bar2");
4483
4484 // For whatever reason on Windows right after we execute a binary it's very
4485 // unlikely that we're able to successfully delete or rename that binary.
4486 // It's not really clear why this is the case or if it's a bug in Cargo
4487 // holding a handle open too long. In an effort to reduce the flakiness of
4488 // this test though we throw this in a loop
4489 //
4490 // For some more information see #5481 and rust-lang/rust#48775
4491 let mut i = 0;
4492 loop {
4493 let error = match fs::rename(p2.root(), &new) {
4494 Ok(()) => break,
4495 Err(e) => e,
4496 };
4497 i += 1;
4498 if !cfg!(windows) || error.kind() != io::ErrorKind::PermissionDenied || i > 10 {
4499 panic!("failed to rename: {}", error);
4500 }
4501 println!("assuming {} is spurious, waiting to try again", error);
4502 thread::sleep(slow_cpu_multiplier(100));
4503 }
4504
4505 p2.cargo(&format!("run{}", target_arg))
4506 .cwd(&new)
4507 .with_stderr(
4508 "\
4509[FINISHED] [..]
4510[RUNNING] [..]
4511",
4512 )
4513 .run();
4514}
4515
4516#[cargo_test]
4517fn optional_build_script_dep() {
4518 let p = project()
4519 .file(
4520 "Cargo.toml",
4521 r#"
4522 [package]
4523 name = "foo"
4524 version = "0.5.0"
4525 authors = []
4526
4527 [dependencies]
4528 bar = { path = "bar", optional = true }
4529
4530 [build-dependencies]
4531 bar = { path = "bar", optional = true }
4532 "#,
4533 )
4534 .file(
4535 "build.rs",
4536 r#"
4537 #[cfg(feature = "bar")]
4538 extern crate bar;
4539
4540 fn main() {
4541 #[cfg(feature = "bar")] {
4542 println!("cargo:rustc-env=FOO={}", bar::bar());
4543 return
4544 }
4545 println!("cargo:rustc-env=FOO=0");
4546 }
4547 "#,
4548 )
4549 .file(
4550 "src/main.rs",
4551 r#"
4552 #[cfg(feature = "bar")]
4553 extern crate bar;
4554
4555 fn main() {
4556 println!("{}", env!("FOO"));
4557 }
4558 "#,
4559 )
4560 .file("bar/Cargo.toml", &basic_manifest("bar", "0.5.0"))
4561 .file("bar/src/lib.rs", "pub fn bar() -> u32 { 1 }");
4562 let p = p.build();
4563
4564 p.cargo("run").with_stdout("0\n").run();
4565 p.cargo("run --features bar").with_stdout("1\n").run();
4566}
4567
4568#[cargo_test]
4569fn optional_build_dep_and_required_normal_dep() {
4570 let p = project()
4571 .file(
4572 "Cargo.toml",
4573 r#"
4574 [package]
4575 name = "foo"
4576 version = "0.1.0"
4577 authors = []
4578
4579 [dependencies]
4580 bar = { path = "./bar", optional = true }
4581
4582 [build-dependencies]
4583 bar = { path = "./bar" }
4584 "#,
4585 )
4586 .file("build.rs", "extern crate bar; fn main() { bar::bar(); }")
4587 .file(
4588 "src/main.rs",
4589 r#"
4590 #[cfg(feature = "bar")]
4591 extern crate bar;
4592
4593 fn main() {
4594 #[cfg(feature = "bar")] {
4595 println!("{}", bar::bar());
4596 }
4597 #[cfg(not(feature = "bar"))] {
4598 println!("0");
4599 }
4600 }
4601 "#,
4602 )
4603 .file("bar/Cargo.toml", &basic_manifest("bar", "0.5.0"))
4604 .file("bar/src/lib.rs", "pub fn bar() -> u32 { 1 }");
4605 let p = p.build();
4606
4607 p.cargo("run")
4608 .with_stdout("0")
4609 .with_stderr(
4610 "\
4611[COMPILING] bar v0.5.0 ([..])
4612[COMPILING] foo v0.1.0 ([..])
4613[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
4614[RUNNING] `[..]foo[EXE]`",
4615 )
4616 .run();
4617
4618 p.cargo("run --all-features")
4619 .with_stdout("1")
4620 .with_stderr(
4621 "\
4622[COMPILING] bar v0.5.0 ([..])
4623[COMPILING] foo v0.1.0 ([..])
4624[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
4625[RUNNING] `[..]foo[EXE]`",
4626 )
4627 .run();
4628}
4629
4630#[cargo_test]
4631fn using_rerun_if_changed_does_not_rebuild() {
4632 let p = project()
4633 .file(
4634 "Cargo.toml",
4635 r#"
4636 [package]
4637 name = "foo"
4638 version = "0.1.0"
4639 authors = []
4640 "#,
4641 )
4642 .file(
4643 "build.rs",
4644 r#"
4645 fn main() {
4646 println!("cargo:rerun-if-changed=build.rs");
4647 }
4648 "#,
4649 )
4650 .file("src/lib.rs", "")
4651 .build();
4652
4653 p.cargo("build").run();
4654 p.cargo("build").with_stderr("[FINISHED] [..]").run();
4655}
4656
4657#[cargo_test]
4658fn links_interrupted_can_restart() {
4659 // Test for a `links` dependent build script getting canceled and then
4660 // restarted. Steps:
4661 // 1. Build to establish fingerprints.
4662 // 2. Change something (an env var in this case) that triggers the
4663 // dependent build script to run again. Kill the top-level build script
4664 // while it is running (such as hitting Ctrl-C).
4665 // 3. Run the build again, it should re-run the build script.
4666 let bar = project()
4667 .at("bar")
4668 .file(
4669 "Cargo.toml",
4670 r#"
4671 [package]
4672 name = "bar"
4673 version = "0.5.0"
4674 authors = []
4675 links = "foo"
4676 build = "build.rs"
4677 "#,
4678 )
4679 .file("src/lib.rs", "")
4680 .file(
4681 "build.rs",
4682 r#"
4683 fn main() {
4684 println!("cargo:rerun-if-env-changed=SOMEVAR");
4685 }
4686 "#,
4687 )
4688 .build();
4689
4690 let p = project()
4691 .file(
4692 "Cargo.toml",
4693 &format!(
4694 r#"
4695 [package]
4696 name = "foo"
4697 version = "0.5.0"
4698 authors = []
4699 build = "build.rs"
4700
4701 [dependencies.bar]
4702 path = '{}'
4703 "#,
4704 bar.root().display()
4705 ),
4706 )
4707 .file("src/lib.rs", "")
4708 .file(
4709 "build.rs",
4710 r#"
4711 use std::env;
4712 fn main() {
4713 println!("cargo:rebuild-if-changed=build.rs");
4714 if std::path::Path::new("abort").exists() {
4715 panic!("Crash!");
4716 }
4717 }
4718 "#,
4719 )
4720 .build();
4721
4722 p.cargo("build").run();
4723 // Simulate the user hitting Ctrl-C during a build.
4724 p.change_file("abort", "");
4725 // Set SOMEVAR to trigger a rebuild.
4726 p.cargo("build")
4727 .env("SOMEVAR", "1")
4728 .with_stderr_contains("[..]Crash![..]")
4729 .with_status(101)
4730 .run();
4731 fs::remove_file(p.root().join("abort")).unwrap();
4732 // Try again without aborting the script.
4733 // ***This is currently broken, the script does not re-run.
4734 p.cargo("build -v")
4735 .env("SOMEVAR", "1")
4736 .with_stderr_contains("[RUNNING] [..]/foo-[..]/build-script-build[..]")
4737 .run();
4738}
4739
4740#[cargo_test]
4741fn dev_dep_with_links() {
4742 let p = project()
4743 .file(
4744 "Cargo.toml",
4745 r#"
4746 [package]
4747 name = "foo"
4748 version = "0.1.0"
4749 authors = []
4750 links = "x"
4751
4752 [dev-dependencies]
4753 bar = { path = "./bar" }
4754 "#,
4755 )
4756 .file("build.rs", "fn main() {}")
4757 .file("src/lib.rs", "")
4758 .file(
4759 "bar/Cargo.toml",
4760 r#"
4761 [package]
4762 name = "bar"
4763 version = "0.1.0"
4764 authors = []
4765 links = "y"
4766
4767 [dependencies]
4768 foo = { path = ".." }
4769 "#,
4770 )
4771 .file("bar/build.rs", "fn main() {}")
4772 .file("bar/src/lib.rs", "")
4773 .build();
4774 p.cargo("check --tests").run()
4775}
4776
4777#[cargo_test]
4778fn rerun_if_directory() {
4779 if !symlink_supported() {
4780 return;
4781 }
4782
4783 // rerun-if-changed of a directory should rerun if any file in the directory changes.
4784 let p = project()
4785 .file("Cargo.toml", &basic_manifest("foo", "0.1.0"))
4786 .file("src/lib.rs", "")
4787 .file(
4788 "build.rs",
4789 r#"
4790 fn main() {
4791 println!("cargo:rerun-if-changed=somedir");
4792 }
4793 "#,
4794 )
4795 .build();
4796
4797 let dirty = |dirty_line: &str, compile_build_script: bool| {
4798 let mut dirty_line = dirty_line.to_string();
4799
4800 if !dirty_line.is_empty() {
4801 dirty_line.push('\n');
4802 }
4803
4804 let compile_build_script_line = if compile_build_script {
4805 "[RUNNING] `rustc --crate-name build_script_build [..]\n"
4806 } else {
4807 ""
4808 };
4809
4810 p.cargo("check -v")
4811 .with_stderr(format!(
4812 "\
4813{dirty_line}\
4814[COMPILING] foo [..]
4815{compile_build_script_line}\
4816[RUNNING] `[..]build-script-build[..]`
4817[RUNNING] `rustc --crate-name foo [..]
4818[FINISHED] [..]",
4819 ))
4820 .run();
4821 };
4822
4823 let fresh = || {
4824 p.cargo("check").with_stderr("[FINISHED] [..]").run();
4825 };
4826
4827 // Start with a missing directory.
4828 dirty("", true);
4829 // Because the directory doesn't exist, it will trigger a rebuild every time.
4830 // https://github.com/rust-lang/cargo/issues/6003
4831 dirty(
4832 "[DIRTY] foo v0.1.0 ([..]): the file `somedir` is missing",
4833 false,
4834 );
4835
4836 if is_coarse_mtime() {
4837 sleep_ms(1000);
4838 }
4839
4840 // Empty directory.
4841 fs::create_dir(p.root().join("somedir")).unwrap();
4842 dirty(
4843 "[DIRTY] foo v0.1.0 ([..]): the file `somedir` has changed ([..])",
4844 false,
4845 );
4846 fresh();
4847
4848 if is_coarse_mtime() {
4849 sleep_ms(1000);
4850 }
4851
4852 // Add a file.
4853 p.change_file("somedir/foo", "");
4854 p.change_file("somedir/bar", "");
4855 dirty(
4856 "[DIRTY] foo v0.1.0 ([..]): the file `somedir` has changed ([..])",
4857 false,
4858 );
4859 fresh();
4860
4861 if is_coarse_mtime() {
4862 sleep_ms(1000);
4863 }
4864
4865 // Add a symlink.
4866 p.symlink("foo", "somedir/link");
4867 dirty(
4868 "[DIRTY] foo v0.1.0 ([..]): the file `somedir` has changed ([..])",
4869 false,
4870 );
4871 fresh();
4872
4873 if is_coarse_mtime() {
4874 sleep_ms(1000);
4875 }
4876
4877 // Move the symlink.
4878 fs::remove_file(p.root().join("somedir/link")).unwrap();
4879 p.symlink("bar", "somedir/link");
4880 dirty(
4881 "[DIRTY] foo v0.1.0 ([..]): the file `somedir` has changed ([..])",
4882 false,
4883 );
4884 fresh();
4885
4886 if is_coarse_mtime() {
4887 sleep_ms(1000);
4888 }
4889
4890 // Remove a file.
4891 fs::remove_file(p.root().join("somedir/foo")).unwrap();
4892 dirty(
4893 "[DIRTY] foo v0.1.0 ([..]): the file `somedir` has changed ([..])",
4894 false,
4895 );
4896 fresh();
4897}
4898
4899#[cargo_test]
4900fn rerun_if_published_directory() {
4901 // build script of a dependency contains a `rerun-if-changed` pointing to a directory
4902 Package::new("mylib-sys", "1.0.0")
4903 .file("mylib/balrog.c", "")
4904 .file("src/lib.rs", "")
4905 .file(
4906 "build.rs",
4907 r#"
4908 fn main() {
4909 // Changing to mylib/balrog.c will not trigger a rebuild
4910 println!("cargo:rerun-if-changed=mylib");
4911 }
4912 "#,
4913 )
4914 .publish();
4915
4916 let p = project()
4917 .file(
4918 "Cargo.toml",
4919 r#"
4920 [package]
4921 name = "foo"
4922 version = "0.0.1"
4923
4924 [dependencies]
4925 mylib-sys = "1.0.0"
4926 "#,
4927 )
4928 .file("src/main.rs", "fn main() {}")
4929 .build();
4930
4931 p.cargo("check").run();
4932
4933 // Delete regitry src to make directories being recreated with the latest timestamp.
4934 cargo_home().join("registry/src").rm_rf();
4935
4936 p.cargo("check --verbose")
4937 .with_stderr(
4938 "\
4939[FRESH] mylib-sys v1.0.0
4940[FRESH] foo v0.0.1 ([CWD])
4941[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
4942",
4943 )
4944 .run();
4945
4946 // Upgrade of a package should still trigger a rebuild
4947 Package::new("mylib-sys", "1.0.1")
4948 .file("mylib/balrog.c", "")
4949 .file("mylib/balrog.h", "")
4950 .file("src/lib.rs", "")
4951 .file(
4952 "build.rs",
4953 r#"
4954 fn main() {
4955 println!("cargo:rerun-if-changed=mylib");
4956 }
4957 "#,
4958 )
4959 .publish();
4960 p.cargo("update").run();
4961 p.cargo("fetch").run();
4962
4963 p.cargo("check -v")
4964 .with_stderr(format!(
4965 "\
4966[COMPILING] mylib-sys [..]
4967[RUNNING] `rustc --crate-name build_script_build [..]
4968[RUNNING] `[..]build-script-build[..]`
4969[RUNNING] `rustc --crate-name mylib_sys [..]
4970[CHECKING] foo [..]
4971[RUNNING] `rustc --crate-name foo [..]
4972[FINISHED] [..]",
4973 ))
4974 .run();
4975}
4976
4977#[cargo_test]
4978fn test_with_dep_metadata() {
4979 let p = project()
4980 .file(
4981 "Cargo.toml",
4982 r#"
4983 [package]
4984 name = "foo"
4985 version = "0.1.0"
4986
4987 [dependencies]
4988 bar = { path = 'bar' }
4989 "#,
4990 )
4991 .file("src/lib.rs", "")
4992 .file(
4993 "build.rs",
4994 r#"
4995 fn main() {
4996 assert_eq!(std::env::var("DEP_BAR_FOO").unwrap(), "bar");
4997 }
4998 "#,
4999 )
5000 .file(
5001 "bar/Cargo.toml",
5002 r#"
5003 [package]
5004 name = "bar"
5005 version = "0.1.0"
5006 links = 'bar'
5007 "#,
5008 )
5009 .file("bar/src/lib.rs", "")
5010 .file(
5011 "bar/build.rs",
5012 r#"
5013 fn main() {
5014 println!("cargo:foo=bar");
5015 }
5016 "#,
5017 )
5018 .build();
5019 p.cargo("test --lib").run();
5020}
5021
5022#[cargo_test]
5023fn duplicate_script_with_extra_env() {
5024 // Test where a build script is run twice, that emits different rustc-env
5025 // and rustc-cfg values. In this case, one is run for host, the other for
5026 // target.
5027 if !cross_compile::can_run_on_host() {
5028 return;
5029 }
5030
5031 let target = cross_compile::alternate();
5032 let p = project()
5033 .file(
5034 "Cargo.toml",
5035 r#"
5036 [workspace]
5037 members = ["foo", "pm"]
5038 "#,
5039 )
5040 .file(
5041 "foo/Cargo.toml",
5042 r#"
5043 [package]
5044 name = "foo"
5045 version = "0.1.0"
5046
5047 [dependencies]
5048 pm = { path = "../pm" }
5049 "#,
5050 )
5051 .file(
5052 "foo/src/lib.rs",
5053 &r#"
5054 //! ```rust
5055 //! #[cfg(not(mycfg="{target}"))]
5056 //! compile_error!{"expected mycfg set"}
5057 //! assert_eq!(env!("CRATE_TARGET"), "{target}");
5058 //! assert_eq!(std::env::var("CRATE_TARGET").unwrap(), "{target}");
5059 //! ```
5060
5061 #[test]
5062 fn check_target() {
5063 #[cfg(not(mycfg="{target}"))]
5064 compile_error!{"expected mycfg set"}
5065 // Compile-time assertion.
5066 assert_eq!(env!("CRATE_TARGET"), "{target}");
5067 // Run-time assertion.
5068 assert_eq!(std::env::var("CRATE_TARGET").unwrap(), "{target}");
5069 }
5070 "#
5071 .replace("{target}", target),
5072 )
5073 .file(
5074 "foo/build.rs",
5075 r#"
5076 fn main() {
5077 println!("cargo:rustc-env=CRATE_TARGET={}", std::env::var("TARGET").unwrap());
5078 println!("cargo:rustc-cfg=mycfg=\"{}\"", std::env::var("TARGET").unwrap());
5079 }
5080 "#,
5081 )
5082 .file(
5083 "pm/Cargo.toml",
5084 r#"
5085 [package]
5086 name = "pm"
5087 version = "0.1.0"
5088
5089 [lib]
5090 proc-macro = true
5091 # This is just here to speed things up.
5092 doctest = false
5093
5094 [dev-dependencies]
5095 foo = { path = "../foo" }
5096 "#,
5097 )
5098 .file("pm/src/lib.rs", "")
5099 .build();
5100
5101 p.cargo("test --workspace --target")
5102 .arg(&target)
5103 .with_stdout_contains("test check_target ... ok")
5104 .run();
5105
5106 if cargo_test_support::is_nightly() {
5107 p.cargo("test --workspace -Z doctest-xcompile --doc --target")
5108 .arg(&target)
5109 .masquerade_as_nightly_cargo(&["doctest-xcompile"])
fe692bf9 5110 .with_stdout_contains("test foo/src/lib.rs - (line 2) ... ok")
0a29b90c
FG
5111 .run();
5112 }
5113}
5114
5115#[cargo_test]
5116fn wrong_output() {
5117 let p = project()
5118 .file("src/lib.rs", "")
5119 .file(
5120 "build.rs",
5121 r#"
5122 fn main() {
5123 println!("cargo:example");
5124 }
5125 "#,
5126 )
5127 .build();
5128
5129 p.cargo("build")
5130 .with_status(101)
5131 .with_stderr(
5132 "\
5133[COMPILING] foo [..]
5134error: invalid output in build script of `foo v0.0.1 ([ROOT]/foo)`: `cargo:example`
5135Expected a line with `cargo:key=value` with an `=` character, but none was found.
5136See https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script \
5137for more information about build script outputs.
5138",
5139 )
5140 .run();
5141}
5142
5143#[cargo_test]
5144fn custom_build_closes_stdin() {
5145 // Ensure stdin is closed to prevent deadlock.
5146 // See https://github.com/rust-lang/cargo/issues/11196
5147 let p = project()
5148 .file(
5149 "Cargo.toml",
5150 r#"
5151 [package]
5152 name = "foo"
5153 version = "0.5.0"
5154 build = "build.rs"
5155 "#,
5156 )
5157 .file("src/main.rs", "fn main() {}")
5158 .file(
5159 "build.rs",
5160 r#"fn main() {
5161 let mut line = String::new();
5162 std::io::stdin().read_line(&mut line).unwrap();
5163 }"#,
5164 )
5165 .build();
5166 p.cargo("build").run();
5167}