1use std::{
5 io::{self, Write},
6 path::{Path, PathBuf},
7};
8
9pub mod cfg_keys {
10 pub const POSIX: &str = "CSP_POSIX";
11 pub const ZEPHYR: &str = "CSP_ZEPHYR";
12
13 pub const HAVE_STDIO: &str = "CSP_HAVE_STDIO";
14 pub const ENABLE_CSP_PRINT: &str = "CSP_ENABLE_CSP_PRINT";
15 pub const PRINT_STDIO: &str = "CSP_PRINT_STDIO";
16
17 pub const REPRODUCIBLE_BUILDS: &str = "CSP_REPRODUCIBLE_BUILDS";
18
19 pub const QFIFO_LEN: &str = "CSP_QFIFO_LEN";
20 pub const PORT_MAX_BIND: &str = "CSP_PORT_MAX_BIND";
21 pub const CONN_RXQUEUE_LEN: &str = "CSP_CONN_RXQUEUE_LEN";
22 pub const CONN_MAX: &str = "CSP_CONN_MAX";
23 pub const BUFFER_SIZE: &str = "CSP_BUFFER_SIZE";
24 pub const BUFFER_COUNT: &str = "CSP_BUFFER_COUNT";
25 pub const RDP_MAX_WINDOW: &str = "CSP_RDP_MAX_WINDOW";
26 pub const RTABLE_SIZE: &str = "CSP_RTABLE_SIZE";
27
28 pub const USE_RDP: &str = "CSP_USE_RDP";
29 pub const USE_HMAC: &str = "CSP_USE_HMAC";
30 pub const USE_PROMISC: &str = "CSP_USE_PROMISC";
31 pub const USE_RTABLE: &str = "CSP_USE_RTABLE";
32 pub const HAVE_LIBSOCKETCAN: &str = "CSP_HAVE_LIBSOCKETCAN";
33 pub const HAVE_LIBZMQ: &str = "CSP_HAVE_LIBZMQ";
34}
35
36const SRCS_LIST: &[&str] = &[
37 "csp_bridge.c",
38 "csp_buffer.c",
39 "csp_crc32.c",
40 "csp_debug.c",
41 "csp_id.c",
42 "csp_iflist.c",
43 "csp_conn.c",
44 "csp_init.c",
45 "csp_io.c",
46 "csp_port.c",
47 "csp_promisc.c",
48 "csp_qfifo.c",
49 "csp_port.c",
50 "csp_route.c",
51 "csp_dedup.c",
52 "csp_services.c",
53 "csp_service_handler.c",
54 "interfaces/csp_if_lo.c",
55 "interfaces/csp_if_kiss.c",
56 "interfaces/csp_if_tun.c",
57 "interfaces/csp_if_udp.c",
58 "crypto/csp_hmac.c",
59 "crypto/csp_sha1.c",
60];
61
62const ARCH_SRCS_UNIX: &[&str] = &[
63 "arch/posix/csp_clock.c",
64 "arch/posix/csp_semaphore.c",
65 "arch/posix/csp_system.c",
66 "arch/posix/csp_time.c",
67 "arch/posix/csp_queue.c",
68 "arch/posix/pthread_queue.c",
69];
70
71pub struct Config {
72 pub have_stdio: bool,
73 pub print_stdio: bool,
74 pub reproducible_builds: bool,
75 pub qfifo_len: u32,
76 pub port_max_bind: u32,
77 pub conn_rx_queue_len: u32,
78 pub conn_max: u32,
79 pub buffer_size: u32,
80 pub buffer_count: u32,
81 pub rdp_max_window: u32,
82 pub rtable_size: u32,
83 pub hmac: bool,
84 pub rtable: bool,
85 pub csp_print: bool,
86 pub promisc: bool,
87 pub rdp: bool,
88 pub yaml: bool,
89}
90
91impl Default for Config {
92 fn default() -> Self {
93 Self {
94 have_stdio: true,
95 print_stdio: true,
96 reproducible_builds: false,
97 qfifo_len: 16,
98 port_max_bind: 16,
99 conn_rx_queue_len: 16,
100 conn_max: 8,
101 buffer_size: 256,
102 buffer_count: 15,
103 rdp_max_window: 5,
104 rtable_size: 10,
105 hmac: true,
106 rtable: false,
107 csp_print: true,
108 promisc: true,
109 rdp: true,
110 yaml: false,
111 }
112 }
113}
114
115pub struct Builder {
127 generate_autoconf_file: bool,
128 libcsp_path: PathBuf,
129 libcsp_src_path_base: PathBuf,
130 out_dir: PathBuf,
131 pub cfg: Config,
132 pub compiler_warnings: bool,
133 build: cc::Build,
134}
135
136#[derive(Debug, Copy, Clone, PartialEq, Eq, thiserror::Error)]
137pub enum BuildCreationError {
138 #[error("The specified libcsp path does not exist")]
139 PathDoesNotExist,
140 #[error("The specified libcsp path does not have the expected format of the library")]
141 InvalidLibcspFormat,
142}
143
144impl Builder {
145 pub fn new(libcsp_path: PathBuf, out_dir: PathBuf) -> Result<Self, BuildCreationError> {
148 if !libcsp_path.exists() {
150 return Err(BuildCreationError::PathDoesNotExist);
151 }
152 if !libcsp_path
153 .join("include")
154 .join("csp")
155 .join("csp.h")
156 .exists()
157 {
158 return Err(BuildCreationError::InvalidLibcspFormat);
159 }
160
161 let mut libcsp_src_path_base = libcsp_path.clone();
162 libcsp_src_path_base.push("src");
163 Ok(Self {
164 generate_autoconf_file: true,
165 libcsp_path,
166 libcsp_src_path_base,
167 out_dir,
168 cfg: Default::default(),
169 compiler_warnings: true,
170 build: Default::default(),
171 })
172 }
173
174 pub fn cc(&mut self) -> &cc::Build {
176 &self.build
177 }
178
179 pub fn cc_mut(&mut self) -> &mut cc::Build {
181 &mut self.build
182 }
183
184 pub fn compile(&mut self) -> io::Result<()> {
185 if self.generate_autoconf_file {
186 self.generate_autoconf_header_file_default_location()?;
187 }
188 for src in SRCS_LIST {
189 let mut next_file = self.libcsp_src_path_base.clone();
190 next_file.push(src);
191 self.build.file(next_file);
192 }
193 if self.cfg.rdp {
194 let mut next_file = self.libcsp_src_path_base.clone();
195 next_file.push("csp_rdp.c");
196 self.build.file(next_file);
197 let mut next_file = self.libcsp_src_path_base.clone();
198 next_file.push("csp_rdp_queue.c");
199 self.build.file(next_file);
200 }
201 if self.cfg.promisc {
202 let mut next_file = self.libcsp_src_path_base.clone();
203 next_file.push("csp_promisc.c");
204 self.build.file(next_file);
205 }
206 if self.cfg.csp_print {
207 let mut next_file = self.libcsp_src_path_base.clone();
208 next_file.push("csp_hex_dump.c");
209 self.build.file(next_file);
210 }
211 if self.cfg.yaml {
212 let mut next_file = self.libcsp_src_path_base.clone();
213 next_file.push("csp_yaml.c");
214 self.build.file(next_file);
215 }
216 if self.cfg.rtable {
217 let mut next_file = self.libcsp_src_path_base.clone();
218 next_file.push("csp_rtable_cidr.c");
219 self.build.file(next_file);
220 }
221
222 #[cfg(unix)]
224 self.posix_arch_files();
225
226 let mut inc_path = self.libcsp_path.clone();
227 inc_path.push("include");
228 self.build.include(inc_path);
229 self.build.include(&self.libcsp_src_path_base);
230 self.build.cargo_warnings(self.compiler_warnings);
231
232 self.build.compile("csp");
233 Ok(())
236 }
237
238 #[cfg(unix)]
239 fn posix_arch_files(&mut self) {
240 for src in ARCH_SRCS_UNIX {
241 let mut next_file = self.libcsp_src_path_base.clone();
242 next_file.push(src);
243 self.build.file(next_file);
244 }
245 }
246
247 pub fn generate_autoconf_header_file_default_location(&mut self) -> io::Result<()> {
248 let mut autoconf_dir = self.out_dir.join("cfg");
249 self.build.include(&autoconf_dir);
250 autoconf_dir.push("csp");
251 std::fs::create_dir_all(&autoconf_dir)?;
252 generate_autoconf_header_file(&autoconf_dir, &self.cfg)
253 }
254
255 pub fn generate_autoconf_header_file(&mut self, dir: impl AsRef<Path>) -> io::Result<()> {
256 generate_autoconf_header_file(dir, &self.cfg)
257 }
258
259 pub fn generate_autoconf_rust_file(&self, dir: impl AsRef<Path>) -> io::Result<()> {
260 generate_autoconf_rust_file(dir, &self.cfg)
261 }
262}
263
264pub fn generate_autoconf_header_file(out_dir: impl AsRef<Path>, cfg: &Config) -> io::Result<()> {
267 let out_dir = out_dir.as_ref();
268 let mut autoconf_file_string = String::new();
269 let version = env!("CARGO_PKG_VERSION");
270 let name = env!("CARGO_PKG_NAME");
271 autoconf_file_string.push_str(&format!(
272 "// This file was auto-generated by {} v{}\n",
273 name, version
274 ));
275 #[cfg(unix)]
276 autoconf_file_string.push_str("#define CSP_POSIX 1\n");
277 #[cfg(not(unix))]
278 autoconf_file_string.push_str("#define CSP_POSIX 0\n");
279 autoconf_file_string.push_str("#define CSP_ZEPHYR 0\n");
280 autoconf_file_string.push('\n');
281 autoconf_file_string.push_str(&format!(
282 "#define {} {}\n",
283 cfg_keys::HAVE_STDIO,
284 cfg.have_stdio as u32
285 ));
286 autoconf_file_string.push_str(&format!(
287 "#define {} {}\n",
288 cfg_keys::ENABLE_CSP_PRINT,
289 cfg.csp_print as u32
290 ));
291 autoconf_file_string.push_str(&format!(
292 "#define {} {}\n",
293 cfg_keys::PRINT_STDIO,
294 cfg.print_stdio as u32
295 ));
296 autoconf_file_string.push_str(&format!(
297 "#define {} {}\n",
298 cfg_keys::REPRODUCIBLE_BUILDS,
299 cfg.reproducible_builds as u32
300 ));
301 autoconf_file_string.push('\n');
302
303 autoconf_file_string.push_str(&format!(
304 "#define {} {}\n",
305 cfg_keys::QFIFO_LEN,
306 cfg.qfifo_len
307 ));
308 autoconf_file_string.push_str(&format!(
309 "#define {} {}\n",
310 cfg_keys::PORT_MAX_BIND,
311 cfg.port_max_bind
312 ));
313 autoconf_file_string.push_str(&format!(
314 "#define {} {}\n",
315 cfg_keys::CONN_RXQUEUE_LEN,
316 cfg.conn_rx_queue_len
317 ));
318 autoconf_file_string.push_str(&format!(
319 "#define {} {}\n",
320 cfg_keys::CONN_MAX,
321 cfg.conn_max
322 ));
323 autoconf_file_string.push_str(&format!(
324 "#define {} {}\n",
325 cfg_keys::BUFFER_SIZE,
326 cfg.buffer_size
327 ));
328 autoconf_file_string.push_str(&format!(
329 "#define {} {}\n",
330 cfg_keys::BUFFER_COUNT,
331 cfg.buffer_count
332 ));
333 autoconf_file_string.push_str(&format!(
334 "#define {} {}\n",
335 cfg_keys::RDP_MAX_WINDOW,
336 cfg.rdp_max_window
337 ));
338 autoconf_file_string.push_str(&format!(
339 "#define {} {}\n",
340 cfg_keys::RTABLE_SIZE,
341 cfg.rtable_size
342 ));
343
344 autoconf_file_string.push('\n');
345 autoconf_file_string.push_str(&format!(
346 "#define {} {}\n",
347 cfg_keys::USE_RDP,
348 cfg.rdp as u32
349 ));
350 autoconf_file_string.push_str(&format!(
351 "#define {} {}\n",
352 cfg_keys::USE_HMAC,
353 cfg.hmac as u32
354 ));
355 autoconf_file_string.push_str(&format!(
356 "#define {} {}\n",
357 cfg_keys::USE_PROMISC,
358 cfg.promisc as u32
359 ));
360 autoconf_file_string.push_str(&format!(
361 "#define {} {}\n",
362 cfg_keys::USE_RTABLE,
363 cfg.rtable as u32
364 ));
365
366 autoconf_file_string.push('\n');
367 autoconf_file_string.push_str(&format!("#define {} {}\n", cfg_keys::HAVE_LIBSOCKETCAN, 0));
369 autoconf_file_string.push_str(&format!("#define {} {}\n", cfg_keys::HAVE_LIBZMQ, 0));
370 let out_file = out_dir.join("autoconfig.h");
371 let mut file = std::fs::File::create(out_file)?;
372 file.write_all(autoconf_file_string.as_bytes())?;
373 Ok(())
374}
375
376pub fn generate_autoconf_rust_file(out_dir: impl AsRef<Path>, cfg: &Config) -> io::Result<()> {
379 let out_dir = out_dir.as_ref();
380 let mut autoconf_file_string = String::new();
381 let version = env!("CARGO_PKG_VERSION");
382 let name = env!("CARGO_PKG_NAME");
383 autoconf_file_string.push_str(&format!(
384 "// This file was auto-generated by {} v{}\n",
385 name, version
386 ));
387 autoconf_file_string.push_str(&format!(
388 "pub const {}: usize = {};\n",
389 cfg_keys::CONN_RXQUEUE_LEN,
390 cfg.conn_rx_queue_len
391 ));
392 autoconf_file_string.push_str(&format!(
393 "pub const {}: usize = {};\n",
394 cfg_keys::QFIFO_LEN,
395 cfg.qfifo_len
396 ));
397 autoconf_file_string.push_str(&format!(
398 "pub const {}: usize = {};\n",
399 cfg_keys::PORT_MAX_BIND,
400 cfg.port_max_bind
401 ));
402 autoconf_file_string.push_str(&format!(
403 "pub const {}: usize = {};\n",
404 cfg_keys::CONN_MAX,
405 cfg.conn_max
406 ));
407 autoconf_file_string.push_str(&format!(
408 "pub const {}: usize = {};\n",
409 cfg_keys::BUFFER_SIZE,
410 cfg.buffer_size
411 ));
412 autoconf_file_string.push_str(&format!(
413 "pub const {}: usize = {};\n",
414 cfg_keys::RDP_MAX_WINDOW,
415 cfg.rdp_max_window
416 ));
417 autoconf_file_string.push_str(&format!(
418 "pub const {}: usize = {};\n",
419 cfg_keys::RTABLE_SIZE,
420 cfg.rtable_size
421 ));
422 let out_file = out_dir.join("autoconfig.rs");
423 let mut file = std::fs::File::create(out_file)?;
424 file.write_all(autoconf_file_string.as_bytes())?;
425 Ok(())
426}
427
428#[cfg(test)]
429mod tests {
430 }