about summary refs log tree commit diff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/run-make/apple-sdk-version/foo.rs1
-rw-r--r--tests/run-make/apple-sdk-version/rmake.rs95
2 files changed, 96 insertions, 0 deletions
diff --git a/tests/run-make/apple-sdk-version/foo.rs b/tests/run-make/apple-sdk-version/foo.rs
new file mode 100644
index 00000000000..f328e4d9d04
--- /dev/null
+++ b/tests/run-make/apple-sdk-version/foo.rs
@@ -0,0 +1 @@
+fn main() {}
diff --git a/tests/run-make/apple-sdk-version/rmake.rs b/tests/run-make/apple-sdk-version/rmake.rs
new file mode 100644
index 00000000000..6463ec00403
--- /dev/null
+++ b/tests/run-make/apple-sdk-version/rmake.rs
@@ -0,0 +1,95 @@
+//! Test codegen when setting SDK version on Apple platforms.
+//!
+//! This is important since its a compatibility hazard. The linker will
+//! generate load commands differently based on what minimum OS it can assume.
+//!
+//! See https://github.com/rust-lang/rust/issues/129432.
+
+//@ only-apple
+
+use run_make_support::{apple_os, cmd, run_in_tmpdir, rustc, target};
+
+/// Run vtool to check the `sdk` field in LC_BUILD_VERSION.
+///
+/// On lower deployment targets, LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS and similar
+/// are used instead of LC_BUILD_VERSION, but both name the relevant variable `sdk`.
+#[track_caller]
+fn has_sdk_version(file: &str, version: &str) {
+    cmd("vtool")
+        .arg("-show-build")
+        .arg(file)
+        .run()
+        .assert_stdout_contains(format!("sdk {version}"));
+}
+
+fn main() {
+    // Fetch rustc's inferred deployment target.
+    let current_deployment_target =
+        rustc().target(target()).print("deployment-target").run().stdout_utf8();
+    let current_deployment_target =
+        current_deployment_target.strip_prefix("deployment_target=").unwrap().trim();
+
+    // Fetch current SDK version via. xcrun.
+    //
+    // Assumes a standard Xcode distribution, where e.g. the macOS SDK's Mac Catalyst
+    // and the iPhone Simulator version is the same as for the iPhone SDK.
+    let sdk_name = match apple_os() {
+        "macos" => "macosx",
+        "ios" => "iphoneos",
+        "watchos" => "watchos",
+        "tvos" => "appletvos",
+        "visionos" => "xros",
+        _ => unreachable!(),
+    };
+    let current_sdk_version =
+        cmd("xcrun").arg("--show-sdk-version").arg("--sdk").arg(sdk_name).run().stdout_utf8();
+    let current_sdk_version = current_sdk_version.trim();
+
+    // Check the SDK version in the object file produced by the codegen backend.
+    rustc().target(target()).crate_type("lib").emit("obj").input("foo.rs").output("foo.o").run();
+    // Set to 0, which means not set or "n/a".
+    has_sdk_version("foo.o", "n/a");
+
+    // Check the SDK version in the .rmeta file, as set in `create_object_file`.
+    //
+    // This is just to ensure that we don't set some odd version in `create_object_file`,
+    // if the rmeta file is packed in a different way in the future, this can safely be removed.
+    rustc().target(target()).crate_type("rlib").input("foo.rs").output("libfoo.rlib").run();
+    // Extra .rmeta file (which is encoded as an object file).
+    cmd("ar").arg("-x").arg("libfoo.rlib").arg("lib.rmeta").run();
+    has_sdk_version("lib.rmeta", "n/a");
+
+    // Test that version makes it to the linker.
+    for (crate_type, file_ext) in [("bin", ""), ("dylib", ".dylib")] {
+        // Non-simulator watchOS targets don't support dynamic linking,
+        // for simplicity we disable the test on all watchOS targets.
+        if crate_type == "dylib" && apple_os() == "watchos" {
+            continue;
+        }
+
+        // Test with clang
+        let file_name = format!("foo_cc{file_ext}");
+        rustc()
+            .target(target())
+            .crate_type("bin")
+            .arg("-Clinker-flavor=gcc")
+            .input("foo.rs")
+            .output(&file_name)
+            .run();
+        has_sdk_version(&file_name, current_sdk_version);
+
+        // Test with ld64
+        let file_name = format!("foo_ld{file_ext}");
+        rustc()
+            .target(target())
+            .crate_type("bin")
+            .arg("-Clinker-flavor=ld")
+            .input("foo.rs")
+            .output(&file_name)
+            .run();
+        // FIXME(madsmtm): This uses the current deployment target
+        // instead of the current SDK version like Clang does.
+        // https://github.com/rust-lang/rust/issues/129432
+        has_sdk_version(&file_name, current_deployment_target);
+    }
+}