调用内联C库中的函数

5
我试图使用CommonMark C库和Inline::C创建一个简单的包装器。我已经在/usr/local/lib/下安装了libcmark.so
我的当前代码如下:
package Text::CommonMark;

use strict;
use warnings;

sub commonmarker {
    my $text = shift;
    return commonmark_to_html($text);
}

use Inline C => qq{

    char* commonmark_to_html(char* thetext) {

        char* result = cmark_markdown_to_html(thetext, strlen(thetext));
        return result;
    }
} => LIBS => '-L/usr/local/lib/ -llibcmark.so';

1;

当我从一个脚本中使用commonmarker时,我得到:

perl: symbol lookup error: /home/erik/sublimeworks/dists/Text-CommonMark/_Inline/lib/auto/Text/CommonMark_33fb/CommonMark_33fb.so: undefined symbol: cmark_markdown_to_html

我猜测我的调用与它的签名不匹配,但我在找到的所有的签名中,都是这样的:found

char *cmark_markdown_to_html(const char *text, int len)

我以前没有接触过C或Inline::C,所以可能会有所遗漏。


1
提示:使用 q{} 而不是 qq{} 可以减少转义的次数。更好的方法是使用 <<'EOC',这样你就不必转义任何东西了。 - ikegami
1
我认为这不是原型不匹配的问题。我认为该符号在库中找不到,或者库本身未被找到。perl -MInline=force,info,noclean script.pl 可能会提供更多信息。 - ikegami
2个回答

4

文档中没有提到LIBS。该选项的名称为libs

use Inline C => config => libs => '-L/usr/local/lib/ -llibcmark.so';
use Inline C => <<'__EOC__';

    char* commonmark_to_html(char* thetext) {
        char* result = cmark_markdown_to_html(thetext, strlen(thetext));
        return result;
    }

__EOC__

请注意,在XS函数中使用char* thetext作为参数是一个错误的迹象。这将给你一个指向字符串缓冲区的指针,而不告诉你缓冲区的格式。
假设该库接受并返回使用UTF-8编码的文本,
SV* commonmark_to_html(SV* text_sv) {
    STRLEN text_len;
    const char* text = SvPVutf8(text_sv, text_len);
    const char* html = cmark_markdown_to_html(text, text_len);
    SV* html_sv = newSVpvn_flags(html, strlen(html), SVf_UTF8);
    free(html);
    return html_sv;
}

稍作优化(由于使用newSVpvn_flags使标量自动回收比由类型映射生成的代码调用sv_2mortal更有效率):

void commonmark_to_html(SV* text_sv) {
    STRLEN text_len;
    const char* text = SvPVutf8(text_sv, text_len);
    const char* html = cmark_markdown_to_html(text, text_len);
    SV* html_sv = newSVpvn_flags(html, strlen(html), SVf_UTF8|SVs_TEMP);
    free(html);
    ST(0) = html_sv;
    XSRETURN(1);
}

我猜应该是:... => config => libs => ...(没有 'libs =>' 会出现 'Invalid usage of Inline module.')但仍然出现相同的错误。我从Inline::C::Cookbook中得到了'LIBS'。 - Csson
1
@Csson,哎呀,是的,已经修复了。那么,要么库中不包含符号“cmark_markdown_to_html”,要么它无法找到库。后者应该会导致警告出现在“perl -MInline=force,info,noclean script.pl”中。 - ikegami
什么是问题? - ikegami
整个内联函数... :) - Csson
我的意思是,你之前提出的问题有什么解决方案?你曾经提到过我的修复没有起作用,但现在你又说一切都好了。我们应该记录下实际的解决方案,以便未来的读者参考。 - ikegami
显示剩余2条评论

2

你的-l参数看起来有问题。通常编译器/链接器会在前缀添加"lib",在后缀添加".so",所以通常你只需要提供

-lcmark

它实际上可以两种方式使用,但了解这一点是很好的。谢谢! - Csson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接