Skip to content

Commit b85a67f

Browse files
committed
builtin headers
1 parent 51f115b commit b85a67f

File tree

9 files changed

+347
-39
lines changed

9 files changed

+347
-39
lines changed

cc/builtin_headers.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//
2+
// Copyright (c) 2025-2026 Jeff Garzik
3+
//
4+
// This file is part of the posixutils-rs project covered under
5+
// the MIT License. For the full license text, please see the LICENSE
6+
// file in the root directory of this project.
7+
// SPDX-License-Identifier: MIT
8+
//
9+
// Builtin headers for pcc
10+
//
11+
// These headers are embedded directly in the compiler binary and are
12+
// searched before system headers. They provide compiler-specific
13+
// implementations of standard headers like <stdarg.h> and <stddef.h>.
14+
//
15+
16+
/// Builtin stdarg.h - variadic function support
17+
pub const STDARG_H: &str = include_str!("include/stdarg.h");
18+
19+
/// Builtin stddef.h - standard type definitions
20+
pub const STDDEF_H: &str = include_str!("include/stddef.h");
21+
22+
/// Look up a builtin header by name
23+
///
24+
/// Returns the header content if found, None otherwise.
25+
/// The name should be the basename without path (e.g., "stdarg.h").
26+
pub fn get_builtin_header(name: &str) -> Option<&'static str> {
27+
match name {
28+
"stdarg.h" => Some(STDARG_H),
29+
"stddef.h" => Some(STDDEF_H),
30+
_ => None,
31+
}
32+
}
33+
34+
#[cfg(test)]
35+
mod tests {
36+
use super::*;
37+
38+
#[test]
39+
fn test_stdarg_exists() {
40+
let header = get_builtin_header("stdarg.h");
41+
assert!(header.is_some());
42+
assert!(header.unwrap().contains("va_list"));
43+
assert!(header.unwrap().contains("va_start"));
44+
}
45+
46+
#[test]
47+
fn test_stddef_exists() {
48+
let header = get_builtin_header("stddef.h");
49+
assert!(header.is_some());
50+
assert!(header.unwrap().contains("size_t"));
51+
assert!(header.unwrap().contains("NULL"));
52+
}
53+
54+
#[test]
55+
fn test_unknown_header() {
56+
assert!(get_builtin_header("unknown.h").is_none());
57+
}
58+
}

cc/cflow.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,8 @@ fn process_file(
459459
defines,
460460
undefines,
461461
include_paths,
462+
false, // no_std_inc
463+
false, // no_builtin_inc
462464
);
463465

464466
// Create symbol table and type table

cc/ctags.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,9 +131,11 @@ fn process_file(path: &str, streams: &mut StreamTable) -> io::Result<Vec<TagEntr
131131
&target,
132132
&mut strings,
133133
path,
134-
&[], // No extra defines
135-
&[], // No undefines
136-
&[], // No include paths
134+
&[], // No extra defines
135+
&[], // No undefines
136+
&[], // No include paths
137+
false, // no_std_inc
138+
false, // no_builtin_inc
137139
);
138140

139141
// Create symbol table and type table

cc/cxref.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,8 @@ fn process_file(
384384
defines,
385385
undefines,
386386
include_paths,
387+
false, // no_std_inc
388+
false, // no_builtin_inc
387389
);
388390

389391
// Create symbol table and type table

cc/include/stdarg.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* pcc builtin stdarg.h
3+
*
4+
* This file is part of the posixutils-rs project covered under
5+
* the MIT License. For the full license text, please see the LICENSE
6+
* file in the root directory of this project.
7+
* SPDX-License-Identifier: MIT
8+
*/
9+
10+
#ifndef _STDARG_H
11+
#define _STDARG_H
12+
13+
typedef __builtin_va_list va_list;
14+
15+
#define va_start(ap, param) __builtin_va_start(ap, param)
16+
#define va_end(ap) __builtin_va_end(ap)
17+
#define va_arg(ap, type) __builtin_va_arg(ap, type)
18+
#define va_copy(dest, src) __builtin_va_copy(dest, src)
19+
20+
/* GCC compatibility */
21+
typedef __builtin_va_list __gnuc_va_list;
22+
#define __va_copy(dest, src) __builtin_va_copy(dest, src)
23+
24+
#endif /* _STDARG_H */

cc/include/stddef.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* pcc builtin stddef.h
3+
*
4+
* This file is part of the posixutils-rs project covered under
5+
* the MIT License. For the full license text, please see the LICENSE
6+
* file in the root directory of this project.
7+
* SPDX-License-Identifier: MIT
8+
*/
9+
10+
#ifndef _STDDEF_H
11+
#define _STDDEF_H
12+
13+
typedef __PTRDIFF_TYPE__ ptrdiff_t;
14+
typedef __SIZE_TYPE__ size_t;
15+
typedef __WCHAR_TYPE__ wchar_t;
16+
17+
#ifndef NULL
18+
#define NULL ((void*)0)
19+
#endif
20+
21+
#define offsetof(type, member) __builtin_offsetof(type, member)
22+
23+
/* max_align_t - type with strictest alignment requirement */
24+
typedef long double max_align_t;
25+
26+
#endif /* _STDDEF_H */

cc/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
//
1414

1515
pub mod arch;
16+
pub mod builtin_headers;
1617
pub mod diag;
1718
pub mod ir;
1819
pub mod opt;

cc/main.rs

Lines changed: 88 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//
1111

1212
mod arch;
13+
mod builtin_headers;
1314
mod diag;
1415
mod ir;
1516
mod opt;
@@ -85,6 +86,14 @@ struct Args {
8586
#[arg(short = 'I', action = clap::ArgAction::Append, value_name = "dir")]
8687
include_paths: Vec<String>,
8788

89+
/// Disable all standard include paths (system and builtin)
90+
#[arg(long = "nostdinc", help = gettext("Disable standard system include paths"))]
91+
no_std_inc: bool,
92+
93+
/// Disable builtin include paths only (keep system paths)
94+
#[arg(long = "nobuiltininc", help = gettext("Disable builtin #include directories"))]
95+
no_builtin_inc: bool,
96+
8897
/// Compile and assemble, but do not link
8998
#[arg(short = 'c', help = gettext("Compile and assemble, but do not link"))]
9099
compile_only: bool,
@@ -124,6 +133,14 @@ struct Args {
124133
/// Pedantic mode (compatibility, currently no-op)
125134
#[arg(long = "pedantic", hide = true)]
126135
pedantic: bool,
136+
137+
/// Add library search path (passed to linker)
138+
#[arg(short = 'L', action = clap::ArgAction::Append, value_name = "dir")]
139+
lib_paths: Vec<String>,
140+
141+
/// Link library (passed to linker)
142+
#[arg(short = 'l', action = clap::ArgAction::Append, value_name = "library")]
143+
libraries: Vec<String>,
127144
}
128145

129146
fn process_file(
@@ -194,6 +211,8 @@ fn process_file(
194211
&args.defines,
195212
&args.undefines,
196213
&args.include_paths,
214+
args.no_std_inc,
215+
args.no_builtin_inc,
197216
);
198217

199218
if args.preprocess_only {
@@ -348,9 +367,17 @@ fn process_file(
348367
}
349368

350369
// Link
351-
let status = Command::new("cc")
352-
.args(["-o", &exe_file, &temp_obj])
353-
.status()?;
370+
let mut link_cmd = Command::new("cc");
371+
link_cmd.args(["-o", &exe_file, &temp_obj]);
372+
// Add library search paths
373+
for lib_path in &args.lib_paths {
374+
link_cmd.arg(format!("-L{}", lib_path));
375+
}
376+
// Add libraries
377+
for lib in &args.libraries {
378+
link_cmd.arg(format!("-l{}", lib));
379+
}
380+
let status = link_cmd.status()?;
354381

355382
let _ = std::fs::remove_file(&temp_obj);
356383

@@ -365,19 +392,59 @@ fn process_file(
365392
Ok(())
366393
}
367394

395+
/// Check if a string is a valid optimization level for -O
396+
fn is_valid_opt_level(s: &str) -> bool {
397+
matches!(s, "0" | "1" | "2" | "3" | "s" | "z" | "fast" | "g")
398+
}
399+
368400
/// Preprocess command-line arguments for gcc compatibility.
369-
/// Converts -Wall → -W all, -Wextra → -W extra, etc.
401+
/// - Converts -Wall → -W all, -Wextra → -W extra, etc.
402+
/// - Handles -O flag: standalone -O followed by non-level becomes -O1
370403
fn preprocess_args() -> Vec<String> {
371-
std::env::args()
372-
.flat_map(|arg| {
373-
if arg.starts_with("-W") && arg.len() > 2 {
374-
// -Wall → -W all, -Wextra → -W extra, etc.
375-
vec!["-W".to_string(), arg[2..].to_string()]
376-
} else {
377-
vec![arg]
404+
let raw_args: Vec<String> = std::env::args().collect();
405+
let mut result = Vec::with_capacity(raw_args.len());
406+
let mut i = 0;
407+
408+
while i < raw_args.len() {
409+
let arg = &raw_args[i];
410+
411+
if arg == "-O" {
412+
// Standalone -O: check if next arg is a valid optimization level
413+
if i + 1 < raw_args.len() && is_valid_opt_level(&raw_args[i + 1]) {
414+
// Next arg is a level like "1", "2", etc. - merge them
415+
result.push(format!("-O{}", raw_args[i + 1]));
416+
i += 2;
417+
continue;
378418
}
379-
})
380-
.collect()
419+
// Next arg is not a valid level (or no next arg) - use default -O1
420+
result.push("-O1".to_string());
421+
i += 1;
422+
} else if arg.starts_with("-O") && arg.len() > 2 {
423+
// -O0, -O1, -O2, -O3, -Os, -Oz, -Ofast, -Og - pass through
424+
result.push(arg.clone());
425+
i += 1;
426+
} else if arg.starts_with("-W") && arg.len() > 2 {
427+
// -Wall → -W all, -Wextra → -W extra, etc.
428+
result.push("-W".to_string());
429+
result.push(arg[2..].to_string());
430+
i += 1;
431+
} else if arg.starts_with("-L") && arg.len() > 2 {
432+
// -L. → -L .
433+
result.push("-L".to_string());
434+
result.push(arg[2..].to_string());
435+
i += 1;
436+
} else if arg.starts_with("-l") && arg.len() > 2 {
437+
// -lz → -l z
438+
result.push("-l".to_string());
439+
result.push(arg[2..].to_string());
440+
i += 1;
441+
} else {
442+
result.push(arg.clone());
443+
i += 1;
444+
}
445+
}
446+
447+
result
381448
}
382449

383450
/// Check if a file is a C source file (by extension)
@@ -437,6 +504,14 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
437504
for obj in &object_files {
438505
link_cmd.arg(*obj);
439506
}
507+
// Add library search paths
508+
for lib_path in &args.lib_paths {
509+
link_cmd.arg(format!("-L{}", lib_path));
510+
}
511+
// Add libraries
512+
for lib in &args.libraries {
513+
link_cmd.arg(format!("-l{}", lib));
514+
}
440515
let status = link_cmd.status()?;
441516
if !status.success() {
442517
eprintln!("pcc: linker failed");

0 commit comments

Comments
 (0)