1 //! Tests for custom json target specifications.
2 
3 use cargo_test_support::is_nightly;
4 use cargo_test_support::{basic_manifest, project};
5 use std::fs;
6 
7 const MINIMAL_LIB: &str = r#"
8 #![feature(no_core)]
9 #![feature(lang_items)]
10 #![no_core]
11 
12 #[lang = "sized"]
13 pub trait Sized {
14     // Empty.
15 }
16 #[lang = "copy"]
17 pub trait Copy {
18     // Empty.
19 }
20 "#;
21 
22 const SIMPLE_SPEC: &str = r#"
23 {
24     "llvm-target": "x86_64-unknown-none-gnu",
25     "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
26     "arch": "x86_64",
27     "target-endian": "little",
28     "target-pointer-width": "64",
29     "target-c-int-width": "32",
30     "os": "none",
31     "linker-flavor": "ld.lld",
32     "linker": "rust-lld",
33     "executables": true
34 }
35 "#;
36 
37 #[cargo_test]
custom_target_minimal()38 fn custom_target_minimal() {
39     if !is_nightly() {
40         // Requires features no_core, lang_items
41         return;
42     }
43     let p = project()
44         .file(
45             "src/lib.rs",
46             &"
47                 __MINIMAL_LIB__
48 
49                 pub fn foo() -> u32 {
50                     42
51                 }
52             "
53             .replace("__MINIMAL_LIB__", MINIMAL_LIB),
54         )
55         .file("custom-target.json", SIMPLE_SPEC)
56         .build();
57 
58     p.cargo("build --lib --target custom-target.json -v").run();
59     p.cargo("build --lib --target src/../custom-target.json -v")
60         .run();
61 
62     // Ensure that the correct style of flag is passed to --target with doc tests.
63     p.cargo("test --doc --target src/../custom-target.json -v -Zdoctest-xcompile")
64         .masquerade_as_nightly_cargo()
65         .with_stderr_contains("[RUNNING] `rustdoc [..]--target [..]foo/custom-target.json[..]")
66         .run();
67 }
68 
69 #[cargo_test]
custom_target_dependency()70 fn custom_target_dependency() {
71     if !is_nightly() {
72         // Requires features no_core, lang_items, auto_traits
73         return;
74     }
75     let p = project()
76         .file(
77             "Cargo.toml",
78             r#"
79                 [package]
80 
81                 name = "foo"
82                 version = "0.0.1"
83                 authors = ["author@example.com"]
84 
85                 [dependencies]
86                 bar = { path = "bar" }
87             "#,
88         )
89         .file(
90             "src/lib.rs",
91             r#"
92                 #![feature(no_core)]
93                 #![feature(lang_items)]
94                 #![feature(auto_traits)]
95                 #![no_core]
96 
97                 extern crate bar;
98 
99                 pub fn foo() -> u32 {
100                     bar::bar()
101                 }
102 
103                 #[lang = "freeze"]
104                 unsafe auto trait Freeze {}
105             "#,
106         )
107         .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1"))
108         .file(
109             "bar/src/lib.rs",
110             &"
111                 __MINIMAL_LIB__
112 
113                 pub fn bar() -> u32 {
114                     42
115                 }
116             "
117             .replace("__MINIMAL_LIB__", MINIMAL_LIB),
118         )
119         .file("custom-target.json", SIMPLE_SPEC)
120         .build();
121 
122     p.cargo("build --lib --target custom-target.json -v").run();
123 }
124 
125 #[cargo_test]
custom_bin_target()126 fn custom_bin_target() {
127     if !is_nightly() {
128         // Requires features no_core, lang_items
129         return;
130     }
131     let p = project()
132         .file(
133             "src/main.rs",
134             &"
135                 #![no_main]
136                 __MINIMAL_LIB__
137             "
138             .replace("__MINIMAL_LIB__", MINIMAL_LIB),
139         )
140         .file("custom-bin-target.json", SIMPLE_SPEC)
141         .build();
142 
143     p.cargo("build --target custom-bin-target.json -v").run();
144 }
145 
146 #[cargo_test]
changing_spec_rebuilds()147 fn changing_spec_rebuilds() {
148     // Changing the .json file will trigger a rebuild.
149     if !is_nightly() {
150         // Requires features no_core, lang_items
151         return;
152     }
153     let p = project()
154         .file(
155             "src/lib.rs",
156             &"
157                 __MINIMAL_LIB__
158 
159                 pub fn foo() -> u32 {
160                     42
161                 }
162             "
163             .replace("__MINIMAL_LIB__", MINIMAL_LIB),
164         )
165         .file("custom-target.json", SIMPLE_SPEC)
166         .build();
167 
168     p.cargo("build --lib --target custom-target.json -v").run();
169     p.cargo("build --lib --target custom-target.json -v")
170         .with_stderr(
171             "\
172 [FRESH] foo [..]
173 [FINISHED] [..]
174 ",
175         )
176         .run();
177     let spec_path = p.root().join("custom-target.json");
178     let spec = fs::read_to_string(&spec_path).unwrap();
179     // Some arbitrary change that I hope is safe.
180     let spec = spec.replace('{', "{\n\"vendor\": \"unknown\",\n");
181     fs::write(&spec_path, spec).unwrap();
182     p.cargo("build --lib --target custom-target.json -v")
183         .with_stderr(
184             "\
185 [COMPILING] foo v0.0.1 [..]
186 [RUNNING] `rustc [..]
187 [FINISHED] [..]
188 ",
189         )
190         .run();
191 }
192 
193 #[cargo_test]
changing_spec_relearns_crate_types()194 fn changing_spec_relearns_crate_types() {
195     // Changing the .json file will invalidate the cache of crate types.
196     if !is_nightly() {
197         // Requires features no_core, lang_items
198         return;
199     }
200     let p = project()
201         .file(
202             "Cargo.toml",
203             r#"
204                 [package]
205                 name = "foo"
206                 version = "0.1.0"
207 
208                 [lib]
209                 crate-type = ["cdylib"]
210             "#,
211         )
212         .file("src/lib.rs", MINIMAL_LIB)
213         .file("custom-target.json", SIMPLE_SPEC)
214         .build();
215 
216     p.cargo("build --lib --target custom-target.json -v")
217         .with_status(101)
218         .with_stderr("error: cannot produce cdylib for `foo [..]")
219         .run();
220 
221     // Enable dynamic linking.
222     let spec_path = p.root().join("custom-target.json");
223     let spec = fs::read_to_string(&spec_path).unwrap();
224     let spec = spec.replace('{', "{\n\"dynamic-linking\": true,\n");
225     fs::write(&spec_path, spec).unwrap();
226 
227     p.cargo("build --lib --target custom-target.json -v")
228         .with_stderr(
229             "\
230 [COMPILING] foo [..]
231 [RUNNING] `rustc [..]
232 [FINISHED] [..]
233 ",
234         )
235         .run();
236 }
237