Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling function in inlined C library

Tags:

c

inline

perl

I'm trying to make a simple wrapper around the CommonMark C library using Inline::C. I have installed libcmark.so in /usr/local/lib/.

My current code looks like this:

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;

When using commonmarker from a script I get:

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

I assume that my call to cmark_markdown_to_html doesn't match its signature, but all signatures for cmark_markdown_to_html that I've found look like this:

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

I haven't touched either C or Inline::C before so I'm probably missing something.

like image 843
Csson Avatar asked Dec 17 '14 18:12

Csson


People also ask

Which functions Cannot be inlined?

The only situation in which a function cannot be inlined is if there is no definition for the function in the compilation unit.

How do you check if a function is inlined or not?

With gdb, if you cannot call to a function, one of its possible meanings is the function is inline. Flipping the reasoning, if you can call a function inside gdb, means the function is not marked inline. Save this answer.

When can a function be inlined?

Only when you want the function to be defined in a header. More exactly only when the function's definition can show up in multiple translation units. It's a good idea to define small (as in one liner) functions in the header file as it gives the compiler more information to work with while optimizing your code.

What does it mean for a function to be inlined?

An inline function is one for which the compiler copies the code from the function definition directly into the code of the calling function rather than creating a separate set of instructions in memory. This eliminates call-linkage overhead and can expose significant optimization opportunities.


2 Answers

No mentioned of LIBS in the docs. The option is named 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__

Note that using char* thetext as an argument to an XS function is a sure sign of a bug. That gives you a pointer to the string buffer without telling you the format of the buffer.

Assuming the library accepts and returns text encoded using 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;
}

Optimized slightly (since having newSVpvn_flags mortalize the scalar is more efficient that having the typemap-generated code call 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);
}
like image 101
ikegami Avatar answered Sep 30 '22 02:09

ikegami


Your -l argument looks suspect. Usually the compiler/linker will prefix the "lib" and suffix the ".so", so normally you should just need to supply

-lcmark
like image 20
LeoNerd Avatar answered Sep 30 '22 02:09

LeoNerd