My Experience with Inline::C

I know I didn't write here for a long time, and I apologise for it, but I have this entry and another one in mind and I hope they can compensate for it.

For my work on Freecell Solver, I've written some code for encoding and decoding game positions into a compact format, by encoding them as a delta from the position of origin. I first wrote it in Perl, in order to prototype it, and later translated it to C (which is the language that Freecell Solver is written in). I have written some rudimentary unit tests for it, but also wanted to test the code against a large number of positions, by runnign it over the solutions of many Freecell deals.

The encoding rearranges the order of the card columns and the freecells, so testing that the output test is correct requires calculating that arrangement. This was also done by the Perl code. I decided to write a small wrapper for an encoding+decoding round-trip in C, and use it from a Perl program I was writing. So far so good.

I first looked at the Perl version of Ctypes, but it failed a large number of its assertions on my system, so I could not really trust it. Then I looked at Inline::C. I could not understand from its main page, how to return an SV * containing a string from it, but this was covered in the extensive Inline::C cookbook and I wrote this Inline::C function:

extern char * fc_solve_user_INTERNAL_delta_states_enc_and_dec(
    const char * init_state_str_proto,
    const char * derived_state_str_proto
    );

SV* enc_and_dec(char * init_state_s, char * derived_state_s) {
    SV * ret;
    char * s;
    s = fc_solve_user_INTERNAL_delta_states_enc_and_dec(init_state_s, derived_state_s);

    ret = newSVpv(s, 0);
    free(s);
    return ret;
}

I don't need to use "sv_2mortal" there because Inline::C does that for us. Then I tried to test it. It failed with this error:

perl: symbol lookup error: /home/shlomif/progs/freecell/trunk/fc-solve/source/_Inline/lib/auto/Mega_Test_for_C_delta_states_pl_9385/Mega_Test_for_C_delta_states_pl_9385.so: undefined symbol: fc_solve_user_INTERNAL_delta_states_enc_and_dec

I was familiar with errors like that, but it took me over an hour of playing with the various Inline::C configuration options, and trying to figure out why it didn't link against the relevant Freecell Solver library to realise what the problem was. It was that the library in question did not export the symbol, and gcc realised it didn't give the XS extension anything and omitted it.

After fixing this line in my C source:

char * DLLEXPORT fc_solve_user_INTERNAL_delta_states_enc_and_dec(

To this line:

DLLEXPORT char * fc_solve_user_INTERNAL_delta_states_enc_and_dec(

Everything worked properly, and I was able to run the so-called "mega-test".

If you're having similar problems with Inline::C, you should try to add CLEAN_AFTER_BUILD => 0 to its configuration. It ended up clarifying a lot for me.

Cheers!

2 Comments

Your use of const on your character pointer arguments makes me happy.

Leave a comment

About Shlomi Fish

user-pic An Israeli software developer, essayist, and writer, and an enthusiast of open/free software and cultural works. I've been working with Perl since 1996.