use std::path::Path;
use async_trait::async_trait;
use rand::rngs::ThreadRng;
use rand::seq::IndexedRandom;
use rand::{Rng, rng};
use crate::args::AppConfig;
use crate::data::{CFILES_LIST, PACKAGES_LIST};
use crate::generators::gen_random_n_from_list_into_string;
use crate::io::{csleep, newline, print};
use crate::modules::Module;
fn generate_includes(file_list: &[&str], max: u32, rng: &mut ThreadRng) -> String {
let mut include_flags = vec![];
for file in file_list {
let path = Path::new(file);
if let Some(dir) = path.parent()
&& let Some(dir_str) = dir.to_str()
&& !include_flags.contains(&dir_str)
{
include_flags.push(dir_str);
}
}
let limited_flags = (0..max).map(|_| include_flags.choose(rng).unwrap());
limited_flags.fold(String::new(), |acc, x| acc + "-I" + x + " ")
}
fn generate_linker_flags(candidates: &[&str], n: usize, rng: &mut ThreadRng) -> String {
let libraries = candidates.choose_multiple(rng, n);
libraries.fold(String::new(), |acc, &x| acc + "-l" + x + " ")
}
pub struct Cc;
#[async_trait(?Send)]
impl Module for Cc {
fn name(&self) -> &'static str {
"cc"
}
fn signature(&self) -> String {
"gcc app.c".to_string()
}
async fn run(&self, appconfig: &AppConfig) {
const COMPILERS: &[&str] = &["gcc", "clang"];
const FLAGS_OPT: &[&str] = &["-O0", "-O1", "-O2", "-O3", "-Og", "-Os"];
const FLAGS_WARN_BASE: &[&str] = &["-Wall", "-Wall -Wextra"];
const FLAGS_WARN: &[&str] = &[
"-Wno-unused-variable",
"-Wno-sign-compare",
"-Wno-unknown-pragmas",
"-Wno-parentheses",
"-Wundef",
"-Wwrite-strings",
"-Wold-style-definition",
];
const FLAGS_F: &[&str] = &["-fsigned-char", "-funroll-loops", "-fgnu89-inline", "-fPIC"];
const FLAGS_ARCH: &[&str] = &["-march=x86-64", "-mtune=generic", "-pipe"];
const FLAGS_DEF_BASE: &[&str] = &["-DDEBUG", "-DNDEBUG"];
const FLAGS_DEF: &[&str] = &[
"-D_REENTRANT",
"-DMATH_LOOP",
"-D_LIBS_REENTRANT",
"-DNAMESPACE=lib",
"-DMODULE_NAME=lib",
"-DPIC",
"-DSHARED",
];
let mut rng = rng();
let package = &PACKAGES_LIST.choose(&mut rng).unwrap();
let compiler = COMPILERS.choose(&mut rng).unwrap();
let num_cfiles = rng.random_range(100..1000);
let mut chosen_files: Vec<&str> = CFILES_LIST
.choose_multiple(&mut rng, num_cfiles)
.cloned()
.collect();
chosen_files.sort_unstable();
let opt = FLAGS_OPT.choose(&mut rng).unwrap();
let warn = FLAGS_WARN_BASE.choose(&mut rng).unwrap().to_string();
let num_additional_warn_flags = rng.random_range(0..FLAGS_WARN.len()) as u64;
let warn_additional =
gen_random_n_from_list_into_string(&mut rng, FLAGS_WARN, num_additional_warn_flags);
let warn_final = warn + &warn_additional;
let num_f_flags = rng.random_range(0..FLAGS_F.len()) as u64;
let f = gen_random_n_from_list_into_string(&mut rng, FLAGS_F, num_f_flags);
let num_arch_flags = rng.random_range(0..FLAGS_ARCH.len()) as u64;
let arch = gen_random_n_from_list_into_string(&mut rng, FLAGS_ARCH, num_arch_flags);
let includes = generate_includes(chosen_files.as_slice(), 20, &mut rng);
let num_linker_flags = rng.random_range(0..10);
let linker_flags = generate_linker_flags(&PACKAGES_LIST, num_linker_flags, &mut rng);
let defs = FLAGS_DEF_BASE.choose(&mut rng).unwrap().to_string();
let num_def_flags = rng.random_range(0..FLAGS_DEF.len()) as u64;
let defs_additional =
gen_random_n_from_list_into_string(&mut rng, FLAGS_DEF, num_def_flags);
let defs_final = defs + &defs_additional;
for cfile in &chosen_files {
print(format!(
"{compiler} -c {opt} {warn}{f}{arch} {includes}{defs} -o {output_file}",
compiler = compiler,
opt = opt,
warn = warn_final,
f = f,
arch = arch,
includes = includes,
defs = defs_final,
output_file = cfile.replace(".c", ".o")
))
.await;
newline().await;
let sleep_length = rng.random_range(30..200);
csleep(sleep_length).await;
if appconfig.should_exit() {
return;
}
}
let object_files = chosen_files
.iter()
.fold(String::new(), |acc, &x| acc + &x.replace(".c", ".o") + " ");
print(format!(
"{compiler} -o {package} {object_files}{linker_flags}"
))
.await;
newline().await;
let sleep_length = rng.random_range(300..1000);
csleep(sleep_length).await;
}
}