Skip to content

Commit ac26538

Browse files
committed
Initial support for dynamically linked crates
1 parent 5fe04cb commit ac26538

File tree

70 files changed

+1533
-117
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+1533
-117
lines changed

Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -4012,6 +4012,7 @@ dependencies = [
40124012
"rustc_session",
40134013
"rustc_span",
40144014
"rustc_target",
4015+
"tempfile",
40154016
"tracing",
40164017
]
40174018

compiler/rustc_ast_lowering/src/item.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1310,7 +1310,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
13101310
// create a fake body so that the entire rest of the compiler doesn't have to deal with
13111311
// this as a special case.
13121312
return self.lower_fn_body(decl, contract, |this| {
1313-
if attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic)) {
1313+
if attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic))
1314+
|| this.tcx.is_sdylib_interface_build()
1315+
{
13141316
let span = this.lower_span(span);
13151317
let empty_block = hir::Block {
13161318
hir_id: this.next_id(),

compiler/rustc_ast_passes/src/ast_validation.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ struct AstValidator<'a> {
8282
/// Used to ban explicit safety on foreign items when the extern block is not marked as unsafe.
8383
extern_mod_safety: Option<Safety>,
8484

85+
is_sdylib_interface: bool,
86+
8587
lint_buffer: &'a mut LintBuffer,
8688
}
8789

@@ -948,7 +950,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
948950
self.check_defaultness(item.span, *defaultness);
949951

950952
let is_intrinsic = item.attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic));
951-
if body.is_none() && !is_intrinsic {
953+
if body.is_none() && !is_intrinsic && !self.is_sdylib_interface {
952954
self.dcx().emit_err(errors::FnWithoutBody {
953955
span: item.span,
954956
replace_span: self.ending_semi_or_hi(item.span),
@@ -1435,7 +1437,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
14351437
});
14361438
}
14371439
AssocItemKind::Fn(box Fn { body, .. }) => {
1438-
if body.is_none() {
1440+
if body.is_none() && !self.is_sdylib_interface {
14391441
self.dcx().emit_err(errors::AssocFnWithoutBody {
14401442
span: item.span,
14411443
replace_span: self.ending_semi_or_hi(item.span),
@@ -1683,6 +1685,7 @@ pub fn check_crate(
16831685
sess: &Session,
16841686
features: &Features,
16851687
krate: &Crate,
1688+
is_sdylib_interface: bool,
16861689
lints: &mut LintBuffer,
16871690
) -> bool {
16881691
let mut validator = AstValidator {
@@ -1694,6 +1697,7 @@ pub fn check_crate(
16941697
outer_impl_trait_span: None,
16951698
disallow_tilde_const: Some(TildeConstReason::Item),
16961699
extern_mod_safety: None,
1700+
is_sdylib_interface,
16971701
lint_buffer: lints,
16981702
};
16991703
visit::walk_crate(&mut validator, krate);

compiler/rustc_ast_pretty/src/pprust/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ use std::borrow::Cow;
77
use rustc_ast as ast;
88
use rustc_ast::token::{Token, TokenKind};
99
use rustc_ast::tokenstream::{TokenStream, TokenTree};
10-
pub use state::{AnnNode, Comments, PpAnn, PrintState, State, print_crate};
10+
pub use state::{
11+
AnnNode, Comments, PpAnn, PrintState, State, print_crate, print_crate_as_interface,
12+
};
1113

1214
/// Print the token kind precisely, without converting `$crate` into its respective crate name.
1315
pub fn token_kind_to_string(tok: &TokenKind) -> Cow<'static, str> {

compiler/rustc_ast_pretty/src/pprust/state.rs

+30-4
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ pub struct State<'a> {
221221
pub s: pp::Printer,
222222
comments: Option<Comments<'a>>,
223223
ann: &'a (dyn PpAnn + 'a),
224+
is_sdylib_interface: bool,
224225
}
225226

226227
const INDENT_UNIT: isize = 4;
@@ -236,10 +237,37 @@ pub fn print_crate<'a>(
236237
is_expanded: bool,
237238
edition: Edition,
238239
g: &AttrIdGenerator,
240+
) -> String {
241+
let mut s = State {
242+
s: pp::Printer::new(),
243+
comments: Some(Comments::new(sm, filename, input)),
244+
ann,
245+
is_sdylib_interface: false,
246+
};
247+
248+
print_crate_inner(&mut s, krate, is_expanded, edition, g);
249+
s.s.eof()
250+
}
251+
252+
pub fn print_crate_as_interface(
253+
krate: &ast::Crate,
254+
edition: Edition,
255+
g: &AttrIdGenerator,
239256
) -> String {
240257
let mut s =
241-
State { s: pp::Printer::new(), comments: Some(Comments::new(sm, filename, input)), ann };
258+
State { s: pp::Printer::new(), comments: None, ann: &NoAnn, is_sdylib_interface: true };
242259

260+
print_crate_inner(&mut s, krate, false, edition, g);
261+
s.s.eof()
262+
}
263+
264+
fn print_crate_inner<'a>(
265+
s: &mut State<'a>,
266+
krate: &ast::Crate,
267+
is_expanded: bool,
268+
edition: Edition,
269+
g: &AttrIdGenerator,
270+
) {
243271
// We need to print shebang before anything else
244272
// otherwise the resulting code will not compile
245273
// and shebang will be useless.
@@ -282,8 +310,6 @@ pub fn print_crate<'a>(
282310
s.print_item(item);
283311
}
284312
s.print_remaining_comments();
285-
s.ann.post(&mut s, AnnNode::Crate(krate));
286-
s.s.eof()
287313
}
288314

289315
/// Should two consecutive tokens be printed with a space between them?
@@ -1111,7 +1137,7 @@ impl<'a> PrintState<'a> for State<'a> {
11111137

11121138
impl<'a> State<'a> {
11131139
pub fn new() -> State<'a> {
1114-
State { s: pp::Printer::new(), comments: None, ann: &NoAnn }
1140+
State { s: pp::Printer::new(), comments: None, ann: &NoAnn, is_sdylib_interface: false }
11151141
}
11161142

11171143
fn commasep_cmnt<T, F, G>(&mut self, b: Breaks, elts: &[T], mut op: F, mut get_span: G)

compiler/rustc_ast_pretty/src/pprust/state/item.rs

+11
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,10 @@ impl<'a> State<'a> {
160160

161161
/// Pretty-prints an item.
162162
pub(crate) fn print_item(&mut self, item: &ast::Item) {
163+
if self.is_sdylib_interface && item.span.is_dummy() {
164+
// Do not print prelude for interface files.
165+
return;
166+
}
163167
self.hardbreak_if_not_bol();
164168
self.maybe_print_comment(item.span.lo());
165169
self.print_outer_attributes(&item.attrs);
@@ -682,6 +686,13 @@ impl<'a> State<'a> {
682686
self.print_contract(contract);
683687
}
684688
if let Some((body, (cb, ib))) = body_cb_ib {
689+
if self.is_sdylib_interface {
690+
self.word(";");
691+
self.end(ib); // end inner head-block
692+
self.end(cb); // end outer head-block
693+
return;
694+
}
695+
685696
self.nbsp();
686697
self.print_block_with_attrs(body, attrs, cb, ib);
687698
} else {

compiler/rustc_codegen_gcc/src/back/lto.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,11 @@ use crate::{GccCodegenBackend, GccContext, SyncContext, to_gcc_opt_level};
4444

4545
pub fn crate_type_allows_lto(crate_type: CrateType) -> bool {
4646
match crate_type {
47-
CrateType::Executable | CrateType::Dylib | CrateType::Staticlib | CrateType::Cdylib => true,
47+
CrateType::Executable
48+
| CrateType::Dylib
49+
| CrateType::Staticlib
50+
| CrateType::Cdylib
51+
| CrateType::Sdylib => true,
4852
CrateType::Rlib | CrateType::ProcMacro => false,
4953
}
5054
}

compiler/rustc_codegen_llvm/src/back/lto.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ fn crate_type_allows_lto(crate_type: CrateType) -> bool {
4242
| CrateType::Dylib
4343
| CrateType::Staticlib
4444
| CrateType::Cdylib
45-
| CrateType::ProcMacro => true,
45+
| CrateType::ProcMacro
46+
| CrateType::Sdylib => true,
4647
CrateType::Rlib => false,
4748
}
4849
}

compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,11 @@ pub(crate) fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool {
9595
// in the `.debug_gdb_scripts` section. For that reason, we make sure that the
9696
// section is only emitted for leaf crates.
9797
let embed_visualizers = cx.tcx.crate_types().iter().any(|&crate_type| match crate_type {
98-
CrateType::Executable | CrateType::Dylib | CrateType::Cdylib | CrateType::Staticlib => {
98+
CrateType::Executable
99+
| CrateType::Dylib
100+
| CrateType::Cdylib
101+
| CrateType::Staticlib
102+
| CrateType::Sdylib => {
99103
// These are crate types for which we will embed pretty printers since they
100104
// are treated as leaf crates.
101105
true

compiler/rustc_codegen_ssa/src/back/link.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -1053,9 +1053,10 @@ fn link_natively(
10531053
strip_with_external_utility(sess, stripcmd, out_filename, &["--strip-debug"])
10541054
}
10551055
// Per the manpage, `-x` is the maximum safe strip level for dynamic libraries. (#93988)
1056-
(Strip::Symbols, CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro) => {
1057-
strip_with_external_utility(sess, stripcmd, out_filename, &["-x"])
1058-
}
1056+
(
1057+
Strip::Symbols,
1058+
CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro | CrateType::Sdylib,
1059+
) => strip_with_external_utility(sess, stripcmd, out_filename, &["-x"]),
10591060
(Strip::Symbols, _) => {
10601061
strip_with_external_utility(sess, stripcmd, out_filename, &["--strip-all"])
10611062
}
@@ -1243,8 +1244,10 @@ fn add_sanitizer_libraries(
12431244
// which should be linked to both executables and dynamic libraries.
12441245
// Everywhere else the runtimes are currently distributed as static
12451246
// libraries which should be linked to executables only.
1246-
if matches!(crate_type, CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro)
1247-
&& !(sess.target.is_like_darwin || sess.target.is_like_msvc)
1247+
if matches!(
1248+
crate_type,
1249+
CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro | CrateType::Sdylib
1250+
) && !(sess.target.is_like_darwin || sess.target.is_like_msvc)
12481251
{
12491252
return;
12501253
}
@@ -1938,6 +1941,7 @@ fn add_late_link_args(
19381941
codegen_results: &CodegenResults,
19391942
) {
19401943
let any_dynamic_crate = crate_type == CrateType::Dylib
1944+
|| crate_type == CrateType::Sdylib
19411945
|| codegen_results.crate_info.dependency_formats.iter().any(|(ty, list)| {
19421946
*ty == crate_type && list.iter().any(|&linkage| linkage == Linkage::Dynamic)
19431947
});

compiler/rustc_codegen_ssa/src/back/linker.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1817,7 +1817,7 @@ pub(crate) fn linked_symbols(
18171817
crate_type: CrateType,
18181818
) -> Vec<(String, SymbolExportKind)> {
18191819
match crate_type {
1820-
CrateType::Executable | CrateType::Cdylib | CrateType::Dylib => (),
1820+
CrateType::Executable | CrateType::Cdylib | CrateType::Dylib | CrateType::Sdylib => (),
18211821
CrateType::Staticlib | CrateType::ProcMacro | CrateType::Rlib => {
18221822
return Vec::new();
18231823
}

compiler/rustc_codegen_ssa/src/back/symbol_export.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ fn crate_export_threshold(crate_type: CrateType) -> SymbolExportLevel {
2929
CrateType::Executable | CrateType::Staticlib | CrateType::ProcMacro | CrateType::Cdylib => {
3030
SymbolExportLevel::C
3131
}
32-
CrateType::Rlib | CrateType::Dylib => SymbolExportLevel::Rust,
32+
CrateType::Rlib | CrateType::Dylib | CrateType::Sdylib => SymbolExportLevel::Rust,
3333
}
3434
}
3535

@@ -45,7 +45,7 @@ pub fn crates_export_threshold(crate_types: &[CrateType]) -> SymbolExportLevel {
4545
}
4646

4747
fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap<SymbolExportInfo> {
48-
if !tcx.sess.opts.output_types.should_codegen() {
48+
if !tcx.sess.opts.output_types.should_codegen() && !tcx.is_sdylib_interface_build() {
4949
return Default::default();
5050
}
5151

@@ -168,7 +168,7 @@ fn exported_symbols_provider_local<'tcx>(
168168
tcx: TyCtxt<'tcx>,
169169
_: LocalCrate,
170170
) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] {
171-
if !tcx.sess.opts.output_types.should_codegen() {
171+
if !tcx.sess.opts.output_types.should_codegen() && !tcx.is_sdylib_interface_build() {
172172
return &[];
173173
}
174174

compiler/rustc_codegen_ssa/src/base.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1092,7 +1092,7 @@ impl CrateInfo {
10921092
}
10931093

10941094
let embed_visualizers = tcx.crate_types().iter().any(|&crate_type| match crate_type {
1095-
CrateType::Executable | CrateType::Dylib | CrateType::Cdylib => {
1095+
CrateType::Executable | CrateType::Dylib | CrateType::Cdylib | CrateType::Sdylib => {
10961096
// These are crate types for which we invoke the linker and can embed
10971097
// NatVis visualizers.
10981098
true

compiler/rustc_driver_impl/src/lib.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ use rustc_metadata::locator;
5454
use rustc_middle::ty::TyCtxt;
5555
use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal};
5656
use rustc_session::config::{
57-
CG_OPTIONS, ErrorOutputType, Input, OptionDesc, OutFileName, OutputType, UnstableOptions,
58-
Z_OPTIONS, nightly_options, parse_target_triple,
57+
CG_OPTIONS, CrateType, ErrorOutputType, Input, OptionDesc, OutFileName, OutputType,
58+
UnstableOptions, Z_OPTIONS, nightly_options, parse_target_triple,
5959
};
6060
use rustc_session::getopts::{self, Matches};
6161
use rustc_session::lint::{Lint, LintId};
@@ -352,6 +352,8 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send))
352352

353353
passes::write_dep_info(tcx);
354354

355+
passes::write_interface(tcx);
356+
355357
if sess.opts.output_types.contains_key(&OutputType::DepInfo)
356358
&& sess.opts.output_types.len() == 1
357359
{
@@ -816,6 +818,7 @@ fn print_crate_info(
816818
let supported_crate_types = CRATE_TYPES
817819
.iter()
818820
.filter(|(_, crate_type)| !invalid_output_for_target(&sess, *crate_type))
821+
.filter(|(_, crate_type)| *crate_type != CrateType::Sdylib)
819822
.map(|(crate_type_sym, _)| *crate_type_sym)
820823
.collect::<BTreeSet<_>>();
821824
for supported_crate_type in supported_crate_types {

compiler/rustc_feature/src/builtin_attrs.rs

+6
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,12 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
536536
// Unstable attributes:
537537
// ==========================================================================
538538

539+
// Linking:
540+
gated!(
541+
export, Normal, template!(Word), WarnFollowing,
542+
EncodeCrossCrate::No, experimental!(export)
543+
),
544+
539545
// Testing:
540546
gated!(
541547
test_runner, CrateLevel, template!(List: "path"), ErrorFollowing,

compiler/rustc_feature/src/unstable.rs

+2
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,8 @@ declare_features! (
483483
(unstable, explicit_extern_abis, "CURRENT_RUSTC_VERSION", Some(134986)),
484484
/// Allows explicit tail calls via `become` expression.
485485
(incomplete, explicit_tail_calls, "1.72.0", Some(112788)),
486+
/// Allows using `#[export]` which indicates that an item is exportable.
487+
(incomplete, export, "CURRENT_RUSTC_VERSION", Some(139939)),
486488
/// Allows using `aapcs`, `efiapi`, `sysv64` and `win64` as calling conventions
487489
/// for functions with varargs.
488490
(unstable, extended_varargs_abi_support, "1.65.0", Some(100189)),

compiler/rustc_interface/src/passes.rs

+27-1
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,11 @@ use rustc_resolve::Resolver;
3131
use rustc_session::config::{CrateType, Input, OutFileName, OutputFilenames, OutputType};
3232
use rustc_session::cstore::Untracked;
3333
use rustc_session::output::{collect_crate_types, filename_for_input};
34+
use rustc_session::parse::feature_err;
3435
use rustc_session::search_paths::PathKind;
3536
use rustc_session::{Limit, Session};
3637
use rustc_span::{
37-
ErrorGuaranteed, FileName, SourceFileHash, SourceFileHashAlgorithm, Span, Symbol, sym,
38+
DUMMY_SP, ErrorGuaranteed, FileName, SourceFileHash, SourceFileHashAlgorithm, Span, Symbol, sym,
3839
};
3940
use rustc_target::spec::PanicStrategy;
4041
use rustc_trait_selection::traits;
@@ -237,6 +238,7 @@ fn configure_and_expand(
237238
sess,
238239
features,
239240
&krate,
241+
tcx.is_sdylib_interface_build(),
240242
resolver.lint_buffer(),
241243
)
242244
});
@@ -253,6 +255,9 @@ fn configure_and_expand(
253255
sess.dcx().emit_err(errors::MixedProcMacroCrate);
254256
}
255257
}
258+
if crate_types.contains(&CrateType::Sdylib) && !tcx.features().export() {
259+
feature_err(sess, sym::export, DUMMY_SP, "`sdylib` crate type is unstable").emit();
260+
}
256261

257262
if is_proc_macro_crate && sess.panic_strategy() == PanicStrategy::Abort {
258263
sess.dcx().emit_warn(errors::ProcMacroCratePanicAbort);
@@ -742,6 +747,25 @@ pub fn write_dep_info(tcx: TyCtxt<'_>) {
742747
}
743748
}
744749

750+
pub fn write_interface<'tcx>(tcx: TyCtxt<'tcx>) {
751+
if !tcx.crate_types().contains(&rustc_session::config::CrateType::Sdylib) {
752+
return;
753+
}
754+
let _timer = tcx.sess.timer("write_interface");
755+
let (_, krate) = &*tcx.resolver_for_lowering().borrow();
756+
757+
let krate = rustc_ast_pretty::pprust::print_crate_as_interface(
758+
krate,
759+
tcx.sess.psess.edition,
760+
&tcx.sess.psess.attr_id_generator,
761+
);
762+
let export_output = tcx.output_filenames(()).interface_path();
763+
let mut file = fs::File::create_buffered(export_output).unwrap();
764+
if let Err(err) = write!(file, "{}", krate) {
765+
tcx.dcx().fatal(format!("error writing interface file: {}", err));
766+
}
767+
}
768+
745769
pub static DEFAULT_QUERY_PROVIDERS: LazyLock<Providers> = LazyLock::new(|| {
746770
let providers = &mut Providers::default();
747771
providers.analysis = analysis;
@@ -930,6 +954,8 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
930954
CStore::from_tcx(tcx).report_unused_deps(tcx);
931955
},
932956
{
957+
tcx.ensure_ok().exportable_items(LOCAL_CRATE);
958+
tcx.ensure_ok().stable_order_of_exportable_impls(LOCAL_CRATE);
933959
tcx.par_hir_for_each_module(|module| {
934960
tcx.ensure_ok().check_mod_loops(module);
935961
tcx.ensure_ok().check_mod_attrs(module);

0 commit comments

Comments
 (0)