1use std::path::Path;
3
4use async_trait::async_trait;
5use rand::rngs::ThreadRng;
6use rand::seq::IndexedRandom;
7use rand::{Rng, rng};
8
9use crate::args::AppConfig;
10use crate::data::{CFILES_LIST, PACKAGES_LIST};
11use crate::generators::gen_random_n_from_list_into_string;
12use crate::io::{csleep, newline, print};
13use crate::modules::Module;
14
15fn generate_includes(file_list: &[&str], max: u32, rng: &mut ThreadRng) -> String {
17 let mut include_flags = vec![];
18 for file in file_list {
19 let path = Path::new(file);
20 if let Some(dir) = path.parent()
21 && let Some(dir_str) = dir.to_str()
22 && !include_flags.contains(&dir_str)
23 {
24 include_flags.push(dir_str);
25 }
26 }
27 let limited_flags = (0..max).map(|_| include_flags.choose(rng).unwrap());
28 limited_flags.fold(String::new(), |acc, x| acc + "-I" + x + " ")
29}
30
31fn generate_linker_flags(candidates: &[&str], n: usize, rng: &mut ThreadRng) -> String {
33 let libraries = candidates.choose_multiple(rng, n);
34 libraries.fold(String::new(), |acc, &x| acc + "-l" + x + " ")
35}
36
37pub struct Cc;
38
39#[async_trait(?Send)]
40impl Module for Cc {
41 fn name(&self) -> &'static str {
42 "cc"
43 }
44
45 fn signature(&self) -> String {
46 "gcc app.c".to_string()
47 }
48
49 async fn run(&self, appconfig: &AppConfig) {
50 const COMPILERS: &[&str] = &["gcc", "clang"];
51 const FLAGS_OPT: &[&str] = &["-O0", "-O1", "-O2", "-O3", "-Og", "-Os"];
52 const FLAGS_WARN_BASE: &[&str] = &["-Wall", "-Wall -Wextra"];
53 const FLAGS_WARN: &[&str] = &[
54 "-Wno-unused-variable",
55 "-Wno-sign-compare",
56 "-Wno-unknown-pragmas",
57 "-Wno-parentheses",
58 "-Wundef",
59 "-Wwrite-strings",
60 "-Wold-style-definition",
61 ];
62 const FLAGS_F: &[&str] = &["-fsigned-char", "-funroll-loops", "-fgnu89-inline", "-fPIC"];
63 const FLAGS_ARCH: &[&str] = &["-march=x86-64", "-mtune=generic", "-pipe"];
64 const FLAGS_DEF_BASE: &[&str] = &["-DDEBUG", "-DNDEBUG"];
65 const FLAGS_DEF: &[&str] = &[
66 "-D_REENTRANT",
67 "-DMATH_LOOP",
68 "-D_LIBS_REENTRANT",
69 "-DNAMESPACE=lib",
70 "-DMODULE_NAME=lib",
71 "-DPIC",
72 "-DSHARED",
73 ];
74
75 let mut rng = rng();
76
77 let package = &PACKAGES_LIST.choose(&mut rng).unwrap();
79
80 let compiler = COMPILERS.choose(&mut rng).unwrap();
81
82 let num_cfiles = rng.random_range(100..1000);
83 let mut chosen_files: Vec<&str> = CFILES_LIST
84 .choose_multiple(&mut rng, num_cfiles)
85 .cloned()
86 .collect();
87 chosen_files.sort_unstable();
88
89 let opt = FLAGS_OPT.choose(&mut rng).unwrap();
90
91 let warn = FLAGS_WARN_BASE.choose(&mut rng).unwrap().to_string();
93 let num_additional_warn_flags = rng.random_range(0..FLAGS_WARN.len()) as u64;
94 let warn_additional =
95 gen_random_n_from_list_into_string(&mut rng, FLAGS_WARN, num_additional_warn_flags);
96 let warn_final = warn + &warn_additional;
97
98 let num_f_flags = rng.random_range(0..FLAGS_F.len()) as u64;
100 let f = gen_random_n_from_list_into_string(&mut rng, FLAGS_F, num_f_flags);
101
102 let num_arch_flags = rng.random_range(0..FLAGS_ARCH.len()) as u64;
104 let arch = gen_random_n_from_list_into_string(&mut rng, FLAGS_ARCH, num_arch_flags);
105
106 let includes = generate_includes(chosen_files.as_slice(), 20, &mut rng);
108
109 let num_linker_flags = rng.random_range(0..10);
111 let linker_flags = generate_linker_flags(&PACKAGES_LIST, num_linker_flags, &mut rng);
112
113 let defs = FLAGS_DEF_BASE.choose(&mut rng).unwrap().to_string();
115 let num_def_flags = rng.random_range(0..FLAGS_DEF.len()) as u64;
116 let defs_additional =
117 gen_random_n_from_list_into_string(&mut rng, FLAGS_DEF, num_def_flags);
118 let defs_final = defs + &defs_additional;
119
120 for cfile in &chosen_files {
122 print(format!(
123 "{compiler} -c {opt} {warn}{f}{arch} {includes}{defs} -o {output_file}",
124 compiler = compiler,
125 opt = opt,
126 warn = warn_final,
127 f = f,
128 arch = arch,
129 includes = includes,
130 defs = defs_final,
131 output_file = cfile.replace(".c", ".o")
132 ))
133 .await;
134 newline().await;
135
136 let sleep_length = rng.random_range(30..200);
137 csleep(sleep_length).await;
138
139 if appconfig.should_exit() {
140 return;
141 }
142 }
143
144 let object_files = chosen_files
146 .iter()
147 .fold(String::new(), |acc, &x| acc + &x.replace(".c", ".o") + " ");
148 print(format!(
149 "{compiler} -o {package} {object_files}{linker_flags}"
150 ))
151 .await;
152 newline().await;
153
154 let sleep_length = rng.random_range(300..1000);
155 csleep(sleep_length).await;
156 }
157}