@@ -23,6 +23,26 @@ fn have_clang() -> bool { |
| 23 | 23 | .unwrap_or(false) |
| 24 | 24 | } |
| 25 | 25 | |
| 26 | +fn have_ld() -> bool { |
| 27 | + Command::new("xcrun") |
| 28 | + .arg("-f") |
| 29 | + .arg("ld") |
| 30 | + .output() |
| 31 | + .map(|o| o.status.success()) |
| 32 | + .unwrap_or(false) |
| 33 | +} |
| 34 | + |
| 35 | +fn sdk_path() -> Option<String> { |
| 36 | + Command::new("xcrun") |
| 37 | + .args(["--sdk", "macosx", "--show-sdk-path"]) |
| 38 | + .output() |
| 39 | + .ok() |
| 40 | + .filter(|out| out.status.success()) |
| 41 | + .and_then(|out| String::from_utf8(out.stdout).ok()) |
| 42 | + .map(|text| text.trim().to_string()) |
| 43 | + .filter(|text| !text.is_empty()) |
| 44 | +} |
| 45 | + |
| 26 | 46 | fn scratch(name: &str) -> PathBuf { |
| 27 | 47 | std::env::temp_dir().join(format!("afs-ld-load-order-{}-{name}", std::process::id())) |
| 28 | 48 | } |
@@ -141,14 +161,18 @@ fn normalize(ids: &[u32]) -> Vec<&'static str> { |
| 141 | 161 | |
| 142 | 162 | #[test] |
| 143 | 163 | fn executable_load_command_order_matches_apple_for_common_surface() { |
| 144 | | - if !have_xcrun() || !have_clang() { |
| 145 | | - eprintln!("skipping: xcrun as / clang unavailable"); |
| 164 | + if !have_xcrun() || !have_ld() { |
| 165 | + eprintln!("skipping: xcrun as / ld unavailable"); |
| 146 | 166 | return; |
| 147 | 167 | } |
| 168 | + let Some(sdk) = sdk_path() else { |
| 169 | + eprintln!("skipping: xcrun --show-sdk-path unavailable"); |
| 170 | + return; |
| 171 | + }; |
| 148 | 172 | |
| 149 | 173 | let obj = scratch("main.o"); |
| 150 | 174 | let ours = scratch("ours-exec"); |
| 151 | | - let theirs = scratch("clang-exec"); |
| 175 | + let theirs = scratch("apple-exec"); |
| 152 | 176 | assemble( |
| 153 | 177 | r#" |
| 154 | 178 | .section __TEXT,__text,regular,pure_instructions |
@@ -159,15 +183,32 @@ fn executable_load_command_order_matches_apple_for_common_surface() { |
| 159 | 183 | &obj, |
| 160 | 184 | ) |
| 161 | 185 | .expect("assemble"); |
| 162 | | - link_with_afs_ld(&[obj.to_str().unwrap(), "-o", ours.to_str().unwrap()]).expect("afs-ld"); |
| 186 | + link_with_afs_ld(&[ |
| 187 | + "-syslibroot", |
| 188 | + &sdk, |
| 189 | + "-lSystem", |
| 190 | + obj.to_str().unwrap(), |
| 191 | + "-o", |
| 192 | + ours.to_str().unwrap(), |
| 193 | + ]) |
| 194 | + .expect("afs-ld"); |
| 163 | 195 | let status = Command::new("xcrun") |
| 164 | | - .args(["--sdk", "macosx", "clang", "-arch", "arm64"]) |
| 165 | | - .arg(&obj) |
| 166 | | - .arg("-o") |
| 196 | + .args([ |
| 197 | + "ld", |
| 198 | + "-arch", |
| 199 | + "arm64", |
| 200 | + "-syslibroot", |
| 201 | + &sdk, |
| 202 | + "-lSystem", |
| 203 | + "-e", |
| 204 | + "_main", |
| 205 | + "-o", |
| 206 | + ]) |
| 167 | 207 | .arg(&theirs) |
| 208 | + .arg(&obj) |
| 168 | 209 | .status() |
| 169 | | - .expect("spawn clang"); |
| 170 | | - assert!(status.success(), "clang link failed"); |
| 210 | + .expect("spawn ld"); |
| 211 | + assert!(status.success(), "ld link failed"); |
| 171 | 212 | |
| 172 | 213 | assert_eq!( |
| 173 | 214 | normalize(&command_ids(&ours)), |
@@ -181,14 +222,18 @@ fn executable_load_command_order_matches_apple_for_common_surface() { |
| 181 | 222 | |
| 182 | 223 | #[test] |
| 183 | 224 | fn dylib_load_command_order_matches_apple_for_common_surface() { |
| 184 | | - if !have_xcrun() || !have_clang() { |
| 185 | | - eprintln!("skipping: xcrun as / clang unavailable"); |
| 225 | + if !have_xcrun() || !have_ld() { |
| 226 | + eprintln!("skipping: xcrun as / ld unavailable"); |
| 186 | 227 | return; |
| 187 | 228 | } |
| 229 | + let Some(sdk) = sdk_path() else { |
| 230 | + eprintln!("skipping: xcrun --show-sdk-path unavailable"); |
| 231 | + return; |
| 232 | + }; |
| 188 | 233 | |
| 189 | 234 | let obj = scratch("lib.o"); |
| 190 | 235 | let ours = scratch("ours.dylib"); |
| 191 | | - let theirs = scratch("clang.dylib"); |
| 236 | + let theirs = scratch("apple.dylib"); |
| 192 | 237 | assemble( |
| 193 | 238 | r#" |
| 194 | 239 | .section __TEXT,__text,regular,pure_instructions |
@@ -201,21 +246,32 @@ fn dylib_load_command_order_matches_apple_for_common_surface() { |
| 201 | 246 | .expect("assemble"); |
| 202 | 247 | link_with_afs_ld(&[ |
| 203 | 248 | "-dylib", |
| 249 | + "-syslibroot", |
| 250 | + &sdk, |
| 251 | + "-lSystem", |
| 204 | 252 | obj.to_str().unwrap(), |
| 205 | 253 | "-o", |
| 206 | 254 | ours.to_str().unwrap(), |
| 207 | 255 | ]) |
| 208 | 256 | .expect("afs-ld dylib"); |
| 209 | 257 | let status = Command::new("xcrun") |
| 210 | | - .args(["--sdk", "macosx", "clang", "-shared", "-arch", "arm64"]) |
| 211 | | - .arg(&obj) |
| 212 | | - .arg("-install_name") |
| 213 | | - .arg("@rpath/libparity.dylib") |
| 214 | | - .arg("-o") |
| 258 | + .args([ |
| 259 | + "ld", |
| 260 | + "-dylib", |
| 261 | + "-arch", |
| 262 | + "arm64", |
| 263 | + "-syslibroot", |
| 264 | + &sdk, |
| 265 | + "-lSystem", |
| 266 | + "-install_name", |
| 267 | + "@rpath/libparity.dylib", |
| 268 | + "-o", |
| 269 | + ]) |
| 215 | 270 | .arg(&theirs) |
| 271 | + .arg(&obj) |
| 216 | 272 | .status() |
| 217 | | - .expect("spawn clang"); |
| 218 | | - assert!(status.success(), "clang dylib link failed"); |
| 273 | + .expect("spawn ld"); |
| 274 | + assert!(status.success(), "ld dylib link failed"); |
| 219 | 275 | |
| 220 | 276 | assert_eq!( |
| 221 | 277 | normalize(&command_ids(&ours)), |
@@ -229,15 +285,19 @@ fn dylib_load_command_order_matches_apple_for_common_surface() { |
| 229 | 285 | |
| 230 | 286 | #[test] |
| 231 | 287 | fn executable_load_command_order_with_dependency_and_rpath_matches_common_surface() { |
| 232 | | - if !have_xcrun() || !have_clang() { |
| 233 | | - eprintln!("skipping: xcrun as / clang unavailable"); |
| 288 | + if !have_xcrun() || !have_clang() || !have_ld() { |
| 289 | + eprintln!("skipping: xcrun as / clang / ld unavailable"); |
| 234 | 290 | return; |
| 235 | 291 | } |
| 292 | + let Some(sdk) = sdk_path() else { |
| 293 | + eprintln!("skipping: xcrun --show-sdk-path unavailable"); |
| 294 | + return; |
| 295 | + }; |
| 236 | 296 | |
| 237 | 297 | let obj = scratch("dep-main.o"); |
| 238 | 298 | let dep = scratch("dep.dylib"); |
| 239 | 299 | let ours = scratch("ours-dep"); |
| 240 | | - let theirs = scratch("clang-dep"); |
| 300 | + let theirs = scratch("apple-dep"); |
| 241 | 301 | assemble( |
| 242 | 302 | r#" |
| 243 | 303 | .section __TEXT,__text,regular,pure_instructions |
@@ -251,6 +311,9 @@ fn executable_load_command_order_with_dependency_and_rpath_matches_common_surfac |
| 251 | 311 | build_test_dylib("int dep(void) { return 1; }\n", &dep, "@rpath/libdep.dylib") |
| 252 | 312 | .expect("build dylib"); |
| 253 | 313 | link_with_afs_ld(&[ |
| 314 | + "-syslibroot", |
| 315 | + &sdk, |
| 316 | + "-lSystem", |
| 254 | 317 | obj.to_str().unwrap(), |
| 255 | 318 | dep.to_str().unwrap(), |
| 256 | 319 | "-rpath", |
@@ -261,15 +324,25 @@ fn executable_load_command_order_with_dependency_and_rpath_matches_common_surfac |
| 261 | 324 | .expect("afs-ld with dep"); |
| 262 | 325 | |
| 263 | 326 | let status = Command::new("xcrun") |
| 264 | | - .args(["--sdk", "macosx", "clang", "-arch", "arm64"]) |
| 327 | + .args([ |
| 328 | + "ld", |
| 329 | + "-arch", |
| 330 | + "arm64", |
| 331 | + "-syslibroot", |
| 332 | + &sdk, |
| 333 | + "-lSystem", |
| 334 | + "-e", |
| 335 | + "_main", |
| 336 | + "-o", |
| 337 | + ]) |
| 338 | + .arg(&theirs) |
| 265 | 339 | .arg(&obj) |
| 266 | 340 | .arg(&dep) |
| 267 | | - .arg("-Wl,-rpath,@executable_path/../lib") |
| 268 | | - .arg("-o") |
| 269 | | - .arg(&theirs) |
| 341 | + .arg("-rpath") |
| 342 | + .arg("@executable_path/../lib") |
| 270 | 343 | .status() |
| 271 | | - .expect("spawn clang"); |
| 272 | | - assert!(status.success(), "clang dep link failed"); |
| 344 | + .expect("spawn ld"); |
| 345 | + assert!(status.success(), "ld dep link failed"); |
| 273 | 346 | |
| 274 | 347 | assert_eq!( |
| 275 | 348 | normalize(&command_ids(&ours)), |