Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit e77a8f4

Browse files
committed
Auto merge of #139037 - jhpratt:rollup-4c74y8a, r=jhpratt
Rollup of 6 pull requests Successful merges: - #138720 (Specify a concrete stack size in channel tests) - #139010 (Improve `xcrun` error handling) - #139021 (std: get rid of pre-Vista fallback code) - #139025 (Do not trim paths in MIR validator) - #139026 (Use `abs_diff` where applicable) - #139030 (saethlin goes on vacation) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 3f690c2 + 6371892 commit e77a8f4

File tree

19 files changed

+384
-147
lines changed

19 files changed

+384
-147
lines changed

‎compiler/rustc_codegen_ssa/messages.ftl

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ codegen_ssa_apple_deployment_target_invalid =
1010
codegen_ssa_apple_deployment_target_too_low =
1111
deployment target in {$env_var} was set to {$version}, but the minimum supported by `rustc` is {$os_min}
1212
13-
codegen_ssa_apple_sdk_error_sdk_path = failed to get {$sdk_name} SDK path: {$error}
14-
1513
codegen_ssa_archive_build_failure = failed to build archive at `{$path}`: {$error}
1614
1715
codegen_ssa_atomic_compare_exchange = Atomic compare-exchange intrinsic missing failure memory ordering
@@ -391,8 +389,6 @@ codegen_ssa_unknown_atomic_ordering = unknown ordering in atomic intrinsic
391389
392390
codegen_ssa_unknown_reuse_kind = unknown cgu-reuse-kind `{$kind}` specified
393391
394-
codegen_ssa_unsupported_arch = unsupported arch `{$arch}` for os `{$os}`
395-
396392
codegen_ssa_unsupported_instruction_set = target does not support `#[instruction_set]`
397393
398394
codegen_ssa_unsupported_link_self_contained = option `-C link-self-contained` is not supported on this target
@@ -402,3 +398,20 @@ codegen_ssa_use_cargo_directive = use the `cargo:rustc-link-lib` directive to sp
402398
codegen_ssa_version_script_write_failure = failed to write version script: {$error}
403399
404400
codegen_ssa_visual_studio_not_installed = you may need to install Visual Studio build tools with the "C++ build tools" workload
401+
402+
codegen_ssa_xcrun_command_line_tools_insufficient =
403+
when compiling for iOS, tvOS, visionOS or watchOS, you need a full installation of Xcode
404+
405+
codegen_ssa_xcrun_failed_invoking = invoking `{$command_formatted}` to find {$sdk_name}.sdk failed: {$error}
406+
407+
codegen_ssa_xcrun_found_developer_dir = found active developer directory at "{$developer_dir}"
408+
409+
# `xcrun` already outputs a message about missing Xcode installation, so we only augment it with details about env vars.
410+
codegen_ssa_xcrun_no_developer_dir =
411+
pass the path of an Xcode installation via the DEVELOPER_DIR environment variable, or an SDK with the SDKROOT environment variable
412+
413+
codegen_ssa_xcrun_sdk_path_warning = output of `xcrun` while finding {$sdk_name}.sdk
414+
.note = {$stderr}
415+
416+
codegen_ssa_xcrun_unsuccessful = failed running `{$command_formatted}` to find {$sdk_name}.sdk
417+
.note = {$stdout}{$stderr}

‎compiler/rustc_codegen_ssa/src/back/apple.rs

Lines changed: 153 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,40 @@
11
use std::env;
2+
use std::ffi::OsString;
23
use std::fmt::{Display, from_fn};
34
use std::num::ParseIntError;
5+
use std::path::PathBuf;
6+
use std::process::Command;
47

8+
use itertools::Itertools;
59
use rustc_middle::middle::exported_symbols::SymbolExportKind;
610
use rustc_session::Session;
711
use rustc_target::spec::Target;
12+
use tracing::debug;
813

9-
use crate::errors::AppleDeploymentTarget;
14+
use crate::errors::{AppleDeploymentTarget, XcrunError, XcrunSdkPathWarning};
15+
use crate::fluent_generated as fluent;
1016

1117
#[cfg(test)]
1218
mod tests;
1319

20+
/// The canonical name of the desired SDK for a given target.
21+
pub(super) fn sdk_name(target: &Target) -> &'static str {
22+
match (&*target.os, &*target.abi) {
23+
("macos", "") => "MacOSX",
24+
("ios", "") => "iPhoneOS",
25+
("ios", "sim") => "iPhoneSimulator",
26+
// Mac Catalyst uses the macOS SDK
27+
("ios", "macabi") => "MacOSX",
28+
("tvos", "") => "AppleTVOS",
29+
("tvos", "sim") => "AppleTVSimulator",
30+
("visionos", "") => "XROS",
31+
("visionos", "sim") => "XRSimulator",
32+
("watchos", "") => "WatchOS",
33+
("watchos", "sim") => "WatchSimulator",
34+
(os, abi) => unreachable!("invalid os '{os}' / abi '{abi}' combination for Apple target"),
35+
}
36+
}
37+
1438
pub(super) fn macho_platform(target: &Target) -> u32 {
1539
match (&*target.os, &*target.abi) {
1640
("macos", _) => object::macho::PLATFORM_MACOS,
@@ -253,3 +277,131 @@ pub(super) fn add_version_to_llvm_target(
253277
format!("{arch}-{vendor}-{os}{major}.{minor}.{patch}")
254278
}
255279
}
280+
281+
pub(super) fn get_sdk_root(sess: &Session) -> Option<PathBuf> {
282+
let sdk_name = sdk_name(&sess.target);
283+
284+
match xcrun_show_sdk_path(sdk_name, sess.verbose_internals()) {
285+
Ok((path, stderr)) => {
286+
// Emit extra stderr, such as if `-verbose` was passed, or if `xcrun` emitted a warning.
287+
if !stderr.is_empty() {
288+
sess.dcx().emit_warn(XcrunSdkPathWarning { sdk_name, stderr });
289+
}
290+
Some(path)
291+
}
292+
Err(err) => {
293+
let mut diag = sess.dcx().create_err(err);
294+
295+
// Recognize common error cases, and give more Rust-specific error messages for those.
296+
if let Some(developer_dir) = xcode_select_developer_dir() {
297+
diag.arg("developer_dir", &developer_dir);
298+
diag.note(fluent::codegen_ssa_xcrun_found_developer_dir);
299+
if developer_dir.as_os_str().to_string_lossy().contains("CommandLineTools") {
300+
if sdk_name != "MacOSX" {
301+
diag.help(fluent::codegen_ssa_xcrun_command_line_tools_insufficient);
302+
}
303+
}
304+
} else {
305+
diag.help(fluent::codegen_ssa_xcrun_no_developer_dir);
306+
}
307+
308+
diag.emit();
309+
None
310+
}
311+
}
312+
}
313+
314+
/// Invoke `xcrun --sdk $sdk_name --show-sdk-path` to get the SDK path.
315+
///
316+
/// The exact logic that `xcrun` uses is unspecified (see `man xcrun` for a few details), and may
317+
/// change between macOS and Xcode versions, but it roughly boils down to finding the active
318+
/// developer directory, and then invoking `xcodebuild -sdk $sdk_name -version` to get the SDK
319+
/// details.
320+
///
321+
/// Finding the developer directory is roughly done by looking at, in order:
322+
/// - The `DEVELOPER_DIR` environment variable.
323+
/// - The `/var/db/xcode_select_link` symlink (set by `xcode-select --switch`).
324+
/// - `/Applications/Xcode.app` (hardcoded fallback path).
325+
/// - `/Library/Developer/CommandLineTools` (hardcoded fallback path).
326+
///
327+
/// Note that `xcrun` caches its result, but with a cold cache this whole operation can be quite
328+
/// slow, especially so the first time it's run after a reboot.
329+
fn xcrun_show_sdk_path(
330+
sdk_name: &'static str,
331+
verbose: bool,
332+
) -> Result<(PathBuf, String), XcrunError> {
333+
let mut cmd = Command::new("xcrun");
334+
if verbose {
335+
cmd.arg("--verbose");
336+
}
337+
// The `--sdk` parameter is the same as in xcodebuild, namely either an absolute path to an SDK,
338+
// or the (lowercase) canonical name of an SDK.
339+
cmd.arg("--sdk");
340+
cmd.arg(&sdk_name.to_lowercase());
341+
cmd.arg("--show-sdk-path");
342+
343+
// We do not stream stdout/stderr lines directly to the user, since whether they are warnings or
344+
// errors depends on the status code at the end.
345+
let output = cmd.output().map_err(|error| XcrunError::FailedInvoking {
346+
sdk_name,
347+
command_formatted: format!("{cmd:?}"),
348+
error,
349+
})?;
350+
351+
// It is fine to do lossy conversion here, non-UTF-8 paths are quite rare on macOS nowadays
352+
// (only possible with the HFS+ file system), and we only use it for error messages.
353+
let stderr = String::from_utf8_lossy_owned(output.stderr);
354+
if !stderr.is_empty() {
355+
debug!(stderr, "original xcrun stderr");
356+
}
357+
358+
// Some versions of `xcodebuild` output beefy errors when invoked via `xcrun`,
359+
// but these are usually red herrings.
360+
let stderr = stderr
361+
.lines()
362+
.filter(|line| {
363+
!line.contains("Writing error result bundle")
364+
&& !line.contains("Requested but did not find extension point with identifier")
365+
})
366+
.join("\n");
367+
368+
if output.status.success() {
369+
Ok((stdout_to_path(output.stdout), stderr))
370+
} else {
371+
// Output both stdout and stderr, since shims of `xcrun` (such as the one provided by
372+
// nixpkgs), do not always use stderr for errors.
373+
let stdout = String::from_utf8_lossy_owned(output.stdout).trim().to_string();
374+
Err(XcrunError::Unsuccessful {
375+
sdk_name,
376+
command_formatted: format!("{cmd:?}"),
377+
stdout,
378+
stderr,
379+
})
380+
}
381+
}
382+
383+
/// Invoke `xcode-select --print-path`, and return the current developer directory.
384+
///
385+
/// NOTE: We don't do any error handling here, this is only used as a canary in diagnostics (`xcrun`
386+
/// will have already emitted the relevant error information).
387+
fn xcode_select_developer_dir() -> Option<PathBuf> {
388+
let mut cmd = Command::new("xcode-select");
389+
cmd.arg("--print-path");
390+
let output = cmd.output().ok()?;
391+
if !output.status.success() {
392+
return None;
393+
}
394+
Some(stdout_to_path(output.stdout))
395+
}
396+
397+
fn stdout_to_path(mut stdout: Vec<u8>) -> PathBuf {
398+
// Remove trailing newline.
399+
if let Some(b'\n') = stdout.last() {
400+
let _ = stdout.pop().unwrap();
401+
}
402+
#[cfg(unix)]
403+
let path = <OsString as std::os::unix::ffi::OsStringExt>::from_vec(stdout);
404+
#[cfg(not(unix))] // Unimportant, this is only used on macOS
405+
let path = OsString::from(String::from_utf8(stdout).unwrap());
406+
PathBuf::from(path)
407+
}

‎compiler/rustc_codegen_ssa/src/back/apple/tests.rs

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::{add_version_to_llvm_target, parse_version};
1+
use super::*;
22

33
#[test]
44
fn test_add_version_to_llvm_target() {
@@ -19,3 +19,69 @@ fn test_parse_version() {
1919
assert_eq!(parse_version("10.12.6"), Ok((10, 12, 6)));
2020
assert_eq!(parse_version("99999999"), Ok((9999, 99, 99)));
2121
}
22+
23+
#[test]
24+
#[cfg_attr(not(target_os = "macos"), ignore = "xcode-select is only available on macOS")]
25+
fn lookup_developer_dir() {
26+
let _developer_dir = xcode_select_developer_dir().unwrap();
27+
}
28+
29+
#[test]
30+
#[cfg_attr(not(target_os = "macos"), ignore = "xcrun is only available on macOS")]
31+
fn lookup_sdk() {
32+
let (sdk_path, stderr) = xcrun_show_sdk_path("MacOSX", false).unwrap();
33+
// Check that the found SDK is valid.
34+
assert!(sdk_path.join("SDKSettings.plist").exists());
35+
assert_eq!(stderr, "");
36+
37+
// Test that the SDK root is a subdir of the developer directory.
38+
if let Some(developer_dir) = xcode_select_developer_dir() {
39+
// Only run this test if SDKROOT is not set (otherwise xcrun may look up via. that).
40+
if std::env::var_os("SDKROOT").is_some() {
41+
assert!(sdk_path.starts_with(&developer_dir));
42+
}
43+
}
44+
}
45+
46+
#[test]
47+
#[cfg_attr(not(target_os = "macos"), ignore = "xcrun is only available on macOS")]
48+
fn lookup_sdk_verbose() {
49+
let (_, stderr) = xcrun_show_sdk_path("MacOSX", true).unwrap();
50+
// Newer xcrun versions should emit something like this:
51+
//
52+
// xcrun: note: looking up SDK with 'xcodebuild -sdk macosx -version Path'
53+
// xcrun: note: xcrun_db = '/var/.../xcrun_db'
54+
// xcrun: note: lookup resolved to: '...'
55+
// xcrun: note: database key is: ...
56+
//
57+
// Or if the value is already cached, something like this:
58+
//
59+
// xcrun: note: database key is: ...
60+
// xcrun: note: lookup resolved in '/var/.../xcrun_db' : '...'
61+
assert!(
62+
stderr.contains("xcrun: note: lookup resolved"),
63+
"stderr should contain lookup note: {stderr}",
64+
);
65+
}
66+
67+
#[test]
68+
#[cfg_attr(not(target_os = "macos"), ignore = "xcrun is only available on macOS")]
69+
fn try_lookup_invalid_sdk() {
70+
// As a proxy for testing all the different ways that `xcrun` can fail,
71+
// test the case where an SDK was not found.
72+
let err = xcrun_show_sdk_path("invalid", false).unwrap_err();
73+
let XcrunError::Unsuccessful { stderr, .. } = err else {
74+
panic!("unexpected error kind: {err:?}");
75+
};
76+
// Either one of (depending on if using Command Line Tools or full Xcode):
77+
// xcrun: error: SDK "invalid" cannot be located
78+
// xcodebuild: error: SDK "invalid" cannot be located.
79+
assert!(
80+
stderr.contains(r#"error: SDK "invalid" cannot be located"#),
81+
"stderr should contain xcodebuild note: {stderr}",
82+
);
83+
assert!(
84+
stderr.contains("xcrun: error: unable to lookup item 'Path' in SDK 'invalid'"),
85+
"stderr should contain xcrun note: {stderr}",
86+
);
87+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /