gpt4 book ai didi

perl - 如何有条件地将 C 代码片段编译到我的 Perl 模块?

转载 作者:行者123 更新时间:2023-12-04 17:58:58 26 4
gpt4 key购买 nike

我有一个针对几个不同操作系统的模块
和配置。有时,一些 C 代码可以完成这个模块的任务
简单一点,所以我有一些我想绑定(bind)的 C 函数
编码。我没有 绑定(bind) C 函数——我不能保证
例如,最终用户甚至有一个 C 编译器,而且它通常是
优雅地故障转移到纯粹的 Perl 完成方式不是问题
同样的事情——但如果我能调用 C 函数就好了
来自 Perl 脚本。

还在我这儿?这是另一个棘手的部分。几乎所有的 C 代码
是系统特定的——为 Windows 编写的函数不会编译
Linux 和反之亦然,以及在
Solaris 看起来会完全不同。

#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;
}

此外,即使对于针对同一系统的 native 代码,它也是
可能只有其中一些可以在任何特定的
配置。
#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;
}

但理想情况下,我们仍然可以使用可以编译的 C 函数
使用该配置。所以我的问题是:
  • 如何有条件地编译 C 函数(只编译
    适用于 $^O 的当前值)?
  • 如何单独编译 C 函数(某些函数可能不
    编译,但我们仍然想使用那些可以的)?
  • 我可以在构建时执行此操作吗(最终用户正在安装
    模块)还是在运行时(例如 Inline::C )?哪一个
    方式更好?
  • 我如何判断哪些函数已成功编译并且是
    可以从 Perl 中使用吗?

  • 所有想法表示赞赏!

    更新:感谢所有回复的人。所以这就是我所做的:

    我考虑了一个运行时绑定(bind)的方案 Inline::C代替 eval声明,但最终确定子类 Module::Build并定制 ACTION_build方法:
    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 $@ = undef;
    do {
    my $r = eval { $self->ACTION_code() };
    if ($@ =~ /error building (\S+\.o) from/i
    || $@ =~ /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 ($@) {
    print STDERR "Compile error not handled in $^O: $@\n";
    }
    } while $@;
    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(@_);
    }
    }

    检查 $@可能很脆弱。它适用于系统
    我已经尝试过(全部使用 gcc),但它可能无法像它所写的那样工作
    到处。

    最佳答案

    理想情况下,使用 Module::Build .在配置时(perl Build.PL),检测平台和头部位置(但也让用户指定命令行选项来覆盖检测),设置相关的extra_compiler_flagsextra_linker_flags在构造函数中,然后从例如复制相关文件contriblib (它们将被 ExtUtils::CBuilder 自动拾取)。现在分发已针对平台进行了定制——接下来的步骤 (./Build ; …) 将正常工作。

    关于perl - 如何有条件地将 C 代码片段编译到我的 Perl 模块?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2590363/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com