fortrangoingonforty/armfortas / 01efd93

Browse files

Resolve afs-ld via AFS_LD env var and forward -L/-l/-rpath flags

AFS_LD=1 (or any non-falsy value) now picks the sibling afs-ld
binary alongside the armfortas executable, in addition to the
existing AFS_LD_PATH override that names a specific path. The
afs-ld backend now forwards library_search_paths, link_libs, and
rpath through to the linker instead of erroring out, so the same
driver invocation works under both system ld and afs-ld for the
common cases.

Test: hello_world_runs_through_driver_with_afs_ld_enable_flag.
Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
01efd93925633a7bfde3a8c6e30be695c985894e
Parents
ff3870d
Tree
da996bb

2 changed files

StatusFile+-
M src/driver/mod.rs 45 12
M tests/standalone_toolchain.rs 76 1
src/driver/mod.rsmodified
@@ -1577,7 +1577,7 @@ fn link(obj: &Path, output: &Path, opts: &Options) -> Result<(), String> {
15771577
 /// Link prebuilt objects and archives with the runtime to produce a
15781578
 /// binary or shared library, preserving the user-supplied input order.
15791579
 fn link_inputs(inputs: &[PathBuf], output: &Path, opts: &Options) -> Result<(), String> {
1580
-    if let Some(linker) = env_override("AFS_LD_PATH") {
1580
+    if let Some(linker) = afs_ld_override() {
15811581
         return link_inputs_with_afs_ld(&linker, inputs, output, opts);
15821582
     }
15831583
 
@@ -1622,19 +1622,10 @@ fn link_inputs_with_afs_ld(
16221622
     opts: &Options,
16231623
 ) -> Result<(), String> {
16241624
     if opts.shared {
1625
-        return Err("AFS_LD_PATH override does not yet support shared-library links".into());
1626
-    }
1627
-    if !opts.library_search_paths.is_empty() {
1628
-        return Err("AFS_LD_PATH override does not yet support -L search paths".into());
1629
-    }
1630
-    if !opts.link_libs.is_empty() {
1631
-        return Err("AFS_LD_PATH override does not yet support -l linker inputs".into());
1632
-    }
1633
-    if !opts.rpath.is_empty() {
1634
-        return Err("AFS_LD_PATH override does not yet support -rpath".into());
1625
+        return Err("AFS_LD override does not yet support shared-library links".into());
16351626
     }
16361627
     if opts.static_link {
1637
-        return Err("AFS_LD_PATH override does not yet support static-link mode".into());
1628
+        return Err("AFS_LD override does not yet support static-link mode".into());
16381629
     }
16391630
 
16401631
     let rt_path = find_runtime_lib()?;
@@ -1652,6 +1643,7 @@ fn link_inputs_with_afs_ld(
16521643
     }
16531644
     args.push(rt_path);
16541645
     args.push(libsystem_tbd);
1646
+    push_afs_ld_link_flags(&mut args, opts);
16551647
 
16561648
     let output = Command::new(linker)
16571649
         .args(&args)
@@ -1694,6 +1686,47 @@ fn push_link_flags(args: &mut Vec<String>, opts: &Options) {
16941686
     }
16951687
 }
16961688
 
1689
+fn push_afs_ld_link_flags(args: &mut Vec<String>, opts: &Options) {
1690
+    for dir in &opts.library_search_paths {
1691
+        args.push("-L".into());
1692
+        args.push(dir.to_string_lossy().into_owned());
1693
+    }
1694
+    for lib in &opts.link_libs {
1695
+        args.push("-l".into());
1696
+        args.push(lib.clone());
1697
+    }
1698
+    for path in &opts.rpath {
1699
+        args.push("-rpath".into());
1700
+        args.push(path.to_string_lossy().into_owned());
1701
+    }
1702
+}
1703
+
1704
+fn afs_ld_override() -> Option<String> {
1705
+    if let Some(linker) = env_override("AFS_LD_PATH") {
1706
+        return Some(linker);
1707
+    }
1708
+    let enabled = env_override("AFS_LD")?;
1709
+    if matches!(
1710
+        enabled.as_str(),
1711
+        "0" | "false" | "FALSE" | "no" | "NO" | "off" | "OFF"
1712
+    ) {
1713
+        return None;
1714
+    }
1715
+    Some(resolve_sibling_tool("afs-ld"))
1716
+}
1717
+
1718
+fn resolve_sibling_tool(name: &str) -> String {
1719
+    if let Ok(exe) = std::env::current_exe() {
1720
+        if let Some(dir) = exe.parent() {
1721
+            let candidate = dir.join(name);
1722
+            if candidate.is_file() {
1723
+                return candidate.to_string_lossy().into_owned();
1724
+            }
1725
+        }
1726
+    }
1727
+    name.into()
1728
+}
1729
+
16971730
 fn env_override(name: &str) -> Option<String> {
16981731
     std::env::var(name)
16991732
         .ok()
tests/standalone_toolchain.rsmodified
@@ -103,12 +103,39 @@ fn compile_with_driver(
103103
     output: &Path,
104104
     extra_envs: &[(&str, &Path)],
105105
     context: &str,
106
+) -> Output {
107
+    compile_with_driver_args(driver, source, output, extra_envs, &[], context)
108
+}
109
+
110
+fn compile_with_driver_args(
111
+    driver: &Path,
112
+    source: &Path,
113
+    output: &Path,
114
+    extra_envs: &[(&str, &Path)],
115
+    extra_args: &[&str],
116
+    context: &str,
117
+) -> Output {
118
+    compile_with_driver_args_and_vars(driver, source, output, extra_envs, &[], extra_args, context)
119
+}
120
+
121
+fn compile_with_driver_args_and_vars(
122
+    driver: &Path,
123
+    source: &Path,
124
+    output: &Path,
125
+    extra_envs: &[(&str, &Path)],
126
+    extra_vars: &[(&str, &str)],
127
+    extra_args: &[&str],
128
+    context: &str,
106129
 ) -> Output {
107130
     let mut cmd = Command::new(driver);
108131
     for (name, value) in extra_envs {
109132
         cmd.env(name, value);
110133
     }
111
-    run_command(cmd.arg(source).arg("-o").arg(output), context)
134
+    for (name, value) in extra_vars {
135
+        cmd.env(name, value);
136
+    }
137
+    cmd.arg(source).arg("-o").arg(output).args(extra_args);
138
+    run_command(&mut cmd, context)
112139
 }
113140
 
114141
 #[test]
@@ -278,6 +305,54 @@ fn hello_world_runs_through_driver_with_standalone_tool_overrides() {
278305
     assert_eq!(standalone_stdout, " Hello, World!\n");
279306
 }
280307
 
308
+#[test]
309
+fn hello_world_runs_through_driver_with_afs_ld_enable_flag() {
310
+    let Some(armfortas) = binary("armfortas") else {
311
+        eprintln!("skipping: armfortas binary not built");
312
+        return;
313
+    };
314
+    let Some(afs_as) = binary("afs-as") else {
315
+        eprintln!("skipping: afs-as binary not built");
316
+        return;
317
+    };
318
+    let Some(_afs_ld) = binary("afs-ld") else {
319
+        eprintln!("skipping: afs-ld binary not built");
320
+        return;
321
+    };
322
+    let Some(runtime) = runtime_archive() else {
323
+        eprintln!("skipping: libarmfortas_rt.a not built");
324
+        return;
325
+    };
326
+    let Some(libsystem) = libsystem_tbd() else {
327
+        eprintln!("skipping: libSystem.tbd not found");
328
+        return;
329
+    };
330
+
331
+    let source = workspace_root().join("test_programs/hello.f90");
332
+    assert!(source.exists(), "hello.f90 missing at {}", source.display());
333
+
334
+    let dir = unique_dir("driver_afs_ld_flag_hello");
335
+    let standalone_bin = dir.join("hello-driver-afs-ld-flag");
336
+
337
+    let standalone_compile = compile_with_driver_args_and_vars(
338
+        &armfortas,
339
+        &source,
340
+        &standalone_bin,
341
+        &[
342
+            ("AFS_AS_PATH", &afs_as),
343
+            ("AFS_RUNTIME_PATH", &runtime),
344
+            ("AFS_LIBSYSTEM_TBD", &libsystem),
345
+        ],
346
+        &[("AFS_LD", "1")],
347
+        &["-L", "/tmp", "-rpath", "/tmp"],
348
+        "AFS_LD=1 armfortas compile",
349
+    );
350
+    assert_success(&standalone_compile, "AFS_LD=1 armfortas compile");
351
+    let standalone_run = run_binary(&standalone_bin, "AFS_LD=1 armfortas run");
352
+    let standalone_stdout = String::from_utf8_lossy(&standalone_run.stdout);
353
+    assert_eq!(standalone_stdout, " Hello, World!\n");
354
+}
355
+
281356
 #[test]
282357
 fn hello_world_compiles_to_object_with_standalone_assembler_override() {
283358
     let Some(armfortas) = binary("armfortas") else {