Skip to content

Commit

Permalink
Work on ObjFW support in objc-sys
Browse files Browse the repository at this point in the history
A lot of functionality is not yet available in ObjFW, this is now reflected in the API.

Support for ObjFW is still not enabled, see #117 for that.
  • Loading branch information
madsmtm committed Apr 4, 2022
1 parent 56c6ca8 commit 5dbf3e7
Show file tree
Hide file tree
Showing 14 changed files with 175 additions and 54 deletions.
37 changes: 27 additions & 10 deletions objc-sys/build.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::env;
use std::{env, path::Path};

/// TODO: Better validation of this
///
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
}
};

Expand All @@ -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_[version]_CC_ARGS
);

if let Runtime::ObjFW(_) = &runtime {
// Add compability headers to make `#include <objc/objc.h>` 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");
}
}
1 change: 1 addition & 0 deletions objc-sys/compat-headers-objfw/objc/objc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#import <ObjFW-RT/ObjFW-RT.h>
1 change: 1 addition & 0 deletions objc-sys/compat-headers-objfw/objc/runtime.h
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#import <ObjFW-RT/ObjFW-RT.h>
29 changes: 25 additions & 4 deletions objc-sys/src/class.rs
Original file line number Diff line number Diff line change
@@ -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)]
Expand All @@ -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,
Expand All @@ -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;
Expand All @@ -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,
Expand All @@ -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;
Expand All @@ -115,14 +133,17 @@ extern_c! {
imp: IMP,
types: *const c_char,
) -> IMP;
#[cfg(not(objfw))]
pub fn class_replaceProperty(
cls: *mut objc_class,
name: *const c_char,
attributes: *const objc_property_attribute_t,
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);
Expand Down
9 changes: 8 additions & 1 deletion objc-sys/src/exception.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<unsafe extern "C" fn(exception: *mut objc_object)>;

/// Only available on macOS.
///
/// Remember that this is non-null!
Expand All @@ -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`].
///
Expand All @@ -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;
Expand Down
19 changes: 12 additions & 7 deletions objc-sys/src/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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

Expand All @@ -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

Expand All @@ -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

Expand Down
10 changes: 8 additions & 2 deletions objc-sys/src/method.rs
Original file line number Diff line number Diff line change
@@ -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)]
Expand All @@ -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);
Expand Down
20 changes: 17 additions & 3 deletions objc-sys/src/object.rs
Original file line number Diff line number Diff line change
@@ -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)]
Expand All @@ -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)]
Expand All @@ -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;
Expand Down
6 changes: 5 additions & 1 deletion objc-sys/src/property.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -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,
Expand Down
Loading

0 comments on commit 5dbf3e7

Please sign in to comment.