@@ -20,10 +20,12 @@ use serde::{Deserialize, Serialize};
20
20
use std:: cell:: RefCell ;
21
21
use std:: collections:: hash_map:: { Entry , HashMap } ;
22
22
use std:: path:: { Path , PathBuf } ;
23
+ use std:: rc:: Rc ;
23
24
use std:: str:: { self , FromStr } ;
24
25
use std:: sync:: Arc ;
25
26
26
- /// Information about the platform target gleaned from querying rustc.
27
+ /// Information about the platform target gleaned from querying rustc and from
28
+ /// merging configs.
27
29
///
28
30
/// [`RustcTargetData`] keeps several of these, one for the host and the others
29
31
/// for other specified targets. If no target is specified, it uses a clone from
@@ -54,6 +56,8 @@ pub struct TargetInfo {
54
56
pub rustflags : Arc < [ String ] > ,
55
57
/// Extra flags to pass to `rustdoc`, see [`extra_args`].
56
58
pub rustdocflags : Arc < [ String ] > ,
59
+ /// Linker to use. If the value is `None` it is left up to rustc.
60
+ pub linker : Option < Rc < PathBuf > > ,
57
61
/// Whether or not rustc (stably) supports the `--check-cfg` flag.
58
62
///
59
63
/// Can be removed once the minimum supported rustc version of Cargo is
@@ -157,6 +161,11 @@ impl TargetInfo {
157
161
requested_kinds : & [ CompileKind ] ,
158
162
rustc : & Rustc ,
159
163
kind : CompileKind ,
164
+ // This config is used for `links_overrides` and `linker`.
165
+ //
166
+ // In the case of target_applies_to_host=true (default) it may contain
167
+ // incorrect rustflags.
168
+ target_config : & TargetConfig ,
160
169
) -> CargoResult < TargetInfo > {
161
170
let mut rustflags =
162
171
extra_args ( gctx, requested_kinds, & rustc. host , None , kind, Flags :: Rust ) ?;
@@ -321,6 +330,7 @@ impl TargetInfo {
321
330
Flags :: Rustdoc ,
322
331
) ?
323
332
. into ( ) ,
333
+ linker : target_linker ( gctx, & cfg, target_config) ?. map ( Rc :: new) ,
324
334
cfg,
325
335
support_split_debuginfo,
326
336
support_check_cfg,
@@ -826,6 +836,42 @@ fn rustflags_from_target(
826
836
}
827
837
}
828
838
839
+ /// Gets the user-specified linker for a particular host or target from the configuration.
840
+ fn target_linker (
841
+ gctx : & GlobalContext ,
842
+ target_cfg : & [ Cfg ] ,
843
+ target_config : & TargetConfig ,
844
+ ) -> CargoResult < Option < PathBuf > > {
845
+ // Try host.linker and target.{}.linker.
846
+ if let Some ( path) = target_config
847
+ . linker
848
+ . as_ref ( )
849
+ . map ( |l| l. val . clone ( ) . resolve_program ( gctx) )
850
+ {
851
+ return Ok ( Some ( path) ) ;
852
+ }
853
+
854
+ // Try target.'cfg(...)'.linker.
855
+ let mut cfgs = gctx
856
+ . target_cfgs ( ) ?
857
+ . iter ( )
858
+ . filter_map ( |( key, cfg) | cfg. linker . as_ref ( ) . map ( |linker| ( key, linker) ) )
859
+ . filter ( |( key, _linker) | CfgExpr :: matches_key ( key, target_cfg) ) ;
860
+ let matching_linker = cfgs. next ( ) ;
861
+ if let Some ( ( key, linker) ) = cfgs. next ( ) {
862
+ anyhow:: bail!(
863
+ "several matching instances of `target.'cfg(..)'.linker` in configurations\n \
864
+ first match `{}` located in {}\n \
865
+ second match `{}` located in {}",
866
+ matching_linker. unwrap( ) . 0 ,
867
+ matching_linker. unwrap( ) . 1 . definition,
868
+ key,
869
+ linker. definition
870
+ ) ;
871
+ }
872
+ Ok ( matching_linker. map ( |( _k, linker) | linker. val . clone ( ) . resolve_program ( gctx) ) )
873
+ }
874
+
829
875
/// Gets compiler flags from `[host]` section in the config.
830
876
/// See [`extra_args`] for more.
831
877
fn rustflags_from_host (
@@ -893,22 +939,28 @@ impl<'gctx> RustcTargetData<'gctx> {
893
939
let mut target_info = HashMap :: new ( ) ;
894
940
let target_applies_to_host = gctx. target_applies_to_host ( ) ?;
895
941
let host_target = CompileTarget :: new ( & rustc. host ) ?;
896
- let host_info = TargetInfo :: new ( gctx, requested_kinds, & rustc, CompileKind :: Host ) ?;
897
942
898
943
// This config is used for link overrides and choosing a linker.
899
944
let host_config = if target_applies_to_host {
900
945
gctx. target_cfg_triple ( & rustc. host ) ?
901
946
} else {
902
947
gctx. host_cfg_triple ( & rustc. host ) ?
903
948
} ;
949
+ let host_info = TargetInfo :: new (
950
+ gctx,
951
+ requested_kinds,
952
+ & rustc,
953
+ CompileKind :: Host ,
954
+ & host_config,
955
+ ) ?;
904
956
905
957
// This is a hack. The unit_dependency graph builder "pretends" that
906
958
// `CompileKind::Host` is `CompileKind::Target(host)` if the
907
959
// `--target` flag is not specified. Since the unit_dependency code
908
960
// needs access to the target config data, create a copy so that it
909
961
// can be found. See `rebuild_unit_graph_shared` for why this is done.
910
962
if requested_kinds. iter ( ) . any ( CompileKind :: is_host) {
911
- target_config . insert ( host_target , gctx. target_cfg_triple ( & rustc. host ) ?) ;
963
+ let host_target_config = gctx. target_cfg_triple ( & rustc. host ) ?;
912
964
913
965
// If target_applies_to_host is true, the host_info is the target info,
914
966
// otherwise we need to build target info for the target.
@@ -920,9 +972,12 @@ impl<'gctx> RustcTargetData<'gctx> {
920
972
requested_kinds,
921
973
& rustc,
922
974
CompileKind :: Target ( host_target) ,
975
+ & host_target_config,
923
976
) ?;
924
977
target_info. insert ( host_target, host_target_info) ;
925
978
}
979
+
980
+ target_config. insert ( host_target, host_target_config) ;
926
981
} ;
927
982
928
983
let mut res = RustcTargetData {
@@ -969,14 +1024,20 @@ impl<'gctx> RustcTargetData<'gctx> {
969
1024
/// Insert `kind` into our `target_info` and `target_config` members if it isn't present yet.
970
1025
pub fn merge_compile_kind ( & mut self , kind : CompileKind ) -> CargoResult < ( ) > {
971
1026
if let CompileKind :: Target ( target) = kind {
972
- if ! self . target_config . contains_key ( & target) {
973
- self . target_config
974
- . insert ( target , self . gctx . target_cfg_triple ( target. short_name ( ) ) ?) ;
975
- }
1027
+ let target_config : & TargetConfig = match self . target_config . entry ( target) {
1028
+ Entry :: Occupied ( o ) => o . into_mut ( ) ,
1029
+ Entry :: Vacant ( v ) => v . insert ( self . gctx . target_cfg_triple ( target. short_name ( ) ) ?) ,
1030
+ } ;
976
1031
if !self . target_info . contains_key ( & target) {
977
1032
self . target_info . insert (
978
1033
target,
979
- TargetInfo :: new ( self . gctx , & self . requested_kinds , & self . rustc , kind) ?,
1034
+ TargetInfo :: new (
1035
+ self . gctx ,
1036
+ & self . requested_kinds ,
1037
+ & self . rustc ,
1038
+ kind,
1039
+ target_config,
1040
+ ) ?,
980
1041
) ;
981
1042
}
982
1043
}
0 commit comments