c++ - Perl 捕获嵌入式脚本的标准输出,如果在 dlopen 加载的共享库中则失败

标签 c++ perl

我在 C++ 程序(Ubuntu 14、Perl 5.18,如果重要的话)中嵌入了一些 Perl 代码,然后像 this example 中那样执行 Perl .

更具体地说,我:

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

    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);
    
  3. 评估我的实际 Perl 代码段

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

Perl 片段正常执行,只是获取标准输出失败。准确地说,这部分不起作用:

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"

最佳答案

我花了很长时间仔细研究这个问题,终于找到了问题:

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

如上所述重新路由标准输出涉及 Perl 库 scalar.so,Perl 在我的 Perl 片段执行时加载它。 lib scalar.so 包含对 PL_no_modify 的未解析引用,它再次在 libperl.so 中定义。现在,由于我在有效地调用 dlopen(mylib.so) 时没有指定 RTLD_GLOBAL scalar.so 没有看到 PL_no_modify 加载失败。

在我的代码中设置 RTLD_GLOBAL 后它起作用了。

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

关于c++ - Perl 捕获嵌入式脚本的标准输出,如果在 dlopen 加载的共享库中则失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32401918/

相关文章:

Perl 使用变量来引用模块会弄乱传递参数

windows - 如何在 Perl 脚本中的 Windows 控制台上询问密码?

c++ - 什么时候使用结构比在 C++ 中使用类更合理?

C++:BMP旋转图像

c++ - 帮助我理解 C++ 头文件和类

regex - 删除一个字段中具有特定模式的行

c++ - 为什么 C++ 编译器会在这里生成一个临时文件?

c++ - 如何使用 C++ 模型填充播放列表 qml 类型?

perl - 如何内联 Perl 子例程?

perl - Perl 作为元数据工具有何用处?