criterion-polyglot 0.1.0

An extension trait for criterion providing benchmark methods for various non-Rust programming languages
Documentation
use std::{ffi::OsStr, process::Command, env};

use tempfile::TempPath;

use crate::{
    helper::{make_empty_tempfile, make_tempdir, get_criterion_env_var, make_spec_tempfile},
    runner::{run_command, CommunicatingBenchmark}, BenchSpec,
};

const HARNESS: &str = include_str!("harness.c.in");
const SOURCE_EXTENSION: &str = ".c";

pub fn compile(
    spec: BenchSpec,
    mut builder: cc::Build,
) -> TempPath {
    // Following env! macro evaluations require build.rs
    // that "copies" TARGET, OPT_LEVEL, and HOST from the
    // build.rs environment to the cargo build environment
    //
    // Compiler path can be overridden via the standard CC
    // environment variable. Allow the usual form of
    // CRITERION_CC for symmetry with the other languages.
    //
    // This is the only language that uses a "special" way
    // of locating the compiler, so use a sigil to represent
    // the default value instead of forcing all the other languages
    // to unwrap an Option<OsString>.
    const NULL_SIGIL: &str = "\0";
    let criterion_c_env_var = get_criterion_env_var("CC", NULL_SIGIL);
    if criterion_c_env_var != NULL_SIGIL {
        builder.compiler(criterion_c_env_var);
    }

    let builder_dir = make_tempdir();
    builder
        .out_dir(&builder_dir)
        .target(env!("TARGET"))
        .opt_level_str(env!("OPT_LEVEL"))
        .host(env!("HOST"))
        .cargo_metadata(false);

    if spec.global.is_some() {
        builder.define("CRITERION_BENCH_INIT", None);
    }
    if spec.sample.is_some() {
        builder.define("CRITERION_BENCH_SETUP", None);
    }

    let source_file = make_spec_tempfile(self::SOURCE_EXTENSION, HARNESS, &spec);

    let executable = make_empty_tempfile(super::BIN_EXTENSION);

    let mut cc_command = builder.get_compiler().to_command();
    cc_command
        .arg("-o")
        .arg(&executable)
        .arg(&source_file);
    run_command("compiling C", &mut cc_command, Some(source_file));

    executable
}

pub fn spawn(executable: impl AsRef<OsStr>) -> CommunicatingBenchmark {
    let command = Command::new(executable.as_ref());

    CommunicatingBenchmark::start("running C", command, None)
}