Tengo un módulo que se dirigirá a varios sistemas operativos diferentes y configuraciones. A veces, algunos códigos C pueden hacer que la tarea de este módulo sea un poco más fácil, por lo que tengo algunas funciones C que me gustaría vincular al código . No tengo tengo para enlazar las funciones C - No puedo garantizar que el usuario final tenga incluso un compilador C, por ejemplo, y generalmente es no es un problema para conmutar por error con gracia a un modo Perl puro de Alcanzando lo mismo, pero sería bueno si pudiera llamar a las funciones C del script de Perl.¿Cómo compilo condicionalmente los fragmentos de código C en mi módulo Perl?
¿Seguirme? Aquí hay otra parte difícil. Casi todo el código C es específico del sistema; una función escrita para Windows no se compilará en Linux y viceversa, y la función que hace algo similar en Solaris se verá totalmente diferente.
#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;
}
Por otra parte, incluso para código nativo que se dirige el mismo sistema, es posible que sólo algunos de ellos puede ser compilado en cualquier configuración particular .
#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;
}
Pero lo ideal aún podríamos utilizar las funciones C que recogería las con esa configuración. Así que mis preguntas son:
cómo puedo compilar condicionalmente funciones C (compilar sólo el código que es adecuado para el valor actual de
$^O
)?¿cómo puedo compilar las funciones de C individualmente (algunas funciones pueden no compilar , pero aún queremos usar las que sí pueden)?
¿Puedo hacer esto en tiempo de compilación (mientras el usuario final está instalando el módulo ) o en tiempo de ejecución (con
Inline::C
, por ejemplo)? ¿Qué forma de es mejor?¿Cómo puedo saber qué funciones se han compilado correctamente y están disponibles para Perl?
Todos los pensamientos apreciados!
Actualización: Gracias a todos los que respondieron.Así que aquí está lo que hice:
consideré un esquema de tiempo de ejecución de unión con Inline::C
interior de eval
declaraciones, pero finalmente se establecieron en la subclasificación Module::Build
y personalizar el ACTION_build
método:
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(@_);
}
}
La comprobación de [email protected]
es probablemente bastante frágil. Funciona en los sistemas Lo he intentado (todos usando gcc), pero probablemente no funcionará, ya que está escrito en todas partes.
intrigante ... voy a morder la bala 'Módulo :: Build' y probar esto. ¿Los archivos en 'contrib /' deberían ser C o XS? XS sería otra bala para morder. – mob
Necesita ser XS. – daxim