use strict;
use warnings;
use Config;
use ExtUtils::MakeMaker;
use File::Basename qw(dirname);
use Getopt::Long;
eval "use ExtUtils::MakeMaker::Coverage";
$@ or print "Adding testcover target\n";
use vars qw($opt_default $opt_libpath $opt_static);
GetOptions(
"default", \$opt_default,
"lib=s", \$opt_libpath,
"static", \$opt_static,
);
$opt_default ||= $ENV{CRYPT_SSLEAY_DEFAULT};
# FIND POSSIBLE SSL INSTALLATIONS
my @POSSIBLE_SSL_DIRS;
if ($opt_libpath) {
# explicit from command-line
@POSSIBLE_SSL_DIRS = ($opt_libpath);
$opt_default = 1;
}
elsif ($^O eq 'MSWin32') {
@POSSIBLE_SSL_DIRS = 'c:\\openssl';
}
elsif ($^O eq 'VMS') {
@POSSIBLE_SSL_DIRS = '/ssl$root';
}
else {
# Unix and the rest
@POSSIBLE_SSL_DIRS = qw(
/local
/local/ssl
/opt/ssl
/usr
/usr/local
/usr/local/ssl
/usr/local/openssl
);
}
my @CANDIDATE = do {
my %seen;
grep {!$seen{$_->{check}}++}
map {Candidate($_)}
@POSSIBLE_SSL_DIRS
};
if (@CANDIDATE == 0) {
$opt_default = 0;
my $bar = '=' x 72;
print <<"INFO";
$bar
No installed SSL libraries found in any of the following places.
INFO
print " $_\n" for @POSSIBLE_SSL_DIRS;
print <<"INFO";
You will have to either specify a directory location at the following
prompt, or rerun the Makefile.PL program and use the --lib switch
to specify the path. If the path in question is considered standard
on your platform, please consider filing a bug report in order to
have it taken into account in a subsequent version of Crypt::SSLeay.
INFO
if (-f '/etc/debian_version') {
print <<"DEBIAN_INFO";
This host looks like it is running Debian. Crypt::SSLeay needs to
be compiled with C headers that the libssl-dev package makes
available. Please install that package before trying to build this
module. (You can always deinstall the package afterwards, once
Crypt::SSLeay has been built).
DEBIAN_INFO
}
}
my $SSL_DIR;
my $pkg_config;
if (@CANDIDATE == 1) {
$pkg_config = $CANDIDATE[0];
if ($opt_default) {
$SSL_DIR = $pkg_config->{dir};
}
else {
print <<"INFO";
=======================================================
Only one $pkg_config->{type} installation found at $pkg_config->{dir}
Consider running 'perl Makefile.PL --default' the next
time Crypt::SSLeay is upgraded to select this directory
automatically thereby avoiding the following prompt.
=======================================================
INFO
}
}
elsif (@CANDIDATE > 1) {
print "Found multiple possibilities for OpenSSL\n";
for my $c (@CANDIDATE) {
print " $c->{dir} ($c->{type} $c->{ver})\n";
}
}
if (not $SSL_DIR) {
my %cand;
for my $c (@CANDIDATE) {
$cand{$c->{dir}} = {%$c};
}
$SSL_DIR = prompt "Which SSL install path do you want to use?",
$CANDIDATE[0]->{dir};
if (exists $cand{$SSL_DIR}) {
# we've already determined that this directory is usable
$pkg_config = $cand{$SSL_DIR};
}
else {
# unknown directory, better check it out
$pkg_config = Candidate($SSL_DIR);
if (not $pkg_config) {
die <<"INFO";
$SSL_DIR does not appear to be an SSL library installation, since
the required header files were not found. The build cannot proceed.
INFO
}
# fix CPAN bug #28680
if (! -e "$pkg_config->{inc}/$pkg_config->{prefix}/ssl.h") {
if (-e "$pkg_config->{inc}/ssl.h") {
$pkg_config->{prefix} = '';
}
else {
print "Failed to understand your layout, the build will probably fail.\n";
}
}
}
}
# note: $SSL_DIR is now sane at this point
my (@INC_FLAGS, @LIB_FLAGS);
if ($^O eq 'VMS') {
push @INC_FLAGS, "-I$pkg_config->{inc}";
push @LIB_FLAGS, qw(-L/SYS$SHARE -lSSL$LIBSSL_SHR32 -lSSL$LIBCRYPTO_SHR32);
}
elsif ($^O eq 'MSWin32') {
# external tools probably expect \ and not / for path separators
$SSL_DIR =~ tr{/}{\\};
# default to drive C: if no drive or relative path
$SSL_DIR = "c:$SSL_DIR" if $SSL_DIR !~ m{\A(?:[a-z]:|\.\.[\\/])}i;
my $inc = $pkg_config->{inc};
$inc =~ tr{/}{\\};
$inc = "c:$inc" if $inc !~ m{\A(?:[a-z]:|\.\.[\\/])}i;
push @INC_FLAGS, "-I$inc";
push @INC_FLAGS, "-I$SSL_DIR\\inc32" if -d "$SSL_DIR/inc32";
my $vanilla = $Config{cc} eq 'gcc' ? 1 : 0;
$vanilla and print "Assuming Vanilla/Strawberry Perl installation\n";
if ($vanilla and -d "$SSL_DIR\\lib\\MinGW") {
push @LIB_FLAGS, "-L$SSL_DIR\\lib\\MinGW";
}
elsif(-d "$SSL_DIR/lib") {
push @LIB_FLAGS, "-L$SSL_DIR\\lib";
}
else {
my $dir = $opt_static ? "$SSL_DIR\\out32" : "$SSL_DIR\\out32dll";
if (-d $dir) {
push @LIB_FLAGS, "-L$dir";
}
else {
# Allow developers to point at OpenSSL source...
push @LIB_FLAGS, "-L$SSL_DIR";
}
}
push @LIB_FLAGS, qw(-lssleay32 -llibeay32);
push @LIB_FLAGS, qw(-lRSAglue -lrsaref) if $pkg_config->{type} ne 'OpenSSL';
}
else {
push @INC_FLAGS, "-I$pkg_config->{inc}";
push @LIB_FLAGS, "-L$pkg_config->{lib}", qw(-lssl -lcrypto -lgcc);
push @LIB_FLAGS, qw(-lRSAglue -lrsaref) if $pkg_config->{type} ne 'OpenSSL';
# ccc on alpha support
if ($^O eq 'linux'
and `uname -m` =~ /alpha/
and !(system("nm $SSL_DIR/lib/libssl.a|grep -q 'U _Ots'")>>8)
) {
push @LIB_FLAGS, '-lots';
}
# this fix was suggested for building on RedHat 9
push @INC_FLAGS, '-I/usr/kerberos/include' if -d '/usr/kerberos/include';
}
# write include file that determines ssl support
# we need to include crypto.h for SSLeay so the version gets picked up in SSLeay.xs
open(INCLUDE, ">crypt_ssleay_version.h") || die("can't open crypt_ssleay_version.h for writing: $!");
print INCLUDE <<"INFO";
#include "$pkg_config->{prefix}ssl.h"
#include "$pkg_config->{prefix}crypto.h"
#include "$pkg_config->{prefix}err.h"
#include "$pkg_config->{prefix}rand.h"
#include "$pkg_config->{prefix}pkcs12.h"
INFO
if ($] < 5.005) {
print "adding PL_sv_undef symbol for this ancient perl installation";
print INCLUDE <<"INFO";
/* defining PL_sv_undef for very old perls ($]) */
#ifndef PL_sv_undef
#define PL_sv_undef sv_undef
#endif
INFO
}
if ($pkg_config->{type} eq 'OpenSSL') {
# OPENSSL_free defined in OpenSSL 0.9.6 and higher
if ($pkg_config->{ver} =~ /\b0\.9\.[2-5]/) {
print INCLUDE "#define CRYPT_SSLEAY_free free\n";
}
else {
print INCLUDE "#define CRYPT_SSLEAY_free OPENSSL_free\n";
}
}
else {
print INCLUDE "#define CRYPT_SSLEAY_free free\n";
}
close INCLUDE or die "Cannot close crypt_ssleay_version.h for output: $!\n";
print <<"INFO";
BUILD INFORMATION
================================================
ssl library: $pkg_config->{type} $pkg_config->{ver} in $SSL_DIR
ssl header: $pkg_config->{prefix}ssl.h
libraries: @LIB_FLAGS
include dir: @INC_FLAGS
================================================
INFO
my @license =
do {
my $version = $ExtUtils::MakeMaker::VERSION;
$version =~ tr/_//d;
$version} > 6.30
? qw(LICENSE perl)
: ();
WriteMakefile(
NAME => 'Crypt::SSLeay',
AUTHOR => 'David Landgren',
ABSTRACT_FROM => 'SSLeay.pm',
VERSION_FROM => 'SSLeay.pm',
LIBS => ["@LIB_FLAGS"],
INC => "@INC_FLAGS",
NEEDS_LINKING => 1,
clean => {
FILES => 'crypt_ssleay_version.h test.config',
},
@license,
);
if (open OUT, '> test.config') {
print OUT <<"INFO";
ssl $pkg_config->{type} $pkg_config->{ver} in $SSL_DIR
lib @LIB_FLAGS
inc @INC_FLAGS
cc $Config{cc}
INFO
print <<"INFO";
The test suite can attempt to connect to public servers
to ensure that the code is working properly. If you are
behind a strict firewall or have no network connectivity,
these tests may fail (through no fault of the code).
INFO
my $network_tests = prompt
"Do you want to run the live tests (y/N) ?",
'N';
print OUT "network_tests ", ($network_tests =~ /y/i) ? 1 : 0, "\n";
close OUT;
}
## HELPERS
sub Candidate {
my $dir = shift;
return unless -d $dir;
my $inc_dir;
my $version_file;
for (
"$dir/inc32/openssl/opensslv.h", # old win32 builds
"$dir/crypto/opensslv.h", # cygwin32 builds
"$dir/include/openssl/opensslv.h",
"$dir/../include/openssl/opensslv.h", # Solaris
"$dir/include/opensslv.h",
"$dir/include/crypto.h"
) {
if (-e $_) {
$version_file = $_;
last;
}
}
return unless defined $version_file;
my $fingerprint = join(':', (stat $version_file)[0,1]);
my $open_ssl = ($version_file =~ /openssl/i) ? 1 : 0;
$inc_dir = dirname($version_file);
return unless -e "$inc_dir/ssl.h";
my $prefix;
if ($^O eq 'MSWin32') {
$inc_dir =~ s{[\\/]openssl\z}{};
$prefix = 'openssl/';
}
elsif (index($inc_dir, '/../') > -1) {
# OpenSSL include directory is in a sibling directory
$inc_dir =~ s{\/openssl\z}{};
$prefix = 'openssl/';
}
else {
$prefix = ($inc_dir =~ /\bopenssl/i) ? 'openssl/' : '';
}
open(VERSION_FILE, $version_file) or return;
my $version_match = $open_ssl ? "OPENSSL_VERSION_NUMBER" : "SSLEAY_VERSION_NUMBER";
my $version;
my $type;
while (<VERSION_FILE>) {
if (/^#define\s+$version_match\s+0x0+(\d\d\d)/) {
$version = $1;
$version =~ s/(\d)0(\d)/$1$2/;
$type = ($version > 92) ? "OpenSSL" : "SSLeay";
$version = join('.', split(//, "0$version"));
last;
}
}
close(VERSION_FILE);
# Silly test to look for the library files
my $found_lib;
my $libd;
my $subdir = $opt_static ? 'out32' : 'out32dll';
if (-d "$dir/$subdir") {
$libd = [$subdir];
}
elsif ($^O eq 'MSWin32' and $Config{cc} eq 'gcc') {
$libd = ['lib/MinGW'];
}
else {
# second attempt is for Solaris, like the include directory, the
# library directory may be in a sibling directory
$libd = ['lib', '../lib'];
}
SCAN:
for my $d (@$libd) {
my $lib_dir = "$dir/$d";
if (opendir(LIBDIR, $lib_dir)) {
while (defined($_ = readdir(LIBDIR))) {
if (/\A(?:lib(?:crypto|eay32|ssl)|ssleay32)/) {
$found_lib = $lib_dir;
last SCAN;
}
}
closedir(LIBDIR);
}
}
if (!$found_lib) {
my @tried = join( ',' => map {"$dir/$_"} @$libd);
print "Did not locate expected SSL library files in @tried\n";
}
return {
dir => $dir,
inc => $inc_dir,
lib => $found_lib,
ver => $version,
type => $type,
prefix => $prefix,
check => $fingerprint,
};
}