diff options
author | Xidorn Quan <me@upsuper.org> | 2017-05-19 10:35:36 +1000 |
---|---|---|
committer | Xidorn Quan <me@upsuper.org> | 2017-05-19 11:08:35 +1000 |
commit | f123b26e6c47b1f317ff3ec213a25f6d7b71dfe5 (patch) | |
tree | 96a7653225ba817088500be4a93e136a232fdd54 | |
parent | 0b3fd8de767c6ad6ea2fd983c396f5c0a20becfc (diff) | |
download | servo-f123b26e6c47b1f317ff3ec213a25f6d7b71dfe5.tar.gz servo-f123b26e6c47b1f317ff3ec213a25f6d7b71dfe5.zip |
Move config info from build_gecko.rs to a toml file in gecko.
-rw-r--r-- | Cargo.lock | 1 | ||||
-rw-r--r-- | components/style/Cargo.toml | 3 | ||||
-rw-r--r-- | components/style/build.rs | 2 | ||||
-rw-r--r-- | components/style/build_gecko.rs | 822 |
4 files changed, 248 insertions, 580 deletions
diff --git a/Cargo.lock b/Cargo.lock index b21ff19f356..ba083e6e890 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2852,6 +2852,7 @@ dependencies = [ "smallvec 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "style_traits 0.0.1", "time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-segmentation 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/components/style/Cargo.toml b/components/style/Cargo.toml index 708488861e8..f9b93b7500d 100644 --- a/components/style/Cargo.toml +++ b/components/style/Cargo.toml @@ -14,7 +14,7 @@ doctest = false [features] gecko = ["nsstring_vendor", "rayon/unstable", "num_cpus", "style_traits/gecko"] -use_bindgen = ["bindgen", "regex"] +use_bindgen = ["bindgen", "regex", "toml"] servo = ["serde", "serde_derive", "heapsize", "heapsize_derive", "style_traits/servo", "servo_atoms", "servo_config", "html5ever", "cssparser/heapsize", "cssparser/serde", "encoding", "smallvec/heapsizeof", @@ -69,3 +69,4 @@ log = "0.3" bindgen = { version = "0.25", optional = true } regex = {version = "0.2", optional = true} walkdir = "1.0" +toml = {version = "0.2.1", optional = true, default-features = false} diff --git a/components/style/build.rs b/components/style/build.rs index 8d40ccb9969..e5d3b40c204 100644 --- a/components/style/build.rs +++ b/components/style/build.rs @@ -10,6 +10,8 @@ extern crate bindgen; extern crate log; #[cfg(feature = "bindgen")] extern crate regex; +#[cfg(feature = "bindgen")] +extern crate toml; extern crate walkdir; use std::env; diff --git a/components/style/build_gecko.rs b/components/style/build_gecko.rs index 0812e902707..a6ecb8ac732 100644 --- a/components/style/build_gecko.rs +++ b/components/style/build_gecko.rs @@ -29,18 +29,20 @@ mod common { mod bindings { use bindgen::{Builder, CodegenConfig}; use bindgen::callbacks::{EnumVariantCustomBehavior, EnumVariantValue, ParseCallbacks}; - use regex::Regex; + use regex::{Regex, RegexSet}; use std::cmp; - use std::collections::HashSet; + use std::collections::{HashSet, HashMap}; use std::env; use std::fs::{self, File}; use std::io::{Read, Write}; use std::path::{Path, PathBuf}; use std::process::{Command, exit}; + use std::slice; use std::sync::Mutex; use std::time::SystemTime; use super::common::*; use super::super::PYTHON; + use toml; const STRUCTS_DEBUG_FILE: &'static str = "structs_debug.rs"; const STRUCTS_RELEASE_FILE: &'static str = "structs_release.rs"; @@ -60,6 +62,41 @@ mod bindings { } lazy_static! { + static ref CONFIG: toml::Table = { + let path = PathBuf::from(env::var("MOZ_SRC").unwrap()) + .join("layout/style/ServoBindings.toml"); + println!("cargo:rerun-if-changed={}", path.to_str().unwrap()); + update_last_modified(&path); + + let mut contents = String::new(); + File::open(path).expect("Failed to open config file") + .read_to_string(&mut contents).expect("Failed to read config file"); + let mut parser = toml::Parser::new(&contents); + if let Some(result) = parser.parse() { + result + } else { + use std::fmt::Write; + let mut reason = String::from("Failed to parse config file:"); + for err in parser.errors.iter() { + let parsed = &contents[..err.lo]; + write!(&mut reason, "\n* line {} column {}: {}", + parsed.lines().count(), + parsed.lines().last().map_or(0, |l| l.len()), + err).unwrap(); + } + panic!(reason) + } + }; + static ref TARGET_INFO: HashMap<String, String> = { + const TARGET_PREFIX: &'static str = "CARGO_CFG_TARGET_"; + let mut result = HashMap::new(); + for (k, v) in env::vars() { + if k.starts_with(TARGET_PREFIX) { + result.insert(k[TARGET_PREFIX.len()..].to_lowercase(), v); + } + } + result + }; static ref INCLUDE_RE: Regex = Regex::new(r#"#include\s*"(.+?)""#).unwrap(); static ref DISTDIR_PATH: PathBuf = { let path = PathBuf::from(env::var("MOZ_DIST").unwrap()); @@ -73,7 +110,7 @@ mod bindings { DISTDIR_PATH.join("include/nspr"), ]; static ref ADDED_PATHS: Mutex<HashSet<PathBuf>> = Mutex::new(HashSet::new()); - pub static ref LAST_MODIFIED: Mutex<SystemTime> = + static ref LAST_MODIFIED: Mutex<SystemTime> = Mutex::new(get_modified_time(&env::current_exe().unwrap()) .expect("Failed to get modified time of executable")); } @@ -82,16 +119,19 @@ mod bindings { file.metadata().and_then(|m| m.modified()).ok() } + fn update_last_modified(file: &Path) { + let modified = get_modified_time(file).unwrap(); + let mut last_modified = LAST_MODIFIED.lock().unwrap(); + *last_modified = cmp::max(modified, *last_modified); + } + fn search_include(name: &str) -> Option<PathBuf> { for path in SEARCH_PATHS.iter() { let file = path.join(name); - if !file.is_file() { - continue; + if file.is_file() { + update_last_modified(&file); + return Some(file); } - let modified = get_modified_time(&file).unwrap(); - let mut last_modified = LAST_MODIFIED.lock().unwrap(); - *last_modified = cmp::max(modified, *last_modified); - return Some(file); } None } @@ -124,22 +164,43 @@ mod bindings { trait BuilderExt { fn get_initial_builder(build_type: BuildType) -> Builder; fn include<T: Into<String>>(self, file: T) -> Builder; - fn zero_size_type(self, ty: &str, structs_list: &[&str]) -> Builder; + fn zero_size_type(self, ty: &str, structs_list: &HashSet<&str>) -> Builder; fn borrowed_type(self, ty: &str) -> Builder; fn mutable_borrowed_type(self, ty: &str) -> Builder; } + fn add_clang_args(mut builder: Builder, config: &toml::Table, matched_os: &mut bool) -> Builder { + fn add_args(mut builder: Builder, values: &[toml::Value]) -> Builder { + for item in values.iter() { + builder = builder.clang_arg(item.as_str().expect("Expect string in list")); + } + builder + } + for (k, v) in config.iter() { + if k == "args" { + builder = add_args(builder, v.as_slice().unwrap()); + continue; + } + let equal_idx = k.find('=').expect(&format!("Invalid key: {}", k)); + let (target_type, target_value) = k.split_at(equal_idx); + if TARGET_INFO[target_type] != target_value[1..] { + continue; + } + if target_type == "os" { + *matched_os = true; + } + builder = match *v { + toml::Value::Table(ref table) => add_clang_args(builder, table, matched_os), + toml::Value::Array(ref array) => add_args(builder, array), + _ => panic!("Unknown type"), + }; + } + builder + } + impl BuilderExt for Builder { fn get_initial_builder(build_type: BuildType) -> Builder { let mut builder = Builder::default().no_unstable_rust(); - let args = [ - "-x", "c++", "-std=c++14", - "-DTRACING=1", "-DIMPL_LIBXUL", "-DMOZ_STYLO_BINDINGS=1", - "-DMOZILLA_INTERNAL_API", "-DRUST_BINDGEN", "-DMOZ_STYLO" - ]; - for &arg in args.iter() { - builder = builder.clang_arg(arg); - } for dir in SEARCH_PATHS.iter() { builder = builder.clang_arg("-I").clang_arg(dir.to_str().unwrap()); } @@ -148,63 +209,11 @@ mod bindings { if build_type == BuildType::Debug { builder = builder.clang_arg("-DDEBUG=1").clang_arg("-DJS_DEBUG=1"); } - // cfg!(...) will check the attributes of the Rust target this file - // is being compiled for. We want the attributes of the target that - // the clang we're going to invoke is being compiled for, which isn't - // necessarily the same thing. Cargo provides the (yet-to-be-documented) - // CARGO_CFG_* environment variables for this purpose. Those variables - // should be used in preference to cfg! checks below. - let target_family = env::var("CARGO_CFG_TARGET_FAMILY").unwrap(); - let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); - let target_pointer_width = env::var("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap(); - let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap(); - let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap(); - - if target_family == "unix" { - builder = builder.clang_arg("-DOS_POSIX=1"); - } - if target_os == "linux" { - builder = builder.clang_arg("-DOS_LINUX=1"); - if target_arch == "x86" { - builder = builder.clang_arg("-m32"); - } else if target_arch == "x86_64" { - builder = builder.clang_arg("-m64"); - } - } else if target_os == "solaris" { - builder = builder.clang_arg("-DOS_SOLARIS=1"); - } else if target_os == "dragonfly" { - builder = builder.clang_arg("-DOS_BSD=1").clang_arg("-DOS_DRAGONFLY=1"); - } else if target_os == "freebsd" { - builder = builder.clang_arg("-DOS_BSD=1").clang_arg("-DOS_FREEBSD=1"); - } else if target_os == "netbsd" { - builder = builder.clang_arg("-DOS_BSD=1").clang_arg("-DOS_NETBSD=1"); - } else if target_os == "openbsd" { - builder = builder.clang_arg("-DOS_BSD=1").clang_arg("-DOS_OPENBSD=1"); - } else if target_os == "macos" { - builder = builder.clang_arg("-DOS_MACOSX=1") - .clang_arg("-stdlib=libc++") - // To disable the fixup bindgen applies which adds search - // paths from clang command line in order to avoid potential - // conflict with -stdlib=libc++. - .clang_arg("--target=x86_64-apple-darwin"); - } else if target_env == "msvc" { - builder = builder.clang_arg("-DOS_WIN=1").clang_arg("-DWIN32=1") - // For compatibility with MSVC 2015 - .clang_arg("-fms-compatibility-version=19") - // To enable the builtin __builtin_offsetof so that CRT wouldn't - // use reinterpret_cast in offsetof() which is not allowed inside - // static_assert(). - .clang_arg("-D_CRT_USE_BUILTIN_OFFSETOF") - // Enable hidden attribute (which is not supported by MSVC and - // thus not enabled by default with a MSVC-compatibile build) - // to exclude hidden symbols from the generated file. - .clang_arg("-DHAVE_VISIBILITY_HIDDEN_ATTRIBUTE=1"); - if target_pointer_width == "32" { - builder = builder.clang_arg("--target=i686-pc-win32"); - } else { - builder = builder.clang_arg("--target=x86_64-pc-win32"); - } - } else { + + let mut matched_os = false; + let build_config = CONFIG["build"].as_table().expect("Malformed config file"); + builder = add_clang_args(builder, build_config, &mut matched_os); + if !matched_os { panic!("Unknown platform"); } builder @@ -220,8 +229,8 @@ mod bindings { // Not 100% sure of how safe this is, but it's what we're using // in the XPCOM ffi too // https://github.com/nikomatsakis/rust-memory-model/issues/2 - fn zero_size_type(self, ty: &str, structs_list: &[&str]) -> Builder { - if !structs_list.contains(&ty) { + fn zero_size_type(self, ty: &str, structs_list: &HashSet<&str>) -> Builder { + if !structs_list.contains(ty) { self.hide_type(ty) .raw_line(format!("enum {}Void {{ }}", ty)) .raw_line(format!("pub struct {0}({0}Void);", ty)) @@ -292,318 +301,123 @@ mod bindings { .collect() } - #[derive(Debug)] - struct Callbacks; - impl ParseCallbacks for Callbacks { - fn enum_variant_behavior(&self, - enum_name: Option<&str>, - variant_name: &str, - _variant_value: EnumVariantValue) - -> Option<EnumVariantCustomBehavior> { - if enum_name.map_or(false, |n| n == "nsCSSPropertyID") && - variant_name.starts_with("eCSSProperty_COUNT") { - Some(EnumVariantCustomBehavior::Constify) - } else { - None + struct BuilderWithConfig<'a> { + builder: Builder, + config: &'a toml::Table, + used_keys: HashSet<&'static str>, + } + impl<'a> BuilderWithConfig<'a> { + fn new(builder: Builder, config: &'a toml::Table) -> Self { + BuilderWithConfig { + builder, config, + used_keys: HashSet::new(), + } + } + + fn handle_list<F>(self, key: &'static str, func: F) -> BuilderWithConfig<'a> + where F: FnOnce(Builder, slice::Iter<'a, toml::Value>) -> Builder { + let mut builder = self.builder; + let config = self.config; + let mut used_keys = self.used_keys; + if let Some(list) = config.get(key) { + used_keys.insert(key); + builder = func(builder, list.as_slice().unwrap().iter()); } + BuilderWithConfig { builder, config, used_keys } + } + fn handle_items<F>(self, key: &'static str, mut func: F) -> BuilderWithConfig<'a> + where F: FnMut(Builder, &'a toml::Value) -> Builder { + self.handle_list(key, |b, iter| iter.fold(b, |b, item| func(b, item))) + } + fn handle_str_items<F>(self, key: &'static str, mut func: F) -> BuilderWithConfig<'a> + where F: FnMut(Builder, &'a str) -> Builder { + self.handle_items(key, |b, item| func(b, item.as_str().unwrap())) + } + fn handle_table_items<F>(self, key: &'static str, mut func: F) -> BuilderWithConfig<'a> + where F: FnMut(Builder, &'a toml::Table) -> Builder { + self.handle_items(key, |b, item| func(b, item.as_table().unwrap())) + } + fn handle_common(self, fixups: &mut Vec<Fixup>) -> BuilderWithConfig<'a> { + self.handle_str_items("headers", |b, item| b.header(add_include(item))) + .handle_str_items("raw-lines", |b, item| b.raw_line(item)) + .handle_str_items("hide-types", |b, item| b.hide_type(item)) + .handle_table_items("fixups", |builder, item| { + fixups.push(Fixup { + pat: item["pat"].as_str().unwrap().into(), + rep: item["rep"].as_str().unwrap().into(), + }); + builder + }) + } + + fn get_builder(self) -> Builder { + for key in self.config.keys() { + if !self.used_keys.contains(key.as_str()) { + panic!(format!("Unknown key: {}", key)); + } + } + self.builder } } fn generate_structs(build_type: BuildType) { - let mut builder = Builder::get_initial_builder(build_type) + #[derive(Debug)] + struct Callbacks(HashMap<String, RegexSet>); + impl ParseCallbacks for Callbacks { + fn enum_variant_behavior(&self, + enum_name: Option<&str>, + variant_name: &str, + _variant_value: EnumVariantValue) + -> Option<EnumVariantCustomBehavior> { + enum_name.and_then(|enum_name| self.0.get(enum_name)) + .and_then(|regex| if regex.is_match(variant_name) { + Some(EnumVariantCustomBehavior::Constify) + } else { + None + }) + } + } + + let builder = Builder::get_initial_builder(build_type) .enable_cxx_namespaces() .with_codegen_config(CodegenConfig { types: true, vars: true, ..CodegenConfig::nothing() - }) - .header(add_include("nsCSSPseudoClasses.h")) // servo/rust-bindgen#599 - .include(add_include("nsStyleStruct.h")) - .include(add_include("mozilla/ServoPropPrefList.h")) - .include(add_include("mozilla/StyleAnimationValue.h")) - .include(add_include("gfxFontConstants.h")) - .include(add_include("nsThemeConstants.h")) - .include(add_include("mozilla/dom/AnimationEffectReadOnlyBinding.h")) - .include(add_include("mozilla/AnimationPropertySegment.h")) - .include(add_include("mozilla/ComputedTiming.h")) - .include(add_include("mozilla/ComputedTimingFunction.h")) - .include(add_include("mozilla/Keyframe.h")) - .include(add_include("mozilla/ServoElementSnapshot.h")) - .include(add_include("mozilla/ServoElementSnapshotTable.h")) - .include(add_include("mozilla/dom/Element.h")) - .include(add_include("mozilla/dom/NameSpaceConstants.h")) - .include(add_include("mozilla/LookAndFeel.h")) - .include(add_include("mozilla/ServoBindings.h")) - .include(add_include("nsCSSCounterStyleRule.h")) - .include(add_include("nsCSSFontFaceRule.h")) - .include(add_include("nsMediaFeatures.h")) - .include(add_include("nsMediaList.h")) - // FIXME(emilio): Incrementally remove these "pub use"s. Probably - // mozilla::css and mozilla::dom are easier. - .raw_line("pub use self::root::*;") - .raw_line("pub use self::root::mozilla::*;") - .raw_line("pub use self::root::mozilla::css::*;") - .raw_line("pub use self::root::mozilla::dom::*;") - .raw_line("use atomic_refcell::AtomicRefCell;") - .raw_line("use data::ElementData;") - .hide_type("nsString") - .bitfield_enum("nsChangeHint") - .bitfield_enum("nsRestyleHint") - .constified_enum("UpdateAnimationsTasks") - .constified_enum("ParsingMode") - .parse_callbacks(Box::new(Callbacks)); - let whitelist_vars = [ - "NS_AUTHOR_SPECIFIED_.*", - "NS_THEME_.*", - "NODE_.*", - "ELEMENT_.*", - "NS_FONT_.*", - "NS_STYLE_.*", - "NS_MATHML_.*", - "NS_RADIUS_.*", - "BORDER_COLOR_.*", - "BORDER_STYLE_.*", - "mozilla::SERVO_PREF_.*", - "CSS_PSEUDO_ELEMENT_.*", - "SERVO_CSS_PSEUDO_ELEMENT_FLAGS_.*", - "kNameSpaceID_.*", - "kGenericFont_.*", - "kPresContext_.*", - ]; - let whitelist = [ - "RawGecko.*", - "mozilla::AnimationPropertySegment", - "mozilla::ComputedTiming", - "mozilla::ComputedTimingFunction", - "mozilla::ComputedTimingFunction::BeforeFlag", - "mozilla::ServoStyleSheet", - "mozilla::ServoElementSnapshot.*", - "mozilla::CSSPseudoClassType", - "mozilla::css::SheetParsingMode", - "mozilla::css::URLMatchingFunction", - "mozilla::HalfCorner", - "mozilla::PropertyStyleAnimationValuePair", - "mozilla::TraversalRestyleBehavior", - "mozilla::TraversalRootBehavior", - "mozilla::StyleShapeRadius", - "mozilla::StyleGrid.*", - "mozilla::UpdateAnimationsTasks", - "mozilla::LookAndFeel", - ".*ThreadSafe.*Holder", - "AnonymousContent", - "AudioContext", - "CapturingContentInfo", - "DefaultDelete", - "DOMIntersectionObserverEntry", - "Element", - "FontFamilyList", - "FontFamilyListRefCnt", - "FontFamilyName", - "FontFamilyType", - "FontSizePrefs", - "FragmentOrURL", - "FrameRequestCallback", - "GeckoParserExtraData", - "GeckoFontMetrics", - "gfxAlternateValue", - "gfxFontFeature", - "gfxFontVariation", - "GridNamedArea", - "HalfCorner", - "Image", - "ImageURL", - "Keyframe", - "nsAttrName", - "nsAttrValue", - "nsBorderColors", - "nscolor", - "nsChangeHint", - "nsCSSCounterStyleRule", - "nsCSSFontFaceRule", - "nsCSSKeyword", - "nsCSSPropertyID", - "nsCSSProps", - "nsCSSRect", - "nsCSSRect_heap", - "nsCSSShadowArray", - "nsCSSValue", - "nsCSSValueFloatColor", - "nsCSSValueGradient", - "nsCSSValueGradientStop", - "nsCSSValueList", - "nsCSSValueList_heap", - "nsCSSValuePair_heap", - "nsCSSValuePairList", - "nsCSSValuePairList_heap", - "nsCSSValueTokenStream", - "nsCSSValueTriplet_heap", - "nsCursorImage", - "nsFont", - "nsIAtom", - "nsMainThreadPtrHandle", - "nsMainThreadPtrHolder", - "nsMargin", - "nsMediaExpression", - "nsMediaFeature", - "nsMediaFeatures", - "nsMediaList", - "nsRect", - "nsRestyleHint", - "nsresult", - "nsSize", - "nsStyleBackground", - "nsStyleBorder", - "nsStyleColor", - "nsStyleColumn", - "nsStyleContent", - "nsStyleContentData", - "nsStyleContext", - "nsStyleCoord", - "nsStyleCounterData", - "nsStyleDisplay", - "nsStyleEffects", - "nsStyleFilter", - "nsStyleFont", - "nsStyleGradient", - "nsStyleGradientStop", - "nsStyleGridTemplate", - "nsStyleImage", - "nsStyleImageLayers", - "nsStyleList", - "nsStyleMargin", - "nsStyleOutline", - "nsStylePadding", - "nsStylePosition", - "nsStyleSVG", - "nsStyleSVGPaint", - "nsStyleSVGReset", - "nsStyleTable", - "nsStyleTableBorder", - "nsStyleText", - "nsStyleTextReset", - "nsStyleUIReset", - "nsStyleUnion", - "nsStyleUnit", - "nsStyleUserInterface", - "nsStyleVariables", - "nsStyleVisibility", - "nsStyleXUL", - "nsTArray", - "nsTArrayHeader", - "Position", - "PropertyValuePair", - "Runnable", - "ServoAttrSnapshot", - "ServoBundledURI", - "ServoElementSnapshot", - "SheetParsingMode", - "StaticRefPtr", - "StyleAnimation", - "StyleBasicShape", - "StyleBasicShapeType", - "StyleGeometryBox", - "StyleShapeSource", - "StyleTransition", - "mozilla::UniquePtr", - "mozilla::DefaultDelete", - "mozilla::Side", - "mozilla::binding_danger::AssertAndSuppressCleanupPolicy", - "mozilla::ParsingMode", - "mozilla::InheritTarget", - ]; - let opaque_types = [ - "std::pair__PCCP", - "std::namespace::atomic___base", "std::atomic__My_base", - "std::atomic", - "std::atomic___base", - "mozilla::gfx::.*", - "FallibleTArray", - "mozilla::dom::Sequence", - "mozilla::dom::Optional", - "mozilla::dom::Nullable", - "RefPtr_Proxy", - "RefPtr_Proxy_member_function", - "nsAutoPtr_Proxy", - "nsAutoPtr_Proxy_member_function", - "mozilla::detail::PointerType", - "mozilla::Pair_Base", - "mozilla::SupportsWeakPtr", - "SupportsWeakPtr", - "mozilla::detail::WeakReference", - "mozilla::WeakPtr", - "nsWritingIterator_reference", "nsReadingIterator_reference", - "nsTObserverArray", // <- Inherits from nsAutoTObserverArray<T, 0> - "nsTHashtable", // <- Inheriting from inner typedefs that clang - // doesn't expose properly. - "nsRefPtrHashtable", "nsDataHashtable", "nsClassHashtable", // <- Ditto - "nsIDocument_SelectorCache", // <- Inherits from nsExpirationTracker<.., 4> - "nsIPresShell_ScrollAxis", // <- For some reason the alignment of this is 4 - // for clang. - "nsPIDOMWindow", // <- Takes the vtable from a template parameter, and we can't - // generate it conditionally. - "JS::Rooted", - "mozilla::Maybe", - "gfxSize", // <- union { struct { T width; T height; }; T components[2] }; - "gfxSize_Super", // Ditto. - "mozilla::ErrorResult", // Causes JSWhyMagic to be included & handled incorrectly. - "mozilla::StyleAnimationValue", - "StyleAnimationValue", // pulls in a whole bunch of stuff we don't need in the bindings - ]; - let blacklist = [ - ".*char_traits", - ".*incompatible_char_type", - ]; - - struct MappedGenericType { - generic: bool, - gecko: &'static str, - servo: &'static str, - } - let servo_mapped_generic_types = [ - MappedGenericType { - generic: true, - gecko: "mozilla::ServoUnsafeCell", - servo: "::std::cell::UnsafeCell" - }, - MappedGenericType { - generic: true, - gecko: "mozilla::ServoCell", - servo: "::std::cell::Cell" - }, - MappedGenericType { - generic: false, - gecko: "ServoNodeData", - servo: "AtomicRefCell<ElementData>", - } - ]; - let mut fixups = vec![ - Fixup { - pat: "root::nsString".into(), - rep: "::nsstring::nsStringRepr".into() - }, - ]; - for &var in whitelist_vars.iter() { - builder = builder.whitelisted_var(var); - } - for &ty in whitelist.iter() { - builder = builder.whitelisted_type(ty); - } - for &ty in opaque_types.iter() { - builder = builder.opaque_type(ty); - } - for &ty in blacklist.iter() { - builder = builder.hide_type(ty); - } - for ty in servo_mapped_generic_types.iter() { - let gecko_name = ty.gecko.rsplit("::").next().unwrap(); - builder = builder.hide_type(ty.gecko) - .raw_line(format!("pub type {0}{2} = {1}{2};", gecko_name, ty.servo, - if ty.generic { "<T>" } else { "" })); - fixups.push(Fixup { - pat: format!("root::{}", ty.gecko), - rep: format!("::gecko_bindings::structs::{}", gecko_name) }); - } + let mut fixups = vec![]; + let builder = BuilderWithConfig::new(builder, CONFIG["structs"].as_table().unwrap()) + .handle_common(&mut fixups) + .handle_str_items("bitfield-enums", |b, item| b.bitfield_enum(item)) + .handle_str_items("constified-enums", |b, item| b.constified_enum(item)) + .handle_str_items("whitelist-vars", |b, item| b.whitelisted_var(item)) + .handle_str_items("whitelist-types", |b, item| b.whitelisted_type(item)) + .handle_str_items("opaque-types", |b, item| b.opaque_type(item)) + .handle_list("constified-enum-variants", |builder, iter| { + let mut map = HashMap::new(); + for item in iter { + let item = item.as_table().unwrap(); + let name = item["enum"].as_str().unwrap(); + let variants = item["variants"].as_slice().unwrap().iter() + .map(|item| item.as_str().unwrap()); + map.insert(name.into(), RegexSet::new(variants).unwrap()); + } + builder.parse_callbacks(Box::new(Callbacks(map))) + }) + .handle_table_items("mapped-generic-types", |builder, item| { + let generic = item["generic"].as_bool().unwrap(); + let gecko = item["gecko"].as_str().unwrap(); + let servo = item["servo"].as_str().unwrap(); + let gecko_name = gecko.rsplit("::").next().unwrap(); + fixups.push(Fixup { + pat: format!("root::{}", gecko), + rep: format!("::gecko_bindings::structs::{}", gecko_name) + }); + builder.hide_type(gecko) + .raw_line(format!("pub type {0}{2} = {1}{2};", gecko_name, servo, + if generic { "<T>" } else { "" })) + }) + .get_builder(); write_binding_file(builder, structs_file(build_type), &fixups); } @@ -653,184 +467,62 @@ mod bindings { } fn generate_bindings() { - let mut builder = Builder::get_initial_builder(BuildType::Release) + let builder = Builder::get_initial_builder(BuildType::Release) .disable_name_namespacing() .with_codegen_config(CodegenConfig { functions: true, ..CodegenConfig::nothing() + }); + let config = CONFIG["bindings"].as_table().unwrap(); + let mut structs_types = HashSet::new(); + let mut fixups = vec![]; + let mut builder = BuilderWithConfig::new(builder, config) + .handle_common(&mut fixups) + .handle_str_items("whitelist-functions", |b, item| b.whitelisted_function(item)) + .handle_str_items("structs-types", |mut builder, ty| { + builder = builder.hide_type(ty) + .raw_line(format!("use gecko_bindings::structs::{};", ty)); + structs_types.insert(ty); + // TODO this is hacky, figure out a better way to do it without + // hardcoding everything... + if ty.starts_with("nsStyle") { + builder = builder + .raw_line(format!("unsafe impl Send for {} {{}}", ty)) + .raw_line(format!("unsafe impl Sync for {} {{}}", ty)); + } + builder }) - .header(add_include("mozilla/ServoBindings.h")) - .hide_type("nsACString_internal") - .hide_type("nsAString_internal") - .raw_line("pub use nsstring::{nsACString, nsAString, nsString, nsStringRepr};") - .raw_line("use gecko_bindings::structs::nsTArray;") - .raw_line("type nsACString_internal = nsACString;") - .raw_line("type nsAString_internal = nsAString;") - .whitelisted_function("Servo_.*") - .whitelisted_function("Gecko_.*"); - let structs_types = [ - "mozilla::css::GridTemplateAreasValue", - "mozilla::css::ImageValue", - "mozilla::css::URLValue", - "mozilla::Side", - "RawGeckoAnimationPropertySegment", - "RawGeckoComputedTiming", - "RawGeckoDocument", - "RawGeckoElement", - "RawGeckoKeyframeList", - "RawGeckoComputedKeyframeValuesList", - "RawGeckoFontFaceRuleList", - "RawGeckoNode", - "RawGeckoAnimationValueList", - "RawServoAnimationValue", - "RawServoDeclarationBlock", - "RawServoStyleRule", - "RawGeckoPresContext", - "RawGeckoPresContextOwned", - "RawGeckoStyleAnimationList", - "RawGeckoServoStyleRuleList", - "RawGeckoURLExtraData", - "RefPtr", - "CSSPseudoClassType", - "CSSPseudoElementType", - "TraversalRestyleBehavior", - "TraversalRootBehavior", - "ComputedTimingFunction_BeforeFlag", - "FontFamilyList", - "FontFamilyType", - "FontSizePrefs", - "GeckoFontMetrics", - "Keyframe", - "ServoBundledURI", - "ServoElementSnapshot", - "ServoElementSnapshotTable", - "SheetParsingMode", - "StyleBasicShape", - "StyleBasicShapeType", - "StyleShapeSource", - "StyleTransition", - "nsCSSCounterStyleRule", - "nsCSSFontFaceRule", - "nsCSSKeyword", - "nsCSSPropertyID", - "nsCSSShadowArray", - "nsCSSUnit", - "nsCSSValue", - "nsCSSValueSharedList", - "nsChangeHint", - "nsCursorImage", - "nsFont", - "nsIAtom", - "nsCompatibility", - "nsMediaFeature", - "nsRestyleHint", - "nsStyleBackground", - "nsStyleBorder", - "nsStyleColor", - "nsStyleColumn", - "nsStyleContent", - "nsStyleContentData", - "nsStyleContentType", - "nsStyleContext", - "nsStyleCoord", - "nsStyleCoord_Calc", - "nsStyleCoord_CalcValue", - "nsStyleDisplay", - "nsStyleEffects", - "nsStyleFilter", - "nsStyleFont", - "nsStyleGradient", - "nsStyleGradientStop", - "nsStyleGridTemplate", - "nsStyleImage", - "nsStyleImageLayers", - "nsStyleImageLayers_Layer", - "nsStyleImageLayers_LayerType", - "nsStyleImageRequest", - "nsStyleList", - "nsStyleMargin", - "nsStyleOutline", - "nsStylePadding", - "nsStylePosition", - "nsStyleQuoteValues", - "nsStyleSVG", - "nsStyleSVGPaint", - "nsStyleSVGReset", - "nsStyleTable", - "nsStyleTableBorder", - "nsStyleText", - "nsStyleTextReset", - "nsStyleUIReset", - "nsStyleUnion", - "nsStyleUnit", - "nsStyleUserInterface", - "nsStyleVariables", - "nsStyleVisibility", - "nsStyleXUL", - "nsTimingFunction", - "nscolor", - "nscoord", - "nsresult", - "Loader", - "ServoStyleSheet", - "EffectCompositor_CascadeLevel", - "UpdateAnimationsTasks", - "ParsingMode", - "InheritTarget", - "URLMatchingFunction", - ]; - struct ArrayType { - cpp_type: &'static str, - rust_type: &'static str - } - let array_types = [ - ArrayType { cpp_type: "uintptr_t", rust_type: "usize" }, - ]; - struct ServoOwnedType { - name: &'static str, - opaque: bool, - } - let servo_owned_types = [ - ServoOwnedType { name: "RawServoStyleSet", opaque: true }, - ServoOwnedType { name: "StyleChildrenIterator", opaque: true }, - ServoOwnedType { name: "ServoElementSnapshot", opaque: false }, - ServoOwnedType { name: "RawServoAnimationValueMap", opaque: true }, - ]; - let servo_immutable_borrow_types = [ - "RawGeckoNode", - "RawGeckoElement", - "RawGeckoDocument", - "RawServoDeclarationBlockStrong", - "RawGeckoPresContext", - "RawGeckoStyleAnimationList", - ]; - let servo_borrow_types = [ - "nsCSSValue", - "nsTimingFunction", - "RawGeckoAnimationPropertySegment", - "RawGeckoAnimationValueList", - "RawGeckoComputedTiming", - "RawGeckoKeyframeList", - "RawGeckoComputedKeyframeValuesList", - "RawGeckoFontFaceRuleList", - "RawGeckoServoStyleRuleList", - ]; - for &ty in structs_types.iter() { - builder = builder.hide_type(ty) - .raw_line(format!("use gecko_bindings::structs::{};", ty)); - // TODO this is hacky, figure out a better way to do it without - // hardcoding everything... - if ty.starts_with("nsStyle") { - builder = builder - .raw_line(format!("unsafe impl Send for {} {{}}", ty)) - .raw_line(format!("unsafe impl Sync for {} {{}}", ty)); - } - } - for &ArrayType { cpp_type, rust_type } in array_types.iter() { - builder = builder.hide_type(format!("nsTArrayBorrowed_{}", cpp_type)) - .raw_line(format!("pub type nsTArrayBorrowed_{}<'a> = &'a mut ::gecko_bindings::structs::nsTArray<{}>;", - cpp_type, rust_type)) - } + // TODO This was added due to servo/rust-bindgen#75, but + // that has been fixed in clang 4.0+. When we switch people + // to libclang 4.0, we can remove this. + .handle_table_items("array-types", |builder, item| { + let cpp_type = item["cpp-type"].as_str().unwrap(); + let rust_type = item["rust-type"].as_str().unwrap(); + builder.hide_type(format!("nsTArrayBorrowed_{}", cpp_type)) + .raw_line(format!(concat!("pub type nsTArrayBorrowed_{}<'a> = ", + "&'a mut ::gecko_bindings::structs::nsTArray<{}>;"), + cpp_type, rust_type)) + }) + .handle_table_items("servo-owned-types", |mut builder, item| { + let name = item["name"].as_str().unwrap(); + builder = builder.hide_type(format!("{}Owned", name)) + .raw_line(format!("pub type {0}Owned = ::gecko_bindings::sugar::ownership::Owned<{0}>;", name)) + .hide_type(format!("{}OwnedOrNull", name)) + .raw_line(format!(concat!("pub type {0}OwnedOrNull = ", + "::gecko_bindings::sugar::ownership::OwnedOrNull<{0}>;"), name)) + .mutable_borrowed_type(name); + if item["opaque"].as_bool().unwrap() { + builder = builder.zero_size_type(name, &structs_types); + } + builder + }) + .handle_str_items("servo-immutable-borrow-types", |b, ty| b.borrowed_type(ty)) + // Right now the only immutable borrow types are ones which we import + // from the |structs| module. As such, we don't need to create an opaque + // type with zero_size_type. If we ever introduce immutable borrow types + // which _do_ need to be opaque, we'll need a separate mode. + .handle_str_items("servo-borrow-types", |b, ty| b.mutable_borrowed_type(ty)) + .get_builder(); for ty in get_arc_types().iter() { builder = builder .hide_type(format!("{}Strong", ty)) @@ -838,34 +530,6 @@ mod bindings { .borrowed_type(ty) .zero_size_type(ty, &structs_types); } - for &ServoOwnedType { name, opaque } in servo_owned_types.iter() { - builder = builder - .hide_type(format!("{}Owned", name)) - .raw_line(format!("pub type {0}Owned = ::gecko_bindings::sugar::ownership::Owned<{0}>;", name)) - .hide_type(format!("{}OwnedOrNull", name)) - .raw_line(format!("pub type {0}OwnedOrNull = ::gecko_bindings::sugar::ownership::OwnedOrNull<{0}>;", - name)) - .mutable_borrowed_type(name); - if opaque { - builder = builder.zero_size_type(name, &structs_types); - } - } - for &ty in servo_immutable_borrow_types.iter() { - builder = builder.borrowed_type(ty); - } - for &ty in servo_borrow_types.iter() { - builder = builder.mutable_borrowed_type(ty); - // Right now the only immutable borrow types are ones which we import - // from the |structs| module. As such, we don't need to create an opaque - // type with zero_size_type. If we ever introduce immutable borrow types - // which _do_ need to be opaque, we'll need a separate mode. - } - let fixups = vec![ - Fixup { // hack for gecko-owned string - pat: "<nsString".into(), - rep: "<nsStringRepr".into() - }, - ]; write_binding_file(builder, BINDINGS_FILE, &fixups); } |