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::fs; 6 use std::fs::File; 7 use std::io::{Read, Write}; 8 use std::path; 9 10 use bindgen::config::{Config, Language}; 11 use bindgen::ir::{ 12 Constant, Function, ItemContainer, ItemMap, Path as BindgenPath, Static, Struct, 13 }; 14 use bindgen::writer::{Source, SourceWriter}; 15 16 /// A bindings header that can be written. 17 pub struct Bindings { 18 pub config: Config, 19 /// The map from path to struct, used to lookup whether a given type is a 20 /// transparent struct. This is needed to generate code for constants. 21 struct_map: ItemMap<Struct>, 22 globals: Vec<Static>, 23 constants: Vec<Constant>, 24 items: Vec<ItemContainer>, 25 functions: Vec<Function>, 26 } 27 28 impl Bindings { new( config: Config, struct_map: ItemMap<Struct>, constants: Vec<Constant>, globals: Vec<Static>, items: Vec<ItemContainer>, functions: Vec<Function>, ) -> Bindings29 pub(crate) fn new( 30 config: Config, 31 struct_map: ItemMap<Struct>, 32 constants: Vec<Constant>, 33 globals: Vec<Static>, 34 items: Vec<ItemContainer>, 35 functions: Vec<Function>, 36 ) -> Bindings { 37 Bindings { 38 config, 39 struct_map, 40 globals, 41 constants, 42 items, 43 functions, 44 } 45 } 46 47 // FIXME(emilio): What to do when the configuration doesn't match? struct_is_transparent(&self, path: &BindgenPath) -> bool48 pub fn struct_is_transparent(&self, path: &BindgenPath) -> bool { 49 let mut any = false; 50 self.struct_map.for_items(path, |s| any |= s.is_transparent); 51 any 52 } 53 struct_exists(&self, path: &BindgenPath) -> bool54 pub fn struct_exists(&self, path: &BindgenPath) -> bool { 55 let mut any = false; 56 self.struct_map.for_items(path, |_| any = true); 57 any 58 } 59 write_to_file<P: AsRef<path::Path>>(&self, path: P) -> bool60 pub fn write_to_file<P: AsRef<path::Path>>(&self, path: P) -> bool { 61 // Don't compare files if we've never written this file before 62 if !path.as_ref().is_file() { 63 if let Some(parent) = path::Path::new(path.as_ref()).parent() { 64 fs::create_dir_all(parent).unwrap(); 65 } 66 self.write(File::create(path).unwrap()); 67 return true; 68 } 69 70 let mut new_file_contents = Vec::new(); 71 self.write(&mut new_file_contents); 72 73 let mut old_file_contents = Vec::new(); 74 { 75 let mut old_file = File::open(&path).unwrap(); 76 old_file.read_to_end(&mut old_file_contents).unwrap(); 77 } 78 79 if old_file_contents != new_file_contents { 80 let mut new_file = File::create(&path).unwrap(); 81 new_file.write_all(&new_file_contents).unwrap(); 82 true 83 } else { 84 false 85 } 86 } 87 write_headers<F: Write>(&self, out: &mut SourceWriter<F>)88 pub fn write_headers<F: Write>(&self, out: &mut SourceWriter<F>) { 89 if let Some(ref f) = self.config.header { 90 out.new_line_if_not_start(); 91 write!(out, "{}", f); 92 out.new_line(); 93 } 94 if let Some(ref f) = self.config.include_guard { 95 out.new_line_if_not_start(); 96 write!(out, "#ifndef {}", f); 97 out.new_line(); 98 write!(out, "#define {}", f); 99 out.new_line(); 100 } 101 if self.config.include_version { 102 out.new_line_if_not_start(); 103 write!( 104 out, 105 "/* Generated with cbindgen:{} */", 106 ::bindgen::config::VERSION 107 ); 108 out.new_line(); 109 } 110 if let Some(ref f) = self.config.autogen_warning { 111 out.new_line_if_not_start(); 112 write!(out, "{}", f); 113 out.new_line(); 114 } 115 116 if self.config.no_includes 117 && self.config.sys_includes.is_empty() 118 && self.config.includes.is_empty() 119 { 120 return; 121 } 122 123 out.new_line_if_not_start(); 124 125 if !self.config.no_includes { 126 if self.config.language == Language::C { 127 out.write("#include <stdarg.h>"); 128 out.new_line(); 129 out.write("#include <stdbool.h>"); 130 out.new_line(); 131 out.write("#include <stdint.h>"); 132 out.new_line(); 133 out.write("#include <stdlib.h>"); 134 out.new_line(); 135 } else { 136 out.write("#include <cstdarg>"); 137 out.new_line(); 138 out.write("#include <cstdint>"); 139 out.new_line(); 140 out.write("#include <cstdlib>"); 141 out.new_line(); 142 out.write("#include <new>"); 143 out.new_line(); 144 if self.config.enumeration.cast_assert_name.is_none() 145 && (self.config.enumeration.derive_mut_casts 146 || self.config.enumeration.derive_const_casts) 147 { 148 out.write("#include <cassert>"); 149 out.new_line(); 150 } 151 } 152 } 153 154 for include in &self.config.sys_includes { 155 write!(out, "#include <{}>", include); 156 out.new_line(); 157 } 158 159 for include in &self.config.includes { 160 write!(out, "#include \"{}\"", include); 161 out.new_line(); 162 } 163 } 164 write<F: Write>(&self, file: F)165 pub fn write<F: Write>(&self, file: F) { 166 let mut out = SourceWriter::new(file, self); 167 168 self.write_headers(&mut out); 169 170 if self.config.language == Language::Cxx { 171 self.open_namespaces(&mut out); 172 } 173 174 for constant in &self.constants { 175 if constant.ty.is_primitive_or_ptr_primitive() { 176 out.new_line_if_not_start(); 177 constant.write(&self.config, &mut out, None); 178 out.new_line(); 179 } 180 } 181 182 for item in &self.items { 183 if item 184 .deref() 185 .annotations() 186 .bool("no-export") 187 .unwrap_or(false) 188 { 189 continue; 190 } 191 192 out.new_line_if_not_start(); 193 match *item { 194 ItemContainer::Constant(..) => unreachable!(), 195 ItemContainer::Static(..) => unreachable!(), 196 ItemContainer::Enum(ref x) => x.write(&self.config, &mut out), 197 ItemContainer::Struct(ref x) => x.write(&self.config, &mut out), 198 ItemContainer::Union(ref x) => x.write(&self.config, &mut out), 199 ItemContainer::OpaqueItem(ref x) => x.write(&self.config, &mut out), 200 ItemContainer::Typedef(ref x) => x.write(&self.config, &mut out), 201 } 202 out.new_line(); 203 } 204 205 for constant in &self.constants { 206 if !constant.ty.is_primitive_or_ptr_primitive() { 207 out.new_line_if_not_start(); 208 constant.write(&self.config, &mut out, None); 209 out.new_line(); 210 } 211 } 212 213 if !self.functions.is_empty() || !self.globals.is_empty() { 214 if self.config.language == Language::C && self.config.cpp_compat { 215 out.new_line_if_not_start(); 216 out.write("#ifdef __cplusplus"); 217 } 218 219 if self.config.language == Language::Cxx || self.config.cpp_compat { 220 out.new_line(); 221 out.write("extern \"C\" {"); 222 out.new_line(); 223 } 224 225 if self.config.language == Language::C && self.config.cpp_compat { 226 out.write("#endif // __cplusplus"); 227 out.new_line(); 228 } 229 230 for global in &self.globals { 231 out.new_line_if_not_start(); 232 global.write(&self.config, &mut out); 233 out.new_line(); 234 } 235 236 for function in &self.functions { 237 out.new_line_if_not_start(); 238 function.write(&self.config, &mut out); 239 out.new_line(); 240 } 241 242 if self.config.language == Language::C && self.config.cpp_compat { 243 out.new_line(); 244 out.write("#ifdef __cplusplus"); 245 } 246 247 if self.config.language == Language::Cxx || self.config.cpp_compat { 248 out.new_line(); 249 out.write("} // extern \"C\""); 250 out.new_line(); 251 } 252 253 if self.config.language == Language::C && self.config.cpp_compat { 254 out.write("#endif // __cplusplus"); 255 out.new_line(); 256 } 257 } 258 259 if self.config.language == Language::Cxx { 260 self.close_namespaces(&mut out); 261 } 262 263 if let Some(ref f) = self.config.include_guard { 264 out.new_line_if_not_start(); 265 if self.config.language == Language::C { 266 write!(out, "#endif /* {} */", f); 267 } else { 268 write!(out, "#endif // {}", f); 269 } 270 out.new_line(); 271 } 272 if let Some(ref f) = self.config.trailer { 273 out.new_line_if_not_start(); 274 write!(out, "{}", f); 275 out.new_line(); 276 } 277 } 278 open_namespaces<F: Write>(&self, out: &mut SourceWriter<F>)279 pub(crate) fn open_namespaces<F: Write>(&self, out: &mut SourceWriter<F>) { 280 let mut wrote_namespace: bool = false; 281 if let Some(ref namespace) = self.config.namespace { 282 wrote_namespace = true; 283 284 out.new_line(); 285 write!(out, "namespace {} {{", namespace); 286 } 287 if let Some(ref namespaces) = self.config.namespaces { 288 wrote_namespace = true; 289 for namespace in namespaces { 290 out.new_line(); 291 write!(out, "namespace {} {{", namespace); 292 } 293 } 294 if wrote_namespace { 295 out.new_line(); 296 } 297 } 298 close_namespaces<F: Write>(&self, out: &mut SourceWriter<F>)299 pub(crate) fn close_namespaces<F: Write>(&self, out: &mut SourceWriter<F>) { 300 let mut wrote_namespace: bool = false; 301 if let Some(ref namespaces) = self.config.namespaces { 302 wrote_namespace = true; 303 304 for namespace in namespaces.iter().rev() { 305 out.new_line_if_not_start(); 306 write!(out, "}} // namespace {}", namespace); 307 } 308 } 309 if let Some(ref namespace) = self.config.namespace { 310 wrote_namespace = true; 311 312 out.new_line_if_not_start(); 313 write!(out, "}} // namespace {}", namespace); 314 } 315 if wrote_namespace { 316 out.new_line(); 317 } 318 } 319 } 320