1
1
//! All functions here are copied from https://github.com/rust-lang/rust/blob/942864a000efd74b73e36bda5606b2cdb55ecf39/src/librustc_codegen_llvm/back/link.rs
2
2
3
- use std:: fmt;
4
- use std:: fs;
5
- use std:: io;
6
- use std:: iter;
7
3
use std:: path:: { Path , PathBuf } ;
8
- use std:: process:: { Output , Stdio } ;
9
-
10
- use log:: info;
11
4
12
5
use rustc:: middle:: cstore:: { NativeLibrary , NativeLibraryKind } ;
13
6
use rustc:: middle:: dependency_format:: Linkage ;
14
7
use rustc:: session:: config:: { self , OutputType , RUST_CGU_EXT } ;
15
8
use rustc:: session:: search_paths:: PathKind ;
16
9
use rustc:: session:: Session ;
17
10
use rustc:: util:: common:: time;
18
- use rustc_codegen_ssa:: back :: command :: Command ;
11
+ use rustc_codegen_ssa:: { METADATA_FILENAME , RLIB_BYTECODE_EXTENSION } ;
19
12
use rustc_codegen_ssa:: back:: linker:: * ;
20
13
use rustc_codegen_ssa:: back:: link:: * ;
21
14
use rustc_data_structures:: fx:: FxHashSet ;
@@ -25,11 +18,6 @@ use syntax::attr;
25
18
use crate :: prelude:: * ;
26
19
27
20
use 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" ;
33
21
34
22
fn archive_search_paths ( sess : & Session ) -> Vec < PathBuf > {
35
23
sess. target_filesearch ( PathKind :: Native ) . search_path_dirs ( )
@@ -46,147 +34,6 @@ fn archive_config<'a>(sess: &'a Session,
46
34
}
47
35
}
48
36
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
-
190
37
// # Rust Crate linking
191
38
//
192
39
// 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,
505
352
parent. unwrap_or ( Path :: new ( "" ) ) ) ;
506
353
}
507
354
}
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