diff options
Diffstat (limited to '')
-rw-r--r-- | js/rust/build.rs | 494 |
1 files changed, 494 insertions, 0 deletions
diff --git a/js/rust/build.rs b/js/rust/build.rs new file mode 100644 index 0000000000..6d16065b7d --- /dev/null +++ b/js/rust/build.rs @@ -0,0 +1,494 @@ +/* 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/. */ + +extern crate bindgen; +extern crate cmake; +extern crate env_logger; +extern crate glob; + +use std::env; +use std::path; + +fn main() { + env_logger::init(); + build_jsapi_bindings(); + build_jsglue_cpp(); +} + +/// Build the ./src/jsglue.cpp file containing C++ glue methods built on top of +/// JSAPI. +fn build_jsglue_cpp() { + let dst = cmake::Config::new(".").build(); + + println!("cargo:rustc-link-search=native={}/lib", dst.display()); + println!("cargo:rustc-link-lib=static=jsglue"); + println!("cargo:rerun-if-changed=src/jsglue.cpp"); +} + +/// Find the public include directory within our mozjs-sys crate dependency. +fn get_mozjs_include_dir() -> path::PathBuf { + let out_dir = env::var("OUT_DIR").expect("cargo should invoke us with the OUT_DIR env var set"); + + let mut target_build_dir = path::PathBuf::from(out_dir); + target_build_dir.push("../../"); + + let mut include_dir_glob = target_build_dir.display().to_string(); + include_dir_glob.push_str("mozjs_sys-*/out/dist/include"); + + let entries = + glob::glob(&include_dir_glob).expect("Should find entries for mozjs-sys include dir"); + + for entry in entries { + if let Ok(path) = entry { + return path + .canonicalize() + .expect("Should canonicalize include path"); + } + } + + panic!("Should have found either a mozjs_sys in target/debug or in target/release"); +} + +/// Invoke bindgen on the JSAPI headers to produce raw FFI bindings for use from +/// Rust. +/// +/// To add or remove which functions, types, and variables get bindings +/// generated, see the `const` configuration variables below. +fn build_jsapi_bindings() { + let mut builder = bindgen::builder() + .rust_target(bindgen::RustTarget::Stable_1_19) + .size_t_is_usize(true) + .header("./etc/wrapper.hpp") + .raw_line("pub use self::root::*;") + // Translate every enum with the "rustified enum" strategy. We should + // investigate switching to the "constified module" strategy, which has + // similar ergonomics but avoids some potential Rust UB footguns. + .rustified_enum(".*") + .enable_cxx_namespaces(); + + if cfg!(feature = "debugmozjs") { + builder = builder + .clang_arg("-DJS_GC_ZEAL") + .clang_arg("-DDEBUG") + .clang_arg("-DJS_DEBUG"); + } + + if cfg!(feature = "bigint") { + builder = builder.clang_arg("-DENABLE_BIGINT"); + } + + let include_dir = get_mozjs_include_dir(); + let include_dir = include_dir + .to_str() + .expect("Path to mozjs include dir should be utf-8"); + builder = builder.clang_arg("-I"); + builder = builder.clang_arg(include_dir); + + for ty in UNSAFE_IMPL_SYNC_TYPES { + builder = builder.raw_line(format!("unsafe impl Sync for {} {{}}", ty)); + } + + for extra in EXTRA_CLANG_FLAGS { + builder = builder.clang_arg(*extra); + } + + for ty in WHITELIST_TYPES { + builder = builder.whitelist_type(ty); + } + + for var in WHITELIST_VARS { + builder = builder.whitelist_var(var); + } + + for func in WHITELIST_FUNCTIONS { + builder = builder.whitelist_function(func); + } + + if cfg!(feature = "bigint") { + builder = builder.whitelist_type("JS::BigInt"); + } + + for ty in OPAQUE_TYPES { + builder = builder.opaque_type(ty); + } + + for ty in BLACKLIST_TYPES { + builder = builder.blacklist_type(ty); + } + + let bindings = builder + .generate() + .expect("Should generate JSAPI bindings OK"); + + let out = path::PathBuf::from(env::var("OUT_DIR").unwrap()); + + if cfg!(feature = "debugmozjs") { + bindings + .write_to_file(out.join("jsapi_debug.rs")) + .expect("Should write bindings to file OK"); + } else { + bindings + .write_to_file(out.join("jsapi.rs")) + .expect("Should write bindings to file OK"); + } + + println!("cargo:rerun-if-changed=etc/wrapper.hpp"); +} + +/// JSAPI types for which we should implement `Sync`. +const UNSAFE_IMPL_SYNC_TYPES: &'static [&'static str] = &[ + "JSClass", + "JSFunctionSpec", + "JSNativeWrapper", + "JSPropertySpec", + "JSTypedMethodJitInfo", +]; + +/// Flags passed through bindgen directly to Clang. +const EXTRA_CLANG_FLAGS: &'static [&'static str] = &[ + "-x", + "c++", + "-std=gnu++17", + "-fno-sized-deallocation", + "-fno-aligned-new", + "-DRUST_BINDGEN", +]; + +/// Types which we want to generate bindings for (and every other type they +/// transitively use). +const WHITELIST_TYPES: &'static [&'static str] = &[ + "JS::AutoCheckCannotGC", + "JS::CallArgs", + "JS::RealmOptions", + "JS::ContextOptions", + "js::DOMCallbacks", + "JS::DOMProxyShadowsResult", + "js::ESClass", + "JS::ForOfIterator", + "JS::Handle", + "JS::HandleFunction", + "JS::HandleId", + "JS::HandleObject", + "JS::HandleString", + "JS::HandleValue", + "JS::HandleValueArray", + "JS::IsAcceptableThis", + "JSAutoRealm", + "JSAutoStructuredCloneBuffer", + "JSClass", + "JSClassOps", + "JSContext", + "JSErrNum", + "JSErrorCallback", + "JSErrorFormatString", + "JSErrorReport", + "JSExnType", + "JSLinearString", + "JSFunction", + "JSFunctionSpec", + "JS::GCDescription", + "JSGCInvocationKind", + "JSGCMode", + "JSGCParamKey", + "JS::GCProgress", + "JSGCStatus", + "JSJitCompilerOption", + "JSJitGetterCallArgs", + "JSJitMethodCallArgs", + "JSJitSetterCallArgs", + "JSNativeWrapper", + "JSPropertySpec", + "JSProtoKey", + "JSObject", + "JSString", + "JSStructuredCloneReader", + "JSStructuredCloneWriter", + "JSScript", + "JSType", + "JSTypedMethodJitInfo", + "JSValueTag", + "JSValueType", + "JSVersion", + "JSWrapObjectCallbacks", + "jsid", + "JS::Compartment", + "JS::Latin1Char", + "JS::detail::RootedPtr", + "JS::detail::RootListEntry", + "JS::MutableHandle", + "JS::MutableHandleObject", + "JS::MutableHandleValue", + "JS::NativeImpl", + "js::ObjectOps", + "JS::ObjectOpResult", + "JS::PersistentRootedIdVector", + "JS::PersistentRootedObjectVector", + "JS::PromiseState", + "JS::PropertyDescriptor", + "JS::Rooted", + "JS::RootedObject", + "JS::RootedValue", + "JS::RootingContext", + "JS::RootKind", + "js::Scalar::Type", + "JS::ServoSizes", + "JS::shadow::Object", + "JS::shadow::ObjectGroup", + "JS::SourceText", + "js::StackFormat", + "JSStructuredCloneCallbacks", + "JS::Symbol", + "JS::SymbolCode", + "JS::TraceKind", + "JS::TransferableOwnership", + "JS::Value", + "JS::WarningReporter", + "JS::shadow::Realm", + "JS::shadow::Zone", + "JS::Zone", +]; + +/// Global variables we want to generate bindings to. +const WHITELIST_VARS: &'static [&'static str] = &[ + "JS_STRUCTURED_CLONE_VERSION", + "JSCLASS_.*", + "JSFUN_.*", + "JSID_TYPE_VOID", + "JSITER_.*", + "JSPROP_.*", + "JS::FalseHandleValue", + "JS::NullHandleValue", + "JS::TrueHandleValue", + "JS::UndefinedHandleValue", +]; + +/// Functions we want to generate bindings to. +const WHITELIST_FUNCTIONS: &'static [&'static str] = &[ + "JS::ExceptionStackOrNull", + "JS_AddExtraGCRootsTracer", + "JS_AddInterruptCallback", + "JS::AddPromiseReactions", + "js::AddRawValueRoot", + "JS_AlreadyHasOwnPropertyById", + "JS_AtomizeAndPinString", + "js::AssertSameCompartment", + "JS::BuildStackString", + "JS::Call", + "JS_CallFunctionName", + "JS_CallFunctionValue", + "JS::CallOriginalPromiseThen", + "JS::CallOriginalPromiseResolve", + "JS::CallOriginalPromiseReject", + "JS::CompileFunctionUtf8", + "JS::Construct", + "JS::ContextOptionsRef", + "JS_CopyOwnPropertiesAndPrivateFields", + "JS::CurrentGlobalOrNull", + "JS_DeletePropertyById", + "js::detail::IsWindowSlow", + "JS::Evaluate", + "JS_ForwardGetPropertyTo", + "JS_ForwardSetPropertyTo", + "JS::GCTraceKindToAscii", + "JS::GetArrayBufferLengthAndData", + "js::GetArrayBufferViewLengthAndData", + "js::GetFunctionNativeReserved", + "JS::GetNonCCWObjectGlobal", + "js::GetObjectProto", + "JS_GetObjectRuntime", + "JS_GetOwnPropertyDescriptorById", + "JS::GetPromiseResult", + "JS::GetPromiseState", + "JS_GetPropertyDescriptorById", + "js::GetPropertyKeys", + "JS_GetPrototype", + "JS_GetRuntime", + "js::GetStaticPrototype", + "JS_HasOwnPropertyById", + "JS_HasProperty", + "JS_HasPropertyById", + "JS::HeapBigIntWriteBarriers", + "JS::HeapObjectWriteBarriers", + "JS::HeapScriptWriteBarriers", + "JS::HeapStringWriteBarriers", + "JS::HeapValueWriteBarriers", + "JS_InitializePropertiesFromCompatibleNativeObject", + "JS::InitSelfHostedCode", + "JS::IsConstructor", + "JS::IsPromiseObject", + "JS_ClearPendingException", + "JS_DefineElement", + "JS_DefineFunction", + "JS_DefineFunctions", + "JS_DefineProperties", + "JS_DefineProperty", + "JS_DefinePropertyById", + "JS_DefineUCProperty", + "JS_DeprecatedStringHasLatin1Chars", + "JS::detail::InitWithFailureDiagnostic", + "JS_DestroyContext", + "JS::DisableIncrementalGC", + "js::Dump.*", + "JS::EnterRealm", + "JS_EnumerateStandardClasses", + "JS_ErrorFromException", + "JS_FireOnNewGlobalObject", + "JS_free", + "JS_GC", + "JS::GetArrayBufferData", + "JS_GetArrayBufferViewType", + "JS_GetFloat32ArrayData", + "JS_GetFloat64ArrayData", + "JS_GetFunctionObject", + "JS_GetGCParameter", + "JS_GetInt16ArrayData", + "JS_GetInt32ArrayData", + "JS_GetInt8ArrayData", + "JS_GetLatin1StringCharsAndLength", + "JS_GetParentRuntime", + "JS_GetPendingException", + "JS_GetProperty", + "JS_GetPropertyById", + "js::GetPropertyKeys", + "JS_GetPrototype", + "JS::GetReservedSlot", + "JS::GetRealmErrorPrototype", + "JS::GetRealmFunctionPrototype", + "JS::GetRealmIteratorPrototype", + "JS::GetRealmObjectPrototype", + "JS::GetScriptedCallerGlobal", + "JS_GetTwoByteStringCharsAndLength", + "JS_GetUint16ArrayData", + "JS_GetUint32ArrayData", + "JS_GetUint8ArrayData", + "JS_GetUint8ClampedArrayData", + "JS::GetWellKnownSymbol", + "JS_GlobalObjectTraceHook", + "JS::HideScriptedCaller", + "JS::InitRealmStandardClasses", + "JS::IsArrayObject", + "JS_IsExceptionPending", + "JS_IsGlobalObject", + "JS::IsCallable", + "JS::LeaveRealm", + "JS_LinkConstructorAndPrototype", + "JS_MayResolveStandardClass", + "JS::NewArrayBuffer", + "JS::NewArrayObject", + "JS_NewContext", + "JS_NewFloat32Array", + "JS_NewFloat64Array", + "JS_NewFunction", + "js::NewFunctionWithReserved", + "JS_NewGlobalObject", + "JS_NewInt16Array", + "JS_NewInt32Array", + "JS_NewInt8Array", + "JS_NewObject", + "JS_NewObjectWithGivenProto", + "JS_NewObjectWithoutMetadata", + "JS_NewPlainObject", + "JS::NewPromiseObject", + "JS_NewStringCopyN", + "JS_NewUCStringCopyN", + "JS_NewUint16Array", + "JS_NewUint32Array", + "JS_NewUint8Array", + "JS_NewUint8ClampedArray", + "JS::ObjectIsDate", + "JS_ParseJSON", + "JS_ReadBytes", + "JS_ReadStructuredClone", + "JS_ReadUint32Pair", + "JS_RemoveExtraGCRootsTracer", + "js::RemoveRawValueRoot", + "JS_ReportErrorASCII", + "JS_ReportErrorNumberUTF8", + "JS_RequestInterruptCallback", + "JS_ResolveStandardClass", + "js::RunJobs", + "JS::SameValue", + "js::SetDOMCallbacks", + "js::SetDOMProxyInformation", + "JS::SetEnqueuePromiseJobCallback", + "js::SetFunctionNativeReserved", + "JS_SetGCCallback", + "JS::SetGCSliceCallback", + "JS_SetGCParameter", + "JS_SetGCZeal", + "JS::SetGetIncumbentGlobalCallback", + "JS_SetGlobalJitCompilerOption", + "JS_SetImmutablePrototype", + "JS_SetNativeStackQuota", + "JS_SetOffthreadIonCompilationEnabled", + "JS_SetParallelParsingEnabled", + "JS_SetPendingException", + "js::SetPreserveWrapperCallback", + "JS::SetPromiseRejectionTrackerCallback", + "JS_SetPrototype", + "js::SetWindowProxy", + "js::SetWindowProxyClass", + "JS_SetProperty", + "JS_SetReservedSlot", + "JS_SetWrapObjectCallbacks", + "JS_ShutDown", + "JS_SplicePrototype", + "js::StopDrainingJobQueue", + "JS_StrictPropertyStub", + "JS_StringEqualsAscii", + "JS_WrapObject", + "JS_WrapValue", + "JS_WriteBytes", + "JS_WriteStructuredClone", + "JS_WriteUint32Pair", + "JS::ResolvePromise", + "JS::RejectPromise", + "JS::SetWarningReporter", + "js::ToBooleanSlow", + "js::ToInt32Slow", + "js::ToInt64Slow", + "js::ToNumberSlow", + "js::ToStringSlow", + "js::ToUint16Slow", + "js::ToUint32Slow", + "js::ToUint64Slow", + "JS_TransplantObject", + "js::detail::ToWindowProxyIfWindowSlow", + "JS::UnhideScriptedCaller", + "JS::UnwrapArrayBuffer", + "js::UnwrapArrayBufferView", + "js::UnwrapFloat32Array", + "js::UnwrapFloat64Array", + "js::UnwrapInt16Array", + "js::UnwrapInt32Array", + "js::UnwrapInt8Array", + "js::UnwrapUint16Array", + "js::UnwrapUint32Array", + "js::UnwrapUint8Array", + "js::UnwrapUint8ClampedArray", + "js::UseInternalJobQueues", + "JS_ValueToFunction", +]; + +/// Types that should be treated as an opaque blob of bytes whenever they show +/// up within a whitelisted type. +/// +/// These are types which are too tricky for bindgen to handle, and/or use C++ +/// features that don't have an equivalent in rust, such as partial template +/// specialization. +const OPAQUE_TYPES: &'static [&'static str] = &[ + "JS::ReadOnlyCompileOptions", + "mozilla::BufferList", + "mozilla::UniquePtr.*", + "JS::PersistentRooted", + "JS::StackGCVector", +]; + +/// Types for which we should NEVER generate bindings, even if it is used within +/// a type or function signature that we are generating bindings for. +const BLACKLIST_TYPES: &'static [&'static str] = &[ + // We provide our own definition because we need to express trait bounds in + // the definition of the struct to make our Drop implementation correct. + "JS::Heap", +]; |