11//! All functions here are copied from https://github.com/rust-lang/rust/blob/942864a000efd74b73e36bda5606b2cdb55ecf39/src/librustc_codegen_llvm/back/link.rs
22
3- use std:: fmt;
4- use std:: fs;
5- use std:: io;
6- use std:: iter;
73use std:: path:: { Path , PathBuf } ;
8- use std:: process:: { Output , Stdio } ;
9-
10- use log:: info;
114
125use rustc:: middle:: cstore:: { NativeLibrary , NativeLibraryKind } ;
136use rustc:: middle:: dependency_format:: Linkage ;
147use rustc:: session:: config:: { self , OutputType , RUST_CGU_EXT } ;
158use rustc:: session:: search_paths:: PathKind ;
169use rustc:: session:: Session ;
1710use rustc:: util:: common:: time;
18- use rustc_codegen_ssa:: back :: command :: Command ;
11+ use rustc_codegen_ssa:: { METADATA_FILENAME , RLIB_BYTECODE_EXTENSION } ;
1912use rustc_codegen_ssa:: back:: linker:: * ;
2013use rustc_codegen_ssa:: back:: link:: * ;
2114use rustc_data_structures:: fx:: FxHashSet ;
@@ -25,11 +18,6 @@ use syntax::attr;
2518use crate :: prelude:: * ;
2619
2720use crate :: archive:: { ArchiveBuilder , ArchiveConfig } ;
28- use crate :: metadata:: METADATA_FILENAME ;
29-
30-
31- // cg_clif doesn't have bytecode, so this is just a dummy
32- const RLIB_BYTECODE_EXTENSION : & str = ".cg_clif_bytecode_dummy" ;
3321
3422fn archive_search_paths ( sess : & Session ) -> Vec < PathBuf > {
3523 sess. target_filesearch ( PathKind :: Native ) . search_path_dirs ( )
@@ -46,147 +34,6 @@ fn archive_config<'a>(sess: &'a Session,
4634 }
4735}
4836
49- pub fn exec_linker ( sess : & Session , cmd : & mut Command , out_filename : & Path , tmpdir : & Path )
50- -> io:: Result < Output >
51- {
52- // When attempting to spawn the linker we run a risk of blowing out the
53- // size limits for spawning a new process with respect to the arguments
54- // we pass on the command line.
55- //
56- // Here we attempt to handle errors from the OS saying "your list of
57- // arguments is too big" by reinvoking the linker again with an `@`-file
58- // that contains all the arguments. The theory is that this is then
59- // accepted on all linkers and the linker will read all its options out of
60- // there instead of looking at the command line.
61- if !cmd. very_likely_to_exceed_some_spawn_limit ( ) {
62- match cmd. command ( ) . stdout ( Stdio :: piped ( ) ) . stderr ( Stdio :: piped ( ) ) . spawn ( ) {
63- Ok ( child) => {
64- let output = child. wait_with_output ( ) ;
65- flush_linked_file ( & output, out_filename) ?;
66- return output;
67- }
68- Err ( ref e) if command_line_too_big ( e) => {
69- info ! ( "command line to linker was too big: {}" , e) ;
70- }
71- Err ( e) => return Err ( e)
72- }
73- }
74-
75- info ! ( "falling back to passing arguments to linker via an @-file" ) ;
76- let mut cmd2 = cmd. clone ( ) ;
77- let mut args = String :: new ( ) ;
78- for arg in cmd2. take_args ( ) {
79- args. push_str ( & Escape {
80- arg : arg. to_str ( ) . unwrap ( ) ,
81- is_like_msvc : sess. target . target . options . is_like_msvc ,
82- } . to_string ( ) ) ;
83- args. push_str ( "\n " ) ;
84- }
85- let file = tmpdir. join ( "linker-arguments" ) ;
86- let bytes = if sess. target . target . options . is_like_msvc {
87- let mut out = Vec :: with_capacity ( ( 1 + args. len ( ) ) * 2 ) ;
88- // start the stream with a UTF-16 BOM
89- for c in iter:: once ( 0xFEFF ) . chain ( args. encode_utf16 ( ) ) {
90- // encode in little endian
91- out. push ( c as u8 ) ;
92- out. push ( ( c >> 8 ) as u8 ) ;
93- }
94- out
95- } else {
96- args. into_bytes ( )
97- } ;
98- fs:: write ( & file, & bytes) ?;
99- cmd2. arg ( format ! ( "@{}" , file. display( ) ) ) ;
100- info ! ( "invoking linker {:?}" , cmd2) ;
101- let output = cmd2. output ( ) ;
102- flush_linked_file ( & output, out_filename) ?;
103- return output;
104-
105- #[ cfg( unix) ]
106- fn flush_linked_file ( _: & io:: Result < Output > , _: & Path ) -> io:: Result < ( ) > {
107- Ok ( ( ) )
108- }
109-
110- #[ cfg( windows) ]
111- fn flush_linked_file ( command_output : & io:: Result < Output > , out_filename : & Path )
112- -> io:: Result < ( ) >
113- {
114- // On Windows, under high I/O load, output buffers are sometimes not flushed,
115- // even long after process exit, causing nasty, non-reproducible output bugs.
116- //
117- // File::sync_all() calls FlushFileBuffers() down the line, which solves the problem.
118- //
119- // А full writeup of the original Chrome bug can be found at
120- // randomascii.wordpress.com/2018/02/25/compiler-bug-linker-bug-windows-kernel-bug/amp
121-
122- if let & Ok ( ref out) = command_output {
123- if out. status . success ( ) {
124- if let Ok ( of) = fs:: OpenOptions :: new ( ) . write ( true ) . open ( out_filename) {
125- of. sync_all ( ) ?;
126- }
127- }
128- }
129-
130- Ok ( ( ) )
131- }
132-
133- #[ cfg( unix) ]
134- fn command_line_too_big ( err : & io:: Error ) -> bool {
135- err. raw_os_error ( ) == Some ( :: libc:: E2BIG )
136- }
137-
138- #[ cfg( windows) ]
139- fn command_line_too_big ( err : & io:: Error ) -> bool {
140- const ERROR_FILENAME_EXCED_RANGE : i32 = 206 ;
141- err. raw_os_error ( ) == Some ( ERROR_FILENAME_EXCED_RANGE )
142- }
143-
144- struct Escape < ' a > {
145- arg : & ' a str ,
146- is_like_msvc : bool ,
147- }
148-
149- impl < ' a > fmt:: Display for Escape < ' a > {
150- fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
151- if self . is_like_msvc {
152- // This is "documented" at
153- // https://msdn.microsoft.com/en-us/library/4xdcbak7.aspx
154- //
155- // Unfortunately there's not a great specification of the
156- // syntax I could find online (at least) but some local
157- // testing showed that this seemed sufficient-ish to catch
158- // at least a few edge cases.
159- write ! ( f, "\" " ) ?;
160- for c in self . arg . chars ( ) {
161- match c {
162- '"' => write ! ( f, "\\ {}" , c) ?,
163- c => write ! ( f, "{}" , c) ?,
164- }
165- }
166- write ! ( f, "\" " ) ?;
167- } else {
168- // This is documented at https://linux.die.net/man/1/ld, namely:
169- //
170- // > Options in file are separated by whitespace. A whitespace
171- // > character may be included in an option by surrounding the
172- // > entire option in either single or double quotes. Any
173- // > character (including a backslash) may be included by
174- // > prefixing the character to be included with a backslash.
175- //
176- // We put an argument on each line, so all we need to do is
177- // ensure the line is interpreted as one whole argument.
178- for c in self . arg . chars ( ) {
179- match c {
180- '\\' | ' ' => write ! ( f, "\\ {}" , c) ?,
181- c => write ! ( f, "{}" , c) ?,
182- }
183- }
184- }
185- Ok ( ( ) )
186- }
187- }
188- }
189-
19037// # Rust Crate linking
19138//
19239// Rust crates are not considered at all when creating an rlib output. All
@@ -505,130 +352,3 @@ pub fn add_upstream_rust_crates(cmd: &mut dyn Linker,
505352 parent. unwrap_or ( Path :: new ( "" ) ) ) ;
506353 }
507354}
508-
509- // # Native library linking
510- //
511- // User-supplied library search paths (-L on the command line). These are
512- // the same paths used to find Rust crates, so some of them may have been
513- // added already by the previous crate linking code. This only allows them
514- // to be found at compile time so it is still entirely up to outside
515- // forces to make sure that library can be found at runtime.
516- //
517- // Also note that the native libraries linked here are only the ones located
518- // in the current crate. Upstream crates with native library dependencies
519- // may have their native library pulled in above.
520- pub fn add_local_native_libraries ( cmd : & mut dyn Linker ,
521- sess : & Session ,
522- codegen_results : & CodegenResults ) {
523- let filesearch = sess. target_filesearch ( PathKind :: All ) ;
524- for search_path in filesearch. search_paths ( ) {
525- match search_path. kind {
526- PathKind :: Framework => { cmd. framework_path ( & search_path. dir ) ; }
527- _ => { cmd. include_path ( & fix_windows_verbatim_for_gcc ( & search_path. dir ) ) ; }
528- }
529- }
530-
531- let relevant_libs = codegen_results. crate_info . used_libraries . iter ( ) . filter ( |l| {
532- relevant_lib ( sess, l)
533- } ) ;
534-
535- let search_path = archive_search_paths ( sess) ;
536- for lib in relevant_libs {
537- let name = match lib. name {
538- Some ( ref l) => l,
539- None => continue ,
540- } ;
541- match lib. kind {
542- NativeLibraryKind :: NativeUnknown => cmd. link_dylib ( & name. as_str ( ) ) ,
543- NativeLibraryKind :: NativeFramework => cmd. link_framework ( & name. as_str ( ) ) ,
544- NativeLibraryKind :: NativeStaticNobundle => cmd. link_staticlib ( & name. as_str ( ) ) ,
545- NativeLibraryKind :: NativeStatic => cmd. link_whole_staticlib ( & name. as_str ( ) ,
546- & search_path)
547- }
548- }
549- }
550-
551- // Link in all of our upstream crates' native dependencies. Remember that
552- // all of these upstream native dependencies are all non-static
553- // dependencies. We've got two cases then:
554- //
555- // 1. The upstream crate is an rlib. In this case we *must* link in the
556- // native dependency because the rlib is just an archive.
557- //
558- // 2. The upstream crate is a dylib. In order to use the dylib, we have to
559- // have the dependency present on the system somewhere. Thus, we don't
560- // gain a whole lot from not linking in the dynamic dependency to this
561- // crate as well.
562- //
563- // The use case for this is a little subtle. In theory the native
564- // dependencies of a crate are purely an implementation detail of the crate
565- // itself, but the problem arises with generic and inlined functions. If a
566- // generic function calls a native function, then the generic function must
567- // be instantiated in the target crate, meaning that the native symbol must
568- // also be resolved in the target crate.
569- pub fn add_upstream_native_libraries ( cmd : & mut dyn Linker ,
570- sess : & Session ,
571- codegen_results : & CodegenResults ,
572- crate_type : config:: CrateType ) {
573- // Be sure to use a topological sorting of crates because there may be
574- // interdependencies between native libraries. When passing -nodefaultlibs,
575- // for example, almost all native libraries depend on libc, so we have to
576- // make sure that's all the way at the right (liblibc is near the base of
577- // the dependency chain).
578- //
579- // This passes RequireStatic, but the actual requirement doesn't matter,
580- // we're just getting an ordering of crate numbers, we're not worried about
581- // the paths.
582- let formats = sess. dependency_formats . borrow ( ) ;
583- let data = formats. get ( & crate_type) . unwrap ( ) ;
584-
585- let crates = & codegen_results. crate_info . used_crates_static ;
586- for & ( cnum, _) in crates {
587- for lib in codegen_results. crate_info . native_libraries [ & cnum] . iter ( ) {
588- let name = match lib. name {
589- Some ( ref l) => l,
590- None => continue ,
591- } ;
592- if !relevant_lib ( sess, & lib) {
593- continue
594- }
595- match lib. kind {
596- NativeLibraryKind :: NativeUnknown => cmd. link_dylib ( & name. as_str ( ) ) ,
597- NativeLibraryKind :: NativeFramework => cmd. link_framework ( & name. as_str ( ) ) ,
598- NativeLibraryKind :: NativeStaticNobundle => {
599- // Link "static-nobundle" native libs only if the crate they originate from
600- // is being linked statically to the current crate. If it's linked dynamically
601- // or is an rlib already included via some other dylib crate, the symbols from
602- // native libs will have already been included in that dylib.
603- if data[ cnum. as_usize ( ) - 1 ] == Linkage :: Static {
604- cmd. link_staticlib ( & name. as_str ( ) )
605- }
606- } ,
607- // ignore statically included native libraries here as we've
608- // already included them when we included the rust library
609- // previously
610- NativeLibraryKind :: NativeStatic => { }
611- }
612- }
613- }
614- }
615-
616- fn relevant_lib ( sess : & Session , lib : & NativeLibrary ) -> bool {
617- match lib. cfg {
618- Some ( ref cfg) => attr:: cfg_matches ( cfg, & sess. parse_sess , None ) ,
619- None => true ,
620- }
621- }
622-
623- fn are_upstream_rust_objects_already_included ( sess : & Session ) -> bool {
624- match sess. lto ( ) {
625- Lto :: Fat => true ,
626- Lto :: Thin => {
627- // If we defer LTO to the linker, we haven't run LTO ourselves, so
628- // any upstream object files have not been copied yet.
629- !sess. opts . cg . linker_plugin_lto . enabled ( )
630- }
631- Lto :: No |
632- Lto :: ThinLocal => false ,
633- }
634- }
0 commit comments