diff --git a/objc_sys/Cargo.toml b/objc_sys/Cargo.toml index f79473ae4..8da275f82 100644 --- a/objc_sys/Cargo.toml +++ b/objc_sys/Cargo.toml @@ -4,10 +4,11 @@ version = "0.0.0" # Remember to update html_root_url in lib.rs authors = ["Mads Marquart "] edition = "2018" -description = "Bindings to the Objective-C core runtime" +description = "Raw bindings to Objective-C runtimes" keywords = ["objective-c", "macos", "ios", "objc_msgSend", "sys"] categories = [ "external-ffi-bindings", + # "no_std" # TODO "os::macos-apis", ] repository = "https://github.com/madsmtm/objc" @@ -20,6 +21,8 @@ exclude = [ "helper-scripts/*", ] +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" diff --git a/objc_sys/README.md b/objc_sys/README.md new file mode 100644 index 000000000..99dbf1839 --- /dev/null +++ b/objc_sys/README.md @@ -0,0 +1,99 @@ +# `objc_sys` + +[![Latest version](https://badgen.net/crates/v/objc_sys)](https://crates.io/crates/objc_sys) +[![License](https://badgen.net/badge/license/MIT/blue)](../LICENSE.txt) +[![Documentation](https://docs.rs/objc_sys/badge.svg)](https://docs.rs/objc_sys/) +[![CI Status](https://github.com/madsmtm/objc/workflows/CI/badge.svg)](https://github.com/madsmtm/objc/actions) + +Raw Rust bindings to core Objective-C runtimes and ABIs. + +## Runtime Support + +`objc_sys` currently supports two runtimes (support for [`ObjFW`] may be +added): +- Apple's [`objc4`] on `cfg(target_vendor = "apple")` targets. +- GNUStep's [`libobjc2`] on all other targets. See their [Objective-C Compiler + and Runtime FAQ][gnustep-faq]. + +This library will probably only ever support ["Modern"][modern] Objective-C +runtimes, since support for reference-counting primitives like `objc_retain` +and `objc_autoreleasePoolPop` is a vital requirement for most applications. + +Just so we're being clear, this rules out the GCC [`libobjc`][gcc-libobjc] +runtime (see [this][gcc-objc-support]), and the [`mulle-objc`] runtime. + +[`ObjFW`]: https://github.com/ObjFW/ObjFW +[`objc4`]: https://opensource.apple.com/source/objc4/ +[`libobjc2`]: https://github.com/gnustep/libobjc2 +[gnustep-faq]: http://wiki.gnustep.org/index.php/Objective-C_Compiler_and_Runtime_FAQ +[modern]: https://en.wikipedia.org/wiki/Objective-C#Modern_Objective-C +[gcc-libobjc]: https://github.com/gcc-mirror/gcc/tree/master/libobjc +[gcc-objc-support]: https://gcc.gnu.org/onlinedocs/gcc/Standards.html#Objective-C-and-Objective-C_002b_002b-Languages +[`mulle-objc`]: https://github.com/mulle-objc/mulle-objc-runtime + + +## Required Versions + +At least `libobjc2` [version 1.7][libobjc2-1.7] or `objc4` +[version 493.9][objc4-493.9] is required. + +`objc4` version 493.9 is available with: +- **macOS 10.7** +- **iOS 5.0** +- **tvOS 9.0** +- **watchOS 1.0** +- **bridgeOS 2.0** + +So those are the **minimum supported Apple versions**. Functionality that was +added after these versions are not (yet?) available in `objc_sys`. + +[libobjc2-1.7]: https://github.com/gnustep/libobjc2/tree/1.7 +[objc4-493.9]: https://opensource.apple.com/source/objc4/ + + +## Configuring linking + +This crate defines the `links` key in `Cargo.toml` so it's possible to +change the linking to `libobjc`, see [the relevant cargo docs][overriding]. + +In the future, this crate may vendor the required source code to automatically +build and link to the runtimes. Choosing static vs. dynamic linking here may +also become an option. + +[overriding]: https://doc.rust-lang.org/cargo/reference/build-scripts.html#overriding-build-scripts + + +## Objective-C compiler ABI configuration + +Objective-C compilers like `clang` and `gcc` requires configuring the calling +ABI to the runtime you're using: +- `clang` uses the [`-fobjc-runtime`] flag, of which there are a few different + [options][clang-objc-kinds]. +- `gcc` uses the [`-fgnu-runtime` or `-fnext-runtime`][gcc-flags] options. + Note that Modern Objective-C features are ill supported. + +This is relevant if you're building and linking to custom Objective-C sources +in a build script. In the future, this crate may expose build script metadata +to help with selecting these (and other required) flags. + +[`-fobjc-runtime`]: https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fobjc-runtime +[clang-objc-kinds]: https://clang.llvm.org/doxygen/classclang_1_1ObjCRuntime.html#af19fe070a7073df4ecc666b44137c4e5 +[gcc-flags]: https://gcc.gnu.org/onlinedocs/gcc/Objective-C-and-Objective-C_002b_002b-Dialect-Options.html + + +## Design choices + +It is recognized that the most primary consumer of this library will be macOS +and secondly iOS applications. Therefore it was chosen not to use `bindgen` in +our build script to not add compilation cost to those targets.1 + +Deprecated functions are also not included for future compability, since they +could be removed in any macOS release, and then our code would break. If you +have a need for these, please open an issue and we can discuss it! + +Some items (in particular the `objc_msgSend_X` family) have `cfg`s that prevent +their usage on different platforms; these are **semver-stable** in the sense +that they will only get less restrictive, never more. + +1 That said, most of this is created with the help of `bindgen`'s +commandline interface, so huge thanks to them! diff --git a/objc_sys/helper-scripts/gen-git.fish b/objc_sys/helper-scripts/gen-git.fish index 1f64b28f1..2a6eca1de 100755 --- a/objc_sys/helper-scripts/gen-git.fish +++ b/objc_sys/helper-scripts/gen-git.fish @@ -2,7 +2,7 @@ # Yup, this is terrible, but was a great help in creating the correct implementations -# Source repo should be a path to https://github.com/madsmtm/objc4.git +# Source repo should be a path to https://github.com/madsmtm/objc4-mirror.git set source_repo $argv[1] set to_repo $argv[2] diff --git a/objc_sys/src/constants.rs b/objc_sys/src/constants.rs index bf2e713c3..3cfed1220 100644 --- a/objc_sys/src/constants.rs +++ b/objc_sys/src/constants.rs @@ -5,16 +5,18 @@ use std::os::raw::c_int; use crate::{id, Class, BOOL}; -/// The equivalent of true for Objective-C's [`BOOL`][`super::BOOL`] type. #[cfg(not(target_arch = "aarch64"))] +/// The equivalent of `true` for Objective-C's [`BOOL`][`super::BOOL`] type. pub const YES: BOOL = 1; #[cfg(target_arch = "aarch64")] +/// The equivalent of `true` for Objective-C's [`BOOL`][`super::BOOL`] type. pub const YES: BOOL = true; -/// The equivalent of false for Objective-C's [`BOOL`][`super::BOOL`] type. #[cfg(not(target_arch = "aarch64"))] +/// The equivalent of `false` for Objective-C's [`BOOL`][`super::BOOL`] type. pub const NO: BOOL = 0; #[cfg(target_arch = "aarch64")] +/// The equivalent of `false` for Objective-C's [`BOOL`][`super::BOOL`] type. pub const NO: BOOL = false; /// A quick alias for a [`null_mut`][`core::ptr::null_mut`] object / instance. diff --git a/objc_sys/src/lib.rs b/objc_sys/src/lib.rs index 11c4b4a18..406496e3b 100644 --- a/objc_sys/src/lib.rs +++ b/objc_sys/src/lib.rs @@ -1,22 +1,28 @@ -//! # Bindings to the objc_objective-C core runtime +//! # Raw bindings to Objective-C runtimes //! -//! # Notable differences +//! These bindings contain almost no documentation, so it is highly +//! recommended to read the documentation of the original libraries: +//! - Apple's [official documentation][apple]. +//! - Apple's `objc4` [source code][objc4] ([`git` mirror][objc4-mirror]), in +//! particular `runtime.h`. +//! - GNUStep's `libobjc2` [source code][libobjc2], in particular `runtime.h`. //! -//! Protocol / objc_protocol is no longer a type alias of objc_object, for -//! better type safety. Their internal representation is the same, so the -//! functionality is just a cast away. -//! -//! Deprecated functions are not included for future compability, since they -//! could be removed at any macOS release, and then our code would break. - -// TODO: Replace `extern "C"` with `extern "C-unwind"`. +//! [apple]: https://developer.apple.com/documentation/objectivec/objective-c_runtime?language=objc +//! [libobjc2]: https://github.com/gnustep/libobjc2/tree/v2.1/objc +//! [objc4]: https://opensource.apple.com/source/objc4/objc4-818.2/runtime/ +//! [objc4-mirror]: https://github.com/madsmtm/objc4-mirror.git #![no_std] #![allow(non_camel_case_types)] #![allow(non_upper_case_globals)] #![doc(html_root_url = "https://docs.rs/objc_sys/0.0.0")] +// TODO: Replace `extern "C"` with `extern "C-unwind"` where applicable. +// See https://rust-lang.github.io/rfcs/2945-c-unwind-abi.html. + // TODO: Remove this and add "no-std" category to Cargo.toml +// Requires a better solution for C-types in `no_std` crates. +// See https://github.com/japaric/cty/issues/14. extern crate std; use core::cell::UnsafeCell; diff --git a/objc_sys/src/message.rs b/objc_sys/src/message.rs index 1695e07b7..e21b5f53d 100644 --- a/objc_sys/src/message.rs +++ b/objc_sys/src/message.rs @@ -16,7 +16,7 @@ pub struct objc_super { pub receiver: *mut objc_object, /// The particular superclass of the instance to message. /// - /// Named `class` in GNUStep and in older Objective-C versions. + /// Named `class` in older Objective-C versions. pub super_class: *const objc_class, } diff --git a/objc_sys/src/method.rs b/objc_sys/src/method.rs index 055f4f597..af1612506 100644 --- a/objc_sys/src/method.rs +++ b/objc_sys/src/method.rs @@ -9,10 +9,13 @@ pub struct objc_method { _p: OpaqueData, } +/// Describes an Objective-C method. #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct objc_method_description { + /// The name of the method. pub name: *const objc_selector, + /// The types of the method arguments. pub types: *const c_char, } diff --git a/objc_sys/src/object.rs b/objc_sys/src/object.rs index 118005e73..491e90538 100644 --- a/objc_sys/src/object.rs +++ b/objc_sys/src/object.rs @@ -3,7 +3,7 @@ use std::os::raw::c_char; use crate::{objc_class, objc_ivar, OpaqueData}; -/// An opaque type that represents an instance of a class. +/// An opaque type that represents an object / an instance of a class. #[repr(C)] pub struct objc_object { // `isa` field is deprecated, so we don't expose it here. diff --git a/objc_sys/src/property.rs b/objc_sys/src/property.rs index 3be35d048..950e2e479 100644 --- a/objc_sys/src/property.rs +++ b/objc_sys/src/property.rs @@ -2,16 +2,22 @@ use std::os::raw::{c_char, c_uint}; use crate::OpaqueData; +/// An opaque type that describes a property in a class. #[repr(C)] pub struct objc_property { _priv: [u8; 0], _p: OpaqueData, } +/// Describes an Objective-C property attribute. #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct objc_property_attribute_t { + /// The name of the attribute. pub name: *const c_char, + /// The value of the attribute + /// + /// Usually NULL. pub value: *const c_char, } diff --git a/objc_sys/src/selector.rs b/objc_sys/src/selector.rs index 92b3318f2..3338eea51 100644 --- a/objc_sys/src/selector.rs +++ b/objc_sys/src/selector.rs @@ -2,7 +2,9 @@ use std::os::raw::c_char; use crate::{OpaqueData, BOOL}; -/// A type that represents a method selector. +/// An opaque type that represents a method selector. +/// +/// Selectors are immutable. #[repr(C)] pub struct objc_selector { _priv: [u8; 0], diff --git a/objc_sys/src/types.rs b/objc_sys/src/types.rs index f98e151c1..4047cd60c 100644 --- a/objc_sys/src/types.rs +++ b/objc_sys/src/types.rs @@ -4,18 +4,22 @@ use crate::{ objc_class, objc_ivar, objc_method, objc_object, objc_property, objc_protocol, objc_selector, }; -/// The Objective-C `BOOL` type. -/// -/// To convert an Objective-C `BOOL` into a Rust [`bool`], compare it with -/// [`NO`][`super::NO`]. #[cfg(all(apple, not(target_arch = "aarch64")))] -pub type BOOL = i8; -/// TODO: Only if STRICT_APPLE_COMPATIBILITY is NOT defined. -/// TODO: (__vxworks || _WIN32) becomes BOOL = c_int. +type BOOL_INNER = i8; + #[cfg(all(gnustep, not(target_arch = "aarch64")))] -pub type BOOL = u8; +// TODO: Only if STRICT_APPLE_COMPATIBILITY is NOT defined. +// TODO: (__vxworks || _WIN32) becomes BOOL = c_int. +type BOOL_INNER = u8; + #[cfg(target_arch = "aarch64")] -pub type BOOL = bool; +type BOOL_INNER = bool; + +/// The Objective-C `BOOL` type. +/// +/// The type of this varies across platforms, so to convert an it into a Rust +/// [`bool`], always compare it with [`YES`][`crate::YES`] or [`NO`][`crate::NO`]. +pub type BOOL = BOOL_INNER; /// An immutable pointer to a selector. /// @@ -44,6 +48,10 @@ 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; diff --git a/objc_sys/src/various.rs b/objc_sys/src/various.rs index 6da437a50..0ad6ecb40 100644 --- a/objc_sys/src/various.rs +++ b/objc_sys/src/various.rs @@ -7,7 +7,7 @@ use std::os::raw::{c_char, c_int}; use crate::objc_class; use crate::{objc_AssociationPolicy, objc_object, OpaqueData, BOOL}; -/// A type that represents an instance variable. +/// An opaque type that represents an instance variable. #[repr(C)] pub struct objc_ivar { _priv: [u8; 0],