[MacPorts] #74169: expat: corrupted expat_config.h in +universal binary archive (ar archive instead of C header)
MacPorts
noreply at macports.org
Sat Aug 29 22:49:17 UTC 2026
#74169: expat: corrupted expat_config.h in +universal binary archive (ar archive
instead of C header)
---------------------+-----------------------
Reporter: cippee | Owner: (none)
Type: defect | Status: new
Priority: Normal | Milestone:
Component: ports | Version:
Resolution: | Keywords: universal
Port: expat |
---------------------+-----------------------
Comment (by jrjsmrtn):
I hit this with `libffi` rather than `expat`, and I think the mechanism is
in the
muniversal merge: `/usr/bin/libtool` succeeds on non-Mach-O input, so the
text-merge
branch is never reached.
== Reproduction, independent of any port ==
{{{
$ printf '#define FOO 1\nint a;\n' > a.h
$ printf '#define FOO 2\nint b;\n' > b.h
$ /usr/bin/lipo -create a.h b.h -output out.h
fatal error: lipo: can't figure out the architecture type of: a.h
$ /usr/bin/libtool a.h b.h -o out.h
libtool: warning: not a mach-o 'a.h'
libtool: warning: not a mach-o 'b.h'
$ echo $?
0
$ file out.h
out.h: current ar archive random library
$ head -1 out.h
!<arch>
}}}
96 bytes, containing only `__.SYMDEF SORTED` — byte-identical in form to
the corrupted
headers.
== Where this happens ==
`_resources/port1.0/group/muniversal-1.0.tcl`, lines 688-694 (and the same
code in
muniversal-1.1.tcl, lines 446-449):
{{{
# First try lipo, then libtool
if { ! [catch {system "/usr/bin/lipo -create ..."}] } {
# lipo worked
} elseif { ! [catch {system "/usr/bin/libtool ... -o ..."}] } {
# libtool worked
} else {
# lipo and libtool have failed, so assume they are text files to be
merged
}}}
For two differing text files, `lipo` fails as the code expects, but macOS
`libtool`
defaults to `-static` and archives arbitrary files, warning and exiting 0.
`catch` sees
success, the `elseif` is taken, and the `diff`-based text merge in the
`else` branch never
runs.
That predicts binaries merge correctly (lipo succeeds first) while
differing text files are
destroyed, which is what the destroots show.
== Observed with libffi ==
macOS 26.6.2 (25G83), arm64, MacPorts 2.12.5, libffi @3.4.8_0+universal:
{{{
$ file /opt/local/include/ffi.h /opt/local/include/ffitarget.h
/opt/local/include/ffi.h: current ar archive random library
/opt/local/include/ffitarget.h: current ar archive random library
}}}
After `sudo port -s destroot libffi +universal`:
{{{
destroot-arm64/opt/local/include/ffi.h C source, ASCII text 14041
bytes
destroot-x86_64/opt/local/include/ffi.h C source, ASCII text 14039
bytes
destroot/opt/local/include/ffi.h current ar archive 96
bytes
}}}
Five installed files differ between the two architecture destroots:
{{{
include/ffi.h -> ar archive (corrupt)
include/ffitarget.h -> ar archive (corrupt)
lib/libffi.8.dylib -> lipo -info: x86_64 arm64 (correct)
lib/libffi.a -> lipo -info: x86_64 arm64 (correct)
lib/libffi.dylib -> symlink
}}}
Everything else is identical across architectures and survives. Rebuilding
from source
does not help — `sudo port -s upgrade --force libffi` rewrites the file
and it is still an
ar archive — so the precompiled archives are presumably corrupt because
they were produced
this way, rather than being damaged in transit.
== Downstream ==
`python313 +universal` fails with roughly 90 errors in `Modules/_ctypes` —
`unknown type
name 'ffi_type'`, `'ffi_cif'`, `'ffi_closure'`, `'ctypes_state'` — across
`_ctypes.o`,
`callbacks.o`, `callproc.o`, `cfield.o`, `malloc_closure.o` and
`stgdict.o`. The compile
line has `-I/opt/local/include` and both `-arch` flags, so the header is
found; it just is
not a header. Reproduces from a cleaned work directory.
The same `python313 +universal` builds and installs fine on an x86_64 host
running macOS
15.7.9, which has no `+universal` libffi and a valid ASCII `ffi.h`.
`expat_config.h` fits the same pattern: a generated, architecture-
dependent header that
differs between the two builds.
--
Ticket URL: <https://trac.macports.org/ticket/74169#comment:3>
MacPorts <https://www.macports.org/>
Ports system for macOS
More information about the macports-tickets
mailing list