1#[cfg(feature = "alloc")]
14use alloc::{format, string::String, vec::Vec};
15
16#[cfg(feature = "alloc")]
18#[derive(Debug, Clone)]
19pub struct IncludePath {
20 pub path: String,
22 pub system: bool,
24}
25
26#[cfg(feature = "alloc")]
28#[derive(Debug, Clone)]
29pub struct LibraryPath {
30 pub path: String,
32 pub name: String,
34}
35
36#[cfg(feature = "alloc")]
41#[derive(Debug, Clone)]
42pub struct PkgConfig {
43 pub name: String,
45 pub version: String,
47 pub description: String,
49 pub include_dirs: Vec<String>,
51 pub lib_dirs: Vec<String>,
53 pub libs: Vec<String>,
55 pub cflags: Vec<String>,
57}
58
59#[cfg(feature = "alloc")]
60impl PkgConfig {
61 pub fn generate_pkg_config(&self) -> String {
66 let sysroot = super::get_sysroot();
67
68 let mut output = String::new();
69
70 output.push_str(&format!("prefix={}\n", sysroot));
72 output.push_str("exec_prefix=${prefix}\n");
73 output.push_str("libdir=${exec_prefix}/lib\n");
74 output.push_str("includedir=${prefix}/include\n");
75 output.push('\n');
76
77 output.push_str(&format!("Name: {}\n", self.name));
79 output.push_str(&format!("Version: {}\n", self.version));
80 output.push_str(&format!("Description: {}\n", self.description));
81
82 let mut cflags_parts: Vec<String> = Vec::new();
84 for dir in &self.include_dirs {
85 cflags_parts.push(format!("-I{}", dir));
86 }
87 for flag in &self.cflags {
88 cflags_parts.push(flag.clone());
89 }
90 if !cflags_parts.is_empty() {
91 output.push_str("Cflags:");
92 for part in &cflags_parts {
93 output.push(' ');
94 output.push_str(part);
95 }
96 output.push('\n');
97 }
98
99 let mut libs_parts: Vec<String> = Vec::new();
101 for dir in &self.lib_dirs {
102 libs_parts.push(format!("-L{}", dir));
103 }
104 for lib in &self.libs {
105 libs_parts.push(format!("-l{}", lib));
106 }
107 if !libs_parts.is_empty() {
108 output.push_str("Libs:");
109 for part in &libs_parts {
110 output.push(' ');
111 output.push_str(part);
112 }
113 output.push('\n');
114 }
115
116 output
117 }
118
119 pub fn find_package(name: &str) -> Option<PkgConfig> {
125 let sysroot = super::get_sysroot();
126 let triple = super::get_target_triple();
127
128 match name {
129 "veridian" => Some(PkgConfig {
130 name: String::from("veridian"),
131 version: String::from("0.4.0"),
132 description: String::from("VeridianOS core system library"),
133 include_dirs: alloc::vec![
134 format!("{}/include", sysroot),
135 format!("{}/include/veridian", sysroot),
136 ],
137 lib_dirs: alloc::vec![format!("{}/lib/{}", sysroot, triple)],
138 libs: alloc::vec![String::from("veridian")],
139 cflags: alloc::vec![
140 String::from("-ffreestanding"),
141 format!("--target={}", triple),
142 ],
143 }),
144 "veridian-ipc" => Some(PkgConfig {
145 name: String::from("veridian-ipc"),
146 version: String::from("0.4.0"),
147 description: String::from("VeridianOS IPC library"),
148 include_dirs: alloc::vec![format!("{}/include/veridian/ipc", sysroot)],
149 lib_dirs: alloc::vec![format!("{}/lib/{}", sysroot, triple)],
150 libs: alloc::vec![String::from("veridian-ipc"), String::from("veridian"),],
151 cflags: alloc::vec![format!("--target={}", triple)],
152 }),
153 "veridian-cap" => Some(PkgConfig {
154 name: String::from("veridian-cap"),
155 version: String::from("0.4.0"),
156 description: String::from("VeridianOS capability library"),
157 include_dirs: alloc::vec![format!("{}/include/veridian/cap", sysroot)],
158 lib_dirs: alloc::vec![format!("{}/lib/{}", sysroot, triple)],
159 libs: alloc::vec![String::from("veridian-cap"), String::from("veridian"),],
160 cflags: alloc::vec![format!("--target={}", triple)],
161 }),
162 _ => {
163 let pc_path = format!("{}/lib/pkgconfig/{}.pc", sysroot, name);
167 if let Some(vfs_lock) = crate::fs::try_get_vfs() {
168 let vfs = vfs_lock.read();
169 if let Ok(node) = vfs.resolve_path(&pc_path) {
170 let mut buf = alloc::vec![0u8; 4096];
171 if let Ok(n) = node.read(0, &mut buf) {
172 if let Ok(content) = core::str::from_utf8(&buf[..n]) {
173 return Self::parse_pc_basic(content, name, sysroot, triple);
174 }
175 }
176 }
177 }
178 None
179 }
180 }
181 }
182
183 pub fn include_paths(&self) -> Vec<IncludePath> {
185 self.include_dirs
186 .iter()
187 .map(|p| IncludePath {
188 path: p.clone(),
189 system: false,
190 })
191 .collect()
192 }
193
194 pub fn library_paths(&self) -> Vec<LibraryPath> {
197 let mut result = Vec::new();
198 for dir in &self.lib_dirs {
199 for lib in &self.libs {
200 result.push(LibraryPath {
201 path: dir.clone(),
202 name: lib.clone(),
203 });
204 }
205 }
206 result
207 }
208
209 fn parse_pc_basic(content: &str, name: &str, sysroot: &str, triple: &str) -> Option<PkgConfig> {
213 let mut version = String::from("0.0.0");
214 let mut description = String::new();
215 let mut cflags = Vec::new();
216 let mut libs = Vec::new();
217 let mut lib_dirs = Vec::new();
218 let mut include_dirs = Vec::new();
219
220 for line in content.lines() {
221 let line = line.trim();
222 if let Some(val) = line.strip_prefix("Version:") {
223 version = String::from(val.trim());
224 } else if let Some(val) = line.strip_prefix("Description:") {
225 description = String::from(val.trim());
226 } else if let Some(val) = line.strip_prefix("Cflags:") {
227 for token in val.split_whitespace() {
228 if let Some(inc) = token.strip_prefix("-I") {
229 include_dirs.push(String::from(inc));
230 }
231 cflags.push(String::from(token));
232 }
233 } else if let Some(val) = line.strip_prefix("Libs:") {
234 for token in val.split_whitespace() {
235 if let Some(dir) = token.strip_prefix("-L") {
236 lib_dirs.push(String::from(dir));
237 } else if let Some(lib) = token.strip_prefix("-l") {
238 libs.push(String::from(lib));
239 }
240 }
241 }
242 }
243
244 if include_dirs.is_empty() {
246 include_dirs.push(format!("{}/include", sysroot));
247 }
248 if lib_dirs.is_empty() {
249 lib_dirs.push(format!("{}/lib/{}", sysroot, triple));
250 }
251
252 Some(PkgConfig {
253 name: String::from(name),
254 version,
255 description,
256 include_dirs,
257 lib_dirs,
258 libs,
259 cflags,
260 })
261 }
262}
263
264#[cfg(feature = "alloc")]
265impl core::fmt::Display for PkgConfig {
266 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
267 write!(f, "{}", self.generate_pkg_config())
268 }
269}
270
271#[cfg(feature = "alloc")]
272impl core::fmt::Display for IncludePath {
273 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
274 if self.system {
275 write!(f, "-isystem {}", self.path)
276 } else {
277 write!(f, "-I{}", self.path)
278 }
279 }
280}
281
282#[cfg(feature = "alloc")]
283impl core::fmt::Display for LibraryPath {
284 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
285 write!(f, "-L{} -l{}", self.path, self.name)
286 }
287}