@@ -12,24 +12,24 @@ fn main() {
1212 return ;
1313 }
1414
15- let out = PathBuf :: from ( env:: var_os ( "OUT_DIR" ) . unwrap ( ) ) ;
16- fs:: remove_dir_all ( & out ) . unwrap ( ) ;
17- fs:: create_dir ( & out ) . unwrap ( ) ;
15+ let out_dir = PathBuf :: from ( env:: var_os ( "OUT_DIR" ) . unwrap ( ) ) ;
16+ fs:: remove_dir_all ( & out_dir ) . unwrap ( ) ;
17+ fs:: create_dir ( & out_dir ) . unwrap ( ) ;
1818
1919 // The following are builds where we want to capture the output (i.e. stdout and
2020 // stderr). We do that by re-running _this_ executable and passing in the
2121 // action as the first argument.
22- run_forked_capture_output ( & out , "metadata-on" ) ;
23- run_forked_capture_output ( & out , "metadata-off" ) ;
22+ run_forked_capture_output ( & out_dir , "metadata-on" ) ;
23+ run_forked_capture_output ( & out_dir , "metadata-off" ) ;
2424
25- run_forked_capture_output ( & out , "warnings-off" ) ;
25+ run_forked_capture_output ( & out_dir , "warnings-off" ) ;
2626 if cc:: Build :: new ( ) . get_compiler ( ) . is_like_msvc ( ) {
2727 // MSVC doesn't output warnings to stderr, so we can't capture them.
2828 // the test will use this env var to know whether to run the test.
2929 println ! ( "cargo:rustc-env=TEST_WARNINGS_ON=0" ) ;
3030 } else {
3131 println ! ( "cargo:rustc-env=TEST_WARNINGS_ON=1" ) ;
32- run_forked_capture_output ( & out , "warnings-on" ) ;
32+ run_forked_capture_output ( & out_dir , "warnings-on" ) ;
3333 }
3434
3535 let mut build = cc:: Build :: new ( ) ;
@@ -104,7 +104,7 @@ fn main() {
104104 // Test that the `windows_registry` module will set PATH by looking for
105105 // nmake which runs vanilla cl, and then also test it after we remove all
106106 // the relevant env vars from our own process.
107- let out = out . join ( "tmp" ) ;
107+ let out = out_dir . join ( "tmp" ) ;
108108 fs:: create_dir ( & out) . unwrap ( ) ;
109109 println ! ( "nmake 1" ) ;
110110 let status = cc:: windows_registry:: find ( & target, "nmake.exe" )
@@ -173,6 +173,37 @@ fn main() {
173173 let out = cc:: Build :: new ( ) . file ( "src/expand.c" ) . expand ( ) ;
174174 let out = String :: from_utf8 ( out) . unwrap ( ) ;
175175 assert ! ( out. contains( "hello world" ) ) ;
176+
177+ // Test static linking of stdc++ on Linux
178+ #[ cfg( target_os = "linux" ) ]
179+ {
180+ // Rust linker has no problem linking against dynamic libraries, for instance
181+ // it doesn't require any additional steps to link against system
182+ // `libstdc++.so`, but if we emit `cargo:rustc-link-lib=static=stdc++`, it will
183+ // not be able to find `libstdc++.a` file despite it almost always located next to
184+ // `libstdc++.so`. So symlinking to OUT dir solves the problem
185+
186+ let mut cmd = Command :: new ( "g++" ) ;
187+ cmd. arg ( "--print-file-name=libstdc++.a" ) ;
188+ if arch == "i686" {
189+ cmd. arg ( "-m32" ) ;
190+ }
191+ let libstdc_path: PathBuf =
192+ String :: from_utf8 ( cmd. output ( ) . expect ( "Failed to run g++" ) . stdout )
193+ . unwrap ( )
194+ . trim ( )
195+ . into ( ) ;
196+
197+ let out_stdlib = out_dir. join ( "libstdc++.a" ) ;
198+ std:: os:: unix:: fs:: symlink ( libstdc_path, out_stdlib) . unwrap ( ) ;
199+
200+ cc:: Build :: new ( )
201+ . file ( "src/baz.cpp" )
202+ . cpp ( true )
203+ . cpp_link_stdlib ( "stdc++" )
204+ . cpp_link_stdlib_static ( true )
205+ . compile ( "baz" ) ;
206+ }
176207}
177208
178209#[ track_caller]
0 commit comments