Skip to content

Commit a54ea62

Browse files
committed
FEATURE-ci-native-linkage-exeext: Honor the configured native audit executable suffix
Forward EXEEXT when building the native linkage audit consumer so MinGW resolves its Automake target. Keep the production audit and all existing inspector controls unchanged. Verify the actual make recipe with GNU make for empty and .exe suffixes, TLS modes and failure propagation. All 17 affected tests, bootstrap/configure, generated-target dry runs, Python syntax and diff checks pass locally. Native Windows package/archive execution remains CI owned.
1 parent 794ecc0 commit a54ea62

3 files changed

Lines changed: 146 additions & 2 deletions

File tree

‎Makefile.am‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ check-v3-native-linkage:
306306
@$(MAKE) -n -C src -W libhttpserver_v3core.la libhttpserver.la AM_LDFLAGS= >check-v3-cxx-link.log
307307
@grep -E -- '--tag=CXX.*--mode=link.*-o libhttpserver.la ' check-v3-cxx-link.log >/dev/null || { cat check-v3-cxx-link.log; echo "FAIL: aggregate must use the C++ linker"; exit 1; }
308308
@echo "=== check-v3-native-linkage: native provider surface audit ==="
309-
@$(MAKE) $(AM_MAKEFLAGS) -C "$(top_builddir)/test" native_linkage >/dev/null
309+
@$(MAKE) $(AM_MAKEFLAGS) -C "$(top_builddir)/test" native_linkage$(EXEEXT) >/dev/null
310310
@BUILD_DIR="$(abs_top_builddir)" SRC_DIR="$(top_srcdir)" V3_TLS_MODE="$(enable_v3_tls)" $(top_srcdir)/scripts/audit-v3-native-linkage.sh
311311

312312
# Enforce the explicit native v3 example source/build inventory.

‎scripts/test-v3-native-linkage.py‎

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,95 @@
11
#!/usr/bin/env python3
2-
"""Adversarial inspector-output fixtures; real binary proof runs separately."""
2+
"""Make gate and inspector-output fixtures; real binary proof runs separately."""
33
import os
44
from pathlib import Path
5+
import shutil
56
import subprocess
67
import tempfile
78
import unittest
89

910
SOURCE = Path(__file__).resolve().parent.parent
1011

12+
class MakeGateFixtures(unittest.TestCase):
13+
"""Run the production recipe with GNU make and controlled build/inspector outputs."""
14+
15+
def gate(self, suffix='', mode='no', linker='CXX', dependency=None,
16+
symbols='', build_fails=False):
17+
make = shutil.which('gmake') or shutil.which('make')
18+
self.assertIsNotNone(make, 'GNU make is required for native linkage gate tests')
19+
recipe = (SOURCE / 'Makefile.am').read_text().split(
20+
'\ncheck-v3-native-linkage:\n', 1)[1].split('\n\n', 1)[0]
21+
if dependency is None:
22+
dependency = 'KERNEL32.dll' if suffix else '/usr/lib/libc++.1.dylib'
23+
with tempfile.TemporaryDirectory() as directory:
24+
root = Path(directory).resolve()
25+
for name in ['src', 'test', 'tools']:
26+
(root / name).mkdir()
27+
(root / 'src/Makefile').write_text(
28+
'libhttpserver.la:\n'
29+
f'\tlibtool --tag={linker} --mode=link -o libhttpserver.la archive\n')
30+
# Like Automake, expose only the configured executable target.
31+
(root / 'test/Makefile').write_text(
32+
'native_linkage$(EXEEXT):\n'
33+
+ ('\t@exit 1\n' if build_fails else
34+
'\t@mkdir -p .libs ../src/.libs\n'
35+
'\t@printf "#!/bin/sh\\nexit 0\\n" > .libs/$@\n'
36+
'\t@chmod +x .libs/$@\n'
37+
'\t@touch ../src/.libs/libhttpserver_v3core.a\n'))
38+
inspectors = {'nm': symbols}
39+
if suffix:
40+
inspectors.update(uname='MINGW64_NT-10.0', objdump=(
41+
'fixture.exe: file format pei-x86-64\n'
42+
+ '\n'.join(' DLL Name: ' + n for n in dependency.splitlines())))
43+
else:
44+
inspectors['otool'] = 'fixture:\n' + dependency
45+
for name, output in inspectors.items():
46+
path = root / 'tools' / name
47+
path.write_text("#!/bin/sh\ncat <<'OUTPUT'\n" + output + '\nOUTPUT\n')
48+
path.chmod(0o755)
49+
env = dict(os.environ, PATH=str(root / 'tools') + os.pathsep + os.environ['PATH'])
50+
return subprocess.run(
51+
[make, '--no-print-directory', '-f', '-', 'check-v3-native-linkage',
52+
'top_srcdir=' + str(SOURCE), 'top_builddir=' + str(root),
53+
'abs_top_builddir=' + str(root), 'EXEEXT=' + suffix,
54+
'enable_v3_tls=' + mode],
55+
input='check-v3-native-linkage:\n' + recipe + '\n', cwd=root,
56+
env=env, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
57+
58+
def test_configured_executable_suffix_reaches_real_audit(self):
59+
for suffix in ['', '.exe']:
60+
with self.subTest(suffix=suffix):
61+
result = self.gate(suffix=suffix)
62+
self.assertEqual(0, result.returncode, result.stdout)
63+
self.assertIn('A1 PASS', result.stdout)
64+
self.assertIn('A2 PASS', result.stdout)
65+
66+
def test_configured_tls_mode_reaches_real_audit(self):
67+
for suffix, dependency in [('', '/tmp/libssl.3.dylib'), ('.exe', 'libssl-3.dll')]:
68+
for mode in ['yes', 'no']:
69+
with self.subTest(suffix=suffix, mode=mode):
70+
result = self.gate(suffix=suffix, dependency=dependency, mode=mode)
71+
self.assertEqual(mode == 'yes', result.returncode == 0, result.stdout)
72+
self.assertIn('A2 PASS' if mode == 'yes' else 'TLS-off load dependency',
73+
result.stdout)
74+
75+
def test_cxx_linker_gate_stops_before_audit(self):
76+
result = self.gate(linker='CC')
77+
self.assertNotEqual(0, result.returncode)
78+
self.assertIn('aggregate must use the C++ linker', result.stdout)
79+
self.assertNotIn('A1 PASS', result.stdout)
80+
81+
def test_build_failure_stops_before_audit(self):
82+
result = self.gate(build_fails=True)
83+
self.assertNotEqual(0, result.returncode)
84+
self.assertNotIn('A1 PASS', result.stdout)
85+
86+
def test_static_provider_rejection_propagates(self):
87+
result = self.gate(symbols=' U _SSL_set_quic_tls_cbs')
88+
self.assertNotEqual(0, result.returncode)
89+
self.assertIn('A1 PASS', result.stdout)
90+
self.assertIn('TLS-off provider symbols', result.stdout)
91+
self.assertNotIn('A2 PASS', result.stdout)
92+
1193
class AuditFixtures(unittest.TestCase):
1294
def audit(self, dependency=None, symbols='', mode='no', binary=True, archive=True, windows=False):
1395
if dependency is None:
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# FEATURE-ci-native-linkage-exeext: respect configured executable suffix
2+
3+
Status: Implemented and locally verified; caller validation/finalization pending.
4+
Base: `v3` at `794ecc08f86e72469eed791c6b13d5a5490cefb4`.
5+
6+
Windows package job `120420001573` in run `39955436208` and archive job
7+
`120420935368` build the library, then fail because the native linkage gate asks
8+
make for `native_linkage`, while Automake exposes `native_linkage.exe`.
9+
The recursive target now uses `native_linkage$(EXEEXT)`, retaining the empty
10+
suffix on Unix and using the configured suffix on Windows.
11+
12+
Action items:
13+
14+
- [x] Create an isolated Groundwork worktree from the recorded v3 head;
15+
preserve the bauth worktree and prior closed repairs.
16+
- [x] Retain both original native Windows logs and bind the relevant unchanged
17+
Makefile/audit inputs to the failed and local base revisions.
18+
- [x] Add a regression executing the actual production recipe with GNU make
19+
for empty and `.exe` suffixes; observe the original missing-target failure
20+
before editing production code.
21+
- [x] Respect configured `EXEEXT` in the recursive native linkage target.
22+
- [x] Verify both suffixes reach the real source/header and artifact audit;
23+
preserve configured TLS mode, C++ linker rejection, build failure propagation
24+
and provider rejection.
25+
- [x] Preserve the complete production inspector and all existing adversarial
26+
tests, including static symbols, missing archive and Windows import controls.
27+
- [x] Run the affected 17-test module, bootstrap, out-of-tree TLS-off configure,
28+
generated-target dry runs for both suffixes, Python syntax and diff checks.
29+
- [x] Retain raw commands, results, source bindings and journal under main
30+
`.debug/FEATURE-ci-native-linkage-exeext/`.
31+
- [ ] Caller: Groundwork validation and local finalization into v3.
32+
- [ ] CI / v3 PR: native Windows package and archive builds and audits.
33+
34+
Local verification: the five new make-gate tests and all 12 existing inspector
35+
tests pass. The original `.exe` RED fails with `No rule to make target
36+
'native_linkage'`; empty suffix behavior passes before and after the change.
37+
The regression reads the production recipe from `Makefile.am`, executes it
38+
with real GNU make, and runs the unchanged production audit against the real
39+
source tree. Small build Makefiles and inspector outputs are controlled
40+
fixtures; they do not compile or inspect native Windows binaries. TLS-on
41+
fixtures accept OpenSSL while TLS-off fixtures reject the same dependencies.
42+
The C linker, failed build and static provider cases fail the gate as required.
43+
44+
Bootstrap and configure pass with existing Automake/Autoconf warnings and
45+
missing optional documentation tools recorded in the logs. Generated test
46+
Makefile dry runs resolve both `native_linkage` and `native_linkage.exe`; the
47+
unbuilt v3core archive is explicitly excluded from those dry runs with `-o`.
48+
These are target-resolution checks, not binary build evidence. The production
49+
audit bytes and entire original `AuditFixtures` class are unchanged. Python
50+
scripts have no documented standalone linter; no C++ files changed.
51+
52+
Native Windows execution remains incomplete and CI / v3 PR owned under
53+
AGENTS. No full native baseline, unrelated repairs, CI reruns, validation loop,
54+
merge or publication was performed. Older Linux parity causality remains
55+
UNCERTAIN after its previously closed bounded diagnosis. Prior production
56+
unwind/entropy fixes, audit policy and nonlocal checks remain untouched.
57+
58+
Project notes: Autotools/C++20 setup uses `bash bootstrap`, out-of-tree
59+
`configure --disable-v3-tls --disable-examples`, then make. This task uses only
60+
targeted Python unittest, GNU make fixtures and configure/dry-run checks.
61+
The worktree identity came verbatim from the Groundwork helper; Git metadata
62+
writes required sandbox escalation.

0 commit comments

Comments
 (0)