use std::{
ffi::OsString,
fs,
path::{Path, PathBuf},
};
use crate::{
arg_parser::without_dependency_flags,
compiler_wrapper::CompilerKind,
error::Error,
utils::{embed_bitcode_filepath_to_object_file, execute_llvm_tool},
};
pub(crate) fn build_marker_object(
bitcode: &Path,
dir: &Path,
compiler: &Path,
kind: CompilerKind,
compile_args: &[String],
) -> Result<PathBuf, Error> {
let extension = match kind {
CompilerKind::Clang => "c",
CompilerKind::ClangXX => "cpp",
};
let source = dir.join(format!("rllvm_marker.{extension}"));
fs::write(
&source,
b"typedef int rllvm_marker_empty_translation_unit;\n",
)?;
let marker = dir.join("rllvm_marker.o");
let mut args: Vec<OsString> = without_dependency_flags(compile_args)
.into_iter()
.map(OsString::from)
.collect();
args.extend([
OsString::from("-c"),
source.into_os_string(),
OsString::from("-o"),
marker.as_os_str().to_owned(),
]);
let status = execute_llvm_tool(compiler, &args)?;
if !status.success() {
return Err(Error::ExecutionFailure(format!(
"Failed to build the rllvm marker object with {compiler:?}: exit_status={status}"
)));
}
embed_bitcode_filepath_to_object_file::<&Path>(bitcode, &marker, None)?;
Ok(marker)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::utils::extract_bitcode_filepaths_from_object_file;
fn placeholder_bitcode(dir: &Path) -> PathBuf {
let bitcode = dir.join("crate.bc");
fs::write(&bitcode, b"placeholder").expect("failed to write the placeholder bitcode");
bitcode
}
#[test]
fn marker_object_carries_the_bitcode_path() {
let tmp = tempfile::tempdir().unwrap();
let bitcode = placeholder_bitcode(tmp.path());
let clang = crate::config::try_rllvm_config()
.expect("configuration")
.clang_filepath()
.clone();
let marker = build_marker_object(&bitcode, tmp.path(), &clang, CompilerKind::Clang, &[])
.expect("marker built");
let paths =
extract_bitcode_filepaths_from_object_file(&marker).expect("marker carries a section");
assert_eq!(paths, vec![bitcode]);
}
}