diff --git a/block-sys/CHANGELOG.md b/block-sys/CHANGELOG.md index 66fcbfae8..a3eef5de6 100644 --- a/block-sys/CHANGELOG.md +++ b/block-sys/CHANGELOG.md @@ -6,6 +6,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## Unreleased - YYYY-MM-DD +### Changed +* **BREAKING**: Changed `links` key from `block` to `block_0_0` for better + future compatibility, until we reach 1.0 (so `DEP_BLOCK_X` in build scripts + becomes `DEP_BLOCK_0_0_X`). + ## 0.0.3 - 2022-01-03 diff --git a/block-sys/Cargo.toml b/block-sys/Cargo.toml index 8cd13f256..725dda78d 100644 --- a/block-sys/Cargo.toml +++ b/block-sys/Cargo.toml @@ -19,7 +19,7 @@ readme = "README.md" # Downstream users can customize the linking! # See https://doc.rust-lang.org/cargo/reference/build-scripts.html#overriding-build-scripts -links = "block" +links = "block_0_0" build = "build.rs" [features] diff --git a/block-sys/README.md b/block-sys/README.md index 1dd0ebf91..88dd7605a 100644 --- a/block-sys/README.md +++ b/block-sys/README.md @@ -94,8 +94,8 @@ TODO. To our knowledge, currently only `clang` supports the [Language Specification for Blocks][block-lang]. To assist in compiling C (or Objective-C) sources -using these features, this crate's build script expose the `DEP_BLOCK_CC_ARGS` -environment variable to downstream build scripts. +using these features, this crate's build script expose the +`DEP_BLOCK_0_0_CC_ARGS` environment variable to downstream build scripts. Example usage in your `build.rs` (using the `cc` crate) would be as follows: @@ -105,7 +105,7 @@ fn main() { builder.compiler("clang"); builder.file("my_script_using_blocks.c"); - for flag in std::env::var("DEP_BLOCK_CC_ARGS").unwrap().split(' ') { + for flag in std::env::var("DEP_BLOCK_0_0_CC_ARGS").unwrap().split(' ') { builder.flag(flag); } diff --git a/block-sys/build.rs b/block-sys/build.rs index 2d6b936eb..a1194b733 100644 --- a/block-sys/build.rs +++ b/block-sys/build.rs @@ -47,17 +47,24 @@ fn main() { // work (on newer GNUStep versions these headers are present) if env::var_os("CARGO_FEATURE_GNUSTEP_2_0").is_none() { let compat_headers = - Path::new(env!("CARGO_MANIFEST_DIR")).join("gnustep-compat-headers"); + Path::new(env!("CARGO_MANIFEST_DIR")).join("compat-headers/gnustep"); cc_args.push_str(" -I"); cc_args.push_str(compat_headers.to_str().unwrap()); } } - (false, false, false, true) => unimplemented!(), + (false, false, false, true) => { + // Add compability headers to make `#include ` work. + let compat_headers = Path::new(env!("CARGO_MANIFEST_DIR")).join("compat-headers/objfw"); + cc_args.push_str(" -I"); + cc_args.push_str(compat_headers.to_str().unwrap()); + println!("cargo:rustc-link-lib=dylib=objfw"); + unimplemented!("ObjFW is not yet supported") + } // Checked in if-let above (false, false, false, false) => unreachable!(), (_, _, _, _) => panic!("Invalid feature combination; only one runtime may be selected!"), } - // Add DEP_BLOCK_CC_ARGS + // Add DEP_BLOCK_[version]_CC_ARGS println!("cargo:cc_args={}", cc_args); } diff --git a/block-sys/gnustep-compat-headers/Block.h b/block-sys/compat-headers/gnustep/Block.h similarity index 100% rename from block-sys/gnustep-compat-headers/Block.h rename to block-sys/compat-headers/gnustep/Block.h diff --git a/block-sys/gnustep-compat-headers/Block_private.h b/block-sys/compat-headers/gnustep/Block_private.h similarity index 100% rename from block-sys/gnustep-compat-headers/Block_private.h rename to block-sys/compat-headers/gnustep/Block_private.h diff --git a/block-sys/compat-headers/objfw/Block.h b/block-sys/compat-headers/objfw/Block.h new file mode 100644 index 000000000..d4d5b3818 --- /dev/null +++ b/block-sys/compat-headers/objfw/Block.h @@ -0,0 +1 @@ +#include diff --git a/block-sys/src/lib.rs b/block-sys/src/lib.rs index 9fb38f84d..f71aab144 100644 --- a/block-sys/src/lib.rs +++ b/block-sys/src/lib.rs @@ -9,9 +9,12 @@ //! //! [ABI]: https://clang.llvm.org/docs/Block-ABI-Apple.html +#![no_std] // Update in Cargo.toml as well. #![doc(html_root_url = "https://docs.rs/block-sys/0.0.3")] +extern crate std; + // Ensure linkage actually happens #[cfg(feature = "gnustep-1-7")] extern crate objc_sys as _; @@ -298,7 +301,6 @@ pub struct Block_descriptor { /// /// Requires BLOCK_HAS_SIGNATURE #[repr(C)] -#[cfg(not(feature = "objfw"))] pub struct Block_descriptor_basic { pub header: Block_descriptor_header, @@ -388,3 +390,50 @@ pub struct Block_byref_extended { pub inner: Block_byref, pub layout: *const c_char, } + +#[cfg(test)] +mod tests { + use super::*; + use core::ptr; + use std::println; + + #[test] + fn smoke() { + assert_eq!(unsafe { _Block_copy(ptr::null()) }, ptr::null_mut()); + } + + #[test] + fn test_linkable() { + println!("{:p}", unsafe { &_NSConcreteGlobalBlock }); + println!("{:p}", unsafe { &_NSConcreteStackBlock }); + println!("{:p}", unsafe { &_NSConcreteMallocBlock }); + println!( + "{:p}", + _Block_copy as unsafe extern "C" fn(*const c_void) -> *mut c_void + ); + println!( + "{:p}", + _Block_object_assign + as unsafe extern "C" fn(*mut c_void, *const c_void, block_assign_dispose_flags) + ); + println!( + "{:p}", + _Block_object_dispose + as unsafe extern "C" fn(*const c_void, block_assign_dispose_flags) + ); + println!( + "{:p}", + _Block_release as unsafe extern "C" fn(*const c_void) + ); + #[cfg(any(feature = "apple", feature = "compiler-rt"))] + { + println!("{:p}", unsafe { &_NSConcreteAutoBlock }); + println!("{:p}", unsafe { &_NSConcreteFinalizingBlock }); + println!("{:p}", unsafe { &_NSConcreteWeakBlockVariable }); + println!( + "{:p}", + Block_size as unsafe extern "C" fn(*mut c_void) -> c_ulong + ); + } + } +} diff --git a/objc-sys/CHANGELOG.md b/objc-sys/CHANGELOG.md index 708319ebb..71934b168 100644 --- a/objc-sys/CHANGELOG.md +++ b/objc-sys/CHANGELOG.md @@ -6,6 +6,19 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## Unreleased - YYYY-MM-DD +### Changed +* **BREAKING**: Changed `links` key from `objc` to `objc_0_2` for better + future compatibility, until we reach 1.0 (so `DEP_OBJC_X` in build scripts + becomes `DEP_OBJC_0_2_X`). + +### Removed +* **BREAKING**: Removed type aliases `Class`, `Ivar`, `Method` and `Protocol` + since they could easily be mistaken for the `objc2::runtime` structs with + the same name. +* **BREAKING**: Removed `objc_property_t`. +* **BREAKING**: Removed `objc_hook_getClass` and `objc_hook_lazyClassNamer` + type aliases (for now). + ## 0.2.0-alpha.1 - 2022-01-03 diff --git a/objc-sys/Cargo.toml b/objc-sys/Cargo.toml index 9a60bd9b2..b755c5cec 100644 --- a/objc-sys/Cargo.toml +++ b/objc-sys/Cargo.toml @@ -19,7 +19,7 @@ readme = "README.md" # Downstream users can customize the linking to libobjc! # See https://doc.rust-lang.org/cargo/reference/build-scripts.html#overriding-build-scripts -links = "objc" +links = "objc_0_2" build = "build.rs" # The default is `apple` on Apple platforms; all other platforms will error diff --git a/objc-sys/README.md b/objc-sys/README.md index 26483c897..5aeacfefa 100644 --- a/objc-sys/README.md +++ b/objc-sys/README.md @@ -116,8 +116,8 @@ ABI to the runtime you're using: This is relevant if you're building and linking to custom Objective-C sources in a build script. To assist in compiling Objective-C sources, this crate's -build script expose the `DEP_OBJC_CC_ARGS` environment variable to downstream -build scripts. +build script expose the `DEP_OBJC_0_2_CC_ARGS` environment variable to +downstream build scripts. Example usage in your `build.rs` (using the `cc` crate) would be as follows: @@ -127,7 +127,7 @@ fn main() { builder.compiler("clang"); builder.file("my_objective_c_script.m"); - for flag in std::env::var("DEP_OBJC_CC_ARGS").unwrap().split(' ') { + for flag in std::env::var("DEP_OBJC_0_2_CC_ARGS").unwrap().split(' ') { builder.flag(flag); } diff --git a/objc-sys/build.rs b/objc-sys/build.rs index 83f4e7c98..437cba691 100644 --- a/objc-sys/build.rs +++ b/objc-sys/build.rs @@ -1,4 +1,4 @@ -use std::env; +use std::{env, path::Path}; /// TODO: Better validation of this /// @@ -114,7 +114,9 @@ fn main() { } } (false, false, true) => { - unimplemented!() + // For now + unimplemented!("ObjFW is not yet supported") + // ObjFW(None) } (false, false, false) => { // Choose sensible defaults when generating docs @@ -142,7 +144,7 @@ fn main() { }; println!("cargo:rustc-cfg={}", runtime_cfg); // Allow downstream build scripts to do the same - println!("cargo:runtime={}", runtime_cfg); // DEP_OBJC_RUNTIME + println!("cargo:runtime={}", runtime_cfg); // DEP_OBJC_[version]_RUNTIME // Tell downstream build scripts our features // match &runtime { @@ -202,8 +204,8 @@ fn main() { WinObjC => "gnustep-1.8".into(), ObjFW(version) => { // Default in clang - let _version = version.as_deref().unwrap_or("0.8"); - todo!() + let version = version.as_deref().unwrap_or("0.8"); + format!("objfw-{}", version) } }; @@ -221,12 +223,27 @@ fn main() { // - `-miphoneos-version-min={}` // - `-mmacosx-version-min={}` // - ... - println!( - "cargo:cc_args=-fobjc-arc -fobjc-arc-exceptions -fobjc-exceptions -fobjc-runtime={}", - // TODO: -fobjc-weak ? + // + // TODO: -fobjc-weak ? + let mut cc_args = format!( + "-fobjc-arc -fobjc-arc-exceptions -fobjc-exceptions -fobjc-runtime={}", clang_runtime - ); // DEP_OBJC_CC_ARGS + ); + + if let Runtime::ObjFW(_) = &runtime { + // Add compability headers to make `#include ` work. + let compat_headers = Path::new(env!("CARGO_MANIFEST_DIR")).join("compat-headers-objfw"); + cc_args.push_str(" -I"); + cc_args.push_str(compat_headers.to_str().unwrap()); + } - // Link to libobjc - println!("cargo:rustc-link-lib=dylib=objc"); + println!("cargo:cc_args={}", cc_args); // DEP_OBJC_[version]_CC_ARGS + + if let Runtime::ObjFW(_) = &runtime { + // Link to libobjfw-rt + println!("cargo:rustc-link-lib=dylib=objfw-rt"); + } else { + // Link to libobjc + println!("cargo:rustc-link-lib=dylib=objc"); + } } diff --git a/objc-sys/compat-headers-objfw/objc/objc.h b/objc-sys/compat-headers-objfw/objc/objc.h new file mode 100644 index 000000000..1d5bfe397 --- /dev/null +++ b/objc-sys/compat-headers-objfw/objc/objc.h @@ -0,0 +1 @@ +#import diff --git a/objc-sys/compat-headers-objfw/objc/runtime.h b/objc-sys/compat-headers-objfw/objc/runtime.h new file mode 100644 index 000000000..1d5bfe397 --- /dev/null +++ b/objc-sys/compat-headers-objfw/objc/runtime.h @@ -0,0 +1 @@ +#import diff --git a/objc-sys/src/class.rs b/objc-sys/src/class.rs index 74396969a..5de95ed60 100644 --- a/objc-sys/src/class.rs +++ b/objc-sys/src/class.rs @@ -1,9 +1,8 @@ use std::os::raw::{c_char, c_int, c_uint}; -use crate::{ - objc_ivar, objc_method, objc_object, objc_property, objc_property_attribute_t, objc_protocol, - objc_selector, OpaqueData, BOOL, IMP, -}; +#[cfg(not(objfw))] +use crate::{objc_ivar, objc_method, objc_object, objc_property, objc_property_attribute_t}; +use crate::{objc_protocol, objc_selector, OpaqueData, BOOL, IMP}; /// An opaque type that represents an Objective-C class. #[repr(C)] @@ -14,6 +13,7 @@ pub struct objc_class { _p: OpaqueData, } +#[cfg(not(objfw))] /// This is `c_char` in GNUStep's libobjc2 and `uint8_t` in Apple's objc4. /// /// The pointer represents opaque data, and is definitely not just an integer, @@ -27,6 +27,7 @@ extern_c! { pub fn objc_getClass(name: *const c_char) -> *const objc_class; pub fn objc_getRequiredClass(name: *const c_char) -> *const objc_class; pub fn objc_lookUpClass(name: *const c_char) -> *const objc_class; + #[cfg(not(objfw))] pub fn objc_getMetaClass(name: *const c_char) -> *const objc_class; pub fn objc_copyClassList(out_len: *mut c_uint) -> *mut *const objc_class; pub fn objc_getClassList(buffer: *mut *const objc_class, buffer_len: c_int) -> c_int; @@ -42,9 +43,11 @@ extern_c! { name: *const c_char, extra_bytes: usize, ) -> *mut objc_class; + #[cfg(not(objfw))] pub fn objc_disposeClassPair(cls: *mut objc_class); pub fn objc_registerClassPair(cls: *mut objc_class); + #[cfg(not(objfw))] pub fn class_addIvar( cls: *mut objc_class, name: *const c_char, @@ -58,53 +61,68 @@ extern_c! { imp: IMP, types: *const c_char, ) -> BOOL; + #[cfg(not(objfw))] pub fn class_addProperty( cls: *mut objc_class, name: *const c_char, attributes: *const objc_property_attribute_t, attributes_count: c_uint, ) -> BOOL; + #[cfg(not(objfw))] pub fn class_addProtocol(cls: *mut objc_class, protocol: *const objc_protocol) -> BOOL; pub fn class_conformsToProtocol(cls: *const objc_class, protocol: *const objc_protocol) -> BOOL; + + #[cfg(not(objfw))] // Available in newer versions pub fn class_copyIvarList( cls: *const objc_class, out_len: *mut c_uint, ) -> *mut *const objc_ivar; + #[cfg(not(objfw))] // Available in newer versions pub fn class_copyMethodList( cls: *const objc_class, out_len: *mut c_uint, ) -> *mut *const objc_method; + #[cfg(not(objfw))] // Available in newer versions pub fn class_copyPropertyList( cls: *const objc_class, out_len: *mut c_uint, ) -> *mut *const objc_property; + #[cfg(not(objfw))] pub fn class_copyProtocolList( cls: *const objc_class, out_len: *mut c_uint, ) -> *mut *const objc_protocol; + #[cfg(not(objfw))] pub fn class_createInstance(cls: *const objc_class, extra_bytes: usize) -> *mut objc_object; + #[cfg(not(objfw))] pub fn class_getClassMethod( cls: *const objc_class, name: *const objc_selector, ) -> *const objc_method; + #[cfg(not(objfw))] pub fn class_getClassVariable(cls: *const objc_class, name: *const c_char) -> *const objc_ivar; #[cfg(apple)] pub fn class_getImageName(cls: *const objc_class) -> *const c_char; + #[cfg(not(objfw))] // Available in newer versions pub fn class_getInstanceMethod( cls: *const objc_class, name: *const objc_selector, ) -> *const objc_method; pub fn class_getInstanceSize(cls: *const objc_class) -> usize; + #[cfg(not(objfw))] pub fn class_getInstanceVariable( cls: *const objc_class, name: *const c_char, ) -> *const objc_ivar; + #[cfg(not(objfw))] pub fn class_getIvarLayout(cls: *const objc_class) -> *const ivar_layout_type; pub fn class_getName(cls: *const objc_class) -> *const c_char; + #[cfg(not(objfw))] pub fn class_getProperty(cls: *const objc_class, name: *const c_char) -> *const objc_property; pub fn class_getSuperclass(cls: *const objc_class) -> *const objc_class; + #[cfg(not(objfw))] pub fn class_getVersion(cls: *const objc_class) -> c_int; #[cfg(apple)] pub fn class_getWeakIvarLayout(cls: *const objc_class) -> *const ivar_layout_type; @@ -115,6 +133,7 @@ extern_c! { imp: IMP, types: *const c_char, ) -> IMP; + #[cfg(not(objfw))] pub fn class_replaceProperty( cls: *mut objc_class, name: *const c_char, @@ -122,7 +141,9 @@ extern_c! { attributes_len: c_uint, ); pub fn class_respondsToSelector(cls: *const objc_class, sel: *const objc_selector) -> BOOL; + #[cfg(not(objfw))] pub fn class_setIvarLayout(cls: *mut objc_class, layout: *const ivar_layout_type); + #[cfg(not(objfw))] pub fn class_setVersion(cls: *mut objc_class, version: c_int); #[cfg(apple)] pub fn class_setWeakIvarLayout(cls: *mut objc_class, layout: *const ivar_layout_type); diff --git a/objc-sys/src/constants.rs b/objc-sys/src/constants.rs index 5e7a976db..474a68ade 100644 --- a/objc-sys/src/constants.rs +++ b/objc-sys/src/constants.rs @@ -3,7 +3,7 @@ #[cfg(apple)] use std::os::raw::c_int; -use crate::{id, Class, BOOL}; +use crate::{id, objc_class, BOOL}; /// The equivalent of `true` for Objective-C's [`BOOL`][`super::BOOL`] type. pub const YES: BOOL = true as BOOL; // true -> 1 @@ -15,7 +15,7 @@ pub const NO: BOOL = false as BOOL; // false -> 0 pub const nil: id = 0 as *mut _; /// A quick alias for a [`null_mut`][`core::ptr::null_mut`] class. -pub const Nil: Class = 0 as *mut _; +pub const Nil: *mut objc_class = 0 as *mut _; pub type objc_AssociationPolicy = usize; pub const OBJC_ASSOCIATION_ASSIGN: objc_AssociationPolicy = 0; diff --git a/objc-sys/src/exception.rs b/objc-sys/src/exception.rs index 815153680..c5be06838 100644 --- a/objc-sys/src/exception.rs +++ b/objc-sys/src/exception.rs @@ -2,6 +2,7 @@ //! Apple: `objc-exception.h` //! GNUStep: `eh_personality.c`, which is a bit brittle to rely on, but I //! think it's fine... +#[cfg(not(objfw))] use core::ffi::c_void; #[cfg(apple)] use std::os::raw::c_int; @@ -24,6 +25,10 @@ pub type objc_exception_preprocessor = #[cfg(apple)] pub type objc_uncaught_exception_handler = unsafe extern "C" fn(exception: *mut objc_object); +#[cfg(objfw)] +pub type objc_uncaught_exception_handler = + Option; + /// Only available on macOS. /// /// Remember that this is non-null! @@ -32,7 +37,9 @@ pub type objc_exception_handler = unsafe extern "C" fn(unused: *mut objc_object, context: *mut c_void); extern_c! { + #[cfg(not(objfw))] pub fn objc_begin_catch(exc_buf: *mut c_void) -> *mut objc_object; + #[cfg(not(objfw))] pub fn objc_end_catch(); /// See [`objc-exception.h`]. /// @@ -49,7 +56,7 @@ extern_c! { pub fn objc_setExceptionPreprocessor( f: objc_exception_preprocessor, ) -> objc_exception_preprocessor; - #[cfg(apple)] + #[cfg(any(apple, objfw))] pub fn objc_setUncaughtExceptionHandler( f: objc_uncaught_exception_handler, ) -> objc_uncaught_exception_handler; diff --git a/objc-sys/src/message.rs b/objc-sys/src/message.rs index 2dcf3668a..8de6f1587 100644 --- a/objc-sys/src/message.rs +++ b/objc-sys/src/message.rs @@ -4,7 +4,7 @@ //! //! TODO: Some of these are only supported on _some_ GNUStep targets! use crate::{objc_class, objc_object}; -#[cfg(gnustep)] +#[cfg(any(gnustep, objfw))] use crate::{objc_selector, IMP}; /// Specifies data used when sending messages to superclasses. @@ -21,16 +21,21 @@ pub struct objc_super { } extern_c! { - #[cfg(gnustep)] + #[cfg(any(gnustep, objfw))] pub fn objc_msg_lookup(receiver: *mut objc_object, sel: *const objc_selector) -> IMP; - #[cfg(gnustep)] + #[cfg(objfw)] + pub fn objc_msg_lookup_stret(receiver: *mut objc_object, sel: *const objc_selector) -> IMP; + #[cfg(any(gnustep, objfw))] pub fn objc_msg_lookup_super(sup: *const objc_super, sel: *const objc_selector) -> IMP; + #[cfg(objfw)] + pub fn objc_msg_lookup_super_stret(sup: *const objc_super, sel: *const objc_selector) -> IMP; // #[cfg(gnustep)] // objc_msg_lookup_sender // objc_msgLookup family available in macOS >= 10.12 // objc_msgSend_noarg + #[cfg(not(objfw))] pub fn objc_msgSend(); // objc_msgSend_debug @@ -48,7 +53,7 @@ extern_c! { // Struct return. Not available on __arm64__: /// Not available on `target_arch = "aarch64"` - #[cfg(not(target_arch = "aarch64"))] + #[cfg(all(not(objfw), not(target_arch = "aarch64")))] pub fn objc_msgSend_stret(); // objc_msgSend_stret_debug @@ -64,14 +69,14 @@ extern_c! { /// Not available on `target_arch = "aarch64"` #[cfg(all(apple, not(target_arch = "aarch64")))] pub fn _objc_msgForward_stret(); - /// Not available on `target_arch = "aarch64"` - #[cfg(not(target_arch = "aarch64"))] + /// Not available on `target_arch = "aarch64"`, always available on ObjFW + #[cfg(any(objfw, not(target_arch = "aarch64")))] pub fn class_getMethodImplementation_stret(); // __x86_64__ and __i386__ /// Only available on `target_arch = "x86_64"` or `target_arch = "x86"` - #[cfg(any(target_arch = "x86_64", target_arch = "x86"))] + #[cfg(all(not(objfw), any(target_arch = "x86_64", target_arch = "x86")))] pub fn objc_msgSend_fpret(); // objc_msgSend_fpret_debug diff --git a/objc-sys/src/method.rs b/objc-sys/src/method.rs index f29ced2ac..7faea6965 100644 --- a/objc-sys/src/method.rs +++ b/objc-sys/src/method.rs @@ -1,6 +1,10 @@ -use std::os::raw::{c_char, c_uint}; +use std::os::raw::c_char; +#[cfg(not(objfw))] +use std::os::raw::c_uint; -use crate::{objc_selector, OpaqueData, IMP}; +#[cfg(not(objfw))] +use crate::IMP; +use crate::{objc_selector, OpaqueData}; /// A type that represents a method in a class definition. #[repr(C)] @@ -20,6 +24,8 @@ pub struct objc_method_description { } extern_c! { + #![cfg(not(objfw))] + pub fn method_copyArgumentType(method: *const objc_method, index: c_uint) -> *mut c_char; pub fn method_copyReturnType(method: *const objc_method) -> *mut c_char; pub fn method_exchangeImplementations(method1: *mut objc_method, method2: *mut objc_method); diff --git a/objc-sys/src/object.rs b/objc-sys/src/object.rs index 58950a0f0..1c852dd4f 100644 --- a/objc-sys/src/object.rs +++ b/objc-sys/src/object.rs @@ -1,7 +1,10 @@ +#[cfg(not(objfw))] use core::ffi::c_void; use std::os::raw::c_char; -use crate::{objc_class, objc_ivar, OpaqueData}; +#[cfg(not(objfw))] +use crate::objc_ivar; +use crate::{objc_class, OpaqueData}; /// An opaque type that represents an object / an instance of a class. #[repr(C)] @@ -15,23 +18,31 @@ pub struct objc_object { extern_c! { pub fn object_getClass(obj: *const objc_object) -> *const objc_class; pub fn object_getClassName(obj: *const objc_object) -> *const c_char; + pub fn object_setClass(obj: *mut objc_object, cls: *const objc_class) -> *const objc_class; + + #[cfg(not(objfw))] pub fn object_getIndexedIvars(obj: *const objc_object) -> *const c_void; + #[cfg(not(objfw))] pub fn object_getIvar(obj: *const objc_object, ivar: *const objc_ivar) -> *const objc_object; - - pub fn object_setClass(obj: *mut objc_object, cls: *const objc_class) -> *const objc_class; + #[cfg(not(objfw))] pub fn object_setIvar(obj: *mut objc_object, ivar: *const objc_ivar, value: *mut objc_object); #[deprecated = "Not needed since ARC"] #[cfg(apple)] pub fn object_copy(obj: *const objc_object, size: usize) -> *mut objc_object; + #[deprecated = "Not needed since ARC"] + #[cfg(not(objfw))] pub fn object_dispose(obj: *mut objc_object) -> *mut objc_object; + #[deprecated = "Not needed since ARC"] + #[cfg(not(objfw))] pub fn object_setInstanceVariable( obj: *mut objc_object, name: *const c_char, value: *mut c_void, ) -> *const objc_ivar; + // Available in macOS 10.12 // #[deprecated = "Not needed since ARC"] // #[cfg(apple)] @@ -40,12 +51,15 @@ extern_c! { // name: *const c_char, // value: *mut c_void, // ) -> *const objc_ivar; + #[deprecated = "Not needed since ARC"] + #[cfg(not(objfw))] pub fn object_getInstanceVariable( obj: *const objc_object, name: *const c_char, out_value: *mut *const c_void, ) -> *const objc_ivar; + #[deprecated = "Not needed since ARC"] #[cfg(apple)] pub fn objc_getFutureClass(name: *const c_char) -> *const objc_class; diff --git a/objc-sys/src/property.rs b/objc-sys/src/property.rs index 57fd62771..6887fa3c4 100644 --- a/objc-sys/src/property.rs +++ b/objc-sys/src/property.rs @@ -1,4 +1,6 @@ -use std::os::raw::{c_char, c_uint}; +use std::os::raw::c_char; +#[cfg(not(objfw))] +use std::os::raw::c_uint; use crate::OpaqueData; @@ -22,6 +24,8 @@ pub struct objc_property_attribute_t { } extern_c! { + #![cfg(not(objfw))] + pub fn property_copyAttributeList( property: *const objc_property, out_len: *mut c_uint, diff --git a/objc-sys/src/protocol.rs b/objc-sys/src/protocol.rs index 064037545..b8684ba0d 100644 --- a/objc-sys/src/protocol.rs +++ b/objc-sys/src/protocol.rs @@ -1,9 +1,10 @@ -use std::os::raw::{c_char, c_uint}; +use std::os::raw::c_char; +#[cfg(not(objfw))] +use std::os::raw::c_uint; -use crate::{ - objc_method_description, objc_property, objc_property_attribute_t, objc_selector, OpaqueData, - BOOL, -}; +#[cfg(not(objfw))] +use crate::{objc_method_description, objc_property, objc_property_attribute_t, objc_selector}; +use crate::{OpaqueData, BOOL}; /// Opaque type for Objective-C protocols. /// @@ -19,12 +20,24 @@ pub struct objc_protocol { } extern_c! { + #[cfg(not(objfw))] pub fn objc_getProtocol(name: *const c_char) -> *const objc_protocol; + #[cfg(not(objfw))] pub fn objc_copyProtocolList(out_len: *mut c_uint) -> *mut *const objc_protocol; + #[cfg(not(objfw))] pub fn objc_allocateProtocol(name: *const c_char) -> *mut objc_protocol; + #[cfg(not(objfw))] pub fn objc_registerProtocol(proto: *mut objc_protocol); + pub fn protocol_conformsToProtocol( + proto: *const objc_protocol, + other: *const objc_protocol, + ) -> BOOL; + pub fn protocol_isEqual(proto: *const objc_protocol, other: *const objc_protocol) -> BOOL; + pub fn protocol_getName(proto: *const objc_protocol) -> *const c_char; + + #[cfg(not(objfw))] pub fn protocol_addMethodDescription( proto: *mut objc_protocol, name: *const objc_selector, @@ -32,6 +45,7 @@ extern_c! { is_required_method: BOOL, is_instance_method: BOOL, ); + #[cfg(not(objfw))] pub fn protocol_addProperty( proto: *mut objc_protocol, name: *const c_char, @@ -40,39 +54,39 @@ extern_c! { is_required_property: BOOL, is_instance_property: BOOL, ); + #[cfg(not(objfw))] pub fn protocol_addProtocol(proto: *mut objc_protocol, addition: *const objc_protocol); - pub fn protocol_conformsToProtocol( - proto: *const objc_protocol, - other: *const objc_protocol, - ) -> BOOL; + #[cfg(not(objfw))] pub fn protocol_copyMethodDescriptionList( proto: *const objc_protocol, is_required_method: BOOL, is_instance_method: BOOL, out_len: *mut c_uint, ) -> *mut objc_method_description; + #[cfg(not(objfw))] pub fn protocol_copyPropertyList( proto: *const objc_protocol, out_len: *mut c_uint, ) -> *mut *const objc_property; + #[cfg(not(objfw))] pub fn protocol_copyProtocolList( proto: *const objc_protocol, out_len: *mut c_uint, ) -> *mut *const objc_protocol; + #[cfg(not(objfw))] pub fn protocol_getMethodDescription( proto: *const objc_protocol, sel: *const objc_selector, is_required_method: BOOL, is_instance_method: BOOL, ) -> objc_method_description; - pub fn protocol_getName(proto: *const objc_protocol) -> *const c_char; + #[cfg(not(objfw))] pub fn protocol_getProperty( proto: *const objc_protocol, name: *const c_char, is_required_property: BOOL, is_instance_property: BOOL, ) -> *const objc_property; - pub fn protocol_isEqual(proto: *const objc_protocol, other: *const objc_protocol) -> BOOL; // #[cfg(macos >= 10.12)] // protocol_copyPropertyList2 diff --git a/objc-sys/src/rc.rs b/objc-sys/src/rc.rs index 62638245c..91b209de7 100644 --- a/objc-sys/src/rc.rs +++ b/objc-sys/src/rc.rs @@ -1,11 +1,13 @@ //! ARC functions. //! -//! All available since macOS `10.7`. +//! Is available in Clang's [documentation][ARC] so these are safe to rely on. //! -//! Defined in `objc-internal.h`, but is available in Clang's -//! [documentation][ARC] so these are safe to rely on. +//! All available since macOS `10.7`. //! -//! On GNUStep these are defined in `objc-arc.h`. +//! Defined in: +//! - Apple: `objc-internal.h` +//! - GNUStep: `objc-arc.h` +//! - ObjFW: `runtime/arc.m` //! //! [ARC]: https://clang.llvm.org/docs/AutomaticReferenceCounting.html#runtime-support> use core::ffi::c_void; @@ -13,11 +15,17 @@ use core::ffi::c_void; use crate::objc_object; extern_c! { - // Autorelease + // Autoreleasepool + // ObjFW: Defined in `autorelease.h`, not available with libobjfw-rt! - pub fn objc_autorelease(value: *mut objc_object) -> *mut objc_object; + #[cfg(not(objfw))] pub fn objc_autoreleasePoolPop(pool: *mut c_void); + #[cfg(not(objfw))] pub fn objc_autoreleasePoolPush() -> *mut c_void; + + // Autorelease + + pub fn objc_autorelease(value: *mut objc_object) -> *mut objc_object; pub fn objc_autoreleaseReturnValue(value: *mut objc_object) -> *mut objc_object; // Weak pointers diff --git a/objc-sys/src/selector.rs b/objc-sys/src/selector.rs index d9caec111..35d968229 100644 --- a/objc-sys/src/selector.rs +++ b/objc-sys/src/selector.rs @@ -13,9 +13,12 @@ pub struct objc_selector { extern_c! { pub fn sel_getName(sel: *const objc_selector) -> *const c_char; - pub fn sel_getUid(name: *const c_char) -> *const objc_selector; pub fn sel_isEqual(lhs: *const objc_selector, rhs: *const objc_selector) -> BOOL; + pub fn sel_registerName(name: *const c_char) -> *const objc_selector; + + #[cfg(not(objfw))] + pub fn sel_getUid(name: *const c_char) -> *const objc_selector; + #[cfg(apple)] pub fn sel_isMapped(sel: *const objc_selector) -> BOOL; - pub fn sel_registerName(name: *const c_char) -> *const objc_selector; } diff --git a/objc-sys/src/types.rs b/objc-sys/src/types.rs index 599647f62..d2f996747 100644 --- a/objc-sys/src/types.rs +++ b/objc-sys/src/types.rs @@ -1,8 +1,6 @@ //! Objective-C type aliases. -use crate::{ - objc_class, objc_ivar, objc_method, objc_object, objc_property, objc_protocol, objc_selector, -}; +use crate::{objc_object, objc_selector}; /// The BOOL typedef for Apple's objc4. /// @@ -55,10 +53,16 @@ mod inner { pub type BOOL = u8; } -// ObjFW??? +// ObjFW #[cfg(objfw)] mod inner { - pub type BOOL = todo!(); + // Defined in ObjFW-RT.h + // C: signed char + // This has changed since v0.90, but we don't support that yet. + pub type BOOL = i8; + + // Note that ObjFW uses `bool` in return types, but that doesn't change + // the ABI, so we'll just use `BOOL` there for ease of use. } /// The Objective-C `BOOL` type. @@ -150,6 +154,9 @@ pub type NSInteger = isize; /// /// ``` /// use objc_sys::NSUInteger; +/// // Or: +/// // use objc2::ffi::NSUInteger; +/// // use objc2_foundation::NSUInteger; /// extern "C" { /// fn some_external_function() -> NSUInteger; /// } @@ -177,39 +184,13 @@ pub const NSUIntegerMax: NSUInteger = NSUInteger::MAX; /// An immutable pointer to a selector. /// -/// Type alias provided for convenience. +/// Type alias provided for convenience. See `objc2::runtime::Sel` for a +/// higher level binding. pub type SEL = *const objc_selector; -/// A mutable pointer to a class. -/// -/// Type alias provided for convenience. -pub type Class = *mut objc_class; - /// A mutable pointer to an object / instance. /// -/// Type alias provided for convenience. +/// Type alias provided for convenience. See `objc2::runtime::Object` for a +/// higher level binding, and `objc2::rc::Id` for an easier way of handling +/// objects. pub type id = *mut objc_object; - -/// An immutable pointer to an instance variable. -/// -/// Type alias provided for convenience. -pub type Ivar = *const objc_ivar; - -/// A mutable pointer to a method. -/// -/// Type alias provided for convenience. -pub type Method = *mut objc_method; - -/// An opaque type that represents a protocol. -/// -/// This is not just a type alias of [`objc_object`], but of [`objc_protocol`] -/// instead, for better type safety. Their internal representation is the same, -/// so the functionality is just a cast away. -/// -/// Type alias provided for convenience. -pub type Protocol = objc_protocol; - -/// A mutable pointer to a property. -/// -/// Type alias provided for convenience. -pub type objc_property_t = *mut objc_property; diff --git a/objc-sys/src/various.rs b/objc-sys/src/various.rs index 0d8b2e4f8..4e7382f7a 100644 --- a/objc-sys/src/various.rs +++ b/objc-sys/src/various.rs @@ -1,9 +1,13 @@ use core::ffi::c_void; +#[cfg(not(objfw))] +use std::os::raw::c_char; +use std::os::raw::c_int; #[cfg(apple)] use std::os::raw::c_uint; -use std::os::raw::{c_char, c_int}; -use crate::{objc_AssociationPolicy, objc_object, OpaqueData, BOOL}; +#[cfg(not(objfw))] +use crate::{objc_AssociationPolicy, BOOL}; +use crate::{objc_object, OpaqueData}; /// An opaque type that represents an instance variable. #[repr(C)] @@ -17,27 +21,33 @@ pub struct objc_ivar { /// Not all APIs are guaranteed to take NULL values; read the docs! pub type IMP = Option; -/// Not available on macOS x86. -/// -/// Remember that this is non-null! -#[cfg(all(apple, not(all(target_os = "macos", target_arch = "x86"))))] -pub type objc_hook_getClass = - unsafe extern "C" fn(name: *const c_char, out_cls: *mut *const crate::objc_class) -> BOOL; - -/// Not available on macOS x86. -/// -/// Remember that this is non-null! -#[cfg(all(apple, not(all(target_os = "macos", target_arch = "x86"))))] -pub type objc_hook_lazyClassNamer = - unsafe extern "C" fn(cls: *const crate::objc_class) -> *const c_char; +// /// Not available on macOS x86. +// /// +// /// Remember that this is non-null! +// #[cfg(all(apple, not(all(target_os = "macos", target_arch = "x86"))))] +// pub type objc_hook_getClass = +// unsafe extern "C" fn(name: *const c_char, out_cls: *mut *const crate::objc_class) -> BOOL; +// +// /// Not available on macOS x86. +// /// +// /// Remember that this is non-null! +// #[cfg(all(apple, not(all(target_os = "macos", target_arch = "x86"))))] +// pub type objc_hook_lazyClassNamer = +// unsafe extern "C" fn(cls: *const crate::objc_class) -> *const c_char; extern_c! { + #[cfg(not(objfw))] pub fn imp_getBlock(imp: IMP) -> *mut objc_object; + #[cfg(not(objfw))] pub fn imp_implementationWithBlock(block: *mut objc_object) -> IMP; + #[cfg(not(objfw))] pub fn imp_removeBlock(imp: IMP) -> BOOL; + #[cfg(not(objfw))] pub fn ivar_getName(ivar: *const objc_ivar) -> *const c_char; + #[cfg(not(objfw))] pub fn ivar_getOffset(ivar: *const objc_ivar) -> isize; + #[cfg(not(objfw))] pub fn ivar_getTypeEncoding(ivar: *const objc_ivar) -> *const c_char; #[cfg(apple)] @@ -49,30 +59,34 @@ extern_c! { pub fn objc_copyImageNames(out_len: *mut c_uint) -> *mut *const c_char; // Instead of being able to change this, it's a weak symbol on GNUStep. - #[cfg(apple)] + #[cfg(any(apple, objfw))] pub fn objc_enumerationMutation(obj: *mut objc_object); - #[cfg(apple)] + #[cfg(any(apple, objfw))] pub fn objc_setEnumerationMutationHandler( handler: Option, ); + #[cfg(not(objfw))] pub fn objc_getAssociatedObject( object: *const objc_object, key: *const c_void, ) -> *const objc_object; + #[cfg(not(objfw))] pub fn objc_setAssociatedObject( object: *mut objc_object, key: *const c_void, value: *mut objc_object, policy: objc_AssociationPolicy, ); + #[cfg(not(objfw))] pub fn objc_removeAssociatedObjects(object: *mut objc_object); - #[cfg(apple)] + #[cfg(any(apple, objfw))] pub fn objc_setForwardHandler(fwd: *mut c_void, fwd_stret: *mut c_void); // These two are defined in: // - Apple: objc-sync.h // - GNUStep: dtable.h / associate.m + // - ObjFW: ObjFW-RT.h pub fn objc_sync_enter(obj: *mut objc_object) -> c_int; pub fn objc_sync_exit(obj: *mut objc_object) -> c_int; diff --git a/objc2-foundation/build.rs b/objc2-foundation/build.rs index 70fdc688a..4e7e791bd 100644 --- a/objc2-foundation/build.rs +++ b/objc2-foundation/build.rs @@ -4,6 +4,6 @@ fn main() { // The script doesn't depend on our code println!("cargo:rerun-if-changed=build.rs"); - let runtime = env::var("DEP_OBJC_RUNTIME").unwrap(); + let runtime = env::var("DEP_OBJC_0_2_RUNTIME").unwrap(); println!("cargo:rustc-cfg={}", runtime); } diff --git a/objc2/build.rs b/objc2/build.rs index 4806c4e28..533227652 100644 --- a/objc2/build.rs +++ b/objc2/build.rs @@ -4,7 +4,7 @@ fn main() { // The script doesn't depend on our code println!("cargo:rerun-if-changed=build.rs"); - let runtime = env::var("DEP_OBJC_RUNTIME").unwrap(); + let runtime = env::var("DEP_OBJC_0_2_RUNTIME").unwrap(); println!("cargo:rustc-cfg={}", runtime); #[cfg(feature = "exception")] @@ -19,7 +19,7 @@ fn main() { let mut builder = cc::Build::new(); builder.file("extern/exception.m"); - for flag in env::var("DEP_OBJC_CC_ARGS").unwrap().split(' ') { + for flag in env::var("DEP_OBJC_0_2_CC_ARGS").unwrap().split(' ') { builder.flag(flag); } diff --git a/objc2/src/runtime.rs b/objc2/src/runtime.rs index 85e3a44c0..7934fb0f1 100644 --- a/objc2/src/runtime.rs +++ b/objc2/src/runtime.rs @@ -53,7 +53,7 @@ pub struct Class(ffi::objc_class); /// A type that represents an Objective-C protocol. #[repr(C)] -pub struct Protocol(ffi::Protocol); +pub struct Protocol(ffi::objc_protocol); macro_rules! standard_pointer_impls { ($($name:ident),*) => { @@ -412,7 +412,7 @@ impl fmt::Debug for Class { } impl Protocol { - pub(crate) fn as_ptr(&self) -> *const ffi::Protocol { + pub(crate) fn as_ptr(&self) -> *const ffi::objc_protocol { self as *const Self as *const _ } diff --git a/tests/build.rs b/tests/build.rs index bea726520..871630270 100644 --- a/tests/build.rs +++ b/tests/build.rs @@ -4,14 +4,14 @@ fn main() { println!("cargo:rerun-if-changed=extern/block_utils.c"); println!("cargo:rerun-if-changed=extern/encode_utils.m"); - let runtime = env::var("DEP_OBJC_RUNTIME").unwrap(); + let runtime = env::var("DEP_OBJC_0_2_RUNTIME").unwrap(); println!("cargo:rustc-cfg={}", runtime); let mut builder = cc::Build::new(); builder.compiler("clang"); builder.file("extern/block_utils.c"); - for flag in env::var("DEP_BLOCK_CC_ARGS").unwrap().split(' ') { + for flag in env::var("DEP_BLOCK_0_0_CC_ARGS").unwrap().split(' ') { builder.flag(flag); } @@ -21,7 +21,7 @@ fn main() { builder.compiler("clang"); builder.file("extern/encode_utils.m"); - for flag in env::var("DEP_OBJC_CC_ARGS").unwrap().split(' ') { + for flag in env::var("DEP_OBJC_0_2_CC_ARGS").unwrap().split(' ') { builder.flag(flag); }