use std::path::{Path, PathBuf};
use super::types::{
ClaimedFile, FileResolution, InputFile, LtoOutput, OutputKind, PluginMessage, UniqueSegment,
};
use crate::args::LinkOptions;
use crate::diag::DiagnosticSink;
use crate::error::{Error, Result};
#[cfg(unix)]
use super::host as backend;
#[cfg(not(unix))]
use unsupported as backend;
#[derive(Clone, Debug, Default)]
pub struct SessionOptions {
pub output_kind: OutputKind,
pub output_name: Option<PathBuf>,
pub wrap_symbols: Vec<Vec<u8>>,
pub save_temps: bool,
pub fatal_hook: Option<fn(&PluginMessage)>,
}
impl SessionOptions {
#[must_use]
pub fn from_link_options(options: &LinkOptions) -> Self {
Self {
output_kind: options.kind.into(),
output_name: Some(
options
.output
.clone()
.unwrap_or_else(|| PathBuf::from("a.out")),
),
wrap_symbols: options
.wrap
.iter()
.map(|symbol| symbol.as_bytes().to_vec())
.collect(),
save_temps: options.plugin_save_temps,
fatal_hook: None,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PluginInfo {
pub path: PathBuf,
pub identifier: Option<String>,
pub version: Option<String>,
pub api_level: Option<i32>,
}
#[derive(Debug)]
pub struct Session {
claimed: Vec<ClaimedFile>,
records: Vec<usize>,
finished: bool,
}
impl Session {
pub fn new(options: SessionOptions) -> Result<Self> {
backend::begin(options)?;
Ok(Self {
claimed: Vec::new(),
records: Vec::new(),
finished: false,
})
}
pub fn load_plugin(
&mut self,
path: &Path,
options: &[String],
diagnostics: &dyn DiagnosticSink,
) -> Result<()> {
backend::load(path, options, diagnostics)
}
pub fn load_plugins(
&mut self,
plugins: &[(PathBuf, Vec<String>)],
diagnostics: &dyn DiagnosticSink,
) -> Result<()> {
for (path, options) in plugins {
self.load_plugin(path, options, diagnostics)?;
}
Ok(())
}
#[must_use]
pub fn plugins(&self) -> Vec<PluginInfo> {
backend::plugins()
}
pub fn claim(
&mut self,
file: &InputFile,
diagnostics: &dyn DiagnosticSink,
) -> Result<Option<&ClaimedFile>> {
match backend::claim(file, diagnostics)? {
Some((record, claimed)) => {
self.records.push(record);
self.claimed.push(claimed);
Ok(self.claimed.last())
}
None => Ok(None),
}
}
#[must_use]
pub fn claimed_files(&self) -> &[ClaimedFile] {
&self.claimed
}
pub fn all_symbols_read(
&mut self,
mut resolve: impl FnMut(&ClaimedFile) -> FileResolution,
diagnostics: &dyn DiagnosticSink,
) -> Result<LtoOutput> {
let mut resolutions = Vec::with_capacity(self.claimed.len());
for (&record, file) in self.records.iter().zip(&self.claimed) {
let resolution = resolve(file);
if let FileResolution::Included(values) = &resolution
&& values.len() != file.symbols.len()
{
return Err(Error::Internal(format!(
"{}: {} resolutions for {} plugin symbols",
file.path.display(),
values.len(),
file.symbols.len()
)));
}
resolutions.push((record, resolution));
}
backend::all_symbols_read(resolutions, diagnostics)
}
pub fn new_input(
&mut self,
file: &InputFile,
diagnostics: &dyn DiagnosticSink,
) -> Result<Vec<UniqueSegment>> {
backend::new_input(file, diagnostics)
}
pub fn finish(mut self, diagnostics: &dyn DiagnosticSink) -> Result<()> {
self.finished = true;
backend::end(Some(diagnostics))
}
}
impl Drop for Session {
fn drop(&mut self) {
if !self.finished {
let _ = backend::end(None);
}
}
}
#[cfg(not(unix))]
mod unsupported {
use std::path::Path;
use std::sync::atomic::{AtomicBool, Ordering};
use super::{PluginInfo, SessionOptions};
use crate::diag::DiagnosticSink;
use crate::error::{Error, Result};
use crate::plugin::types::{ClaimedFile, FileResolution, InputFile, LtoOutput, UniqueSegment};
static ACTIVE: AtomicBool = AtomicBool::new(false);
pub(super) fn begin(_options: SessionOptions) -> Result<()> {
if ACTIVE.swap(true, Ordering::SeqCst) {
return Err(Error::Limit(
"only one LTO plugin session can be active in a process".to_owned(),
));
}
Ok(())
}
pub(super) fn load(
path: &Path,
_options: &[String],
_diagnostics: &dyn DiagnosticSink,
) -> Result<()> {
Err(Error::Unimplemented(format!(
"{}: LTO plugins on this host (M6)",
path.display()
)))
}
pub(super) fn plugins() -> Vec<PluginInfo> {
Vec::new()
}
pub(super) fn claim(
_file: &InputFile,
_diagnostics: &dyn DiagnosticSink,
) -> Result<Option<(usize, ClaimedFile)>> {
Ok(None)
}
pub(super) fn all_symbols_read(
_resolutions: Vec<(usize, FileResolution)>,
_diagnostics: &dyn DiagnosticSink,
) -> Result<LtoOutput> {
Ok(LtoOutput::default())
}
pub(super) fn new_input(
_file: &InputFile,
_diagnostics: &dyn DiagnosticSink,
) -> Result<Vec<UniqueSegment>> {
Ok(Vec::new())
}
pub(super) fn end(_diagnostics: Option<&dyn DiagnosticSink>) -> Result<()> {
ACTIVE.store(false, Ordering::SeqCst);
Ok(())
}
}