99//!
1010//! These tests are all disabled on rust-lang/rust's CI, but run in Cargo's CI.
1111
12- use crate :: { basic_bin_manifest, main_file, project} ;
12+ use crate :: { basic_manifest, main_file, project} ;
13+ use cargo:: util:: ProcessError ;
14+ use cargo:: CargoResult ;
1315use std:: env;
14- use std:: process:: Command ;
16+ use std:: fmt:: Write ;
17+ use std:: process:: { Command , Output } ;
1518use std:: sync:: atomic:: { AtomicBool , Ordering } ;
1619use std:: sync:: Once ;
1720
21+ /// Whether or not the resulting cross binaries can run on the host.
22+ static CAN_RUN_ON_HOST : AtomicBool = AtomicBool :: new ( false ) ;
23+
1824pub fn disabled ( ) -> bool {
19- // First, disable if `./configure` requested so .
25+ // First, disable if requested.
2026 match env:: var ( "CFG_DISABLE_CROSS_TESTS" ) {
2127 Ok ( ref s) if * s == "1" => return true ,
2228 _ => { }
2329 }
2430
25- // Right now, the Windows bots cannot cross compile due to the Mingw setup,
26- // so we disable ourselves on all but macOS/Linux setups where the rustc
27- // install script ensures we have both architectures.
31+ // Cross tests are only tested to work on macos, linux, and MSVC windows.
2832 if !( cfg ! ( target_os = "macos" ) || cfg ! ( target_os = "linux" ) || cfg ! ( target_env = "msvc" ) ) {
2933 return true ;
3034 }
3135
3236 // It's not particularly common to have a cross-compilation setup, so
3337 // try to detect that before we fail a bunch of tests through no fault
3438 // of the user.
35- static CAN_RUN_CROSS_TESTS : AtomicBool = AtomicBool :: new ( false ) ;
39+ static CAN_BUILD_CROSS_TESTS : AtomicBool = AtomicBool :: new ( false ) ;
3640 static CHECK : Once = Once :: new ( ) ;
3741
3842 let cross_target = alternate ( ) ;
3943
40- CHECK . call_once ( || {
44+ let run_cross_test = || -> CargoResult < Output > {
4145 let p = project ( )
4246 . at ( "cross_test" )
43- . file ( "Cargo.toml" , & basic_bin_manifest ( "cross_test" ) )
44- . file ( "src/cross_test .rs" , & main_file ( r#""testing!""# , & [ ] ) )
47+ . file ( "Cargo.toml" , & basic_manifest ( "cross_test" , "1.0.0 ") )
48+ . file ( "src/main .rs" , & main_file ( r#""testing!""# , & [ ] ) )
4549 . build ( ) ;
4650
47- let result = p
51+ let build_result = p
4852 . cargo ( "build --target" )
4953 . arg ( & cross_target)
5054 . exec_with_output ( ) ;
5155
56+ if build_result. is_ok ( ) {
57+ CAN_BUILD_CROSS_TESTS . store ( true , Ordering :: SeqCst ) ;
58+ }
59+
60+ let result = p
61+ . cargo ( "run --target" )
62+ . arg ( & cross_target)
63+ . exec_with_output ( ) ;
64+
5265 if result. is_ok ( ) {
53- CAN_RUN_CROSS_TESTS . store ( true , Ordering :: SeqCst ) ;
66+ CAN_RUN_ON_HOST . store ( true , Ordering :: SeqCst ) ;
5467 }
68+ build_result
69+ } ;
70+
71+ CHECK . call_once ( || {
72+ drop ( run_cross_test ( ) ) ;
5573 } ) ;
5674
57- if CAN_RUN_CROSS_TESTS . load ( Ordering :: SeqCst ) {
75+ if CAN_BUILD_CROSS_TESTS . load ( Ordering :: SeqCst ) {
5876 // We were able to compile a simple project, so the user has the
5977 // necessary `std::` bits installed. Therefore, tests should not
6078 // be disabled.
@@ -75,74 +93,134 @@ pub fn disabled() -> bool {
7593 }
7694
7795 // We are responsible for warning the user, which we do by panicking.
78- let rustup_available = Command :: new ( "rustup" ) . output ( ) . is_ok ( ) ;
79-
80- let linux_help = if cfg ! ( target_os = "linux" ) {
96+ let mut message = format ! (
8197 "
98+ Cannot cross compile to {}.
8299
83- You may need to install runtime libraries for your Linux distribution as well."
84- . to_string ( )
85- } else {
86- "" . to_string ( )
87- } ;
100+ This failure can be safely ignored. If you would prefer to not see this
101+ failure, you can set the environment variable CFG_DISABLE_CROSS_TESTS to \" 1\" .
88102
89- let rustup_help = if rustup_available {
90- format ! (
103+ Alternatively, you can install the necessary libraries to enable cross
104+ compilation tests. Cross compilation tests depend on your host platform.
105+ " ,
106+ cross_target
107+ ) ;
108+
109+ if cfg ! ( target_os = "linux" ) {
110+ message. push_str (
91111 "
112+ Linux cross tests target i686-unknown-linux-gnu, which requires the ability to
113+ build and run 32-bit targets. This requires the 32-bit libraries to be
114+ installed. For example, on Ubuntu, run `sudo apt install gcc-multilib` to
115+ install the necessary libraries.
116+ " ,
117+ ) ;
118+ } else if cfg ! ( target_os = "macos" ) {
119+ message. push_str (
120+ "
121+ macOS cross tests target x86_64-apple-ios, which requires the iOS SDK to be
122+ installed. This should be included with Xcode automatically. If you are using
123+ the Xcode command line tools, you'll need to install the full Xcode app (from
124+ the Apple App Store), and switch to it with this command:
92125
93- Alternatively, you can install the necessary libraries for cross-compilation with
126+ sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer
94127
95- rustup target add {}{}" ,
96- cross_target, linux_help
97- )
128+ Some cross-tests want to *run* the executables on the host. These tests will
129+ be ignored if this is not possible. On macOS, this means you need an iOS
130+ simulator installed to run these tests. To install a simulator, open Xcode, go
131+ to preferences > Components, and download the latest iOS simulator.
132+ " ,
133+ ) ;
134+ } else if cfg ! ( target_os = "windows" ) {
135+ message. push_str (
136+ "
137+ Windows cross tests target i686-pc-windows-msvc, which requires the ability
138+ to build and run 32-bit targets. This should work automatically if you have
139+ properly installed Visual Studio build tools.
140+ " ,
141+ ) ;
98142 } else {
99- "" . to_string ( )
100- } ;
143+ // The check at the top should prevent this.
144+ panic ! ( "platform should have been skipped" ) ;
145+ }
101146
102- panic ! (
103- "Cannot cross compile to {}.
147+ let rustup_available = Command :: new ( "rustup" ) . output ( ) . is_ok ( ) ;
148+ if rustup_available {
149+ write ! (
150+ message,
151+ "
152+ Make sure that the appropriate `rustc` target is installed with rustup:
104153
105- This failure can be safely ignored. If you would prefer to not see this
106- failure, you can set the environment variable CFG_DISABLE_CROSS_TESTS to \" 1\" .{}
154+ rustup target add {}
107155" ,
108- cross_target, rustup_help
109- ) ;
156+ cross_target
157+ )
158+ . unwrap ( ) ;
159+ } else {
160+ write ! (
161+ message,
162+ "
163+ rustup does not appear to be installed. Make sure that the appropriate
164+ `rustc` target is installed for the target `{}`.
165+ " ,
166+ cross_target
167+ )
168+ . unwrap ( ) ;
169+ }
170+
171+ // Show the actual error message.
172+ match run_cross_test ( ) {
173+ Ok ( _) => message. push_str ( "\n Uh oh, second run succeeded?\n " ) ,
174+ Err ( err) => match err. downcast_ref :: < ProcessError > ( ) {
175+ Some ( proc_err) => write ! ( message, "\n Test error: {}\n " , proc_err) . unwrap ( ) ,
176+ None => write ! ( message, "\n Unexpected non-process error: {}\n " , err) . unwrap ( ) ,
177+ } ,
178+ }
179+
180+ panic ! ( message) ;
110181}
111182
112- pub fn alternate ( ) -> String {
113- let platform = match env :: consts :: OS {
114- "linux" => "unknown-linux-gnu" ,
115- "macos" => "apple-darwin" ,
116- "windows" => "pc-windows-msvc" ,
117- _ => unreachable ! ( ) ,
118- } ;
119- let arch = match env :: consts :: ARCH {
120- "x86" => "x86_64" ,
121- "x86_64" => " i686" ,
122- _ => unreachable ! ( ) ,
123- } ;
124- format ! ( "{}-{}" , arch , platform )
183+ /// The alternate target-triple to build with.
184+ ///
185+ /// Only use this function on tests that check `cross_compile::disabled`.
186+ pub fn alternate ( ) -> & ' static str {
187+ if cfg ! ( target_os = "macos" ) {
188+ "x86_64-apple-ios"
189+ } else if cfg ! ( target_os = "linux" ) {
190+ "i686-unknown-linux-gnu"
191+ } else if cfg ! ( all ( target_os = "windows" , target_env = "msvc" ) ) {
192+ "i686-pc-windows-msvc"
193+ } else {
194+ panic ! ( "This test should be gated on cross_compile::disabled." ) ;
195+ }
125196}
126197
127198pub fn alternate_arch ( ) -> & ' static str {
128- match env :: consts :: ARCH {
129- "x86" => " x86_64",
130- "x86_64" => "x86" ,
131- _ => unreachable ! ( ) ,
199+ if cfg ! ( target_os = "macos" ) {
200+ "x86_64"
201+ } else {
202+ "x86"
132203 }
133204}
134205
135- pub fn host ( ) -> String {
136- let platform = match env:: consts:: OS {
137- "linux" => "unknown-linux-gnu" ,
138- "macos" => "apple-darwin" ,
139- "windows" => "pc-windows-msvc" ,
140- _ => unreachable ! ( ) ,
141- } ;
142- let arch = match env:: consts:: ARCH {
143- "x86" => "i686" ,
144- "x86_64" => "x86_64" ,
145- _ => unreachable ! ( ) ,
146- } ;
147- format ! ( "{}-{}" , arch, platform)
206+ /// Whether or not the host can run cross-compiled executables.
207+ pub fn can_run_on_host ( ) -> bool {
208+ if disabled ( ) {
209+ return false ;
210+ }
211+ // macos is currently configured to cross compile to x86_64-apple-ios
212+ // which requires a simulator to run. Azure's CI image appears to have the
213+ // SDK installed, but are not configured to launch iOS images with a
214+ // simulator.
215+ if cfg ! ( target_os = "macos" ) {
216+ if CAN_RUN_ON_HOST . load ( Ordering :: SeqCst ) {
217+ return true ;
218+ } else {
219+ println ! ( "Note: Cannot run on host, skipping." ) ;
220+ return false ;
221+ }
222+ } else {
223+ assert ! ( CAN_RUN_ON_HOST . load( Ordering :: SeqCst ) ) ;
224+ return true ;
225+ }
148226}
0 commit comments