Skip to content

Instantly share code, notes, and snippets.

@somian
Last active December 15, 2015 19:39
Show Gist options
  • Save somian/5312767 to your computer and use it in GitHub Desktop.
Save somian/5312767 to your computer and use it in GitHub Desktop.
External Dependency (lib to compile /link against) Makefile.PL
ARG-1            ARG-2     ARG-3
  [$obj or Class "ExtUtils::Liblist"]->ext($potential_libs, $verbose, $need_names);

So $_[1] (ARG-2 ) and $_[2] (ARG-3) are BOOLEANS.

The POD says:

It returns an array of four or five scalar values: EXTRALIBS, BSLOADLIBS, LDLOADLIBS, LD_RUN_PATH, and, optionally, a reference to the array of the filenames of actual libraries.

Win32 implementation

The version of ext() which is executed under Win32 differs from the Unix-OS/2 version in several respects:

  • If $potential_libs is empty, the return value will be empty. Otherwise, the libraries specified by $Config{perllibs} will be appended (see Config.pm).

    # I<$potential_libs> is ARG-1. Who would call ext() with an empty arg 1? Why
    # that design?
    
    # Telling people to go look at "Config.pm" for illumination concerning
    # I<perllibs> is unhelpful. There are too many cross references in this
    # document. It makes it extremely difficult to get a working understanding of
    # how this all works, fits together.
    
    # What is an actual example of C<$Config{perllibs}>?
    
    $ perl -V:perllibs
      perllibs='-lmsvcrt -lmoldname -lkernel32 -luser32 -lgdi32 -lwinspool -lcomdlg32 -ladvapi32 -lshell32 -lole32 -loleaut32 -lnetapi32 -luuid -lws2_32 -lmpr -lwinmm -lversion -lodbc32 -lodbccp32';
    
    # It seems like on Win32, perllibs is a conflation of the "C library" (what
    # would be -lc for gcc on a GNU/Linux system), and libraries implementing the
    # Win32 API.

    The libraries will be searched for in the directories specified in $potential_libs, $Config{libpth}, and in $Config{installarchlib}/CORE. For each library that is found, a space-separated list of fully qualified library pathnames is generated.

    # $Config{libpth} eh. Ok, what does an example of that from an actual Win32 perl look like?:
    
      $ perl -V:libpth
      libpth='C:\strawberry\c\lib C:\strawberry\c\i686-w64-mingw32\lib';
    
      $ perl -V:libpth
      libpth='C:\camelbox\lib';
    
    # It seems advisable to add those to ARG-1 before calling ext() in the first place.
    
    # 
      $ perl -V:installarchlib
        installarchlib='C:\strawberry\perl\lib';
    
    # That makes C<$Config{installarchlib}/CORE> C<C:\strawberry\perl\lib/CORE>.
    
      $ perl -V:installarchlib
        installarchlib='C:\camelbox\lib';
    
    # Ouch. That makes C<libpth> and C<installarchlib> the same.
      That has got me thinking that any reasonable code used in a Makefile.PL
      that calls ext() ought to vett the dirs in those Config keys first.

    For each library that is found, a space-separated list of fully qualified library pathnames is generated.

    # And right there is a good reason why a general rule like "do not install perl to a path with (embedded) spaces," is a good rule.
  • LDLOADLIBS and EXTRALIBS are always identical under Win32, and BSLOADLIBS and LD_RUN_PATH are always empty (this may change in future).

  • Entries in $potential_libs beginning with a colon and followed by alphanumeric characters are treated as flags. Unknown flags will be ignored.

    # Sounds like a kludge for the MSVC compiler.

    An entry that matches /:nodefault/i disables the appending of default libraries found in $Config{perllibs} (this should be only needed very rarely).

    An entry that matches /:nosearch/i disables all searching for the libraries specified after it. Translation of -Lfoo and -lfoo still happens as appropriate (depending on compiler being used, as reflected by $Config{cc}), but the entries are not verified to be valid files or directories.

    An entry that matches /:search/i reenables searching for the libraries specified after it. You can put it at the end to enable searching for default libraries specified by $Config{perllibs}.

    # It sounds like one would often want to use C<:nosearch>. The extra noise
    # that EU::MM makes when an external library dependency is being located is
    # often useless; it merely emits a new-user-unfriendly warning and then goes
    # on to allow compilation to fail in the code-building state.
  • Since this module is most often used only indirectly from extension Makefile.PL files, here is an example Makefile.PL entry to add a library to the build process for an extension:

    LIBS => ['-lgl']
    
     # It is using LIBS that triggers the EU::MM mechanism to attempt to use
     # EU::LibList. One way to avoid using EU::LibList might be to scrupulously
     # avoid using LIBS.
use ExtUtils::MakeMaker;
use vars ('%Config');
use ExtUtils::MakeMaker::Config; # our %Config is now mutable.
use Text::ParseWords qw(parse_line);
use File::Which qw(which);
use File::Spec;
use Cwd qw(realpath cwd);
my ($defs, $libshnd, $lib_preq, $lib_prim, $lddflags, $d_RL_lib, $d_RL_inc);
# my $libname = '-lreadline';
my $libname = '-lpng12'; # XXX
my $pelsep = $Config{path_sep};
# TODO Use subroutine to get params multiple ways...
my @guessd;
my $uq = {};
my $fncmp = sub { return File::Spec->case_tolerant() ? uc $_[0] : $_[0] };
for my $_dir (
parse_line(q[ ],q[K],join(q[ ]=> $Config{installarchlib}, $Config{libpth}))
)
{
$_dir =~tr{\\}{/};
$_dir .= "/pkgconfig";
push @guessd, $_dir if -d $_dir and !$uq->{$fncmp->($_dir)}++;
}
=begin :Notes
My cygwin seems to have these pkgconfig/ locations:
/usr/share/pkgconfig
/usr/lib/ncurses/pkgconfig
/usr/lib/ncursesw/pkgconfig
/usr/lib/pkgconfig
Use to get default search path list
$ pkg-config [--print-errors] --variable pc_path pkg-config
Camelbox Perl bundled pkg-config does not have any default. Cygwin does:
/usr/lib/pkgconfig:/usr/share/pkgconfig
When we try to run this under a Cygwin sh shell we get a non-Zero return
inside EU::PkgConfig: 32256 == $CHILD_ERROR. Under msWin CMD it is fine.
=end
=cut
my $eupc = eval "require ExtUtils::PkgConfig; 1" && !$@;
die "No ExtUtils::PkgConfig" unless $eupc;
my $def_spl;
my $pcprog = which(q/pkg-config/);
$pcprog ||= which(q/PkgConfig/); # "pure Perl"
if($pcprog) {
open my($SPH), qq[$pcprog --variable pc_path pkg-config |]
or die "Cannot open process";
($def_spl) = readline $SPH;
close $SPH or warn $?;
$def_spl =~s{[[:cntrl:]]}{}g;
my @pels = split $pelsep, $def_spl;
die qq[Bad pel sep, or command output?: $def_spl]
if $def_spl and (! grep( -d, @pels ));
unshift @guessd, (grep {$_ and -d and !$uq->{$fncmp->($_)}++} @pels);
}
if($pcprog and $pcprog =~m{\bbin\b}i) {
my($pv, $loc_pc, undef) = File::Spec->splitpath($pcprog);
for my $spec ( qw< share lib lib/ncurses lib/ncursesw > ) {
my $_pc = File::Spec->catdir($loc_pc, File::Spec->updir(), $spec, 'pkgconfig');
$_pc = File::Spec->catpath($pv,$_pc);
next unless -d $_pc;
$_pc = realpath($_pc);
if ( !$uq->{$fncmp->($_pc)}++ ) { push @guessd, $_pc }
}
}
$ENV{'PKG_CONFIG_PATH'} = join($pelsep, @guessd);
my %pc;
my $capt;
my $by = _lib_pcname($libname);
PINGLIB: # requires 5.8.0 ...works on Cygwin, not really on msWin.
{
local $@;
open SAVEERR, ">&STDERR";
close STDERR;
$capt = '';
open STDERR, '>', \$capt or die "Cannot capture STDERR: $!";
my $_c2e = 'ExtUtils::PkgConfig->find("' . $by . '");';
print "Trying $by ...\n";
eval $_c2e;
close STDERR;
open STDERR, ">&SAVEERR";
# warn "in eval local:\n$@\n" if $capt or $@;
if ($@ and $by =~ m{^lib}) {
$by = substr $by, 3;
redo PINGLIB
} elsif (! $@) {
%pc = ExtUtils::PkgConfig->find($by)
}
$capt = $@ if
( $capt !~ / was not found /
or $capt !~ / can not find / ); # msWin
}
warn <<" BWAHAHA" if $capt;
We could not locate a .pc file corresponding to $libname. Sorry.
The pkg-config command found was $pcprog
The error seen was:
$capt
Search pathlist contained:
@{[join qq[\n] => @guessd ]}
BWAHAHA
exit 1 unless %pc;
$d_RL_lib = ExtUtils::PkgConfig->libs_only_L( $by) ;
$d_RL_inc = ExtUtils::PkgConfig->cflags_only_I( $by) ;
$lib_preq = ExtUtils::PkgConfig->libs_only_other($by) ;
$lib_prim = ExtUtils::PkgConfig->libs($by) ;
print "$_\n" for ( $d_RL_lib, $d_RL_inc , $lib_preq, $libshnd, $lib_prim );
my %Llib =
(
INC => $d_RL_inc,
DEFINE => $defs,
LIBS => [ "$d_RL_lib $libshnd $lib_preq" ],
LDDLFLAGS => "$d_RL_lib $Config{lddlflags}",
dynamic_lib => { OTHERLDFLAGS => $lddflags },
);
# generate a Makefile
WriteMakefile
(
NAME => '...',
VERSION_FROM => '...',
%Llib,
);
#-# SUPPORTING SUBROUTINES
sub _lib_pcname {
my ($lib) = @_;
unless ($lib =~ /^-l/) {
warn q[search_lib: malformed input argument, "$lib"]."\n";
return undef;
}
my $libbase = 'lib' . substr($lib, 2);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment