-
Notifications
You must be signed in to change notification settings - Fork 458
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Parse default Apple deployment target from SDK properties #1009
base: main
Are you sure you want to change the base?
Conversation
0384905
to
4da8604
Compare
4da8604
to
8e5b4a6
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you!
Would it makes sense to parse them before build and generate a .rs file, like #1004 does?
If that's not possible, then I'd like you to use json-deserializer or tinyjson, instead of putting a json implementation into cc-rs
@NobodyXu Yeah those could work. I was trying to keep the build time for For a cursory review For build times, it looks like the vendored JSON implementation is the fastest. For reference and the with the JSON handlers:
|
Thanks, so the in-house json implementation is actually the fastest. @BlackHoleFox Would it be possible to parse them before build and generate a .rs file, like #1004 does? I know that it's probably a bit hard and might be impossible since the |
@BlackHoleFox If that's not possible, then I suggest further simplify the json parser by cutting unused features. From the code, it seems that only I'd suggest remove all code except for the one handling objects, null and string, since we don't care about arrays or other stuff. I'd suggest parsing the entire json file into a enum Value<'json> {
Object(BTreeMap<&'json str, Value>),
String(&'json str),
Null,
} Using We also don't need validation of json, we don't care about that, the json provided by macOS sdk should always be valid. Parsing the entire file into a |
@NobodyXu I can trim it down further, yeah. For string escaping though, I disagree with removing support for that. We can have a minimally-useful JSON parser in Do you really think its worth making it basically nothing just to assume the XCode JSON is valid? |
I'm ok keeping the string escapes, I just want to keep cc-rs maintainable. Last time I tried introducing a jobserver impl into cc-rs and I ended up removing it, so I prefer the json implementation to be simple. So how about parsing the json into: enum Value<'json> {
Object(BTreeMap<Cow<'json, str>, Value>),
String(Cow<'json, str>),
Boolean(bool),
Null,
} If we ever need to get more fields (e.g. array, integer, float) then we can add that in future, though I'm pretty sure we won't ever need to parse float. |
I can certainly try, but I'm bad at writing parsers so we will see how well "parse this blob into an |
@NobodyXu BTW, do we think that |
That's a really good question that I have no answer with. |
Yes they always exist inside XCode and it's CommandLineTools variants even past what stable Rust supports. If you use a weird/mangled build environment you can just set the deployment target manually and this codepath will be skipped. |
13f6e17
to
28a2666
Compare
28a2666
to
c5fcd93
Compare
@NobodyXu I wasn't up to being able to figure out the nested object parsing, apologies. I did trim down more unused stuff from the JSON parser though so its now <500 lines. I don't really think this code will need touched but if you want to have a try at this feel free. I don't think removing types from the parsers capabilities simplifies anything though because you still have to know what integers etc look like to skip/error on them. |
let default_deployment_from_sdk = || { | ||
let is_catalyst = matches!(sdk_parts.arch, AppleArchSpec::Catalyst(_)); | ||
// Needs to be both to distinguish between two targets inside the same SDK, like catalyst in the mac SDK. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// Needs to be both to distinguish between two targets inside the same SDK, like catalyst in the mac SDK. | |
// Needs to distinguish between two targets inside the same SDK, like catalyst in the mac SDK. |
.read_str_from_object("DefaultDeploymentTarget", None) | ||
.ok() | ||
.or_else(|| { | ||
self.cargo_output.print_warning(&format_args!( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There're quite a few map_err that makes them hard to read.
Can you extract them into a function that returns Result
, then match
on the return value of that function, log the error and convert the result to Option
there?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wish that we have a large stdlib so we don't have to re-invent the wheels
} | ||
|
||
#[derive(Debug, Clone, Copy, PartialEq)] | ||
pub struct Error(()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you could put a str there to make the error more readable:
pub struct Error(()); | |
pub struct Error(Cow<'static, str>); |
} | ||
|
||
fn bnext_if(&mut self, b: u8) -> bool { | ||
if self.pos < self.bytes.len() && self.bytes[self.pos] == b { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could use self.bytes.get
here
} | ||
|
||
fn bnext(&mut self) -> Option<u8> { | ||
if self.pos < self.bytes.len() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could use self.bytes.get
Ok(acc) | ||
} | ||
|
||
fn read_hex_escape(&mut self) -> Result<()> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is quite complex, I don't think we need hex, could we simplify this somehow, since we don't care about its value?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Most of the complexity comes from the handling of unpaired surrogates, and turning them into (the correct number of) replacement characters. We can just make that an error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That'd be nice
} | ||
} | ||
|
||
fn skip_line_comment(&mut self) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment stuff is an extension and can be removed.
pub(crate) enum Token<'s> { | ||
Null, | ||
Bool(bool), | ||
NumU(u64), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can just use Num(f64), I think. The i64/u64 is because I had a special use for that code.
NumU(u64), | ||
NumI(i64), | ||
NumF(f64), | ||
StrBorrow(&'s str), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can combine this and the next one as Str(Cow<'s, str>)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that SDKSettings.json
is only available since the macOS 10.14 SDK (not that big of a problem, except that you can actually only compile for 32-bit macOS using a 10.13 SDK). The file SDKSettings.plist
has been available since the 10.0 SDK.
Additionally, I think it's a really bad idea to pull in own json parser.
So maybe we could resolve both of these concerns by shelling out to plutil
? E.g. the following can be used to extract a version from the version map:
plutil -extract VersionMap.macOS_iOSMac."14\.3" raw /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/SDKSettings.plist
According to the man page of
But it indeed has better support than |
Huh indeed, I guess I miscounted supported macOS host versions to XCode releases when I started on this PR. I will start on replacing this with |
They could also just set |
This actually seems like its a badly written replacement for |
The question is if anyone does cross compiling without setting it though. I don't have any data for it. |
I think it's fine to ask them to set it when cross-compiling. I'd care if we broke it without a way forward (e.g. if we had a hard dep on plutil without an env var workaround), but this seems fine to me. |
plutil seems to be only available in macOS 10.2 and later man page of plutil:
Maybe we can fallback to the |
The minimum supported macOS version for |
Thanks, that's good to hear, though |
Please forgive me if I am not fully understanding the issues here. Might On macOS Sonoma (version 14.4.1), the following all give 14.4:
In addition, both
The advantage to On macOS Sierra (version 10.12), the following both give the same result:
While While macOS older than 10.12 is not supported by Rust, MacPorts stills attempts to maintain older systems. |
That sounds nice, we could use |
I don't think that has an effect on crosscompiling with any fallback, so we should just use one. None of these tools are on Linux etc so I wouldn't expect crosscompilers to have any. I'm fine with switching to use |
I think it's fine for us to defer use of plistbuddy to a future PR. (Or, frankly, to not use it at all -- maintenance of this crate is already hard enough without supporting out of date macOS versions...). |
That's true, I agree |
Please forgive me if I was unclear. |
This implements a slimmed-down version of clang's default version parsing to obtain default deployment targets in Apple's ecosystem. As opposed to using
xcrun
, this gets a correct value in all XCode installations and should be more reliable since its the same thingclang
does (which we emulate in some places).It also means compilation for Apple targets on non-macOS hosts (with the right SDK) should get the right version again too (no more
xcrun
), even if that's not officially supported.Closes #1001 and #963