diff options
author | Xidorn Quan <me@upsuper.org> | 2016-12-09 13:55:49 -1000 |
---|---|---|
committer | Xidorn Quan <me@upsuper.org> | 2016-12-10 00:33:41 -1000 |
commit | 1cefd1bef037c361a785345e619508312883389e (patch) | |
tree | adf34e40e9c45c54f9eddcb79506f8869e80aff5 | |
parent | 6dd4b4822fa788694153ee61a04dd9a5dfb748ec (diff) | |
download | servo-1cefd1bef037c361a785345e619508312883389e.tar.gz servo-1cefd1bef037c361a785345e619508312883389e.zip |
Do build-time bindgen
Majority of build_gecko.rs is just the straightforward conversion from
regen.py. There are two differences that:
1. Side in whitelist is changed to mozilla::Side
2. std::atomic__My_base is added to opaque types for Windows
-rw-r--r-- | Cargo.lock | 74 | ||||
-rw-r--r-- | components/style/Cargo.toml | 4 | ||||
-rwxr-xr-x | components/style/binding_tools/regen.py | 820 | ||||
-rw-r--r-- | components/style/build.rs | 23 | ||||
-rw-r--r-- | components/style/build_gecko.rs | 617 | ||||
-rw-r--r-- | components/style/gecko_bindings/mod.rs | 19 | ||||
-rw-r--r-- | ports/geckolib/Cargo.toml | 3 | ||||
-rw-r--r-- | python/servo/build_commands.py | 14 |
8 files changed, 739 insertions, 835 deletions
diff --git a/Cargo.lock b/Cargo.lock index 8a79b8eda44..0f5db66439d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -69,6 +69,14 @@ dependencies = [ ] [[package]] +name = "aster" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "syntex_syntax 0.50.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "audio-video-metadata" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -282,6 +290,14 @@ dependencies = [ ] [[package]] +name = "cexpr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nom 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "cfg-if" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -296,6 +312,16 @@ dependencies = [ ] [[package]] +name = "clang-sys" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "clippy_lints" version = "0.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1380,6 +1406,26 @@ dependencies = [ ] [[package]] +name = "libbindgen" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aster 0.34.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cexpr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "clang-sys 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quasi 0.26.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quasi_codegen 0.26.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.1.76 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex_syntax 0.50.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "libc" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2068,6 +2114,26 @@ dependencies = [ ] [[package]] +name = "quasi" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "syntex_errors 0.50.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex_syntax 0.50.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quasi_codegen" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aster 0.34.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex 0.50.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex_errors 0.50.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex_syntax 0.50.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "quickersort" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2601,6 +2667,7 @@ dependencies = [ "html5ever-atoms 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libbindgen 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "nsstring_vendor 0.1.0", @@ -2616,6 +2683,7 @@ dependencies = [ "quickersort 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.1.76 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "selectors 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.8.18 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3212,6 +3280,7 @@ dependencies = [ "checksum angle 0.1.2 (git+https://github.com/servo/angle?branch=servo)" = "<none>" "checksum app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "636ee56f12e31dbc11dc0a1ac6004f08b04e6e6595963716fc8130e90d4e04cf" "checksum arrayvec 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "80a137392e2e92ce7387c063d98a11f0d47115426c5f8759657af3c7b385c860" +"checksum aster 0.34.0 (registry+https://github.com/rust-lang/crates.io-index)" = "88bb8ecdf6a7eaddb7bfd872ebf5e085d343ca42ce98c582dba8046e3450b524" "checksum audio-video-metadata 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "03da2550cb89fe3faf218c179261c26cf7891c4234707c15f5d09ebb32ae2400" "checksum azure 0.9.1 (git+https://github.com/servo/rust-azure)" = "<none>" "checksum backtrace 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "346d7644f0b5f9bc73082d3b2236b69a05fd35cce0cfa3724e184e6a5c9e2a2f" @@ -3230,8 +3299,10 @@ dependencies = [ "checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" "checksum bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c129aff112dcc562970abb69e2508b40850dd24c274761bb50fb8a0067ba6c27" "checksum caseless 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b6893f86ac0c9275b5cbba9212ccd71020b447d4c3e2eebad70e1bc47fdd6dfb" +"checksum cexpr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "393a5f0088efbe41f9d1fcd062f24e83c278608420e62109feb2c8abee07de7d" "checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c" "checksum cgl 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8bdd78cca65a739cb5475dbf6b6bbb49373e327f4a6f2b499c0f98632df38c10" +"checksum clang-sys 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "19911f7964ce61a02d382adee8400f919d0fedd53c5441e3d6a9858ba73e249e" "checksum clippy_lints 0.0.98 (registry+https://github.com/rust-lang/crates.io-index)" = "4329699b62341fd3ce3ebe13ade6c87d35b8778091e0c2f6da51399e081b9671" "checksum cmake 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "dfcf5bcece56ef953b8ea042509e9dcbdfe97820b7e20d86beb53df30ed94978" "checksum cocoa 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d24ed9a15e9c0892cdb20c7acc3e50441501b990ee6dc318c176981829a7941" @@ -3313,6 +3384,7 @@ dependencies = [ "checksum lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "49247ec2a285bb3dcb23cbd9c35193c025e7251bfce77c1d5da97e6362dffe7f" "checksum leak 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bd100e01f1154f2908dfa7d02219aeab25d0b9c7fa955164192e3245255a0c73" "checksum leaky-cow 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40a8225d44241fd324a8af2806ba635fc7c8a7e9a7de4d5cf3ef54e71f5926fc" +"checksum libbindgen 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6a46e95efa501b2940e9c81dbb727e557b39b41f77f1170aba6eed5a546e9964" "checksum libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "044d1360593a78f5c8e5e710beccdc24ab71d1f01bc19a29bcacdba22e8475d8" "checksum libloading 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "eceb2637ee9a27c7f19764048a9f377e40e3a70a322722f348e6bc7704d565f2" "checksum libressl-pnacl-sys 2.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "cbc058951ab6a3ef35ca16462d7642c4867e6403520811f28537a4e2f2db3e71" @@ -3367,6 +3439,8 @@ dependencies = [ "checksum pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8cee804ecc7eaf201a4a207241472cc870e825206f6c031e3ee2a72fa425f2fa" "checksum pnacl-build-helper 1.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "61c9231d31aea845007443d62fcbb58bb6949ab9c18081ee1e09920e0cf1118b" "checksum png 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "06208e2ee243e3118a55dda9318f821f206d8563fb8d4df258767f8e62bb0997" +"checksum quasi 0.26.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ab7992920bf5bc5f1ed6fdc49090bf665cd00b3aa4b78c16ac3465286257db1" +"checksum quasi_codegen 0.26.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d52e5e2c92ffdad67a9b86ad27ad999bf1a652723f1d4cc93b7cf6c272b5f8e0" "checksum quickersort 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e952ea7699262481636004bc4ab8afaccf2bc13f91b79d1aee6617bd8fc39651" "checksum quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "07589615d719a60c8dd8a4622e7946465dfef20d1a428f969e3443e7386d5f45" "checksum quote 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1e0c9bc6bfb0a60d539aab6e338207c1a5456e62f5bd5375132cee119aa4b3" diff --git a/components/style/Cargo.toml b/components/style/Cargo.toml index 95778b61c88..cb386d1ac7e 100644 --- a/components/style/Cargo.toml +++ b/components/style/Cargo.toml @@ -14,6 +14,7 @@ doctest = false [features] gecko = ["nsstring_vendor", "num_cpus", "rayon/unstable"] +bindgen = ["libbindgen", "regex"] servo = ["serde/unstable", "serde", "serde_derive", "heapsize_derive", "style_traits/servo", "app_units/plugins", "servo_atoms", "html5ever-atoms", "cssparser/heap_size", "cssparser/serde-serialization", @@ -65,5 +66,8 @@ version = "1.0" kernel32-sys = "0.2" [build-dependencies] +lazy_static = "0.2" +libbindgen = {version = "0.1.1", optional = true} phf_codegen = "0.7.20" +regex = {version = "0.1", optional = true} walkdir = "0.1" diff --git a/components/style/binding_tools/regen.py b/components/style/binding_tools/regen.py deleted file mode 100755 index 248d50ea9ea..00000000000 --- a/components/style/binding_tools/regen.py +++ /dev/null @@ -1,820 +0,0 @@ -#!/usr/bin/env python - -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -from __future__ import print_function - -import re -import os -import sys -import argparse -import platform -import copy -import subprocess -import fileinput - -import regen_atoms - -DESCRIPTION = 'Regenerate the rust version of the structs or the bindings file.' -TOOLS_DIR = os.path.dirname(os.path.abspath(__file__)) -COMMON_BUILD_KEY = "__common__" - -COMPILATION_TARGETS = { - # Flags common for all the targets. - COMMON_BUILD_KEY: { - "flags": [ - "--no-unstable-rust", - ], - "clang_flags": [ - "-x", "c++", "-std=c++14", - "-DTRACING=1", "-DIMPL_LIBXUL", "-DMOZ_STYLO_BINDINGS=1", - "-DMOZILLA_INTERNAL_API", "-DRUST_BINDGEN", "-DMOZ_STYLO" - ], - "search_dirs": [ - "{}/dist/include", - "{}/dist/include/nspr", - "{}/../nsprpub/pr/include" - ], - "includes": [ - "{}/mozilla-config.h", - ], - }, - # Generation of style structs. - "structs": { - "target_dir": "../gecko_bindings", - "flags": [ - "--enable-cxx-namespaces", - # FIXME(emilio): Incrementally remove these. 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::*;", - "--generate", "types,vars", - ], - "includes": [ - "{}/dist/include/gfxFontConstants.h", - "{}/dist/include/nsThemeConstants.h", - "{}/dist/include/mozilla/dom/AnimationEffectReadOnlyBinding.h", - "{}/dist/include/mozilla/ServoElementSnapshot.h", - "{}/dist/include/mozilla/dom/Element.h", - "{}/dist/include/mozilla/ServoBindings.h", - ], - "files": [ - "{}/dist/include/nsStyleStruct.h", - ], - "build_kinds": { - "debug": { - "clang_flags": [ - "-DDEBUG=1", - "-DJS_DEBUG=1", - ] - }, - "release": { - } - }, - "raw_lines": [ - "use atomic_refcell::AtomicRefCell;", - "use data::ElementData;", - ], - "blacklist_types": [ - "nsString", - ], - "whitelist_vars": [ - "NS_THEME_.*", - "NODE_.*", - "NS_FONT_.*", - "NS_STYLE_.*", - "NS_CORNER_.*", - "NS_RADIUS_.*", - "BORDER_COLOR_.*", - "BORDER_STYLE_.*" - ], - "whitelist": [ - "RawGecko.*", - "mozilla::ServoElementSnapshot.*", - "mozilla::ConsumeStyleBehavior", - "mozilla::LazyComputeBehavior", - "mozilla::css::SheetParsingMode", - "mozilla::SkipRootBehavior", - "mozilla::DisplayItemClip", # Needed because bindgen generates - # specialization tests for this even - # though it shouldn't. - ".*ThreadSafe.*Holder", - "AnonymousContent", - "AudioContext", - "CapturingContentInfo", - "ConsumeStyleBehavior", - "DefaultDelete", - "DOMIntersectionObserverEntry", - "Element", - "FontFamilyList", - "FontFamilyListRefCnt", - "FontFamilyName", - "FontFamilyType", - "FragmentOrURL", - "FrameRequestCallback", - "gfxAlternateValue", - "gfxFontFeature", - "gfxFontVariation", - "GridNamedArea", - "Image", - "ImageURL", - "LazyComputeBehavior", - "nsAttrName", - "nsAttrValue", - "nsBorderColors", - "nscolor", - "nsChangeHint", - "nsCSSKeyword", - "nsCSSPropertyID", - "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", - "nsRect", - "nsRestyleHint", - "nsresult", - "nsSize", - "nsStyleBackground", - "nsStyleBorder", - "nsStyleColor", - "nsStyleColumn", - "nsStyleContent", - "nsStyleContentData", - "nsStyleContext", - "nsStyleCoord", - "nsStyleCounterData", - "nsStyleDisplay", - "nsStyleEffects", - "nsStyleFilter", - "nsStyleFont", - "nsStyleGradient", - "nsStyleGradientStop", - "nsStyleImage", - "nsStyleImageLayers", - "nsStyleList", - "nsStyleMargin", - "nsStyleOutline", - "nsStylePadding", - "nsStylePosition", - "nsStyleSVG", - "nsStyleSVGReset", - "nsStyleTable", - "nsStyleTableBorder", - "nsStyleText", - "nsStyleTextReset", - "nsStyleUIReset", - "nsStyleUnion", - "nsStyleUnit", - "nsStyleUserInterface", - "nsStyleVariables", - "nsStyleVisibility", - "nsStyleXUL", - "nsTArray", - "nsTArrayHeader", - "pair", - "Position", - "Runnable", - "ServoAttrSnapshot", - "ServoElementSnapshot", - "SheetParsingMode", - "Side", - "StaticRefPtr", - "StyleAnimation", - "StyleBasicShape", - "StyleBasicShapeType", - "StyleClipPath", - "StyleClipPathGeometryBox", - "StyleTransition", - "mozilla::UniquePtr", - "mozilla::DefaultDelete", - ], - "bitfield_enum_types": ["nsChangeHint", "nsRestyleHint"], - "opaque_types": [ - "atomic___base", - "nsAString_internal_char_traits", - "nsAString_internal_incompatible_char_type", - "nsACString_internal_char_traits", - "nsACString_internal_incompatible_char_type", - "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. - ], - "manual_fixups": [ - ["root::nsString", "::nsstring::nsStringRepr"] - ], - "servo_mapped_generic_types": [ - { - "generic": True, - "gecko": "mozilla::ServoUnsafeCell", - "servo": "::std::cell::UnsafeCell" - }, { - "generic": True, - "gecko": "mozilla::ServoCell", - "servo": "::std::cell::Cell" - }, { - "generic": False, - "gecko": "ServoNodeData", - "servo": "AtomicRefCell<ElementData>", - } - ], - }, - # Generation of the ffi bindings. - "bindings": { - "target_dir": "../gecko_bindings", - "raw_lines": [ - "pub use nsstring::{nsACString, nsAString};", - "type nsACString_internal = nsACString;", - "type nsAString_internal = nsAString;" - ], - "flags": [ - "--generate", "functions", - "--disable-name-namespacing", - ], - "match_headers": [ - "ServoBindingList.h", - "ServoBindings.h", - "ServoTypes.h", - "nsStyleStructList.h", - ], - "files": [ - "{}/dist/include/mozilla/ServoBindings.h", - ], - # Types to just use from the `structs` target. - "structs_types": [ - "RawGeckoDocument", - "RawGeckoElement", - "RawGeckoNode", - "ThreadSafeURIHolder", - "ThreadSafePrincipalHolder", - "ConsumeStyleBehavior", - "LazyComputeBehavior", - "SkipRootBehavior", - "FontFamilyList", - "FontFamilyType", - "ServoElementSnapshot", - "SheetParsingMode", - "StyleBasicShape", - "StyleBasicShapeType", - "StyleClipPath", - "nsCSSKeyword", - "nsCSSShadowArray", - "nsCSSValue", - "nsCSSValueSharedList", - "nsChangeHint", - "nsCursorImage", - "nsFont", - "nsIAtom", - "nsRestyleHint", - "nsStyleBackground", - "nsStyleBorder", - "nsStyleColor", - "nsStyleColumn", - "nsStyleContent", - "nsStyleContext", - "nsStyleCoord", - "nsStyleCoord_Calc", - "nsStyleCoord_CalcValue", - "nsStyleDisplay", - "nsStyleEffects", - "nsStyleFont", - "nsStyleGradient", - "nsStyleGradientStop", - "nsStyleImage", - "nsStyleImageLayers", - "nsStyleImageLayers_Layer", - "nsStyleImageLayers_LayerType", - "nsStyleImageRequest", - "nsStyleList", - "nsStyleMargin", - "nsStyleOutline", - "nsStylePadding", - "nsStylePosition", - "nsStyleQuoteValues", - "nsStyleSVG", - "nsStyleSVGReset", - "nsStyleTable", - "nsStyleTableBorder", - "nsStyleText", - "nsStyleTextReset", - "nsStyleUIReset", - "nsStyleUnion", - "nsStyleUnit", - "nsStyleUserInterface", - "nsStyleVariables", - "nsStyleVisibility", - "nsStyleXUL", - "nscoord", - "nsresult", - ], - "array_types": { - "uintptr_t": "usize", - }, - "servo_nullable_arc_types": [ - "ServoComputedValues", - "ServoCssRules", - "RawServoStyleSheet", - "RawServoDeclarationBlock", - "RawServoStyleRule", - ], - "servo_owned_types": [ - { - "name": "RawServoStyleSet", - "opaque": True, - }, { - "name": "StyleChildrenIterator", - "opaque": True, - }, { - "name": "ServoElementSnapshot", - "opaque": False, - }, - ], - "servo_immutable_borrow_types": [ - "RawGeckoNode", - "RawGeckoElement", - "RawGeckoDocument", - "RawServoDeclarationBlockStrong", - ], - "servo_borrow_types": [ - "nsCSSValue", - ], - "whitelist_functions": [ - "Servo_.*", - "Gecko_.*" - ] - }, - - "atoms": { - "custom_build": regen_atoms.build, - } -} - - -def platform_dependent_defines(): - ret = [] - - if os.name == "posix": - ret.append("-DOS_POSIX=1") - - system = platform.system() - if system == "Linux": - ret.append("-DOS_LINUX=1") - elif system == "Darwin": - ret.append("-DOS_MACOSX=1") - elif system == "Windows": - ret.append("-DOS_WIN=1") - ret.append("-DWIN32=1") - msvc_platform = os.environ["PLATFORM"] - if msvc_platform == "X86": - ret.append("--target=i686-pc-win32") - elif msvc_platform == "X64": - ret.append("--target=x86_64-pc-win32") - else: - raise Exception("Only MSVC builds are supported on Windows") - # For compatibility with MSVC 2015 - ret.append("-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(). - ret.append("-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. - ret.append("-DHAVE_VISIBILITY_HIDDEN_ATTRIBUTE=1") - else: - raise Exception("Unknown platform") - - return ret - - -def extend_object(obj, other): - if not obj or not other: - return obj - - if isinstance(obj, list) and isinstance(other, list): - obj.extend(other) - return - - assert isinstance(obj, dict) and isinstance(other, dict) - - for key in other.keys(): - if key in obj: - extend_object(obj[key], other[key]) - else: - obj[key] = copy.deepcopy(other[key]) - - -def build(objdir, target_name, debug, debugger, kind_name=None, - output_filename=None, bindgen=None, skip_test=False, - verbose=False): - assert target_name in COMPILATION_TARGETS - - current_target = COMPILATION_TARGETS[target_name] - if COMMON_BUILD_KEY in COMPILATION_TARGETS: - current_target = copy.deepcopy(COMPILATION_TARGETS[COMMON_BUILD_KEY]) - extend_object(current_target, COMPILATION_TARGETS[target_name]) - - assert ((kind_name is None and "build_kinds" not in current_target) or - (kind_name in current_target["build_kinds"])) - - if "custom_build" in current_target: - print("[CUSTOM] {}::{} in \"{}\"... ".format(target_name, kind_name, objdir), end='') - sys.stdout.flush() - ret = current_target["custom_build"](objdir, verbose=True) - if ret != 0: - print("FAIL") - else: - print("OK") - - return ret - - if bindgen is None: - bindgen = os.path.join(TOOLS_DIR, "rust-bindgen") - - if os.path.isdir(bindgen): - bindgen = ["cargo", "run", "--manifest-path", - os.path.join(bindgen, "Cargo.toml"), "--features", "llvm_stable", "--release", "--"] - else: - bindgen = [bindgen] - - if kind_name is not None: - current_target = copy.deepcopy(current_target) - extend_object(current_target, current_target["build_kinds"][kind_name]) - - target_dir = None - if output_filename is None and "target_dir" in current_target: - target_dir = current_target["target_dir"] - - if output_filename is None: - output_filename = "{}.rs".format(target_name) - - if kind_name is not None: - output_filename = "{}_{}.rs".format(target_name, kind_name) - - if target_dir: - output_filename = "{}/{}".format(target_dir, output_filename) - - print("[BINDGEN] {}::{} in \"{}\"... ".format(target_name, kind_name, objdir), end='') - sys.stdout.flush() - - flags = [] - - # Types we have to fixup since we insert them manually. - # - # Bindgen only allows us to add stuff outside of the root module. This - # wasn't intended to add new types, but we do so, so we postprocess the - # bindgen output to fixup the path to these types. - fixups = [] - - if "manual_fixups" in current_target: - fixups = current_target["manual_fixups"] - - # This makes an FFI-safe void type that can't be matched on - # &VoidType is UB to have, because you can match on it - # to produce a reachable unreachable. If it's wrapped in - # a struct as a private field it becomes okay again - # - # 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 - def zero_size_type(ty, flags): - flags.append("--blacklist-type") - flags.append(ty) - flags.append("--raw-line") - flags.append("enum {0}Void{{ }}".format(ty)) - flags.append("--raw-line") - flags.append("pub struct {0}({0}Void);".format(ty)) - - if "flags" in current_target: - flags.extend(current_target["flags"]) - - clang_flags = [] - - if "clang_flags" in current_target: - clang_flags.extend(current_target["clang_flags"]) - - clang_flags.extend(platform_dependent_defines()) - - if platform.system() == "Windows": - flags.append("--use-msvc-mangling") - - if "raw_lines" in current_target: - for raw_line in current_target["raw_lines"]: - flags.append("--raw-line") - flags.append(raw_line) - - if "search_dirs" in current_target: - for dir_name in current_target["search_dirs"]: - clang_flags.append("-I") - clang_flags.append(dir_name.format(objdir)) - - if "includes" in current_target: - for file_name in current_target["includes"]: - clang_flags.append("-include") - clang_flags.append(file_name.format(objdir)) - - if "whitelist" in current_target: - for header in current_target["whitelist"]: - flags.append("--whitelist-type") - flags.append(header) - - if "whitelist_functions" in current_target: - for header in current_target["whitelist_functions"]: - flags.append("--whitelist-function") - flags.append(header) - - if "whitelist_vars" in current_target: - for header in current_target["whitelist_vars"]: - flags.append("--whitelist-var") - flags.append(header) - - if "bitfield_enum_types" in current_target: - for ty in current_target["bitfield_enum_types"]: - flags.append("--bitfield-enum") - flags.append(ty) - - if "opaque_types" in current_target: - for ty in current_target["opaque_types"]: - flags.append("--opaque-type") - flags.append(ty) - - if "array_types" in current_target: - for cpp_type, rust_type in current_target["array_types"].items(): - flags.append("--blacklist-type") - flags.append("nsTArrayBorrowed_{}".format(cpp_type)) - flags.append("--raw-line") - flags.append("pub type nsTArrayBorrowed_{0}<'a> = &'a mut ::gecko_bindings::structs::nsTArray<{1}>;" - .format(cpp_type, rust_type)) - - if "blacklist_types" in current_target: - for ty in current_target["blacklist_types"]: - flags.append("--blacklist-type") - flags.append(ty) - - if "servo_nullable_arc_types" in current_target: - for ty in current_target["servo_nullable_arc_types"]: - flags.append("--blacklist-type") - flags.append("{}Strong".format(ty)) - flags.append("--raw-line") - flags.append("pub type {0}Strong = ::gecko_bindings::sugar::ownership::Strong<{0}>;" - .format(ty)) - flags.append("--blacklist-type") - flags.append("{}BorrowedOrNull".format(ty)) - flags.append("--raw-line") - flags.append("pub type {0}BorrowedOrNull<'a> = \ -Option<&'a {0}>;".format(ty)) - flags.append("--blacklist-type") - flags.append("{}Borrowed".format(ty)) - flags.append("--raw-line") - flags.append("pub type {0}Borrowed<'a> = &'a {0};".format(ty)) - zero_size_type(ty, flags) - - if "servo_immutable_borrow_types" in current_target: - for ty in current_target.get("servo_immutable_borrow_types", []) + current_target.get("servo_borrow_types", []): - flags.append("--blacklist-type") - flags.append("{}Borrowed".format(ty)) - flags.append("--raw-line") - flags.append("pub type {0}Borrowed<'a> = &'a {0};".format(ty)) - flags.append("--blacklist-type") - flags.append("{}BorrowedOrNull".format(ty)) - flags.append("--raw-line") - flags.append("pub type {0}BorrowedOrNull<'a> = Option<&'a {0}>;".format(ty)) - if "servo_borrow_types" in current_target: - for ty in current_target["servo_borrow_types"]: - flags.append("--blacklist-type") - flags.append("{}BorrowedMut".format(ty)) - flags.append("--raw-line") - flags.append("pub type {0}BorrowedMut<'a> = &'a mut {0};".format(ty)) - flags.append("--blacklist-type") - flags.append("{}BorrowedMutOrNull".format(ty)) - flags.append("--raw-line") - flags.append("pub type {0}BorrowedMutOrNull<'a> = \ -Option<&'a mut {0}>;".format(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. - - if "servo_mapped_generic_types" in current_target: - for ty in current_target["servo_mapped_generic_types"]: - flags.append("--blacklist-type") - flags.append(ty["gecko"]) - - gecko_name = ty["gecko"].split("::")[-1] - flags.append("--raw-line") - flags.append("pub type {0}{2} = {1}{2};".format(gecko_name, ty["servo"], "<T>" if ty["generic"] else "")) - fixups.append(["root::{}".format(ty["gecko"]), "::gecko_bindings::structs::{}".format(gecko_name)]) - - if "servo_owned_types" in current_target: - for entry in current_target["servo_owned_types"]: - ty = entry["name"] - flags.append("--blacklist-type") - flags.append("{}Borrowed".format(ty)) - flags.append("--raw-line") - flags.append("pub type {0}Borrowed<'a> = &'a {0};".format(ty)) - flags.append("--blacklist-type") - flags.append("{}BorrowedMut".format(ty)) - flags.append("--raw-line") - flags.append("pub type {0}BorrowedMut<'a> = &'a mut {0};".format(ty)) - flags.append("--blacklist-type") - flags.append("{}Owned".format(ty)) - flags.append("--raw-line") - flags.append("pub type {0}Owned = ::gecko_bindings::sugar::ownership::Owned<{0}>;".format(ty)) - flags.append("--blacklist-type") - flags.append("{}BorrowedOrNull".format(ty)) - flags.append("--raw-line") - flags.append("pub type {0}BorrowedOrNull<'a> = Option<&'a {0}>;" - .format(ty)) - flags.append("--blacklist-type") - flags.append("{}BorrowedMutOrNull".format(ty)) - flags.append("--raw-line") - flags.append("pub type {0}BorrowedMutOrNull<'a> = Option<&'a mut {0}>;" - .format(ty)) - flags.append("--blacklist-type") - flags.append("{}OwnedOrNull".format(ty)) - flags.append("--raw-line") - flags.append("pub type {0}OwnedOrNull = ::gecko_bindings::sugar::ownership::OwnedOrNull<{0}>;".format(ty)) - if entry["opaque"]: - zero_size_type(ty, flags) - - if "structs_types" in current_target: - for ty in current_target["structs_types"]: - flags.append("--blacklist-type") - flags.append(ty) - flags.append("--raw-line") - flags.append("use gecko_bindings::structs::{};".format(ty)) - - # TODO: this is hacky, figure out a better way to do it without - # hardcoding everything... - if ty.startswith("nsStyle"): - flags.extend([ - "--raw-line", - "unsafe impl Send for {} {{}}".format(ty), - "--raw-line", - "unsafe impl Sync for {} {{}}".format(ty), - ]) - - flags.append("-o") - flags.append(output_filename) - - assert len(current_target["files"]) == 1 - flags.append(current_target["files"][0].format(objdir)) - - flags = bindgen + flags + ["--"] + clang_flags - - if verbose: - print(flags) - - output = "" - try: - if debug: - flags = [debugger, "--args"] + flags - subprocess.check_call(flags) - else: - output = subprocess.check_output(flags, stderr=subprocess.STDOUT, - universal_newlines=True) - except subprocess.CalledProcessError as e: - print("FAIL\n", e.output) - return 1 - - generated = fileinput.input(output_filename, inplace=True) - for line in generated: - for fixup in fixups: - line = re.sub("\\b{}\\b".format(fixup[0]), fixup[1], line) - print(line, end='') - generated.close() - - print("OK") - print("(please test with ./mach test-stylo)") - - if verbose: - print(output) - - return 0 - - -def builds_for(target_name, kind): - if target_name == "all": - for target in COMPILATION_TARGETS.keys(): - if target == COMMON_BUILD_KEY: - continue - - if "build_kinds" in COMPILATION_TARGETS[target]: - for kind in COMPILATION_TARGETS[target]["build_kinds"].keys(): - yield (target, kind) - else: - yield (target, None) - return - - target = COMPILATION_TARGETS[target_name] - if "build_kinds" in target: - if kind is None: - for kind in target["build_kinds"].keys(): - yield(target_name, kind) - else: - yield (target_name, kind) - return - - yield (target_name, None) - - -def main(): - parser = argparse.ArgumentParser(description=DESCRIPTION) - parser.add_argument('--target', default='all', - help='The target to build, either "structs" or "bindings"') - parser.add_argument('--kind', - help='Kind of build') - parser.add_argument('--bindgen', - help='Override bindgen binary') - parser.add_argument('--output', '-o', - help='Output of the script') - parser.add_argument('--skip-test', - action='store_true', - help='Skip automatic tests, useful for debugging') - parser.add_argument('--verbose', '-v', - action='store_true', - help='Be... verbose') - parser.add_argument('--debug', - action='store_true', - help='Try to use a debugger to debug bindgen commands (default: gdb)') - parser.add_argument('--debugger', default='gdb', - help='Debugger to use. Only used if --debug is passed.') - parser.add_argument('objdir') - - args = parser.parse_args() - - if not os.path.isdir(args.objdir): - print("\"{}\" doesn't seem to be a directory".format(args.objdir)) - return 1 - - if (args.target != "all" and args.target not in COMPILATION_TARGETS) or args.target == COMMON_BUILD_KEY: - print("{} is not a valid compilation target.".format(args.target)) - print("Valid compilation targets are:") - for target in COMPILATION_TARGETS.keys(): - if target != COMMON_BUILD_KEY: - print("\t * {}".format(target)) - return 1 - - current_target = COMPILATION_TARGETS.get(args.target, {}) - if args.kind and "build_kinds" in current_target and args.kind not in current_target["build_kinds"]: - print("{} is not a valid build kind.".format(args.kind)) - print("Valid build kinds are:") - for kind in current_target["build_kinds"].keys(): - print("\t * {}".format(kind)) - return 1 - - for target, kind in builds_for(args.target, args.kind): - ret = build(args.objdir, target, kind_name=kind, - debug=args.debug, debugger=args.debugger, - bindgen=args.bindgen, skip_test=args.skip_test, - output_filename=args.output, - verbose=args.verbose) - if ret != 0: - print("{}::{} failed".format(target, kind)) - return ret - - return 0 - -if __name__ == '__main__': - sys.exit(main()) diff --git a/components/style/build.rs b/components/style/build.rs index 8d68fe45ce6..fb8d4a5e5f9 100644 --- a/components/style/build.rs +++ b/components/style/build.rs @@ -2,6 +2,12 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#[macro_use] +extern crate lazy_static; +#[cfg(feature = "bindgen")] +extern crate libbindgen; +#[cfg(feature = "bindgen")] +extern crate regex; extern crate walkdir; extern crate phf_codegen; @@ -12,6 +18,14 @@ use std::path::Path; use std::process::{Command, exit}; use walkdir::WalkDir; +#[cfg(feature = "gecko")] +mod build_gecko; + +#[cfg(not(feature = "gecko"))] +mod build_gecko { + pub fn generate() {} +} + #[cfg(windows)] fn find_python() -> String { if Command::new("python2.7.exe").arg("--version").output().is_ok() { @@ -39,8 +53,7 @@ fn find_python() -> String { }.to_owned() } -fn main() { - println!("cargo:rerun-if-changed=build.rs"); +fn generate_properties() { for entry in WalkDir::new("properties") { let entry = entry.unwrap(); match entry.path().extension().and_then(|e| e.to_str()) { @@ -82,3 +95,9 @@ fn main() { map.build(&mut file).unwrap(); write!(&mut file, ";\n").unwrap(); } + +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + generate_properties(); + build_gecko::generate(); +} diff --git a/components/style/build_gecko.rs b/components/style/build_gecko.rs new file mode 100644 index 00000000000..a96a92e9871 --- /dev/null +++ b/components/style/build_gecko.rs @@ -0,0 +1,617 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +mod common { + use std::env; + use std::path::PathBuf; + + lazy_static! { + pub static ref OUTDIR_PATH: PathBuf = PathBuf::from(env::var("OUT_DIR").unwrap()).join("gecko"); + } + + pub const STRUCTS_DEBUG_FILE: &'static str = "structs_debug.rs"; + pub const STRUCTS_RELEASE_FILE: &'static str = "structs_release.rs"; + pub const BINDINGS_FILE: &'static str = "bindings.rs"; + + #[derive(Clone, Copy, PartialEq)] + pub enum BuildType { + Debug, + Release, + } + + pub fn structs_file(build_type: BuildType) -> &'static str { + match build_type { + BuildType::Debug => STRUCTS_DEBUG_FILE, + BuildType::Release => STRUCTS_RELEASE_FILE + } + } +} + +#[cfg(feature = "bindgen")] +mod bindings { + use libbindgen::{Builder, CodegenConfig}; + use regex::Regex; + use std::collections::HashSet; + use std::env; + use std::fs::File; + use std::io::{BufWriter, Read, Write}; + use std::path::PathBuf; + use std::sync::Mutex; + use super::common::*; + + lazy_static! { + static ref INCLUDE_RE: Regex = Regex::new(r#"#include\s*"(.+?)""#).unwrap(); + static ref DISTDIR_PATH: PathBuf = PathBuf::from(env::var("MOZ_DIST").unwrap()); + static ref SEARCH_PATHS: Vec<PathBuf> = vec![ + DISTDIR_PATH.join("include"), + DISTDIR_PATH.join("include/nspr"), + ]; + static ref ADDED_PATHS: Mutex<HashSet<PathBuf>> = Mutex::new(HashSet::new()); + } + + fn search_include(name: &str) -> Option<PathBuf> { + for path in SEARCH_PATHS.iter() { + let file = path.join(name); + if file.is_file() { + return Some(file); + } + } + None + } + + fn add_headers_recursively(path: PathBuf, added_paths: &mut HashSet<PathBuf>) { + if added_paths.contains(&path) { + return; + } + let mut file = File::open(&path).unwrap(); + let mut content = String::new(); + file.read_to_string(&mut content).unwrap(); + println!("cargo:rerun-if-changed={}", path.to_str().unwrap()); + added_paths.insert(path); + // Find all includes and add them recursively + for cap in INCLUDE_RE.captures_iter(&content) { + if let Some(path) = search_include(cap.at(1).unwrap()) { + add_headers_recursively(path, added_paths); + } + } + } + + fn add_include(name: &str) -> String { + let mut added_paths = ADDED_PATHS.lock().unwrap(); + let file = search_include(name).unwrap(); + let result = String::from(file.to_str().unwrap()); + add_headers_recursively(file, &mut *added_paths); + result + } + + 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) -> Builder; + fn borrowed_type(self, ty: &str) -> Builder; + fn mutable_borrowed_type(self, ty: &str) -> 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()); + } + builder = builder.include(add_include("mozilla-config.h")); + + if build_type == BuildType::Debug { + builder = builder.clang_arg("-DDEBUG=1").clang_arg("-DJS_DEBUG=1"); + } + if cfg!(target_family = "unix") { + builder = builder.clang_arg("-DOS_POSIX=1"); + } + if cfg!(target_os = "linux") { + builder = builder.clang_arg("-DOS_LINUX=1"); + } else if cfg!(target_os = "macos") { + builder = builder.clang_arg("-DOS_MACOSX=1"); + } else if cfg!(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 cfg!(target_pointer_width = "32") { + builder = builder.clang_arg("--target=i686-pc-win32"); + } else { + builder = builder.clang_arg("--target=x86_64-pc-win32"); + } + } else { + panic!("Unknown platform"); + } + builder + } + fn include<T: Into<String>>(self, file: T) -> Builder { + self.clang_arg("-include").clang_arg(file) + } + // This makes an FFI-safe void type that can't be matched on + // &VoidType is UB to have, because you can match on it + // to produce a reachable unreachable. If it's wrapped in + // a struct as a private field it becomes okay again + // + // 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) -> Builder { + self.hide_type(ty) + .raw_line(format!("enum {}Void {{ }}", ty)) + .raw_line(format!("pub struct {0}({0}Void);", ty)) + } + fn borrowed_type(self, ty: &str) -> Builder { + self.hide_type(format!("{}Borrowed", ty)) + .raw_line(format!("pub type {0}Borrowed<'a> = &'a {0};", ty)) + .hide_type(format!("{}BorrowedOrNull", ty)) + .raw_line(format!("pub type {0}BorrowedOrNull<'a> = Option<&'a {0}>;", ty)) + } + fn mutable_borrowed_type(self, ty: &str) -> Builder { + self.borrowed_type(ty) + .hide_type(format!("{}BorrowedMut", ty)) + .raw_line(format!("pub type {0}BorrowedMut<'a> = &'a mut {0};", ty)) + .hide_type(format!("{}BorrowedMutOrNull", ty)) + .raw_line(format!("pub type {0}BorrowedMutOrNull<'a> = Option<&'a mut {0}>;", ty)) + } + } + + fn write_binding_file(builder: Builder, file: &str) { + let bindings = builder.generate().expect("Unable to generate bindings"); + let binding_file = File::create(&OUTDIR_PATH.join(file)).unwrap(); + bindings.write(Box::new(BufWriter::new(binding_file))).expect("Unable to write output"); + } + + pub fn generate_structs(build_type: BuildType) { + let mut builder = Builder::get_initial_builder(build_type) + .enable_cxx_namespaces() + .with_codegen_config(CodegenConfig { + types: true, + vars: true, + ..CodegenConfig::nothing() + }) + .header(add_include("nsStyleStruct.h")) + .include(add_include("gfxFontConstants.h")) + .include(add_include("nsThemeConstants.h")) + .include(add_include("mozilla/dom/AnimationEffectReadOnlyBinding.h")) + .include(add_include("mozilla/ServoElementSnapshot.h")) + .include(add_include("mozilla/dom/Element.h")) + .include(add_include("mozilla/ServoBindings.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"); + let whitelist_vars = [ + "NS_THEME_.*", + "NODE_.*", + "NS_FONT_.*", + "NS_STYLE_.*", + "NS_CORNER_.*", + "NS_RADIUS_.*", + "BORDER_COLOR_.*", + "BORDER_STYLE_.*" + ]; + let whitelist = [ + "RawGecko.*", + "mozilla::ServoElementSnapshot.*", + "mozilla::ConsumeStyleBehavior", + "mozilla::LazyComputeBehavior", + "mozilla::css::SheetParsingMode", + "mozilla::SkipRootBehavior", + "mozilla::DisplayItemClip", // Needed because bindgen generates + // specialization tests for this even + // though it shouldn't. + ".*ThreadSafe.*Holder", + "AnonymousContent", + "AudioContext", + "CapturingContentInfo", + "ConsumeStyleBehavior", + "DefaultDelete", + "DOMIntersectionObserverEntry", + "Element", + "FontFamilyList", + "FontFamilyListRefCnt", + "FontFamilyName", + "FontFamilyType", + "FragmentOrURL", + "FrameRequestCallback", + "gfxAlternateValue", + "gfxFontFeature", + "gfxFontVariation", + "GridNamedArea", + "Image", + "ImageURL", + "LazyComputeBehavior", + "nsAttrName", + "nsAttrValue", + "nsBorderColors", + "nscolor", + "nsChangeHint", + "nsCSSKeyword", + "nsCSSPropertyID", + "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", + "nsRect", + "nsRestyleHint", + "nsresult", + "nsSize", + "nsStyleBackground", + "nsStyleBorder", + "nsStyleColor", + "nsStyleColumn", + "nsStyleContent", + "nsStyleContentData", + "nsStyleContext", + "nsStyleCoord", + "nsStyleCounterData", + "nsStyleDisplay", + "nsStyleEffects", + "nsStyleFilter", + "nsStyleFont", + "nsStyleGradient", + "nsStyleGradientStop", + "nsStyleImage", + "nsStyleImageLayers", + "nsStyleList", + "nsStyleMargin", + "nsStyleOutline", + "nsStylePadding", + "nsStylePosition", + "nsStyleSVG", + "nsStyleSVGReset", + "nsStyleTable", + "nsStyleTableBorder", + "nsStyleText", + "nsStyleTextReset", + "nsStyleUIReset", + "nsStyleUnion", + "nsStyleUnit", + "nsStyleUserInterface", + "nsStyleVariables", + "nsStyleVisibility", + "nsStyleXUL", + "nsTArray", + "nsTArrayHeader", + "pair", + "Position", + "Runnable", + "ServoAttrSnapshot", + "ServoElementSnapshot", + "SheetParsingMode", + "mozilla::Side", + "StaticRefPtr", + "StyleAnimation", + "StyleBasicShape", + "StyleBasicShapeType", + "StyleClipPath", + "StyleClipPathGeometryBox", + "StyleTransition", + "mozilla::UniquePtr", + "mozilla::DefaultDelete", + ]; + let opaque_types = [ + "atomic___base", "std::atomic__My_base", + "nsAString_internal_char_traits", + "nsAString_internal_incompatible_char_type", + "nsACString_internal_char_traits", + "nsACString_internal_incompatible_char_type", + "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. + ]; + 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>", + } + ]; + struct Fixup { + pat: String, + rep: String + } + 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 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 result = builder.generate().expect("Unable to generate bindings").to_string(); + for fixup in fixups.iter() { + result = Regex::new(&format!(r"\b{}\b", fixup.pat)).unwrap().replace_all(&result, fixup.rep.as_str()); + } + File::create(&OUTDIR_PATH.join(structs_file(build_type))).unwrap() + .write_all(&result.into_bytes()).unwrap(); + } + + pub fn generate_bindings() { + let mut builder = Builder::get_initial_builder(BuildType::Release) + .disable_name_namespacing() + .with_codegen_config(CodegenConfig { + functions: true, + ..CodegenConfig::nothing() + }) + .header(add_include("mozilla/ServoBindings.h")) + .hide_type("nsACString_internal") + .hide_type("nsAString_internal") + .raw_line("pub use nsstring::{nsACString, nsAString};") + .raw_line("type nsACString_internal = nsACString;") + .raw_line("type nsAString_internal = nsAString;") + .whitelisted_function("Servo_.*") + .whitelisted_function("Gecko_.*"); + let structs_types = [ + "RawGeckoDocument", + "RawGeckoElement", + "RawGeckoNode", + "ThreadSafeURIHolder", + "ThreadSafePrincipalHolder", + "ConsumeStyleBehavior", + "LazyComputeBehavior", + "SkipRootBehavior", + "FontFamilyList", + "FontFamilyType", + "ServoElementSnapshot", + "SheetParsingMode", + "StyleBasicShape", + "StyleBasicShapeType", + "StyleClipPath", + "nsCSSKeyword", + "nsCSSShadowArray", + "nsCSSValue", + "nsCSSValueSharedList", + "nsChangeHint", + "nsCursorImage", + "nsFont", + "nsIAtom", + "nsRestyleHint", + "nsStyleBackground", + "nsStyleBorder", + "nsStyleColor", + "nsStyleColumn", + "nsStyleContent", + "nsStyleContext", + "nsStyleCoord", + "nsStyleCoord_Calc", + "nsStyleCoord_CalcValue", + "nsStyleDisplay", + "nsStyleEffects", + "nsStyleFont", + "nsStyleGradient", + "nsStyleGradientStop", + "nsStyleImage", + "nsStyleImageLayers", + "nsStyleImageLayers_Layer", + "nsStyleImageLayers_LayerType", + "nsStyleImageRequest", + "nsStyleList", + "nsStyleMargin", + "nsStyleOutline", + "nsStylePadding", + "nsStylePosition", + "nsStyleQuoteValues", + "nsStyleSVG", + "nsStyleSVGReset", + "nsStyleTable", + "nsStyleTableBorder", + "nsStyleText", + "nsStyleTextReset", + "nsStyleUIReset", + "nsStyleUnion", + "nsStyleUnit", + "nsStyleUserInterface", + "nsStyleVariables", + "nsStyleVisibility", + "nsStyleXUL", + "nscoord", + "nsresult", + ]; + struct ArrayType { + cpp_type: &'static str, + rust_type: &'static str + } + let array_types = [ + ArrayType { cpp_type: "uintptr_t", rust_type: "usize" }, + ]; + let servo_nullable_arc_types = [ + "ServoComputedValues", + "ServoCssRules", + "RawServoStyleSheet", + "RawServoDeclarationBlock", + "RawServoStyleRule", + ]; + 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 }, + ]; + let servo_immutable_borrow_types = [ + "RawGeckoNode", + "RawGeckoElement", + "RawGeckoDocument", + "RawServoDeclarationBlockStrong", + ]; + let servo_borrow_types = [ + "nsCSSValue", + ]; + 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)) + } + for &ty in servo_nullable_arc_types.iter() { + builder = builder + .hide_type(format!("{}Strong", ty)) + .raw_line(format!("pub type {0}Strong = ::gecko_bindings::sugar::ownership::Strong<{0}>;", ty)) + .borrowed_type(ty) + .zero_size_type(ty); + } + 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); + } + } + 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. + } + write_binding_file(builder, BINDINGS_FILE); + } +} + +#[cfg(not(feature = "bindgen"))] +mod bindings { + use std::fs; + use std::path::{Path, PathBuf}; + use super::common::*; + + lazy_static! { + static ref BINDINGS_PATH: PathBuf = Path::new(file!()).parent().unwrap().join("gecko_bindings"); + } + + pub fn generate_structs(build_type: BuildType) { + let file = structs_file(build_type); + let source = BINDINGS_PATH.join(file); + println!("cargo:rerun-if-changed={}", source.display()); + fs::copy(source, OUTDIR_PATH.join(file)).unwrap(); + } + + pub fn generate_bindings() { + let source = BINDINGS_PATH.join(BINDINGS_FILE); + println!("cargo:rerun-if-changed={}", source.display()); + fs::copy(source, OUTDIR_PATH.join(BINDINGS_FILE)).unwrap(); + } +} + +pub fn generate() { + use self::common::*; + use std::fs; + fs::create_dir_all(&*OUTDIR_PATH).unwrap(); + bindings::generate_structs(BuildType::Debug); + bindings::generate_structs(BuildType::Release); + bindings::generate_bindings(); +} diff --git a/components/style/gecko_bindings/mod.rs b/components/style/gecko_bindings/mod.rs index 7201bdb2668..d86bfb60484 100644 --- a/components/style/gecko_bindings/mod.rs +++ b/components/style/gecko_bindings/mod.rs @@ -3,22 +3,23 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #[allow(dead_code, improper_ctypes, non_camel_case_types)] -pub mod bindings; +pub mod bindings { + include!(concat!(env!("OUT_DIR"), "/gecko/bindings.rs")); +} // FIXME: We allow `improper_ctypes` (for now), because the lint doesn't allow // foreign structs to have `PhantomData`. We should remove this once the lint // ignores this case. -#[cfg(debug_assertions)] -#[allow(dead_code, improper_ctypes, non_camel_case_types, non_snake_case, non_upper_case_globals)] -pub mod structs { - include!("structs_debug.rs"); -} - -#[cfg(not(debug_assertions))] #[allow(dead_code, improper_ctypes, non_camel_case_types, non_snake_case, non_upper_case_globals)] pub mod structs { - include!("structs_release.rs"); + cfg_if! { + if #[cfg(debug_assertions)] { + include!(concat!(env!("OUT_DIR"), "/gecko/structs_debug.rs")); + } else { + include!(concat!(env!("OUT_DIR"), "/gecko/structs_release.rs")); + } + } } pub mod sugar; diff --git a/ports/geckolib/Cargo.toml b/ports/geckolib/Cargo.toml index 0df70bc465b..23e9db63a13 100644 --- a/ports/geckolib/Cargo.toml +++ b/ports/geckolib/Cargo.toml @@ -9,6 +9,9 @@ name = "geckoservo" path = "lib.rs" crate-type = ["staticlib", "rlib"] +[features] +bindgen = ["style/bindgen"] + [dependencies] app_units = "0.3" cssparser = {version = "0.7"} diff --git a/python/servo/build_commands.py b/python/servo/build_commands.py index 514a8f87e69..a54d667f5f4 100644 --- a/python/servo/build_commands.py +++ b/python/servo/build_commands.py @@ -384,6 +384,9 @@ class MachCommands(CommandBase): @Command('build-geckolib', description='Build a static library of components used by Gecko', category='build') + @CommandArgument('--with-gecko', + default=None, + help='Build with Gecko dist directory') @CommandArgument('--jobs', '-j', default=None, help='Number of jobs to run in parallel') @@ -393,12 +396,18 @@ class MachCommands(CommandBase): @CommandArgument('--release', '-r', action='store_true', help='Build in release mode') - def build_geckolib(self, jobs=None, verbose=False, release=False): + def build_geckolib(self, with_gecko=None, jobs=None, verbose=False, release=False): self.set_use_stable_rust() self.ensure_bootstrapped() + env = self.build_env(is_build=True) + env["CARGO_TARGET_DIR"] = path.join(self.context.topdir, "target", "geckolib").encode("UTF-8") + ret = None opts = [] + if with_gecko is not None: + opts += ["--features", "bindgen"] + env["MOZ_DIST"] = path.abspath(with_gecko) if jobs is not None: opts += ["-j", jobs] if verbose: @@ -406,9 +415,6 @@ class MachCommands(CommandBase): if release: opts += ["--release"] - env = self.build_env(is_build=True) - env["CARGO_TARGET_DIR"] = path.join(self.context.topdir, "target", "geckolib").encode("UTF-8") - build_start = time() with cd(path.join("ports", "geckolib")): ret = call(["cargo", "build"] + opts, env=env, verbose=verbose) |