Fixup macports usr vs opt precedence #267
Description
This is a severe Configure bug, both in perl5 and cperl.
/usr/local/include vs /usr/local/lib and /opt/local vs /usr/local.
Test: egrep -- '-[IL]/.*/local/(include|lib)' config.sh
/opt/local vs /usr/local precedence needs to match.
Currently:
ccflags='-fno-common -DPERL_DARWIN -mmacosx-version-min=10.11 -DNO_MATHOMS -march=corei7 -fwrapv -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include -I/opt/local/include -DPERL_USE_SAFE_PUTENV'
lddlflags=' -mmacosx-version-min=10.11 -bundle -undefined dynamic_lookup -L/opt/local/lib -L/usr/local/lib -L/opt/local/lib/libgcc -fstack-protector'
ldflags=' -mmacosx-version-min=10.11 -fstack-protector -L/opt/local/lib -L/usr/local/lib -L/opt/local/lib/libgcc'
It leads to wrong compile-time diagnostics with a run-time mismatch in a loaded dylib.
Probably also on other platforms.
Policies:
- either prefer stable libs over customized ones: then -L/opt/local/lib over -L/usr/local/lib
- or prefer customized libs (default).
packagers could enforce the first policy for stability, ignoring updates or old cruft in /usr/local.
But the mismatch with inc is a bug.
Note that with -L/opt/local/lib the path to the dylib is enforced at compile-time, which leads to stable packaged-only dylibs, i.e. shared cpan XS libraries.
With -L/usr/local/lib preferred, which is in DYLD_FALLBACK_LIBRARY_PATH, the path is stripped, i.e.
the dylib is sensible to DYLD_LIBRARY_PATH overrides.
$ man dyld
DYLD_LIBRARY_PATH, DYLD_FALLBACK_FRAMEWORK_PATH and DYLD_FALLBACK_LIBRARY_PATH
check:
otool -L blib/arch/auto/PATH/NAME.bundle
Makefile.PL recipe for your cpan module:
# fixup darwin macports usr vs opt precedence. /usr/local/include vs /usr/local/lib
my $ccflags = $Config{ccflags};
my $ldflags = $Config{ldflags};
my $lddlflags = $Config{lddlflags};
if ($lddlflags =~ m| -L/opt/local/lib| and $ccflags =~ m| -I/opt/local/include|) {
# opt first?
if ($lddlflags =~ m| -L/opt/local/lib.*-L/usr/local/lib|
and $ccflags =~ m| -I/usr/local/include.*-I/opt/local/include|)
{
warn("Your perl has corrupt /opt/local vs /usr/local precedence!\n");
warn("include prefers /usr/local, but lib /opt/local\n");
warn("Fixing it up for you...\n");
$lddlflags =~ s|(-L/opt/local/lib.*)(-L/usr/local/lib)|$2 $1|;
if ($ldflags =~ m| -L/opt/local/lib.*-L/usr/local/lib|) {
$ldflags =~ s|(-L/opt/local/lib.*)(-L/usr/local/lib)|$2 $1|;
}
}
}
my %WriteMakefileArgs = (
...
'CCFLAGS' => $ccflags,
'LDFLAGS' => $ldflags,
'LDDLFLAGS' => $lddlflags,
Cause:
locincpth vs loclibpth is correct:
locincpth='/usr/local/include /opt/local/include /usr/gnu/include /opt/gnu/include /usr/GNU/include /opt/GNU/include'
loclibpth='/usr/local/lib /opt/local/lib /usr/gnu/lib /opt/gnu/lib /usr/GNU/lib /opt/GNU/lib /opt/local/lib/libgcc'
the compiler settings incpth vs libpth are also correct:
$ grep '^...pth=' config.sh
incpth='/opt/local/lib/gcc6/gcc/x86_64-apple-darwin15/6.3.0/include /opt/local/include /opt/local/lib/gcc6/gcc/x86_64-apple-darwin15/6.3.0/include-fixed /usr/include'
libpth='/opt/local/lib /opt/local/lib/gcc6/gcc/x86_64-apple-darwin15/6.3.0/include-fixed /usr/lib /usr/local/lib /opt/local/lib/libgcc'
Only the merge logic for -I/usr/local/include is wrong.
But there are more errors in the hiding:
The libpth detection in Configure is lying. The paths in libpth are not actually searched, they are only constructed analog to incpth. e.g. macports gcc does not search -L/opt/local/lib