Skip to content

Commit 308af65

Browse files
committed
Redo linking logic
- Use X_DEPLOYMENT_TARGET to figure out apple versions - Use RUNTIME_VERSION to figure out GNUStep versions - More detailed README instructions
1 parent 1c7c8fc commit 308af65

File tree

2 files changed

+104
-112
lines changed

2 files changed

+104
-112
lines changed

objc2_sys/README.md

Lines changed: 59 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -10,56 +10,76 @@ Raw Rust bindings to core Objective-C runtimes and ABIs.
1010

1111
## Runtime Support
1212

13-
`objc2_sys` currently supports three runtimes (support for [`ObjFW`] may be
14-
added):
15-
- Apple's [`objc4`] \(default on `target_vendor = "apple"`\).
16-
- GNUStep's [`libobjc2`] \(default on other systems\).
17-
- Window's [`WinObjC`] uses [a fork][ms-libobjc2] of GNUStep's `libobjc2`
18-
based on version 1.8 with very few user-facing changes \(default on
19-
`target_os = "windows"`\).
20-
21-
A default is chosen automatically from the compilation target as seen above,
22-
but it is recommended to set the `OBJC_RUNTIME` environment variable to the
23-
desired runtime when building (see below).
13+
### Apple's [`objc4`](https://opensource.apple.com/source/objc4/)
14+
15+
This is the default on Apple platforms:
16+
```rust , ignore
17+
#[cfg(any(
18+
target_os = "macos",
19+
target_os = "ios",
20+
target_os = "tvos",
21+
target_os = "watchos",
22+
))]
23+
```
24+
25+
The supported runtime version (higher versions lets the compiler enable newer
26+
optimizations, at the cost of not supporting older operating systems) can be
27+
chosen using the standard `X_DEPLOYMENT_TARGET` environment variables:
28+
- macOS: `MACOSX_DEPLOYMENT_TARGET`
29+
- Default: `10.7` ([same as Rust](https://github.com/rust-lang/rust/blob/1.56.0/compiler/rustc_target/src/spec/apple_base.rs#L67))
30+
- Minimum: `10.7`
31+
- iOS: `IPHONEOS_DEPLOYMENT_TARGET`
32+
- Default: `7.0` ([same as Rust](https://github.com/rust-lang/rust/blob/1.56.0/compiler/rustc_target/src/spec/apple_base.rs#L92))
33+
- Minimum: `5.0` (theoretically)
34+
- tvOS: `TVOS_DEPLOYMENT_TARGET`
35+
- Default: TODO
36+
- Minimum: `9.0` (theoretically)
37+
- watchOS: `WATCHOS_DEPLOYMENT_TARGET`
38+
- Default: TODO
39+
- Minimum: `1.0` (theoretically)
40+
41+
42+
### Window's [`WinObjC`](https://github.com/microsoft/WinObjC)
43+
44+
This is the default on `#[cfg(target_os = "windows")]`.
45+
46+
This is essentially just [a fork](https://github.com/microsoft/libobjc2) based
47+
on GNUStep's `libobjc2` version 1.8, with very few user-facing changes.
48+
49+
50+
### GNUStep's [`libobjc2`](https://github.com/gnustep/libobjc2)
51+
52+
This is the default on all other systems.
53+
54+
The version can be chosen by setting the standard (used by GNUStep already)
55+
`RUNTIME_VERSION` environment variable to one of the following:
56+
- `gnustep-1.7`
57+
- `gnustep-1.8` (default)
58+
- `gnustep-1.9`
59+
- `gnustep-2.0`
60+
- `gnustep-2.1`
61+
62+
If you wish to force using the GNUStep runtime on Apple or Windows systems,
63+
set the `RUNTIME_VERSION` environment variable to one of the values above.
64+
65+
66+
### Other runtimes
2467

2568
This library will probably only ever support ["Modern"][modern] Objective-C
2669
runtimes, since support for reference-counting primitives like `objc_retain`
2770
and `objc_autoreleasePoolPop` is a vital requirement for most applications.
2871

2972
Just so we're being clear, this rules out the GCC [`libobjc`][gcc-libobjc]
30-
runtime (see [this][gcc-objc-support]), and the [`mulle-objc`] runtime. More
31-
information on different runtimes can be found in GNUStep's [Objective-C
32-
Compiler and Runtime FAQ][gnustep-faq].
73+
runtime (see [this][gcc-objc-support]), and the [`mulle-objc`] runtime. (But
74+
support for [`ObjFW`] may be added). More information on different runtimes
75+
can be found in GNUStep's [Objective-C Compiler and Runtime FAQ][gnustep-faq].
3376

34-
[`ObjFW`]: https://github.com/ObjFW/ObjFW
35-
[`objc4`]: https://opensource.apple.com/source/objc4/
36-
[`libobjc2`]: https://github.com/gnustep/libobjc2
37-
[gnustep-faq]: http://wiki.gnustep.org/index.php/Objective-C_Compiler_and_Runtime_FAQ
38-
[`WinObjC`]: https://github.com/microsoft/WinObjC
39-
[ms-libobjc2]: https://github.com/microsoft/libobjc2
4077
[modern]: https://en.wikipedia.org/wiki/Objective-C#Modern_Objective-C
4178
[gcc-libobjc]: https://github.com/gcc-mirror/gcc/tree/master/libobjc
4279
[gcc-objc-support]: https://gcc.gnu.org/onlinedocs/gcc/Standards.html#Objective-C-and-Objective-C_002b_002b-Languages
4380
[`mulle-objc`]: https://github.com/mulle-objc/mulle-objc-runtime
44-
45-
46-
## Required Versions
47-
48-
At least `libobjc2` [version 1.7][libobjc2-1.7] or `objc4`
49-
[version 493.9][objc4-493.9] is required.
50-
51-
`objc4` version 493.9 is available with:
52-
- **macOS 10.7**
53-
- **iOS 5.0**
54-
- **tvOS 9.0**
55-
- **watchOS 1.0**
56-
- **bridgeOS 2.0**
57-
58-
So those are the **minimum supported Apple versions**. Functionality that was
59-
added after these versions are not (yet?) available in `objc2_sys`.
60-
61-
[libobjc2-1.7]: https://github.com/gnustep/libobjc2/tree/1.7
62-
[objc4-493.9]: https://opensource.apple.com/source/objc4/
81+
[`ObjFW`]: https://github.com/ObjFW/ObjFW
82+
[gnustep-faq]: http://wiki.gnustep.org/index.php/Objective-C_Compiler_and_Runtime_FAQ
6383

6484

6585
## Configuring linking

objc2_sys/build.rs

Lines changed: 45 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,8 @@ use std::env;
2121
/// clang version 13's source code:
2222
/// https://github.com/llvm/llvm-project/blob/llvmorg-13.0.0/clang/include/clang/Basic/ObjCRuntime.h
2323
///
24-
/// Anyhow, it's not ultra important, but enables some optimizations if this
25-
/// is specified. In the future, Rust will hopefully get something similar to
26-
/// clang's `-mmacosx-version-min`, and then we won't need this for the
27-
/// Apple runtimes.
24+
/// In short, it's not ultra important, but enables some optimizations if this
25+
/// is specified.
2826
type Version = Option<String>;
2927

3028
// For clang "-fobjc-runtime" support
@@ -37,32 +35,28 @@ enum AppleRuntime {
3735
}
3836
use AppleRuntime::*;
3937

40-
impl AppleRuntime {
41-
fn get_default(target_os: &str) -> Option<Self> {
42-
match target_os {
43-
"macos" => Some(Self::MacOS(None)),
44-
"ios" => Some(Self::IOS(None)),
45-
"watchos" => Some(Self::WatchOS(None)),
46-
"tvos" => Some(Self::TvOS(None)),
47-
_ => None,
48-
}
49-
}
50-
}
51-
5238
enum Runtime {
5339
Apple(AppleRuntime),
54-
GNUStep(Version),
55-
WinObjc(Version),
56-
ObjFW(Version),
40+
GNUStep(u8, u8),
41+
WinObjc,
42+
#[allow(dead_code)]
43+
ObjFW(Option<String>),
5744
}
5845
use Runtime::*;
5946

47+
fn get_env(env: &str) -> Option<String> {
48+
println!("cargo:rerun-if-env-changed={}", env);
49+
match env::var(env) {
50+
Ok(var) => Some(var),
51+
Err(env::VarError::NotPresent) => None,
52+
Err(env::VarError::NotUnicode(var)) => panic!("Invalid unicode for {}: {:?}", env, var),
53+
}
54+
}
55+
6056
fn main() {
6157
// The script doesn't depend on our code
6258
println!("cargo:rerun-if-changed=build.rs");
6359

64-
println!("cargo:rerun-if-env-changed=OBJC_RUNTIME");
65-
6660
// Used to figure out when BOOL should be i8 vs. bool
6761
if env::var("TARGET").unwrap().ends_with("macabi") {
6862
println!("cargo:rustc-cfg=target_abi_macabi");
@@ -71,51 +65,36 @@ fn main() {
7165
// TODO: Figure out when to enable this
7266
// println!("cargo:rustc-cfg=libobjc2_strict_apple_compat");
7367

74-
let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap();
75-
let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap();
76-
77-
// OBJC_RUNTIME syntax: `RUNTIME ("-" VERSION)?`
78-
let runtime = if let Ok(runtime) = env::var("OBJC_RUNTIME") {
79-
let (runtime, version) = if let Some((runtime, version)) = runtime.split_once('-') {
80-
(runtime, Some(version.into()))
81-
} else {
82-
(&*runtime, None)
83-
};
84-
85-
match runtime {
86-
"apple" => {
87-
if version.is_some() {
88-
panic!("Invalid OBJC_RUNTIME: Version doesn't make sense for the `apple` runtime; use `macos`, `ios`, `tvos` or `watchos`");
89-
}
90-
Apple(AppleRuntime::get_default(&target_os).expect("Invalid OBJC_RUNTIME: Target OS invalid for the `apple` runtime; specify manually with `macos`, `ios`, `tvos` or `watchos`"))
91-
}
92-
"gnustep" => GNUStep(version),
93-
"winobjc" => WinObjc(version),
94-
"objfw" => ObjFW(version),
95-
// Support clang "syntax" (`macosx`)
96-
"macos" | "macosx" => Apple(MacOS(version)),
97-
"ios" => Apple(IOS(version)),
98-
"tvos" => Apple(TvOS(version)),
99-
"watchos" => Apple(WatchOS(version)),
100-
_ => {
101-
panic!("Invalid OBJC_RUNTIME: {}", runtime)
102-
}
103-
}
104-
} else {
105-
if target_vendor == "apple" {
106-
Apple(AppleRuntime::get_default(&target_os).unwrap())
107-
} else if target_os == "windows" {
108-
WinObjc(None)
109-
} else {
110-
GNUStep(None)
111-
}
68+
let runtime = match get_env("RUNTIME_VERSION").as_deref() {
69+
// Force using GNUStep on all platforms
70+
Some("gnustep-1.7") => GNUStep(1, 7),
71+
Some("gnustep-1.8") => GNUStep(1, 8),
72+
Some("gnustep-1.9") => GNUStep(1, 9),
73+
Some("gnustep-2.0") => GNUStep(2, 0),
74+
Some("gnustep-2.1") => GNUStep(2, 1),
75+
76+
// Pick the relevant runtime to use, and find target versions
77+
None => match &*env::var("CARGO_CFG_TARGET_OS").unwrap() {
78+
"macos" => Apple(MacOS(Some(
79+
get_env("MACOSX_DEPLOYMENT_TARGET").unwrap_or_else(|| "10.7".into()),
80+
))),
81+
"ios" => Apple(IOS(Some(
82+
get_env("IPHONEOS_DEPLOYMENT_TARGET").unwrap_or_else(|| "7.0".into()),
83+
))),
84+
"tvos" => Apple(TvOS(get_env("TVOS_DEPLOYMENT_TARGET"))),
85+
"watchos" => Apple(WatchOS(get_env("WATCHOS_DEPLOYMENT_TARGET"))),
86+
"windows" => WinObjc,
87+
_ => GNUStep(1, 8), // GNUStep's own default
88+
},
89+
90+
Some(runtime) => panic!("Invalid RUNTIME_VERSION: {}", runtime),
11291
};
11392

11493
// Add `#[cfg(RUNTIME)]` directive
11594
let runtime_cfg = match runtime {
11695
Apple(_) => "apple",
117-
GNUStep(_) => "gnustep",
118-
WinObjc(_) => "winobjc",
96+
GNUStep(_, _) => "gnustep",
97+
WinObjc => "winobjc",
11998
ObjFW(_) => "objfw",
12099
};
121100
println!("cargo:rustc-cfg={}", runtime_cfg);
@@ -140,17 +119,10 @@ fn main() {
140119
}
141120
}
142121
}
143-
GNUStep(version) => {
144-
// GNUStep default in clang is 1.6; we require at least 1.7
145-
let version = version.as_deref().unwrap_or("1.7");
146-
format!("gnustep-{}", version)
147-
}
148-
WinObjc(version) => {
149-
// WinObjc use a small fork of GNUStep version 1.8; so lower
150-
// versions doesn't make sense.
151-
let version = version.as_deref().unwrap_or("1.8");
152-
format!("gnustep-{}", version)
153-
}
122+
// Default in clang is 1.6
123+
GNUStep(major, minor) => format!("gnustep-{}.{}", major, minor),
124+
// WinObjC's libobjc2 is just a fork of gnustep's from version 1.8
125+
WinObjc => "gnustep-1.8".into(),
154126
ObjFW(version) => {
155127
// Default in clang
156128
let _version = version.as_deref().unwrap_or("0.8");
@@ -160,7 +132,7 @@ fn main() {
160132

161133
// Add clang arguments
162134
println!(
163-
"cargo:clang_args=-fobjc-link-runtime -fobjc-arc -fobjc-arc-exceptions -fobjc-exceptions -fobjc-runtime={}",
135+
"cargo:clang_args=-fobjc-arc -fobjc-arc-exceptions -fobjc-exceptions -fobjc-runtime={}",
164136
// `-fobjc-link-runtime` -> people don't need to specify `-lobjc`.
165137

166138
// -fobjc-weak ?

0 commit comments

Comments
 (0)