From 6a6ebb4403683e1e12d3916cabc1a4898ce798cf Mon Sep 17 00:00:00 2001 From: Victor Ding Date: Sat, 21 Dec 2019 21:37:15 +1100 Subject: [PATCH] Add `-Z no-link` flag Adds a compiler option to allow rustc compile a crate without linking. With this flag, rustc serializes codegen_results into a .rlink file. --- Cargo.lock | 1 + src/librustc/middle/cstore.rs | 5 ++-- src/librustc/middle/dependency_format.rs | 2 +- src/librustc_codegen_llvm/Cargo.toml | 1 + src/librustc_codegen_llvm/lib.rs | 14 ++++++++++ src/librustc_codegen_ssa/back/linker.rs | 1 + src/librustc_codegen_ssa/lib.rs | 14 +++++++--- src/librustc_hir/def_id.rs | 34 ++++++++++++++++++++---- src/librustc_session/config.rs | 2 +- src/librustc_session/options.rs | 2 ++ src/librustc_session/search_paths.rs | 2 +- 11 files changed, 65 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0a76aabc3a312..237b3dda670df 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3428,6 +3428,7 @@ dependencies = [ "rustc_session", "rustc_span", "rustc_target", + "serialize", "smallvec 1.0.0", "syntax", ] diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 5b1e7673629b1..0e7ff3a3393ef 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -27,7 +27,7 @@ pub use rustc_session::utils::NativeLibraryKind; /// Where a crate came from on the local filesystem. One of these three options /// must be non-None. -#[derive(PartialEq, Clone, Debug, HashStable)] +#[derive(PartialEq, Clone, Debug, HashStable, RustcEncodable, RustcDecodable)] pub struct CrateSource { pub dylib: Option<(PathBuf, PathKind)>, pub rlib: Option<(PathBuf, PathKind)>, @@ -75,7 +75,7 @@ impl DepKind { } } -#[derive(PartialEq, Clone, Debug)] +#[derive(PartialEq, Clone, Debug, RustcEncodable, RustcDecodable)] pub enum LibSource { Some(PathBuf), MetadataOnly, @@ -160,6 +160,7 @@ pub enum ExternCrateSource { Path, } +#[derive(RustcEncodable, RustcDecodable)] pub struct EncodedMetadata { pub raw_data: Vec, } diff --git a/src/librustc/middle/dependency_format.rs b/src/librustc/middle/dependency_format.rs index 8b2bf55ccc120..6ece51fe86674 100644 --- a/src/librustc/middle/dependency_format.rs +++ b/src/librustc/middle/dependency_format.rs @@ -19,7 +19,7 @@ pub type DependencyList = Vec; /// This is local to the tcx, and is generally relevant to one session. pub type Dependencies = Vec<(config::CrateType, DependencyList)>; -#[derive(Copy, Clone, PartialEq, Debug, HashStable)] +#[derive(Copy, Clone, PartialEq, Debug, HashStable, RustcEncodable, RustcDecodable)] pub enum Linkage { NotLinked, IncludedFromDylib, diff --git a/src/librustc_codegen_llvm/Cargo.toml b/src/librustc_codegen_llvm/Cargo.toml index 3ff5495e29136..dd9eadde098ec 100644 --- a/src/librustc_codegen_llvm/Cargo.toml +++ b/src/librustc_codegen_llvm/Cargo.toml @@ -28,6 +28,7 @@ rustc_incremental = { path = "../librustc_incremental" } rustc_index = { path = "../librustc_index" } rustc_llvm = { path = "../librustc_llvm" } rustc_session = { path = "../librustc_session" } +rustc_serialize = { path = "../libserialize", package = "serialize" } rustc_target = { path = "../librustc_target" } smallvec = { version = "1.0", features = ["union", "may_dangle"] } syntax = { path = "../libsyntax" } diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs index a6168128c4d44..70e3874035b60 100644 --- a/src/librustc_codegen_llvm/lib.rs +++ b/src/librustc_codegen_llvm/lib.rs @@ -33,6 +33,7 @@ use rustc_codegen_ssa::CompiledModule; use rustc_errors::{FatalError, Handler}; use std::any::Any; use std::ffi::CStr; +use std::fs; use std::sync::Arc; use syntax::expand::allocator::AllocatorKind; @@ -44,6 +45,7 @@ use rustc::ty::{self, TyCtxt}; use rustc::util::common::ErrorReported; use rustc_codegen_ssa::ModuleCodegen; use rustc_codegen_utils::codegen_backend::CodegenBackend; +use rustc_serialize::json; mod back { pub mod archive; @@ -298,6 +300,18 @@ impl CodegenBackend for LlvmCodegenBackend { return Ok(()); } + if sess.opts.debugging_opts.no_link { + // FIXME: use a binary format to encode the `.rlink` file + let rlink_data = json::encode(&codegen_results).map_err(|err| { + sess.fatal(&format!("failed to encode rlink: {}", err)); + })?; + let rlink_file = outputs.with_extension("rlink"); + fs::write(&rlink_file, rlink_data).map_err(|err| { + sess.fatal(&format!("failed to write file {}: {}", rlink_file.display(), err)); + })?; + return Ok(()); + } + // Run the linker on any artifacts that resulted from the LLVM run. // This should produce either a finished executable or library. sess.time("link_crate", || { diff --git a/src/librustc_codegen_ssa/back/linker.rs b/src/librustc_codegen_ssa/back/linker.rs index 4679f6501336c..695f171dfb49c 100644 --- a/src/librustc_codegen_ssa/back/linker.rs +++ b/src/librustc_codegen_ssa/back/linker.rs @@ -20,6 +20,7 @@ use rustc_target::spec::{LinkerFlavor, LldFlavor}; /// For all the linkers we support, and information they might /// need out of the shared crate context before we get rid of it. +#[derive(RustcEncodable, RustcDecodable)] pub struct LinkerInfo { exports: FxHashMap>, } diff --git a/src/librustc_codegen_ssa/lib.rs b/src/librustc_codegen_ssa/lib.rs index aba77231268e7..b69def5428ccf 100644 --- a/src/librustc_codegen_ssa/lib.rs +++ b/src/librustc_codegen_ssa/lib.rs @@ -87,7 +87,7 @@ impl ModuleCodegen { } } -#[derive(Debug)] +#[derive(Debug, RustcEncodable, RustcDecodable)] pub struct CompiledModule { pub name: String, pub kind: ModuleKind, @@ -101,7 +101,7 @@ pub struct CachedModuleCodegen { pub source: WorkProduct, } -#[derive(Copy, Clone, Debug, PartialEq)] +#[derive(Copy, Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)] pub enum ModuleKind { Regular, Metadata, @@ -117,7 +117,14 @@ bitflags::bitflags! { } /// Misc info we load from metadata to persist beyond the tcx. -#[derive(Debug)] +/// +/// Note: though `CrateNum` is only meaningful within the same tcx, information within `CrateInfo` +/// is self-contained. `CrateNum` can be viewed as a unique identifier within a `CrateInfo`, where +/// `used_crate_source` contains all `CrateSource` of the dependents, and maintains a mapping from +/// identifiers (`CrateNum`) to `CrateSource`. The other fields map `CrateNum` to the crate's own +/// additional properties, so that effectively we can retrieve each dependent crate's `CrateSource` +/// and the corresponding properties without referencing information outside of a `CrateInfo`. +#[derive(Debug, RustcEncodable, RustcDecodable)] pub struct CrateInfo { pub panic_runtime: Option, pub compiler_builtins: Option, @@ -135,6 +142,7 @@ pub struct CrateInfo { pub dependency_formats: Lrc, } +#[derive(RustcEncodable, RustcDecodable)] pub struct CodegenResults { pub crate_name: Symbol, pub modules: Vec, diff --git a/src/librustc_hir/def_id.rs b/src/librustc_hir/def_id.rs index f8cacdc6238e8..7ee778ddd8ec7 100644 --- a/src/librustc_hir/def_id.rs +++ b/src/librustc_hir/def_id.rs @@ -1,7 +1,8 @@ use rustc_data_structures::AtomicRef; use rustc_index::vec::Idx; +use rustc_serialize::{Decoder, Encoder}; use std::fmt; -use std::u32; +use std::{u32, u64}; rustc_index::newtype_index! { pub struct CrateId { @@ -86,8 +87,18 @@ impl fmt::Display for CrateNum { } } -impl rustc_serialize::UseSpecializedEncodable for CrateNum {} -impl rustc_serialize::UseSpecializedDecodable for CrateNum {} +/// As a local identifier, a `CrateNum` is only meaningful within its context, e.g. within a tcx. +/// Therefore, make sure to include the context when encode a `CrateNum`. +impl rustc_serialize::UseSpecializedEncodable for CrateNum { + fn default_encode(&self, e: &mut E) -> Result<(), E::Error> { + e.emit_u32(self.as_u32()) + } +} +impl rustc_serialize::UseSpecializedDecodable for CrateNum { + fn default_decode(d: &mut D) -> Result { + Ok(CrateNum::from_u32(d.read_u32()?)) + } +} rustc_index::newtype_index! { /// A DefIndex is an index into the hir-map for a crate, identifying a @@ -135,8 +146,21 @@ impl DefId { } } -impl rustc_serialize::UseSpecializedEncodable for DefId {} -impl rustc_serialize::UseSpecializedDecodable for DefId {} +impl rustc_serialize::UseSpecializedEncodable for DefId { + fn default_encode(&self, s: &mut S) -> Result<(), S::Error> { + let krate = u64::from(self.krate.as_u32()); + let index = u64::from(self.index.as_u32()); + s.emit_u64((krate << 32) | index) + } +} +impl rustc_serialize::UseSpecializedDecodable for DefId { + fn default_decode(d: &mut D) -> Result { + let def_id = d.read_u64()?; + let krate = CrateNum::from_u32((def_id >> 32) as u32); + let index = DefIndex::from_u32((def_id & 0xffffffff) as u32); + Ok(DefId { krate, index }) + } +} pub fn default_def_id_debug(def_id: DefId, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("DefId").field("krate", &def_id.krate).field("index", &def_id.index).finish() diff --git a/src/librustc_session/config.rs b/src/librustc_session/config.rs index b6b22e298ca62..b1ba81aa95b19 100644 --- a/src/librustc_session/config.rs +++ b/src/librustc_session/config.rs @@ -619,7 +619,7 @@ pub enum EntryFnType { impl_stable_hash_via_hash!(EntryFnType); -#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug)] +#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub enum CrateType { Executable, Dylib, diff --git a/src/librustc_session/options.rs b/src/librustc_session/options.rs index 2a0ed27b63b08..34da2188a51d2 100644 --- a/src/librustc_session/options.rs +++ b/src/librustc_session/options.rs @@ -950,4 +950,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, (such as entering an empty infinite loop) by inserting llvm.sideeffect"), deduplicate_diagnostics: Option = (None, parse_opt_bool, [UNTRACKED], "deduplicate identical diagnostics"), + no_link: bool = (false, parse_bool, [TRACKED], + "compile without linking"), } diff --git a/src/librustc_session/search_paths.rs b/src/librustc_session/search_paths.rs index b15f4e8f6c18e..06f408b4a8d64 100644 --- a/src/librustc_session/search_paths.rs +++ b/src/librustc_session/search_paths.rs @@ -9,7 +9,7 @@ pub struct SearchPath { pub files: Vec, } -#[derive(PartialEq, Clone, Copy, Debug, Hash, Eq)] +#[derive(PartialEq, Clone, Copy, Debug, Hash, Eq, RustcEncodable, RustcDecodable)] pub enum PathKind { Native, Crate,