/* 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) .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++14", "-fno-sized-deallocation", "-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::Class", "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", "JSFlatString", "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::MaybeWrapped", "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] = &[ "INTERNED_STRING_TO_JSID", "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_CopyPropertiesFrom", "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::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::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_NewObjectWithUniqueType", "JS_NewPlainObject", "JS::NewPromiseObject", "JS_NewStringCopyN", "JS_NewUCStringCopyN", "JS_NewUint16Array", "JS_NewUint32Array", "JS_NewUint8Array", "JS_NewUint8ClampedArray", "js::ObjectClassName", "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_StringHasLatin1Chars", "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", ];