Initial Commit

This commit is contained in:
Riley Schneider
2025-12-03 16:38:10 +01:00
parent c5e26bf594
commit b732d8d4b5
17680 changed files with 5977495 additions and 2 deletions

View File

@@ -0,0 +1,194 @@
package FFI::Probe::Runner;
use strict;
use warnings;
use 5.008004;
use Capture::Tiny qw( capture );
use FFI::Probe::Runner::Result;
# ABSTRACT: Probe runner for FFI
our $VERSION = '1.34'; # VERSION
sub new
{
my($class, %args) = @_;
$args{exe} ||= do {
require FFI::Platypus::ShareConfig;
require File::Spec;
require Config;
File::Spec->catfile(FFI::Platypus::ShareConfig::dist_dir('FFI::Platypus'), 'probe', 'bin', "dlrun$Config::Config{exe_ext}");
};
defined $args{flags} or $args{flags} = '-';
die "probe runner executable not found at: $args{exe}" unless -f $args{exe};
my $self = bless {
exe => $args{exe},
flags => $args{flags},
}, $class;
$self;
}
sub exe { shift->{exe} }
sub flags { shift->{flags} }
sub verify
{
my($self) = @_;
my $exe = $self->exe;
my($out, $err, $ret) = capture {
$! = 0;
system $exe, 'verify', 'self';
};
return 1 if $ret == 0 && $out =~ /dlrun verify self ok/;
print $out;
print STDERR $err;
die "verify failed";
}
sub run
{
my($self, $dll, @args) = @_;
my $exe = $self->exe;
my $flags = $self->flags;
my($out, $err, $ret) = capture {
my @cmd = ($exe, $dll, $flags, @args);
$! = 0;
system @cmd;
$?;
};
FFI::Probe::Runner::Result->new(
stdout => $out,
stderr => $err,
rv => $ret >> 8,
signal => $ret & 127,
);
}
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
FFI::Probe::Runner - Probe runner for FFI
=head1 VERSION
version 1.34
=head1 SYNOPSIS
use FFI::Probe::Runner;
my $runner = FFI::Probe::Runner->new;
$runner->run('foo.so');
=head1 DESCRIPTION
This class executes code in a dynamic library for probing and detecting platform
properties.
=head1 CONSTRUCTOR
=head2 new
my $runner = FFI::Probe::Runner->new(%args);
Creates a new instance.
=over 4
=item exe
The path to the dlrun wrapper. The default is usually correct.
=item flags
The flags to pass into C<dlopen>. The default is C<RTLD_LAZY> on Unix
and C<0> on windows..
=back
=head1 METHODS
=head2 exe
my $exe = $runner->exe;
The path to the dlrun wrapper.
=head2 flags
my $flags = $runner->flags;
The flags to pass into C<dlopen>.
=head2 verify
$runner->verify;
Verifies the dlrun wrapper is working. Throws an exception in the event of failure.
=head2 run
$runner->run($dll, @args);
Runs the C<dlmain> function in the given dynamic library, passing in the
given arguments. Returns a L<FFI::Probe::Runner::Result> object which
contains the results.
=head1 AUTHOR
Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>
Contributors:
Bakkiaraj Murugesan (bakkiaraj)
Dylan Cali (calid)
pipcet
Zaki Mughal (zmughal)
Fitz Elliott (felliott)
Vickenty Fesunov (vyf)
Gregor Herrmann (gregoa)
Shlomi Fish (shlomif)
Damyan Ivanov
Ilya Pavlov (Ilya33)
Petr Pisar (ppisar)
Mohammad S Anwar (MANWAR)
Håkon Hægland (hakonhagland, HAKONH)
Meredith (merrilymeredith, MHOWARD)
Diab Jerius (DJERIUS)
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2015,2016,2017,2018,2019,2020 by Graham Ollis.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut

View File

@@ -0,0 +1,528 @@
package FFI::Probe::Runner::Builder;
use strict;
use warnings;
use 5.008004;
use Config;
use Capture::Tiny qw( capture_merged );
use Text::ParseWords ();
use FFI::Build::Platform;
# ABSTRACT: Probe runner builder for FFI
our $VERSION = '1.34'; # VERSION
sub new
{
my($class, %args) = @_;
$args{dir} ||= 'blib/lib/auto/share/dist/FFI-Platypus/probe';
my $platform = FFI::Build::Platform->new;
my $self = bless {
dir => $args{dir},
platform => $platform,
# we don't use the platform ccflags, etc because they are geared
# for building dynamic libs not exes
cc => [$platform->shellwords($Config{cc})],
ld => [$platform->shellwords($Config{ld})],
ccflags => [$platform->shellwords($Config{ccflags})],
optimize => [$platform->shellwords($Config{optimize})],
ldflags => [$platform->shellwords($Config{ldflags})],
libs =>
$^O eq 'MSWin32'
? [[]]
: [['-ldl'], [], map { [$_] } grep !/^-ldl/, $platform->shellwords($Config{perllibs})],
}, $class;
$self;
}
sub dir
{
my($self, @subdirs) = @_;
my $dir = $self->{dir};
if(@subdirs)
{
require File::Spec;
$dir = File::Spec->catdir($dir, @subdirs);
}
unless(-d $dir)
{
require File::Path;
File::Path::mkpath($dir, 0, oct(755));
}
$dir;
}
sub cc { shift->{cc} }
sub ccflags { shift->{ccflags} }
sub optimize { shift->{optimize} }
sub ld { shift->{ld} }
sub ldflags { shift->{ldflags} }
sub libs { shift->{libs} }
sub file
{
my($self, @sub) = @_;
@sub >= 1 or die 'usage: $builder->file([@subdirs], $filename)';
my $filename = pop @sub;
require File::Spec;
File::Spec->catfile($self->dir(@sub), $filename);
}
my $source;
sub exe
{
my($self) = @_;
my $xfn = $self->file('bin', "dlrun$Config{exe_ext}");
}
sub source
{
unless($source)
{
local $/;
$source = <DATA>;
}
$source;
}
our $VERBOSE = !!$ENV{V};
sub extract
{
my($self) = @_;
# the source src/dlrun.c
{
print "XX src/dlrun.c\n" unless $VERBOSE;
my $fh;
my $fn = $self->file('src', 'dlrun.c');
my $source = $self->source;
open $fh, '>', $fn or die "unable to write $fn $!";
print $fh $source;
close $fh;
}
# the bin directory bin
{
print "XX bin/\n" unless $VERBOSE;
$self->dir('bin');
}
}
sub run
{
my($self, $type, @cmd) = @_;
@cmd = map { ref $_ ? @$_ : $_ } @cmd;
my($out, $ret) = capture_merged {
$self->{platform}->run(@cmd);
};
if($ret)
{
print STDERR $out;
die "$type failed";
}
print $out if $VERBOSE;
$out;
}
sub run_list
{
my($self, $type, @commands) = @_;
my $log = '';
foreach my $cmd (@commands)
{
my($out, $ret) = capture_merged {
$self->{platform}->run(@$cmd);
};
if($VERBOSE)
{
print $out;
}
else
{
$log .= $out;
}
return if !$ret;
}
print $log;
die "$type failed";
}
sub build
{
my($self) = @_;
$self->extract;
# this should really be done in `new` but the build
# scripts for FFI-Platypus edit the ldfalgs from there
# so. Also this may actually belong in FFI::Build::Platform
# which would resolve the problem.
if($^O eq 'MSWin32' && $Config{ccname} eq 'cl')
{
$self->{ldflags} = [
grep !/^-nodefaultlib$/i,
@{ $self->{ldflags} }
];
}
my $cfn = $self->file('src', 'dlrun.c');
my $ofn = $self->file('src', "dlrun$Config{obj_ext}");
my $xfn = $self->exe;
# compile
print "CC src/dlrun.c\n" unless $VERBOSE;
$self->run(
compile =>
$self->cc,
$self->ccflags,
$self->optimize,
'-c',
$self->{platform}->flag_object_output($ofn),
$cfn,
);
# link
print "LD src/dlrun$Config{obj_ext}\n" unless $VERBOSE;
$self->run_list(link =>
map { [
$self->ld,
$self->ldflags,
$self->{platform}->flag_exe_output($xfn),
$ofn,
@$_
] } @{ $self->libs },
);
## FIXME
if($^O eq 'MSWin32' && $Config{ccname} eq 'cl')
{
if(-f 'dlrun.exe' && ! -f $xfn)
{
rename 'dlrun.exe', $xfn;
}
}
# verify
print "VV bin/dlrun$Config{exe_ext}\n" unless $VERBOSE;
my $out = $self->run(verify => $xfn, 'verify', 'self');
if($out !~ /dlrun verify self ok/)
{
print $out;
die "verify failed string match";
}
# remove object
print "UN src/dlrun$Config{obj_ext}\n" unless $VERBOSE;
unlink $ofn;
$xfn;
}
1;
=pod
=encoding UTF-8
=head1 NAME
FFI::Probe::Runner::Builder - Probe runner builder for FFI
=head1 VERSION
version 1.34
=head1 SYNOPSIS
use FFI::Probe::Runner::Builder;
my $builder = FFI::Probe::Runner::Builder->new
dir => "/foo/bar",
);
my $exe = $builder->build;
=head1 DESCRIPTION
This is a builder class for the FFI probe runner. It is mostly only of
interest if you are hacking on L<FFI::Platypus> itself.
The interface may and will change over time without notice. Use in
external dependencies at your own peril.
=head1 CONSTRUCTORS
=head2 new
my $builder = FFI::Probe::Runner::Builder->new(%args);
Create a new instance.
=over 4
=item dir
The root directory for where to place the probe runner files.
Will be created if it doesn't already exist. The default
makes sense for when L<FFI::Platypus> is being built.
=back
=head1 METHODS
=head2 dir
my $dir = $builder->dir(@subdirs);
Returns a subdirectory from the builder root. Directory
will be created if it doesn't already exist.
=head2 cc
my @cc = @{ $builder->cc };
The C compiler to use. Returned as an array reference so that it may be modified.
=head2 ccflags
my @ccflags = @{ $builder->ccflags };
The C compiler flags to use. Returned as an array reference so that it may be modified.
=head2 optimize
The C optimize flags to use. Returned as an array reference so that it may be modified.
=head2 ld
my @ld = @{ $builder->ld };
The linker to use. Returned as an array reference so that it may be modified.
=head2 ldflags
my @ldflags = @{ $builder->ldflags };
The linker flags to use. Returned as an array reference so that it may be modified.
=head2 libs
my @libs = @{ $builder->libs };
The library flags to use. Returned as an array reference so that it may be modified.
=head2 file
my $file = $builder->file(@subdirs, $filename);
Returns a file in a subdirectory from the builder root.
Directory will be created if it doesn't already exist.
File will not be created.
=head2 exe
my $exe = $builder->exe;
The name of the executable, once it is built.
=head2 source
my $source = $builder->source;
The C source for the probe runner.
=head2 extract
$builder->extract;
Extract the source for the probe runner.
=head2 run
$builder->run($type, @command);
Runs the given command. Dies if the command fails.
=head2 run_list
$builder->run($type, \@command, \@command, ...);
Runs the given commands in order until one succeeds.
Dies if they all fail.
=head2 build
my $exe = $builder->build;
Builds the probe runner. Returns the path to the executable.
=head1 AUTHOR
Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>
Contributors:
Bakkiaraj Murugesan (bakkiaraj)
Dylan Cali (calid)
pipcet
Zaki Mughal (zmughal)
Fitz Elliott (felliott)
Vickenty Fesunov (vyf)
Gregor Herrmann (gregoa)
Shlomi Fish (shlomif)
Damyan Ivanov
Ilya Pavlov (Ilya33)
Petr Pisar (ppisar)
Mohammad S Anwar (MANWAR)
Håkon Hægland (hakonhagland, HAKONH)
Meredith (merrilymeredith, MHOWARD)
Diab Jerius (DJERIUS)
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2015,2016,2017,2018,2019,2020 by Graham Ollis.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut
__DATA__
#if defined __CYGWIN__
#include <dlfcn.h>
#elif defined _WIN32
#include <windows.h>
#else
#include <dlfcn.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#if defined __CYGWIN__
typedef void * dlib;
#elif defined _WIN32
#define RTLD_LAZY 0
typedef HMODULE dlib;
dlib
dlopen(const char *filename, int flags)
{
(void)flags;
return LoadLibrary(filename);
}
void *
dlsym(dlib handle, const char *symbol_name)
{
return GetProcAddress(handle, symbol_name);
}
int
dlclose(dlib handle)
{
FreeLibrary(handle);
return 0;
}
const char *
dlerror()
{
return "an error";
}
#else
typedef void * dlib;
#endif
int
main(int argc, char **argv)
{
char *filename;
int flags;
int (*dlmain)(int, char **);
char **dlargv;
dlib handle;
int n;
int ret;
if(argc < 3)
{
fprintf(stderr, "usage: %s dlfilename dlflags [ ... ]\n", argv[0]);
return 1;
}
if(!strcmp(argv[1], "verify") && !strcmp(argv[2], "self"))
{
printf("dlrun verify self ok\n");
return 0;
}
#if defined WIN32
SetErrorMode(SetErrorMode(0) | SEM_NOGPFAULTERRORBOX);
#endif
dlargv = malloc(sizeof(char*)*(argc-2));
dlargv[0] = argv[0];
filename = argv[1];
flags = !strcmp(argv[2], "-") ? RTLD_LAZY : atoi(argv[2]);
for(n=3; n<argc; n++)
dlargv[n-2] = argv[n];
handle = dlopen(filename, flags);
if(handle == NULL)
{
fprintf(stderr, "error loading %s (%d|%s): %s", filename, flags, argv[2], dlerror());
return 1;
}
dlmain = dlsym(handle, "dlmain");
if(dlmain == NULL)
{
fprintf(stderr, "no dlmain symbol");
return 1;
}
ret = dlmain(argc-2, dlargv);
dlclose(handle);
return ret;
}

View File

@@ -0,0 +1,124 @@
package FFI::Probe::Runner::Result;
use strict;
use warnings;
use 5.008004;
# ABSTRACT: The results from a probe run.
our $VERSION = '1.34'; # VERSION
sub new
{
my($class, %args) = @_;
my $self = bless \%args, $class;
$self;
}
sub stdout { shift->{stdout} }
sub stderr { shift->{stderr} }
sub rv { shift->{rv} }
sub signal { shift->{signal} }
sub pass
{
my($self) = @_;
$self->rv == 0 && $self->signal == 0;
}
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
FFI::Probe::Runner::Result - The results from a probe run.
=head1 VERSION
version 1.34
=head1 SYNOPSIS
=head1 DESCRIPTION
=head1 CONSTRUCTOR
=head2 new
my $result = FFI::Probe::Runner::Result->new(%args);
Creates a new instance of the class.
=head1 METHODS
=head2 stdout
my $stdout = $result->stdout;
=head2 stderr
my $stderr = $result->stderr;
=head2 rv
my $rv = $result->rv;
=head2 signal
my $signal = $result->signal;
=head2 pass
my $pass = $result->pass;
=head1 AUTHOR
Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>
Contributors:
Bakkiaraj Murugesan (bakkiaraj)
Dylan Cali (calid)
pipcet
Zaki Mughal (zmughal)
Fitz Elliott (felliott)
Vickenty Fesunov (vyf)
Gregor Herrmann (gregoa)
Shlomi Fish (shlomif)
Damyan Ivanov
Ilya Pavlov (Ilya33)
Petr Pisar (ppisar)
Mohammad S Anwar (MANWAR)
Håkon Hægland (hakonhagland, HAKONH)
Meredith (merrilymeredith, MHOWARD)
Diab Jerius (DJERIUS)
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2015,2016,2017,2018,2019,2020 by Graham Ollis.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut