Perl捕获嵌入式脚本的stdout,如果在dlopen加载的共享库中失败

时间:2015-09-04 15:43:17

标签: c++ perl

我在C ++程序中有一些嵌入式Perl代码(Ubuntu 14,Perl 5.18,如果这很重要),我在this example中执行Perl。

更具体地说,我:

  1. 创建perl实例,然后按照“perlembed”手册
  2. 中的说明加载持久性代码
  3. 评估一些“准备”代码:

    static const char * redirPre = "$scriptOutput = \"\";\n"
            "open(SCRIPTOUTPUT, '> :scalar', \\$scriptOutput) || print STDERR \"Failed to open scriptoutput: $!\";\n"
            "print SCRIPTOUTPUT \"huhu\\n\";\n"
            "select SCRIPTOUTPUT;\n"
            "print SCRIPTOUTPUT \"huhu2\\n\";\n"
            "print STDOUT \"huhu2a\\n\";\n";
    printf("PRE: '%s'\n", redirPre);
    eval_pv(redirPre, FALSE);
    
  4. 评估我的实际Perl片段

  5. 现在奇怪的是,如果我静态链接调用所有Perl函数的代码,或者这些函数是在直接链接到主程序的共享库中,这可以很好地工作,而如果这些函数驻留在一个共享的lib,主程序使用dlopen加载。

    Perl片段正常执行,只是stdout失败。确切地说,这部分不起作用:

    open(SCRIPTOUTPUT, '> :scalar', \$scriptOutput) ||
      print STDERR "Failed to open scriptoutput: $!";
    

    无论我是指定>:scalar还是>

    有趣的是,输出也没有出现在stdout上,而是显示Failed to open scriptoutput:(但没有任何实际错误)。

    想法?

    编辑:使用完全相同的代码将stdout重新路由到/ tmp / xx可以很好地工作,唯一的区别是:

    "open(SCRIPTOUTPUT, '>', \"/tmp/xx\") || print STDERR \"Failed: $!\";\n"
    

1 个答案:

答案 0 :(得分:1)

我花了很长时间仔细研究这个问题,最后发现了问题:

最初我使用dlopen("mylib.so", RTLD_LAZY)加载了我自己的共享库,而lib又是使用libperl.so的引用构建的。 dlopen手册页指出,当隐式加载依赖库时,标志会向下传播,因此加载libperl也只是RTLD_LAZY。

如上所述重新路由stdout涉及Perl lib scalar.so,Perl在我的Perl片段执行时加载。 lib scalar.so包含对PL_no_modify的未解析引用,该引用再次在libperl.so中定义。现在,由于我在有效调用RTLD_GLOBAL时没有指定dlopen(mylib.so) scalar.so没有看到PL_no_modify并且无法加载。

在我的代码中设置RTLD_GLOBAL之后就可以了。

唯一剩下的问题是为什么Perl没有告诉我......: -