我在 C++ 程序(Ubuntu 14、Perl 5.18,如果重要的话)中嵌入了一些 Perl 代码,然后像 this example 中那样执行 Perl .
更具体地说,我:
- 创建 perl 实例,然后按照“perlembed”手册中的描述加载持久性代码
评估一些“准备”代码:
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);
评估我的实际 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/