Ich habe ein Modul, das auf verschiedene Betriebssysteme und Konfigurationen zielt. Manchmal kann ein C-Code die Aufgabe dieses Moduls ein wenig einfacher machen, also habe ich einige C-Funktionen, die ich den Code binden möchte. Ich habe keine haben binden die C-Funktionen - Ich kann nicht garantieren , dass der Endbenutzer sogar einen C-Compiler zum Beispiel hat, und es ist in der Regel kein Problem, Failover anmutig zu einem reinen Perl Weg Vollendung das gleiche - aber es wäre schön, wenn ich die C-Funktionen aus dem Perl-Skript aufrufen könnte.Wie kompiliere ich C-Code-Snippets zu meinem Perl-Modul bedingt?
Immer noch mit mir? Hier ist ein weiterer kniffliger Teil. Fast alle der C-Code ist systemspezifisch - eine für Windows geschriebene Funktion kompiliert nicht auf Linux und umgekehrt, und die Funktion, die eine ähnliche Sache auf Solaris tut, wird völlig anders aussehen.
#include <some/Windows/headerfile.h>
int foo_for_Windows_c(int a,double b)
{
do_windows_stuff();
return 42;
}
#include <path/to/linux/headerfile.h>
int foo_for_linux_c(int a,double b)
{
do_linux_stuff(7);
return 42;
}
Darüber hinaus auch für native Code, der das gleiche System zielt, ist es möglich, dass nur einige von ihnen können auf eine bestimmte Konfiguration zusammengestellt werden.
#include <some/headerfile/that/might/not/even/exist.h>
int bar_for_solaris_c(int a,double b)
{
call_solaris_library_that_might_be_installed_here(11);
return 19;
}
Aber im Idealfall könnten wir noch die C-Funktionen verwenden, die mit dieser Konfiguration zusammenstellen würde. Also meine Fragen sind:
wie kann ich kompilieren C-Funktionen bedingt (kompilieren nur den Code, dass für den aktuellen Wert von
$^O
geeignet ist)?Wie kann ich C-Funktionen einzeln kompilieren (einige Funktionen könnten nicht kompilieren, aber wir wollen immer noch diejenigen verwenden, die)?
kann ich dies während der Bauzeit (während der Endbenutzer das Modul installiert) oder zur Laufzeit (z. B. mit
Inline::C
) tun? Welcher Weg ist besser?Wie würde ich sagen, welche Funktionen erfolgreich kompiliert wurden und sind zur Verwendung von Perl zur Verfügung?
Alle Gedanken geschätzt!
Update: Vielen Dank an alle, die geantwortet haben.Also hier ist, was ich tat:
ich ein System von Laufzeit mit Inline::C
innerhalb von eval
Aussagen bindend betrachtet, aber letztlich setzte sich auf Subklassen Module::Build
und das Anpassen der ACTION_build
Methode:
my $builderclass = Module::Build->subclass(
class => 'My::Custom::Builder',
code => <<'__CUSTOM_BUILD_CODE__,',
sub ACTION_build {
use File::Copy;
my $self = shift;
### STEP 1: Compile all .xs files, remove the ones that fail ###
if (! -f "./lib/xs/step1") {
unlink <lib/xs/*>;
foreach my $contrib_file (glob("contrib/*.xs")) {
File::Copy::copy($contrib_file, "lib/xs/");
}
open my $failed_units_fh, '>', 'lib/xs/step1';
local [email protected] = undef;
do {
my $r = eval { $self->ACTION_code() };
if ([email protected] =~ /error building (\S+\.o) from/i
|| [email protected] =~ /error building dll file from '(\S+\.c)'/i) {
my $bad_file = $1;
$bad_file =~ s!\\!/!g;
my $bad_xs = $bad_file;
$bad_xs =~ s/.[oc]$/.xs/;
print STDERR "ERROR COMPILING UNIT $bad_xs ... removing\n\n";
unlink $bad_xs;
print $failed_units_fh "$bad_xs\n";
} elsif ([email protected]) {
print STDERR "Compile error not handled in $^O: [email protected]\n";
}
} while [email protected];
print "Removed all uncompilable units from lib/xs/\n";
close $failed_units_fh;
}
### STEP 2: Combine valid .xs files into a single .xs file ###
if (! -f "./lib/xs/step2") {
open my $valid_units_fh, '>', "lib/xs/step2";
my (@INCLUDE,%INCLUDE,$MODULE,@PREMOD,@POSTMOD);
foreach my $xs (glob("lib/xs/*.xs")) {
open my $xs_fh, '<', $xs;
while (<$xs_fh>) {
if (m/#include/) {
next if $INCLUDE{$_}++;
push @INCLUDE, $_;
} elsif (/^MODULE/) {
$MODULE = $_;
push @POSTMOD, <$xs_fh>;
} else {
push @PREMOD, $_;
}
}
close $xs_fh;
print $valid_units_fh "$xs\n";
}
close $valid_units_fh;
unlink <lib/xs/*>, <blib/arch/auto/xs/*/*>;
unlink 'lib/My/Module.xs';
open my $xs_fh, '>', 'lib/My/Module.xs' or croak $!;
print $xs_fh @INCLUDE, @PREMOD, $MODULE, @POSTMOD;
close $xs_fh;
print "Assembled remaining XS files into lib/My/Module.xs\n";
}
### STEP 3: Clean all .xs stuff and compile My/Module.xs ###
unlink <lib/xs/*>;
$self->ACTION_code();
return $self->SUPER::ACTION_build(@_);
}
}
Die Überprüfung [email protected]
ist wahrscheinlich ziemlich zerbrechlich. Es funktioniert auf den Systemen Ich habe versucht (alle mit gcc), aber es wird wahrscheinlich nicht funktionieren, wie es überall geschrieben wird.
Intriguing ... Ich werde das 'Module :: Build' Kugel beißen und versuchen dies. Sollten die Dateien in 'contrib /' C oder XS sein? XS wäre eine weitere Kugel zu beißen. – mob
Muss XS sein. – daxim