use inc::Module::Install 0.91;
use Cwd;
use Config;
use File::Glob qw(bsd_glob);
use strict;
use warnings;
my $win32 = ($^O eq 'MSWin32');
my $darwin = ($^O eq 'darwin');
my $solaris = ($^O eq 'solaris');
my $linux = !($win32 || $darwin || $solaris ); # yea, more than linux are going to end here!
my $cc_gcc = $Config{cc} =~ /gcc/;
my $cc_wincl = $win32 && $Config{cc} =~ /cl/;
my $path_sep = $Config{path_sep};
print <<'EOF';
The libssh2 library is required by this module. If you don't have it, you can
download it from http://www.libssh2.org; you may also need OpenSSL, which can
be obtained from http://www.openssl.org , or libgcrypt, which can be obtained
from http://www.gnupg.org .
Debian: sudo aptitude install libssh2-1-dev
OpenSUSE: sudo zypper in libssh2-1 libssh2-devel
You can pass your libssh2 lib and include dirs (and extra link args) on the
command line. E.g.:
perl Makefile.PL lib=$HOME/libssh2/lib inc=$HOME/libssh2/include \
ldargs="-lz"
These can also be set through the LIBSSH2_LIB/LIBSSH2_INCLUDE/LIBSSH2_LDARGS
environment variables.
To build with libgcrypt instead of OpenSSL, pass 'gcrypt' as a parameter to
Makefile.PL, e.g.:
perl Makefile.PL gcrypt
If you want to build on Windows, see the file BUILDING.WIN32 in the
distribution.
EOF
my $crypto_backend;
my $do_not_check_libs;
sub makemaker_append_once;
sub capture;
sub findlib;
name 'Net-SSH2';
all_from 'lib/Net/SSH2.pm';
perl_version '5.006000';
auto_provides;
makemaker_append_once CCFLAGS => $Config{ccflags};
makemaker_append_once LDDLFLAGS => $Config{lddlflags};
my %arg2mmappend = ( inc => 'INC',
lib => 'LIBS',
ldargs => 'LDDLFLAGS' );
my %arg2prefix = (inc => '-I',
lib => '-L');
my $arg_keys = join('|', map quotemeta, keys %arg2mmappend);
my $do_not_check_libs_keys = 'lib|inc';
for (keys %ENV) {
if (/^LIBSSH2_($arg_keys)$/) {
my $value = $ENV{$_};
my $prefix = $arg2prefix{lc $1} || '';
$value = File::Spec->rel2abs($value) if $prefix;
makemaker_append_once $arg2mmappend{lc $1} => $prefix . $value;
$do_not_check_libs ||= /^LIBSSH2_($do_not_check_libs_keys)$/i;
}
}
my @pass_through_args;
for (@ARGV) {
if (/^($arg_keys)=(.*)\z/) {
my $prefix = $arg2prefix{$1} || '';
my $value = $2;
$value = File::Spec->rel2abs($value) if $prefix;
makemaker_append_once $arg2mmappend{$1} => $prefix.$value;
$do_not_check_libs ||= /^($do_not_check_libs_keys)=/;
}
elsif ($_ eq 'gcrypt') {
$crypto_backend = 'gcrypt';
}
elsif ($_ eq 'openssl') {
$crypto_backend = 'openssl';
}
else {
push @pass_through_args, $_;
}
}
@ARGV = @pass_through_args;
my @search_paths;
for my $env ('LD_RUN_PATH', ($darwin ? 'DYLD_LIBRARY_PATH' : 'LD_LIBRARY_PATH')) {
my $v = $ENV{$env};
push @search_paths, split(/\Q$path_sep\E/, $v) if defined $v;
}
push @search_paths,
split(' ', $Config{libspath}),
$Config{siteprefixexp}, $Config{prefixexp},
'/usr', '/usr/local', '/opt', '/opt/local',
'/usr/local/libssh2', '/opt/libssh2',
'/usr/local/libssh2/*', '/usr/local/ssl';
push @search_paths, $ENV{HOME}, "$ENV{HOME}/libssh2" if defined $ENV{HOME};
# mac homebrew support
if ($^O eq 'darwin' && -x '/usr/local/bin/brew') {
system("/usr/local/bin/brew info libssh2 | grep '^Not installed' >/dev/null");
if ($? >> 8 == 0) {
system("/usr/local/bin/brew -v install libssh2");
}
system("/usr/local/bin/brew info openssl | grep '^Not installed' >/dev/null");
if ($? >> 8 == 0) {
system("/usr/local/bin/brew -v install openssl");
}
push @search_paths, '/usr/local/Cellar/openssl/*';
}
@search_paths = map { /\*/
? (sort { (stat $b)[9] <=> (stat $a)[9] } grep -d, bsd_glob($_))
: $_ } @search_paths;
my %sp_seen;
@search_paths = grep !$sp_seen{$_}++, @search_paths;
sub findlib {
local $Module::Install::AUTHOR;
my %args = @_;
my @search_paths = @{delete $args{search_paths} || []};
for my $sp (undef, @search_paths) {
for my $libpath (defined $sp ? (map [$_], grep -d, "$sp/lib", "$sp/lib64", $sp) : []) {
my $incpath = (defined $sp ? [grep -d, "$sp/include"] : []);
my @ldflags = '';
push @ldflags, "-Wl,-rpath=".$libpath->[0] if $cc_gcc and defined $sp;
for my $ldflags (@ldflags) {
if (eval {
assertlibs( %args,
libpath => $libpath,
incpath => $incpath,
ldflags => $ldflags);
1; }) {
warn "Library $args{lib} found in ".(defined $sp ? $sp : "standard place")."\n";
makemaker_append_once INC => "-I$_" for @$incpath;
makemaker_append_once LIBS => "-L$_" for @$libpath;
makemaker_append_once LIBS => "-l$args{lib}";
makemaker_append_once LDDLFLAGS => $ldflags if $ldflags;
return 1;
}
else {
warn $@ if $@ and $ENV{AUTOMATED_TESTING};
}
}
}
}
die "Unable to find a working version of library $args{lib} in the following directories:\n ".
(join "\n ", @search_paths)."\n";
}
if ($do_not_check_libs) {
$crypto_backend ||= 'openssl';
}
else {
warn "Looking for libraries...\n";
my $detected_crypto_backend;
# This is a workaround for Module::Install::CheckLib behaving
# differently in user and author mode. Specifically, in author
# mode, we call M::I::CheckLib normally so that it can copy
# its files under "inc/", and then, we hide we are in author
# mode and call it again so that it actually runs the
# checklibs stuff..
if ($Module::Install::AUTHOR) {
eval {
assertlibs( lib => 'ssh2',
header => 'libssh2.h',
libpath => [],
incpath => []);
};
}
findlib(lib => 'ssh2',
header => 'libssh2.h',
search_paths => \@search_paths,
function => <<EOF,
if (libssh2_init(0))
return 1;
/* check that library and headers are on par */
return (libssh2_version(LIBSSH2_VERSION_NUM) ? 0 : 1);
EOF
analyze_binary => sub {
warn "Analyzing file $_[1]\n";
local $@;
eval {
my $out = capture ldd => $_[1];
# warn "out:\n$out";
if ($out =~ /gcrypt/i) {
$detected_crypto_backend = 'gcrypt';
}
elsif ($out =~ /lib(ssl|crypto)/i) {
$detected_crypto_backend = 'openssl';
}
else {
warn "Unable to detect crypto backend used by libssh2!\n"
}
};
warn $@ if $@ and $ENV{AUTOMATED_TESTING};
1;
},
run_checks_as_author => 1, );
if (defined $detected_crypto_backend) {
if (defined $crypto_backend) {
$crypto_backend eq $detected_crypto_backend or
warn "Detected crypto backend ($detected_crypto_backend) does not match ".
"the one requested on the command line ($crypto_backend)";
}
else {
warn "Detected crypto backend: $detected_crypto_backend\n";
$crypto_backend = $detected_crypto_backend;
}
}
$crypto_backend ||= 'openssl';
unless ($win32) {
findlib(lib => 'z',
header => 'zlib.h',
search_paths => \@search_paths,
run_checks_as_author => 1);
if ($crypto_backend eq 'gcrypt') {
findlib(lib => 'gcrypt',
header => 'gcrypt.h',
search_paths => \@search_paths,
run_checks_as_author => 1);
}
else {
findlib(lib => 'ssl',
header => 'openssl/ssl.h',
search_paths => \@search_paths,
run_checks_as_author => 1);
findlib(lib => 'crypto',
header => 'openssl/crypto.h',
search_paths => \@search_paths,
run_checks_as_author => 1);
}
}
}
if ($crypto_backend eq 'gcrypt') {
makemaker_append_once(LDDLFLAGS => '-lgcrypt');
}
else {
if ($cc_wincl) {
makemaker_append_once(LIBS => "-l$_") for qw(ssleay32 libeay32); # Win32 + MSVC compiler
}
if ($cc_gcc && $win32) {
makemaker_append_once(LIBS => "-l$_") for qw(ssl32 eay32); # Win32 + GCC compiler (mingw)
}
else {
makemaker_append_once(LIBS => "-l$_") for qw(ssl crypto);
}
}
makemaker_append_once(DEFINE => '-DLIBSSH2_WIN32') if $win32;
makemaker_append_once(DEFINE => '-DUSE_GCRYPT') if $crypto_backend eq 'gcrypt';
makemaker_append_once(CCFLAGS => '-Wno-deprecated-declarations') if $^O eq 'darwin';
makemaker_append_once(CCFLAGS => '-DPERL_GCC_PEDANTIC -std=c99 -pedantic-errors -Wno-long-long')
if $Module::Install::AUTHOR and $linux and $cc_gcc;
resources repository => 'git://github.com/rkitover/net-ssh2.git';
makemaker_append_once LIBS => '-lssh2', '-lz';
my $gen = "util/gen_constants.pl";
if (-f $gen) {
system $^X, $gen
and warn "$gen failed: $?\n";
}
WriteAll;
my %appended;
sub makemaker_append_once {
my $key = shift;
for (@_) {
makemaker_append $key, $_
unless $appended{$key}{$_}++;
}
}
sub capture {
if (open my $fh, '-|', @_) {
my $out = do { local $/, <$fh> };
close $fh;
return $out;
}
''
}