1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 use std::cell::RefCell; 6 use std::collections::HashMap; 7 use std::fs; 8 use std::fs::File; 9 use std::io::{Read, Write}; 10 use std::path; 11 use std::rc::Rc; 12 13 use crate::bindgen::config::{Config, Language}; 14 use crate::bindgen::ir::{ 15 Constant, Function, ItemContainer, ItemMap, Path as BindgenPath, Static, Struct, 16 }; 17 use crate::bindgen::writer::{Source, SourceWriter}; 18 19 /// A bindings header that can be written. 20 pub struct Bindings { 21 pub config: Config, 22 /// The map from path to struct, used to lookup whether a given type is a 23 /// transparent struct. This is needed to generate code for constants. 24 struct_map: ItemMap<Struct>, 25 struct_fileds_memo: RefCell<HashMap<BindgenPath, Rc<Vec<String>>>>, 26 globals: Vec<Static>, 27 constants: Vec<Constant>, 28 items: Vec<ItemContainer>, 29 functions: Vec<Function>, 30 } 31 32 #[derive(PartialEq)] 33 enum NamespaceOperation { 34 Open, 35 Close, 36 } 37 38 impl Bindings { new( config: Config, struct_map: ItemMap<Struct>, constants: Vec<Constant>, globals: Vec<Static>, items: Vec<ItemContainer>, functions: Vec<Function>, ) -> Bindings39 pub(crate) fn new( 40 config: Config, 41 struct_map: ItemMap<Struct>, 42 constants: Vec<Constant>, 43 globals: Vec<Static>, 44 items: Vec<ItemContainer>, 45 functions: Vec<Function>, 46 ) -> Bindings { 47 Bindings { 48 config, 49 struct_map, 50 struct_fileds_memo: Default::default(), 51 globals, 52 constants, 53 items, 54 functions, 55 } 56 } 57 58 // FIXME(emilio): What to do when the configuration doesn't match? struct_is_transparent(&self, path: &BindgenPath) -> bool59 pub fn struct_is_transparent(&self, path: &BindgenPath) -> bool { 60 let mut any = false; 61 self.struct_map.for_items(path, |s| any |= s.is_transparent); 62 any 63 } 64 struct_exists(&self, path: &BindgenPath) -> bool65 pub fn struct_exists(&self, path: &BindgenPath) -> bool { 66 let mut any = false; 67 self.struct_map.for_items(path, |_| any = true); 68 any 69 } 70 struct_field_names(&self, path: &BindgenPath) -> Rc<Vec<String>>71 pub fn struct_field_names(&self, path: &BindgenPath) -> Rc<Vec<String>> { 72 let mut memos = self.struct_fileds_memo.borrow_mut(); 73 if let Some(memo) = memos.get(path) { 74 return memo.clone(); 75 } 76 77 let mut fields = Vec::<String>::new(); 78 self.struct_map.for_items(path, |st| { 79 let mut pos: usize = 0; 80 for field in &st.fields { 81 if let Some(found_pos) = fields.iter().position(|v| *v == field.0) { 82 pos = found_pos + 1; 83 } else { 84 fields.insert(pos, field.0.clone()); 85 pos += 1; 86 } 87 } 88 }); 89 90 let fields = Rc::new(fields); 91 memos.insert(path.clone(), fields.clone()); 92 fields 93 } 94 write_to_file<P: AsRef<path::Path>>(&self, path: P) -> bool95 pub fn write_to_file<P: AsRef<path::Path>>(&self, path: P) -> bool { 96 // Don't compare files if we've never written this file before 97 if !path.as_ref().is_file() { 98 if let Some(parent) = path::Path::new(path.as_ref()).parent() { 99 fs::create_dir_all(parent).unwrap(); 100 } 101 self.write(File::create(path).unwrap()); 102 return true; 103 } 104 105 let mut new_file_contents = Vec::new(); 106 self.write(&mut new_file_contents); 107 108 let mut old_file_contents = Vec::new(); 109 { 110 let mut old_file = File::open(&path).unwrap(); 111 old_file.read_to_end(&mut old_file_contents).unwrap(); 112 } 113 114 if old_file_contents != new_file_contents { 115 let mut new_file = File::create(&path).unwrap(); 116 new_file.write_all(&new_file_contents).unwrap(); 117 true 118 } else { 119 false 120 } 121 } 122 write_headers<F: Write>(&self, out: &mut SourceWriter<F>)123 pub fn write_headers<F: Write>(&self, out: &mut SourceWriter<F>) { 124 if let Some(ref f) = self.config.header { 125 out.new_line_if_not_start(); 126 write!(out, "{}", f); 127 out.new_line(); 128 } 129 if let Some(ref f) = self.config.include_guard { 130 out.new_line_if_not_start(); 131 write!(out, "#ifndef {}", f); 132 out.new_line(); 133 write!(out, "#define {}", f); 134 out.new_line(); 135 } 136 if self.config.include_version { 137 out.new_line_if_not_start(); 138 write!( 139 out, 140 "/* Generated with cbindgen:{} */", 141 crate::bindgen::config::VERSION 142 ); 143 out.new_line(); 144 } 145 if let Some(ref f) = self.config.autogen_warning { 146 out.new_line_if_not_start(); 147 write!(out, "{}", f); 148 out.new_line(); 149 } 150 151 if self.config.no_includes 152 && self.config.sys_includes.is_empty() 153 && self.config.includes.is_empty() 154 { 155 return; 156 } 157 158 out.new_line_if_not_start(); 159 160 if !self.config.no_includes { 161 if self.config.language == Language::C { 162 out.write("#include <stdarg.h>"); 163 out.new_line(); 164 out.write("#include <stdbool.h>"); 165 out.new_line(); 166 out.write("#include <stdint.h>"); 167 out.new_line(); 168 out.write("#include <stdlib.h>"); 169 out.new_line(); 170 } else { 171 out.write("#include <cstdarg>"); 172 out.new_line(); 173 out.write("#include <cstdint>"); 174 out.new_line(); 175 out.write("#include <cstdlib>"); 176 out.new_line(); 177 out.write("#include <new>"); 178 out.new_line(); 179 if self.config.enumeration.cast_assert_name.is_none() 180 && (self.config.enumeration.derive_mut_casts 181 || self.config.enumeration.derive_const_casts) 182 { 183 out.write("#include <cassert>"); 184 out.new_line(); 185 } 186 } 187 } 188 189 for include in &self.config.sys_includes { 190 write!(out, "#include <{}>", include); 191 out.new_line(); 192 } 193 194 for include in &self.config.includes { 195 write!(out, "#include \"{}\"", include); 196 out.new_line(); 197 } 198 } 199 write<F: Write>(&self, file: F)200 pub fn write<F: Write>(&self, file: F) { 201 let mut out = SourceWriter::new(file, self); 202 203 self.write_headers(&mut out); 204 205 self.open_namespaces(&mut out); 206 207 for constant in &self.constants { 208 if constant.ty.is_primitive_or_ptr_primitive() { 209 out.new_line_if_not_start(); 210 constant.write(&self.config, &mut out, None); 211 out.new_line(); 212 } 213 } 214 215 for item in &self.items { 216 if item 217 .deref() 218 .annotations() 219 .bool("no-export") 220 .unwrap_or(false) 221 { 222 continue; 223 } 224 225 out.new_line_if_not_start(); 226 match *item { 227 ItemContainer::Constant(..) => unreachable!(), 228 ItemContainer::Static(..) => unreachable!(), 229 ItemContainer::Enum(ref x) => x.write(&self.config, &mut out), 230 ItemContainer::Struct(ref x) => x.write(&self.config, &mut out), 231 ItemContainer::Union(ref x) => x.write(&self.config, &mut out), 232 ItemContainer::OpaqueItem(ref x) => x.write(&self.config, &mut out), 233 ItemContainer::Typedef(ref x) => x.write(&self.config, &mut out), 234 } 235 out.new_line(); 236 } 237 238 for constant in &self.constants { 239 if !constant.ty.is_primitive_or_ptr_primitive() { 240 out.new_line_if_not_start(); 241 constant.write(&self.config, &mut out, None); 242 out.new_line(); 243 } 244 } 245 246 if !self.functions.is_empty() || !self.globals.is_empty() { 247 if self.config.language == Language::C && self.config.cpp_compat { 248 out.new_line_if_not_start(); 249 out.write("#ifdef __cplusplus"); 250 } 251 252 if self.config.language == Language::Cxx { 253 if let Some(ref using_namespaces) = self.config.using_namespaces { 254 for namespace in using_namespaces { 255 out.new_line(); 256 write!(out, "using namespace {};", namespace); 257 } 258 out.new_line(); 259 } 260 } 261 262 if self.config.language == Language::Cxx || self.config.cpp_compat { 263 out.new_line(); 264 out.write("extern \"C\" {"); 265 out.new_line(); 266 } 267 268 if self.config.language == Language::C && self.config.cpp_compat { 269 out.write("#endif // __cplusplus"); 270 out.new_line(); 271 } 272 273 for global in &self.globals { 274 out.new_line_if_not_start(); 275 global.write(&self.config, &mut out); 276 out.new_line(); 277 } 278 279 for function in &self.functions { 280 out.new_line_if_not_start(); 281 function.write(&self.config, &mut out); 282 out.new_line(); 283 } 284 285 if self.config.language == Language::C && self.config.cpp_compat { 286 out.new_line(); 287 out.write("#ifdef __cplusplus"); 288 } 289 290 if self.config.language == Language::Cxx || self.config.cpp_compat { 291 out.new_line(); 292 out.write("} // extern \"C\""); 293 out.new_line(); 294 } 295 296 if self.config.language == Language::C && self.config.cpp_compat { 297 out.write("#endif // __cplusplus"); 298 out.new_line(); 299 } 300 } 301 302 self.close_namespaces(&mut out); 303 304 if let Some(ref f) = self.config.include_guard { 305 out.new_line_if_not_start(); 306 if self.config.language == Language::C { 307 write!(out, "#endif /* {} */", f); 308 } else { 309 write!(out, "#endif // {}", f); 310 } 311 out.new_line(); 312 } 313 if let Some(ref f) = self.config.trailer { 314 out.new_line_if_not_start(); 315 write!(out, "{}", f); 316 if !f.ends_with('\n') { 317 out.new_line(); 318 } 319 } 320 } 321 all_namespaces(&self) -> Vec<&str>322 fn all_namespaces(&self) -> Vec<&str> { 323 if self.config.language != Language::Cxx && !self.config.cpp_compat { 324 return vec![]; 325 } 326 let mut ret = vec![]; 327 if let Some(ref namespace) = self.config.namespace { 328 ret.push(&**namespace); 329 } 330 if let Some(ref namespaces) = self.config.namespaces { 331 for namespace in namespaces { 332 ret.push(&**namespace); 333 } 334 } 335 ret 336 } 337 open_close_namespaces<F: Write>(&self, op: NamespaceOperation, out: &mut SourceWriter<F>)338 fn open_close_namespaces<F: Write>(&self, op: NamespaceOperation, out: &mut SourceWriter<F>) { 339 let mut namespaces = self.all_namespaces(); 340 if namespaces.is_empty() { 341 return; 342 } 343 344 if op == NamespaceOperation::Close { 345 namespaces.reverse(); 346 } 347 348 let write_ifdefs = self.config.cpp_compat && self.config.language == Language::C; 349 if write_ifdefs { 350 out.new_line_if_not_start(); 351 out.write("#ifdef __cplusplus"); 352 } 353 354 for namespace in namespaces { 355 out.new_line(); 356 match op { 357 NamespaceOperation::Open => write!(out, "namespace {} {{", namespace), 358 NamespaceOperation::Close => write!(out, "}} // namespace {}", namespace), 359 } 360 } 361 362 out.new_line(); 363 if write_ifdefs { 364 out.write("#endif // __cplusplus"); 365 out.new_line(); 366 } 367 } 368 open_namespaces<F: Write>(&self, out: &mut SourceWriter<F>)369 pub(crate) fn open_namespaces<F: Write>(&self, out: &mut SourceWriter<F>) { 370 self.open_close_namespaces(NamespaceOperation::Open, out); 371 } 372 close_namespaces<F: Write>(&self, out: &mut SourceWriter<F>)373 pub(crate) fn close_namespaces<F: Write>(&self, out: &mut SourceWriter<F>) { 374 self.open_close_namespaces(NamespaceOperation::Close, out); 375 } 376 } 377