Skip to content

Commit 39ffea3

Browse files
Implement a file-path remapping feature in support of debuginfo and reproducible builds.
1 parent b0a4074 commit 39ffea3

File tree

34 files changed

+462
-313
lines changed

34 files changed

+462
-313
lines changed

src/grammar/verify.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ fn main() {
296296
syntax::errors::registry::Registry::new(&[]),
297297
Rc::new(DummyCrateStore));
298298
let filemap = session.parse_sess.codemap()
299-
.new_filemap("<n/a>".to_string(), None, code);
299+
.new_filemap("<n/a>".to_string(), code);
300300
let mut lexer = lexer::StringReader::new(session.diagnostic(), filemap);
301301
let cm = session.codemap();
302302

src/librustc/session/config.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use lint;
2525
use middle::cstore;
2626

2727
use syntax::ast::{self, IntTy, UintTy};
28+
use syntax::codemap::FilePathMapping;
2829
use syntax::parse::token;
2930
use syntax::parse;
3031
use syntax::symbol::Symbol;
@@ -492,6 +493,14 @@ impl Options {
492493
self.incremental.is_none() ||
493494
self.cg.codegen_units == 1
494495
}
496+
497+
pub fn file_path_mapping(&self) -> FilePathMapping {
498+
FilePathMapping::new(
499+
self.debugging_opts.remap_path_prefix_from.iter().zip(
500+
self.debugging_opts.remap_path_prefix_to.iter()
501+
).map(|(src, dst)| (src.clone(), dst.clone())).collect()
502+
)
503+
}
495504
}
496505

497506
// The type of entry function, so
@@ -1012,6 +1021,10 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
10121021
"Set the optimization fuel quota for a crate."),
10131022
print_fuel: Option<String> = (None, parse_opt_string, [TRACKED],
10141023
"Make Rustc print the total optimization fuel used by a crate."),
1024+
remap_path_prefix_from: Vec<String> = (vec![], parse_string_push, [TRACKED],
1025+
"add a source pattern to the file path remapping config"),
1026+
remap_path_prefix_to: Vec<String> = (vec![], parse_string_push, [TRACKED],
1027+
"add a mapping target to the file path remapping config"),
10151028
}
10161029

10171030
pub fn default_lib_output() -> CrateType {
@@ -1319,7 +1332,7 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
13191332
// Convert strings provided as --cfg [cfgspec] into a crate_cfg
13201333
pub fn parse_cfgspecs(cfgspecs: Vec<String> ) -> ast::CrateConfig {
13211334
cfgspecs.into_iter().map(|s| {
1322-
let sess = parse::ParseSess::new();
1335+
let sess = parse::ParseSess::new(FilePathMapping::empty());
13231336
let mut parser =
13241337
parse::new_parser_from_source_str(&sess, "cfgspec".to_string(), s.to_string());
13251338

src/librustc/session/mod.rs

+17-12
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,10 @@ pub struct Session {
7474
// The name of the root source file of the crate, in the local file system.
7575
// The path is always expected to be absolute. `None` means that there is no
7676
// source file.
77-
pub local_crate_source_file: Option<PathBuf>,
78-
pub working_dir: PathBuf,
77+
pub local_crate_source_file: Option<String>,
78+
// The directory the compiler has been executed in plus a flag indicating
79+
// if the value stored here has been affected by path remapping.
80+
pub working_dir: (String, bool),
7981
pub lint_store: RefCell<lint::LintStore>,
8082
pub lints: RefCell<lint::LintTable>,
8183
/// Set of (LintId, span, message) tuples tracking lint (sub)diagnostics
@@ -553,12 +555,14 @@ pub fn build_session(sopts: config::Options,
553555
registry: errors::registry::Registry,
554556
cstore: Rc<CrateStore>)
555557
-> Session {
558+
let file_path_mapping = sopts.file_path_mapping();
559+
556560
build_session_with_codemap(sopts,
557561
dep_graph,
558562
local_crate_source_file,
559563
registry,
560564
cstore,
561-
Rc::new(codemap::CodeMap::new()),
565+
Rc::new(codemap::CodeMap::new(file_path_mapping)),
562566
None)
563567
}
564568

@@ -622,7 +626,7 @@ pub fn build_session_(sopts: config::Options,
622626
Ok(t) => t,
623627
Err(e) => {
624628
panic!(span_diagnostic.fatal(&format!("Error loading host specification: {}", e)));
625-
}
629+
}
626630
};
627631
let target_cfg = config::build_target_config(&sopts, &span_diagnostic);
628632
let p_s = parse::ParseSess::with_span_handler(span_diagnostic, codemap);
@@ -631,21 +635,22 @@ pub fn build_session_(sopts: config::Options,
631635
None => Some(filesearch::get_or_default_sysroot())
632636
};
633637

638+
let file_path_mapping = sopts.file_path_mapping();
639+
634640
// Make the path absolute, if necessary
635-
let local_crate_source_file = local_crate_source_file.map(|path|
636-
if path.is_absolute() {
637-
path.clone()
638-
} else {
639-
env::current_dir().unwrap().join(&path)
640-
}
641-
);
641+
let local_crate_source_file = local_crate_source_file.map(|path| {
642+
file_path_mapping.map_prefix(path.to_string_lossy().into_owned()).0
643+
});
642644

643645
let optimization_fuel_crate = sopts.debugging_opts.fuel.as_ref().map(|i| i.0.clone());
644646
let optimization_fuel_limit = Cell::new(sopts.debugging_opts.fuel.as_ref()
645647
.map(|i| i.1).unwrap_or(0));
646648
let print_fuel_crate = sopts.debugging_opts.print_fuel.clone();
647649
let print_fuel = Cell::new(0);
648650

651+
let working_dir = env::current_dir().unwrap().to_string_lossy().into_owned();
652+
let working_dir = file_path_mapping.map_prefix(working_dir);
653+
649654
let sess = Session {
650655
dep_graph: dep_graph.clone(),
651656
target: target_cfg,
@@ -660,7 +665,7 @@ pub fn build_session_(sopts: config::Options,
660665
derive_registrar_fn: Cell::new(None),
661666
default_sysroot: default_sysroot,
662667
local_crate_source_file: local_crate_source_file,
663-
working_dir: env::current_dir().unwrap(),
668+
working_dir: working_dir,
664669
lint_store: RefCell::new(lint::LintStore::new()),
665670
lints: RefCell::new(lint::LintTable::new()),
666671
one_time_diagnostics: RefCell::new(FxHashSet()),

src/librustc_driver/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ pub fn run_compiler<'a>(args: &[String],
206206
let cstore = Rc::new(CStore::new(&dep_graph));
207207

208208
let loader = file_loader.unwrap_or(box RealFileLoader);
209-
let codemap = Rc::new(CodeMap::with_file_loader(loader));
209+
let codemap = Rc::new(CodeMap::with_file_loader(loader, sopts.file_path_mapping()));
210210
let mut sess = session::build_session_with_codemap(
211211
sopts, &dep_graph, input_file_path, descriptions, cstore.clone(), codemap, emitter_dest,
212212
);

src/librustc_driver/test.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use rustc::session::{self, config};
3131
use std::rc::Rc;
3232
use syntax::ast;
3333
use syntax::abi::Abi;
34-
use syntax::codemap::CodeMap;
34+
use syntax::codemap::{CodeMap, FilePathMapping};
3535
use errors;
3636
use errors::emitter::Emitter;
3737
use errors::{Level, DiagnosticBuilder};
@@ -108,7 +108,7 @@ fn test_env<F>(source_string: &str,
108108
&dep_graph,
109109
None,
110110
diagnostic_handler,
111-
Rc::new(CodeMap::new()),
111+
Rc::new(CodeMap::new(FilePathMapping::empty())),
112112
cstore.clone());
113113
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
114114
let input = config::Input::Str {

src/librustc_metadata/cstore_impl.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,7 @@ impl CrateStore for cstore::CStore {
395395
let (name, def) = data.get_macro(id.index);
396396
let source_name = format!("<{} macros>", name);
397397

398-
let filemap = sess.parse_sess.codemap().new_filemap(source_name, None, def.body);
398+
let filemap = sess.parse_sess.codemap().new_filemap(source_name, def.body);
399399
let local_span = Span { lo: filemap.start_pos, hi: filemap.end_pos, ctxt: NO_EXPANSION };
400400
let body = filemap_to_stream(&sess.parse_sess, filemap);
401401

src/librustc_metadata/decoder.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1134,7 +1134,7 @@ impl<'a, 'tcx> CrateMetadata {
11341134
// We can't reuse an existing FileMap, so allocate a new one
11351135
// containing the information we need.
11361136
let syntax_pos::FileMap { name,
1137-
abs_path,
1137+
name_was_remapped,
11381138
start_pos,
11391139
end_pos,
11401140
lines,
@@ -1158,7 +1158,7 @@ impl<'a, 'tcx> CrateMetadata {
11581158
}
11591159

11601160
let local_version = local_codemap.new_imported_filemap(name,
1161-
abs_path,
1161+
name_was_remapped,
11621162
source_length,
11631163
lines,
11641164
multibyte_chars);

src/librustc_metadata/encoder.rs

+30-2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ use std::hash::Hash;
3030
use std::intrinsics;
3131
use std::io::prelude::*;
3232
use std::io::Cursor;
33+
use std::path::Path;
3334
use std::rc::Rc;
3435
use std::u32;
3536
use syntax::ast::{self, CRATE_NODE_ID};
@@ -1268,13 +1269,40 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
12681269
fn encode_codemap(&mut self) -> LazySeq<syntax_pos::FileMap> {
12691270
let codemap = self.tcx.sess.codemap();
12701271
let all_filemaps = codemap.files.borrow();
1271-
self.lazy_seq_ref(all_filemaps.iter()
1272+
let adapted = all_filemaps.iter()
12721273
.filter(|filemap| {
12731274
// No need to re-export imported filemaps, as any downstream
12741275
// crate will import them from their original source.
12751276
!filemap.is_imported()
12761277
})
1277-
.map(|filemap| &**filemap))
1278+
.map(|filemap| {
1279+
// When exporting FileMaps, we expand all paths to absolute
1280+
// paths because any relative paths are potentially relative to
1281+
// a wrong directory.
1282+
// However, if a path has been modified via
1283+
// `-Zremap-path-prefix` we assume the user has already set
1284+
// things up the way they want and don't touch the path values
1285+
// anymore.
1286+
let name = Path::new(&filemap.name);
1287+
let (ref working_dir, working_dir_was_remapped) = self.tcx.sess.working_dir;
1288+
if filemap.name_was_remapped ||
1289+
(name.is_relative() && working_dir_was_remapped) {
1290+
// This path of this FileMap has been modified by
1291+
// path-remapping, so we use it verbatim (and avoid cloning
1292+
// the whole map in the process).
1293+
filemap.clone()
1294+
} else {
1295+
let mut adapted = (**filemap).clone();
1296+
let abs_path = Path::new(working_dir).join(name)
1297+
.to_string_lossy()
1298+
.into_owned();
1299+
adapted.name = abs_path;
1300+
Rc::new(adapted)
1301+
}
1302+
})
1303+
.collect::<Vec<_>>();
1304+
1305+
self.lazy_seq_ref(adapted.iter().map(|fm| &**fm))
12781306
}
12791307

12801308
fn encode_def_path_table(&mut self) -> Lazy<DefPathTable> {

src/librustc_save_analysis/dump_visitor.rs

+2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ use rustc::ty::{self, TyCtxt, AssociatedItemContainer};
3737
use std::collections::HashSet;
3838
use std::collections::hash_map::DefaultHasher;
3939
use std::hash::*;
40+
use std::path::Path;
4041

4142
use syntax::ast::{self, NodeId, PatKind, Attribute, CRATE_NODE_ID};
4243
use syntax::parse::token;
@@ -128,6 +129,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
128129
pub fn dump_crate_info(&mut self, name: &str, krate: &ast::Crate) {
129130
let source_file = self.tcx.sess.local_crate_source_file.as_ref();
130131
let crate_root = source_file.map(|source_file| {
132+
let source_file = Path::new(source_file);
131133
match source_file.file_name() {
132134
Some(_) => source_file.parent().unwrap().display().to_string(),
133135
None => source_file.display().to_string(),

src/librustc_trans/debuginfo/create_scope_map.rs

+13-10
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use super::FunctionDebugContext;
11+
use super::{FunctionDebugContext, FunctionDebugContextData};
1212
use super::metadata::file_metadata;
1313
use super::utils::{DIB, span_start};
1414

1515
use llvm;
16-
use llvm::debuginfo::{DIScope, DISubprogram};
16+
use llvm::debuginfo::DIScope;
1717
use common::CrateContext;
1818
use rustc::mir::{Mir, VisibilityScope};
1919

@@ -53,8 +53,8 @@ pub fn create_mir_scopes(ccx: &CrateContext, mir: &Mir, debug_context: &Function
5353
};
5454
let mut scopes = IndexVec::from_elem(null_scope, &mir.visibility_scopes);
5555

56-
let fn_metadata = match *debug_context {
57-
FunctionDebugContext::RegularContext(ref data) => data.fn_metadata,
56+
let debug_context = match *debug_context {
57+
FunctionDebugContext::RegularContext(ref data) => data,
5858
FunctionDebugContext::DebugInfoDisabled |
5959
FunctionDebugContext::FunctionWithoutDebugInfo => {
6060
return scopes;
@@ -71,7 +71,7 @@ pub fn create_mir_scopes(ccx: &CrateContext, mir: &Mir, debug_context: &Function
7171
// Instantiate all scopes.
7272
for idx in 0..mir.visibility_scopes.len() {
7373
let scope = VisibilityScope::new(idx);
74-
make_mir_scope(ccx, &mir, &has_variables, fn_metadata, scope, &mut scopes);
74+
make_mir_scope(ccx, &mir, &has_variables, debug_context, scope, &mut scopes);
7575
}
7676

7777
scopes
@@ -80,7 +80,7 @@ pub fn create_mir_scopes(ccx: &CrateContext, mir: &Mir, debug_context: &Function
8080
fn make_mir_scope(ccx: &CrateContext,
8181
mir: &Mir,
8282
has_variables: &BitVector,
83-
fn_metadata: DISubprogram,
83+
debug_context: &FunctionDebugContextData,
8484
scope: VisibilityScope,
8585
scopes: &mut IndexVec<VisibilityScope, MirDebugScope>) {
8686
if scopes[scope].is_valid() {
@@ -89,13 +89,13 @@ fn make_mir_scope(ccx: &CrateContext,
8989

9090
let scope_data = &mir.visibility_scopes[scope];
9191
let parent_scope = if let Some(parent) = scope_data.parent_scope {
92-
make_mir_scope(ccx, mir, has_variables, fn_metadata, parent, scopes);
92+
make_mir_scope(ccx, mir, has_variables, debug_context, parent, scopes);
9393
scopes[parent]
9494
} else {
9595
// The root is the function itself.
9696
let loc = span_start(ccx, mir.span);
9797
scopes[scope] = MirDebugScope {
98-
scope_metadata: fn_metadata,
98+
scope_metadata: debug_context.fn_metadata,
9999
file_start_pos: loc.file.start_pos,
100100
file_end_pos: loc.file.end_pos,
101101
};
@@ -109,14 +109,17 @@ fn make_mir_scope(ccx: &CrateContext,
109109
// However, we don't skip creating a nested scope if
110110
// our parent is the root, because we might want to
111111
// put arguments in the root and not have shadowing.
112-
if parent_scope.scope_metadata != fn_metadata {
112+
if parent_scope.scope_metadata != debug_context.fn_metadata {
113113
scopes[scope] = parent_scope;
114114
return;
115115
}
116116
}
117117

118118
let loc = span_start(ccx, scope_data.span);
119-
let file_metadata = file_metadata(ccx, &loc.file.name, &loc.file.abs_path);
119+
let file_metadata = file_metadata(ccx,
120+
&loc.file.name,
121+
debug_context.defining_crate);
122+
120123
let scope_metadata = unsafe {
121124
llvm::LLVMRustDIBuilderCreateLexicalBlock(
122125
DIB(ccx),

0 commit comments

Comments
 (0)