Repository: mun-lang/mun (language: rust)

Issue:
MacOS build fails with unable to find library for `-lsystem`
Tests on macOS are failing with:

```
thread 'ch02_02_functions_sect_functions_line_56' panicked at 'could not link object file: -arch x86_64: warning: -sdk_version is required when emitting min version load command.  Setting sdk version to match provided min version
-arch x86_64: error: Unable to find library for -lsystem
', crates/mun_codegen/src/assembly.rs:107:10
test ch02_02_functions_sect_functions_line_56 ... FAILED
```


Discussion / hints:

Fix patch:
diff --git a/crates/mun_codegen/Cargo.toml b/crates/mun_codegen/Cargo.toml
index 1bec71fb5..187811f19 100644
--- a/crates/mun_codegen/Cargo.toml
+++ b/crates/mun_codegen/Cargo.toml
@@ -33,6 +33,7 @@ inkwell = { version = "=0.1.0-beta.2", features = ["llvm11-0", "no-libffi-linkin
 by_address = "1.0.4"
 paths = { version="=0.1.0", path="../mun_paths", package="mun_paths"}
 smallvec = "1.6.1"
+once_cell = "1.4.0"
 
 [dev-dependencies]
 abi = { path = "../mun_abi", package = "mun_abi" }
diff --git a/crates/mun_codegen/src/apple.rs b/crates/mun_codegen/src/apple.rs
new file mode 100644
index 000000000..498d462c2
--- /dev/null
+++ b/crates/mun_codegen/src/apple.rs
@@ -0,0 +1,39 @@
+use once_cell::sync::OnceCell;
+use std::{
+    env, io,
+    path::{Path, PathBuf},
+    process::Command,
+};
+
+/// Finds the Apple SDK root directory by checking the `SDKROOT` environment variable or running
+/// `xcrun --show-sdk-path`. The result is cached so multiple calls to this function should be
+/// fast.
+pub fn get_apple_sdk_root() -> Result<&'static Path, String> {
+    static SDK_PATH: OnceCell<PathBuf> = OnceCell::new();
+
+    SDK_PATH
+        .get_or_try_init(|| {
+            if let Ok(sdkroot) = env::var("SDKROOT") {
+                return Ok(PathBuf::from(sdkroot));
+            }
+
+            let res = Command::new("xcrun")
+                .arg("--show-sdk-path")
+                .output()
+                .and_then(|output| {
+                    if output.status.success() {
+                        Ok(String::from_utf8(output.stdout).unwrap())
+                    } else {
+                        let error = String::from_utf8(output.stderr);
+                        let error = format!("process exit with error: {}", error.unwrap());
+                        Err(io::Error::new(io::ErrorKind::Other, &error[..]))
+                    }
+                });
+
+            match res {
+                Ok(output) => Ok(PathBuf::from(output.trim())),
+                Err(e) => Err(format!("failed to get SDK path: {}", e)),
+            }
+        })
+        .map(AsRef::as_ref)
+}
diff --git a/crates/mun_codegen/src/lib.rs b/crates/mun_codegen/src/lib.rs
index a433c13d9..54259a1ce 100644
--- a/crates/mun_codegen/src/lib.rs
+++ b/crates/mun_codegen/src/lib.rs
@@ -22,6 +22,7 @@ mod test;
 
 pub mod value;
 
+mod apple;
 pub(crate) mod intrinsics;
 mod linker;
 mod module_group;
diff --git a/crates/mun_codegen/src/linker.rs b/crates/mun_codegen/src/linker.rs
index 222c8b687..4fb3e84a0 100644
--- a/crates/mun_codegen/src/linker.rs
+++ b/crates/mun_codegen/src/linker.rs
@@ -1,3 +1,4 @@
+use crate::apple::get_apple_sdk_root;
 use mun_target::spec;
 use mun_target::spec::LinkerFlavor;
 use std::fmt;
@@ -11,6 +12,9 @@ pub enum LinkerError {
 
     /// Error in path conversion
     PathError(PathBuf),
+
+    /// Could not locate platform SDK
+    PlatformSdkMissing(String),
 }
 
 impl fmt::Display for LinkerError {
@@ -22,6 +26,9 @@ impl fmt::Display for LinkerError {
                 "path contains invalid UTF-8 characters: {}",
                 path.display()
             ),
+            LinkerError::PlatformSdkMissing(err) => {
+                write!(f, "could not find platform sdk: {}", err)
+            }
         }
     }
 }
@@ -119,6 +126,9 @@ impl Linker for Ld64Linker {
 
         // Link as dynamic library
         self.args.push("-dylib".to_owned());
+
+        let sdk_root = get_apple_sdk_root().map_err(LinkerError::PlatformSdkMissing)?;
+        self.args.push(format!("-L{}/usr/lib", sdk_root.display()));
         self.args.push("-lsystem".to_owned());
 
         // Specify output path
diff --git a/crates/mun_target/src/spec/apple_base.rs b/crates/mun_target/src/spec/apple_base.rs
index 27b944ab3..13a69f643 100644
--- a/crates/mun_target/src/spec/apple_base.rs
+++ b/crates/mun_target/src/spec/apple_base.rs
@@ -12,10 +12,7 @@ fn macos_deployment_target() -> (u32, u32) {
     let deployment_target = env::var("MACOSX_DEPLOYMENT_TARGET").ok();
     let version = deployment_target
         .as_ref()
-        .and_then(|s| {
-            let mut i = s.splitn(2, '.');
-            i.next().and_then(|a| i.next().map(|b| (a, b)))
-        })
+        .and_then(|s| s.split_once('.'))
         .and_then(|(a, b)| {
             a.parse::<u32>()
                 .and_then(|a| b.parse::<u32>().map(|b| (a, b)))


Test patch: