1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
//! # wrapc
//!
//! A zero-fuss parser for rustc arguments, designed for RUSTC_WRAPPER tools.
//! Provides comprehensive and type-safe coverage of `rustc`'s CLI surface area.
//!
//! ## Usage Guide: Building Bulletproof `RUSTC_WRAPPER` Tools
//!
//! ### 1. The Core Concept
//!
//! When Cargo invokes a `RUSTC_WRAPPER`, it doesn't just pass rustc arguments.
//! It uses a specific protocol: `<wrapper_binary> - <actual_rustc_path> <rustc_args...>`
//!
//! `wrapc` automatically detects this protocol, extracts the real `rustc` path, and
//! parses the remaining arguments into a strongly-typed `Info` struct.
//!
//! > **Experimental:**
//! > If invoked directly (without Cargo's `-` separator), it gracefully falls back to standard parsing.
//!
//! ### 2. Basic Setup & Execution
//!
//! Add wrapc to your wrapper tool's dependencies:
//! ```shell
//! cargo add wrapc
//! ```
//!
//! Here is the canonical skeleton for a `RUSTC_WRAPPER` executable:
//!
//! ```rust
//! use std::process::Command;
//! use wrapc::fetch;
//!
//! fn main() {
//! // `fetch()` reads `std::env::args()` and parses them.
//! let info = fetch().expect("Failed to parse rustc arguments");
//!
//! // 1. Handle passthrough commands (help/version)
//! if info.help || info.version {
//! // Just execute rustc and exit
//! }
//!
//! // 2. Inspect the compilation context
//! println!("Wrapper: Compiling crate {:?}", info.crate_name);
//! println!("Wrapper: Target is {:?}", info.target);
//!
//! // 3. Determine the real rustc path
//! // If invoked via Cargo, `info.rustc` contains the path.
//! // Otherwise, fallback to "rustc" in PATH.
//! let rustc_path = info.rustc.unwrap_or_else(|| "rustc".to_string());
//!
//! // 4. Reconstruct the arguments perfectly
//! let args = info.to_args();
//!
//! // 5. Execute the actual compiler
//! let status = Command::new(rustc_path)
//! .args(&args)
//! .status()
//! .expect("Failed to spawn rustc");
//!
//! std::process::exit(status.code().unwrap_or(1));
//! }
//! ```
//!
//! ### 3. Inspecting Parsed Data
//!
//! `wrapc` categorizes `rustc` flags into logical, type-safe collections.
//!
//! #### Configurations and Crate Metadata
//!
//! ```rust
//! // --cfg and --check-cfg
//! for cfg in &info.configs {
//! if cfg == "test" {
//! println!("Compiling in test mode!");
//! }
//! }
//!
//! // --crate-type (e.g., bin, rlib, dylib)
//! if info.crate_types.contains(&"dylib".to_string()) {
//! println!("Building a dynamic library.");
//! }
//! ```
//!
//! #### Complex Linking (`-l` and `-L`)
//!
//! `rustc`'s linking flags are highly structured. `wrapc` parses modifiers, kinds, and renames automatically.
//!
//! ```rust
//! use wrapc::{LibrarySearchPathKind, LSPK, LinkLibKind};
//!
//! // Inspecting -L (Library Search Paths)
//! for lib_path in &info.libpaths {
//! match lib_path.kind {
//! LibrarySearchPathKind::Native => println!("Native search path: {:?}", lib_path.path),
//! // LSPK is an alias to LibrarySearchPathKind
//! LSPK::Framework => println!("macOS Framework path: {:?}", lib_path.path),
//! _ => println!("Generic search path: {:?}", lib_path.path),
//! }
//! }
//!
//! // Inspecting -l (Link Libraries)
//! // Example parsed: `-lstatic:+bundle,+whole-archive=mylib:renamed_lib`
//! for link in &info.links {
//! println!("Linking: {}", link.name);
//! if let Some(kind) = &link.kind {
//! println!(" Kind: {:?}", kind); // e.g., LinkLibKind::Static
//! }
//! if !link.modifiers.is_empty() {
//! println!(" Modifiers: {:?}", link.modifiers); // e.g., ["+bundle", "+whole-archive"]
//! }
//! if let Some(rename) = &link.rename {
//! println!(" Renamed to: {}", rename);
//! }
//! }
//! ```
//!
//! ### 4. Mutating Arguments (The Wrapper Superpower)
//!
//! The most common use case for a wrapper is to inject or modify flags before passing
//! them to `rustc`. Because [`Info`] is just a standard Rust struct, you can mutate it freely.
//! [`Info::to_args()`] will flawlessly reconstruct the CLI string.
//!
//! ```rust
//! let mut info = fetch().unwrap();
//!
//! // Inject a custom linker argument
//! info.codegen_opts.push("link-arg=-Wl,-rpath,/opt/my-tool/lib".to_string());
//!
//! // Force a specific optimization level for a specific crate
//! if info.crate_name.as_deref() == Some("legacy_crate") {
//! // Remove existing opt-levels
//! info.codegen_opts.retain(|opt| !opt.starts_with("opt-level="));
//! // Inject our own
//! info.codegen_opts.push("opt-level=1".to_string());
//! }
//!
//! // Add a custom configuration flag
//! info.configs.push("my_wrapper_active".to_string());
//!
//! // Pass to rustc
//! let args = info.to_args();
//! ```
//!
//! ### 5. Handling Edge Cases & "Unknown" Flags
//!
//! `rustc` has hundreds of flags, including unstable nightly flags (`-Z`) and internal
//! compiler queries. `wrapc` captures everything it explicitly knows, and safely
//! buckets the rest into info.unknown.
//!
//! #### The `--` Separator
//!
//! In `rustc`, anything after `--` is usually ignored or passed to specific internal tools.
//! `wrapc` stops parsing at `--` and dumps the rest into [`Info::unknown`] to prevent
//! accidental misinterpretation.
//!
//! ```rust
//! // If rustc is called with: `rustc --crate-name foo -- --some-internal-flag`
//! assert_eq!(info.crate_name, Some("foo".to_string()));
//! assert_eq!(info.unknown, vec!["--", "--some-internal-flag"]);
//! ```
//!
//! #### Unrecognized / Nightly Flags
//!
//! If a user passes a brand new nightly flag that `wrapc` hasn't explicitly modeled
//! yet, it won't crash. It goes to [`Info::unknown`] and is perfectly
//! preserved by [`Info::to_args()`].
//!
//! ```rust
//! for unknown_arg in &info.unknown {
//! // Safe to pass through to rustc
//! println!("Passing through: {}", unknown_arg);
//! }
//! ```
//!
//! #### The `stdin` Edge Case (`-`)
//!
//! Tools like `cargo` or IDEs sometimes pass `-` as the input file
//! to tell `rustc` to read source code from stdin.
//! Because Cargo's wrapper protocol also uses `-` as a separator
//! (`<wrapper> - <rustc>`), naive parsers break here.
//! `wrapc` handles this contextually:
//!
//! ```rust
//! // Invocation: `my_wrapper - rustc -`
//! let info = fetch().unwrap();
//!
//! assert_eq!(info.rustc, Some("rustc".to_string()));
//! assert_eq!(info.inputs, vec![std::path::PathBuf::from("-")]); // Correctly identified as input!
//! ```
//!
//! ### 6. Testing Your Wrapper
//!
//! To test your wrapper locally without publishing it, use the `RUSTC_WRAPPER` environment variable:
//!
//! ```bash
//! # Build your wrapper
//! cargo build --release
//!
//! # Point Cargo to your wrapper
//! export RUSTC_WRAPPER="/path/to/your/project/target/release/my_wrapper"
//!
//! # Run a standard cargo command
//! cargo build
//! ```
//!
//! Your wrapper will intercept every `rustc` invocation, allowing you to log,
//! mutate, or cache the compilation process using the type-safe
//! data provided by `wrapc`.
//!
pub use *;
pub use *;
pub use *;