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.
The only situation in which a function cannot be inlined is if there is no definition for the function in the compilation unit.
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.
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.
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.
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);
}
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With