summaryrefslogtreecommitdiff
path: root/t/lib/Helper.pm
blob: ca08b35a33a37ee594db5ebf40fe1d58d4ce557b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package Helper;
use strict;
# compatible use warnings
BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } }

use Config;
use Cwd;
use Exporter;
use IO::File;
use File::Spec::Functions qw/catfile canonpath splitdir/;
use File::Temp qw/tempdir/;

use vars qw/@EXPORT @ISA/;
@ISA = qw/Exporter/;
@EXPORT = qw(
    create_testlib
    find_compiler
    find_binary
);

my $orig_wd = cwd;

BEGIN { require Devel::CheckLib; } # for _quiet_system()
sub _quiet_system {
    goto &Devel::CheckLib::_quiet_system;
}

#--------------------------------------------------------------------------#
# create_testlib( 'bazbam' )
#
# takes a library name and compiles a simple library with two functions, 
# foo() (which returns 0) and libversion() (which returns 42), in a temp
# directory and returns the temp directory.  Returns undef if something
# went wrong
#--------------------------------------------------------------------------#

sub create_testlib {
    my ($libname) = (@_);
    return unless $libname;
    my $tempdir = tempdir(CLEANUP => 1, TEMPLATE => "Devel-Assert-testlib-XXXXXXXX");
    chdir $tempdir;
    my $code_fh = IO::File->new("${libname}.c", ">");
    print {$code_fh} "int libversion() { return 42; }\nint foo() { return 0; }\n";
    $code_fh->close;

    my $cc = (split(/\s+/, $Config{cc}))[0];
    my $gccv = $Config{gccversion};
    my $rv =
        $cc eq 'gcc'    ? _gcc_lib( $libname )  :
        $cc eq 'cc'     ? _gcc_lib( $libname )  :
        $cc eq 'cl'     ? _cl_lib( $libname )   :
        $gccv           ? _gcc_lib( $libname )  :
                          undef         ;

    chdir $orig_wd;
    return $rv ? canonpath($tempdir) : undef;
}

sub _gcc_lib {
    my ($libname) = @_;
    my $cc = find_compiler() or return;
    my $ar = find_binary('ar') or return;
    my $ranlib = find_binary('ranlib') or return;
    my $ccflags = $Config{ccflags};
    my $libfile = "lib${libname}.a";
    _quiet_system(qq{"$cc" $ccflags -c ${libname}.c}) and return;
    _quiet_system($ar, 'rc', $libfile, "${libname}$Config{_o}") and return;
    _quiet_system($ranlib, $libfile) and return;
    return -f $libfile
}

sub _cl_lib {
    my ($libname) = @_;
    my $cc = find_compiler() or return;
    my $ar = find_binary('lib') or return;
    _quiet_system($cc, '/c',  "${libname}.c") and return;
    _quiet_system($ar, "${libname}$Config{_o}") and return;
    return -f "${libname}.lib";
}

#--------------------------------------------------------------------------#
# find_binary, find_compiler
#
# Returns absolute path to an executable file in $ENV{PATH} or undef 
# if it can't be found.  find_binary() takes a program argument;
# find_compiler takes no arguments and just returns the path to $Config{cc}
#--------------------------------------------------------------------------#

sub find_binary {
    my ($program) = @_;
    if ($Config{_exe} && $program !~ /$Config{_exe}$/) {
        $program .= $Config{_exe};
    }
    return $program if -x $program;

    my @search_paths = split /$Config{path_sep}/, $ENV{PATH};
    my @lib_search_paths = map lib_to_bin($_), split /$Config{path_sep}/, $ENV{LIBRARY_PATH}||'';

    for my $path ( @search_paths, @lib_search_paths ) {
        my $binary = catfile( $path, $program );
        return $binary if -x $binary;
    }

    return;
}

sub lib_to_bin {
    my ( $lib_dir ) = @_;
    my @parts = splitdir $lib_dir;
    pop @parts;
    push @parts, 'bin';
    my $bin_dir = catfile(@parts);
    return $bin_dir;
}

sub find_compiler {
    my $result = find_binary($Config{cc});
    return $result if($result);

    # sometimes $Config{cc} isn't very clean eg it can be 'cc -q32' on AIX
    return find_binary((split(/\s+/, $Config{cc}))[0])
        if($Config{cc} =~ /\s/);

    undef;
}

1; # must be true