Sprint 21: Runtime Archive Linking
Prerequisites
Sprints 4, 8, 20 — archives, resolution, driver swap.
Goals
Link libarmfortas_rt.a end-to-end into every armfortas-produced binary. The full parent integration suite runs green under AFS_LD=1. This is the sprint that proves afs-ld can do real work on real armfortas output, not just staging fixtures.
Deliverables
1. Runtime inventory
Walk libarmfortas_rt.a and catalog every exported symbol. Groups:
- Lifecycle:
_afs_program_init,_afs_program_finalize. - Array:
_afs_allocate_array,_afs_deallocate_array,_afs_check_bounds,_afs_fill_*,_afs_array_add_*,_afs_array_mul_*,_afs_transpose_*,_afs_matmul_*. - I/O:
_afs_write_*,_afs_read_*,_afs_open_file,_afs_close_file,_afs_flush, formatted/unformatted/list-directed helpers. - String:
_afs_string_*(allocatable, deferred-length variants). - Math intrinsics:
_afs_i128_*,_afs_cmplx_*, etc. - System:
_afs_stop,_afs_command_argument_*,_afs_get_environment.
This inventory gets persisted as tests/runtime_symbols.txt so the test suite can assert no symbol silently disappears between runtime rebuilds.
2. Archive fetch verification
Verify Sprint 4's archive reader pulls members correctly:
- Parse
libarmfortas_rt.a, walk its BSD symbol index. - For each inventory symbol, look up the defining member.
- Cross-check:
nmon each member file agrees.
3. End-to-end integration tests
Run the parent armfortas/tests/ suite under AFS_LD=1:
tests/run_programs.rs: full program tests (array, I/O, derived types, modules).tests/multifile.rs: multi-object link; module globals resolved correctly.tests/i128_cross_object.rs: 128-bit integer interop across C/Fortran boundary.tests/fortsh_module_graph.rs: complex USE chains.tests/incremental.rs: incremental module dependency tracking.
Every failure here is a real linker bug — triage and fix.
4. Known gotchas to verify
Based on afs-as + runtime history, pay particular attention to:
_afs_program_initlifecycle wrapping: the driver-synthesized_mainatsrc/driver/mod.rs:371-392calls_afs_program_init→ user prog →_afs_program_finalize. All three must resolve.- I/O state machine in
libarmfortas_rt: references_errno,_malloc,_freefrom libSystem;_afs_io_stateas a BSS symbol. Verify__DATA,__bssplacement matches ld. - Common symbols: some module globals come through as common; verify promotion to BSS (Sprint 7 matrix).
- Weak refs to optional runtime hooks (if any). Check that unresolved weak refs evaluate to 0 and the call-site null-check dispatches correctly.
5. Archive-ordering edge cases
Some programs pull symbols that create new undefined references in the middle of resolution. Fixed-point loop from Sprint 8 handles this; verify it holds for the runtime archive with its ~40 members.
6. Diagnostic polish
Every runtime symbol that fails to resolve must produce a diagnostic that:
- Names the missing symbol.
- Cites at least one referrer in user code.
- Hints at the rebuild path (
cargo build -p armfortas-rt).
7. Regression corpus
Any test that once broke becomes a permanent corpus entry. The afs-ld tests/runtime_*.rs pattern mirrors armfortas's.
Testing Strategy
- Full parent integration suite under
AFS_LD=1(this is the primary deliverable). tests/runtime_inventory.rs: assert every symbol intests/runtime_symbols.txtis still defined by the currentlibarmfortas_rt.a.- Archive fetch coverage: every inventoried symbol pulls its member exactly once.
Definition of Done
AFS_LD=1 cargo test -p armfortasgreen.- Runtime inventory stable and asserted.
- No silent skips; every test that was passing under
AFS_LD=0passes underAFS_LD=1. - Diagnostics on missing runtime symbols are actionable.
View source
| 1 | # Sprint 21: Runtime Archive Linking |
| 2 | |
| 3 | ## Prerequisites |
| 4 | Sprints 4, 8, 20 — archives, resolution, driver swap. |
| 5 | |
| 6 | ## Goals |
| 7 | Link `libarmfortas_rt.a` end-to-end into every armfortas-produced binary. The full parent integration suite runs green under `AFS_LD=1`. This is the sprint that proves afs-ld can do real work on real armfortas output, not just staging fixtures. |
| 8 | |
| 9 | ## Deliverables |
| 10 | |
| 11 | ### 1. Runtime inventory |
| 12 | Walk `libarmfortas_rt.a` and catalog every exported symbol. Groups: |
| 13 | |
| 14 | - Lifecycle: `_afs_program_init`, `_afs_program_finalize`. |
| 15 | - Array: `_afs_allocate_array`, `_afs_deallocate_array`, `_afs_check_bounds`, `_afs_fill_*`, `_afs_array_add_*`, `_afs_array_mul_*`, `_afs_transpose_*`, `_afs_matmul_*`. |
| 16 | - I/O: `_afs_write_*`, `_afs_read_*`, `_afs_open_file`, `_afs_close_file`, `_afs_flush`, formatted/unformatted/list-directed helpers. |
| 17 | - String: `_afs_string_*` (allocatable, deferred-length variants). |
| 18 | - Math intrinsics: `_afs_i128_*`, `_afs_cmplx_*`, etc. |
| 19 | - System: `_afs_stop`, `_afs_command_argument_*`, `_afs_get_environment`. |
| 20 | |
| 21 | This inventory gets persisted as `tests/runtime_symbols.txt` so the test suite can assert no symbol silently disappears between runtime rebuilds. |
| 22 | |
| 23 | ### 2. Archive fetch verification |
| 24 | Verify Sprint 4's archive reader pulls members correctly: |
| 25 | |
| 26 | - Parse `libarmfortas_rt.a`, walk its BSD symbol index. |
| 27 | - For each inventory symbol, look up the defining member. |
| 28 | - Cross-check: `nm` on each member file agrees. |
| 29 | |
| 30 | ### 3. End-to-end integration tests |
| 31 | Run the parent `armfortas/tests/` suite under `AFS_LD=1`: |
| 32 | |
| 33 | - `tests/run_programs.rs`: full program tests (array, I/O, derived types, modules). |
| 34 | - `tests/multifile.rs`: multi-object link; module globals resolved correctly. |
| 35 | - `tests/i128_cross_object.rs`: 128-bit integer interop across C/Fortran boundary. |
| 36 | - `tests/fortsh_module_graph.rs`: complex USE chains. |
| 37 | - `tests/incremental.rs`: incremental module dependency tracking. |
| 38 | |
| 39 | Every failure here is a real linker bug — triage and fix. |
| 40 | |
| 41 | ### 4. Known gotchas to verify |
| 42 | Based on afs-as + runtime history, pay particular attention to: |
| 43 | |
| 44 | - **`_afs_program_init` lifecycle wrapping**: the driver-synthesized `_main` at `src/driver/mod.rs:371-392` calls `_afs_program_init` → user prog → `_afs_program_finalize`. All three must resolve. |
| 45 | - **I/O state machine in `libarmfortas_rt`**: references `_errno`, `_malloc`, `_free` from libSystem; `_afs_io_state` as a BSS symbol. Verify `__DATA,__bss` placement matches ld. |
| 46 | - **Common symbols**: some module globals come through as common; verify promotion to BSS (Sprint 7 matrix). |
| 47 | - **Weak refs** to optional runtime hooks (if any). Check that unresolved weak refs evaluate to 0 and the call-site null-check dispatches correctly. |
| 48 | |
| 49 | ### 5. Archive-ordering edge cases |
| 50 | Some programs pull symbols that create new undefined references in the middle of resolution. Fixed-point loop from Sprint 8 handles this; verify it holds for the runtime archive with its ~40 members. |
| 51 | |
| 52 | ### 6. Diagnostic polish |
| 53 | Every runtime symbol that fails to resolve must produce a diagnostic that: |
| 54 | - Names the missing symbol. |
| 55 | - Cites at least one referrer in user code. |
| 56 | - Hints at the rebuild path (`cargo build -p armfortas-rt`). |
| 57 | |
| 58 | ### 7. Regression corpus |
| 59 | Any test that once broke becomes a permanent corpus entry. The afs-ld `tests/runtime_*.rs` pattern mirrors armfortas's. |
| 60 | |
| 61 | ## Testing Strategy |
| 62 | - Full parent integration suite under `AFS_LD=1` (this is the primary deliverable). |
| 63 | - `tests/runtime_inventory.rs`: assert every symbol in `tests/runtime_symbols.txt` is still defined by the current `libarmfortas_rt.a`. |
| 64 | - Archive fetch coverage: every inventoried symbol pulls its member exactly once. |
| 65 | |
| 66 | ## Definition of Done |
| 67 | - `AFS_LD=1 cargo test -p armfortas` green. |
| 68 | - Runtime inventory stable and asserted. |
| 69 | - No silent skips; every test that was passing under `AFS_LD=0` passes under `AFS_LD=1`. |
| 70 | - Diagnostics on missing runtime symbols are actionable. |