rustc_codegen_llvm/llvm/
tpde_ffi.rs1use std::path::PathBuf;
2use std::sync::OnceLock;
3
4use rustc_session::config::{self, Sysroot, host_tuple};
5use rustc_session::filesearch;
6
7unsafe extern "C" {
8 type LLVMPassPluginLibraryInfo;
9}
10
11type LLVMGetPassPluginInfoFn = unsafe extern "C" fn() -> LLVMPassPluginLibraryInfo;
12
13#[repr(C)]
15#[derive(#[automatically_derived]impl ::core::clone::Clone for LLVMRustTpdeMode {
#[inline]
#[rustc_trivial_field_reads]
fn clone(&self) -> Self {
match self {
Self::None => LLVMRustTpdeMode::None,
Self::Only => LLVMRustTpdeMode::Only,
Self::Try => LLVMRustTpdeMode::Try,
}
}
}Clone)]
16pub(crate) enum LLVMRustTpdeMode {
17 None,
18 Only,
19 Try,
20}
21
22#[repr(C)]
24#[derive(#[automatically_derived]impl ::core::clone::Clone for LLVMRustTpdeOptions {
#[inline]
#[rustc_trivial_field_reads]
fn clone(&self) -> Self {
LLVMRustTpdeOptions {
mode: ::core::clone::Clone::clone(&self.mode),
plugin: ::core::clone::Clone::clone(&self.plugin),
}
}
}Clone)]
25pub(crate) struct LLVMRustTpdeOptions {
26 mode: LLVMRustTpdeMode,
27 plugin: Option<LLVMGetPassPluginInfoFn>,
29}
30
31pub(crate) struct TpdeWrapper {
32 options: LLVMRustTpdeOptions,
33 _lib: Option<libloading::Library>,
35}
36
37static TPDE_INSTANCE: OnceLock<TpdeWrapper> = OnceLock::new();
38
39#[derive(#[automatically_derived]impl ::core::fmt::Debug for TpdeLibraryError {
#[inline]
#[rustc_trivial_field_reads]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
Self::NotFound { err: __self_0 } =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"NotFound err", &__self_0),
Self::LoadFailed { err: __self_0 } =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"LoadFailed err", &__self_0),
}
}
}Debug)]
40pub(crate) enum TpdeLibraryError {
41 NotFound { err: String },
42 LoadFailed { err: String },
43}
44
45impl From<libloading::Error> for TpdeLibraryError {
46 fn from(err: libloading::Error) -> Self {
47 Self::LoadFailed { err: ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:?}", err))
})format!("{err:?}") }
48 }
49}
50
51impl TpdeWrapper {
52 pub(crate) fn get_or_init(
55 sysroot: &rustc_session::config::Sysroot,
56 mode: &Option<config::LlvmTpde>,
57 ) -> Result<&'static Self, TpdeLibraryError> {
58 let wrapper = TPDE_INSTANCE.get_or_try_init(|| {
59 let w = match mode {
60 Some(mode) => Self::call_dynamic(sysroot, mode)?,
61 None => Self {
62 options: LLVMRustTpdeOptions { mode: LLVMRustTpdeMode::None, plugin: None },
63 _lib: None,
64 },
65 };
66 Ok::<_, TpdeLibraryError>(w)
67 })?;
68
69 Ok(wrapper)
70 }
71
72 pub(crate) fn get_instance() -> &'static Self {
74 TPDE_INSTANCE
75 .get()
76 .expect("TpdeWrapper not initialized. Call get_or_init with sysroot first.")
77 }
78
79 pub(crate) fn options(&self) -> &LLVMRustTpdeOptions {
80 &self.options
81 }
82
83 fn call_dynamic(
84 sysroot: &rustc_session::config::Sysroot,
85 mode: &config::LlvmTpde,
86 ) -> Result<Self, TpdeLibraryError> {
87 let mode = match mode {
88 config::LlvmTpde::Only => LLVMRustTpdeMode::Only,
89 config::LlvmTpde::Try => LLVMRustTpdeMode::Try,
90 };
91 let tpde_path = Self::get_tpde_path(sysroot)?;
92 let lib = unsafe { libloading::Library::new(tpde_path)? };
93 let llvm_get_pass_plugin_info =
94 *unsafe { lib.get::<LLVMGetPassPluginInfoFn>(b"llvmGetPassPluginInfo\0")? };
95 let options = LLVMRustTpdeOptions { mode, plugin: Some(llvm_get_pass_plugin_info) };
96 Ok(Self { options, _lib: Some(lib) })
97 }
98
99 fn get_tpde_path(sysroot: &Sysroot) -> Result<PathBuf, TpdeLibraryError> {
100 let path_buf = sysroot
101 .all_paths()
102 .map(|sysroot_path| {
103 filesearch::make_target_lib_path(sysroot_path, host_tuple())
104 .join("lib")
105 .with_file_name("tpde-plugin")
106 .with_extension(std::env::consts::DLL_EXTENSION)
107 })
108 .find(|f| f.exists())
109 .ok_or_else(|| {
110 let candidates = sysroot
111 .all_paths()
112 .map(|p| p.join("lib").display().to_string())
113 .collect::<Vec<String>>()
114 .join("\n* ");
115 TpdeLibraryError::NotFound {
116 err: ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("failed to find the `tpde-plugin` shared library in the sysroot candidates:\n* {0}",
candidates))
})format!(
117 "failed to find the `tpde-plugin` shared library \
118 in the sysroot candidates:\n* {candidates}"
119 ),
120 }
121 })?;
122
123 Ok(path_buf)
124 }
125}