9
$\begingroup$

There's an example of LinkObject-based passing in the LibraryLink documentation. Unfortunately the cell in the documentation notebook is corrupted, but to skip that problem I'm going to reproduce it in plain text here:

funLink = LibraryFunctionLoad["demo_LinkObject", "reverseString", LinkObject, LinkObject];
funLink["forward"]

On OS X I get the output LibraryFunctionError["LIBRARY_FUNCTION_ERROR", 6] instead of the expected drawrof. On Windows it works. Looking at the source code of the example, I cannot immediately see what's wrong with it. A precompiled version of this example library comes with Mathematica, and it's what the above commands should load (verified with FindLibrary). So I tried recompiling it, but the error is still there.

You'll find the complete source code in:

SystemOpen@FileNameJoin[{$InstallationDirectory, "SystemFiles", "Links", "LibraryLink", "LibraryResources", "Source"}]

Question: Is this a bug in LibraryLink/MathLink itself? Or is there a flaw in the example program that I didn't find?

$\endgroup$
6
  • $\begingroup$ as you are asking many LibraryLink related questions lately, may I ask what you are working on? $\endgroup$ Aug 21, 2015 at 8:56
  • $\begingroup$ @AlbertRetey I need small simple things that are better done in C(++) from time to time, sometimes things as simple as shuffling around the edges of a graph. I find writing or extending LibraryLink code cumbersome because of all the boilerplate that's necessary and limitations with multiple return or strings (both solved by MathLink) or LinkObject passing). I tried to automate writing the boilerplate with a package and by using C++. $\endgroup$
    – Szabolcs
    Aug 21, 2015 at 9:45
  • $\begingroup$ @Albert At this point this package is really just an experiment to discover what would work well in practice (through actually using it) rather than the final result. I tried to ask for feedback on it, but got little. Due to lack of time, I think I'll keep it for personal use only for now, and based on the experience I get with it, maybe in the far future, I'll try again. It would be nice to make it easy to add translation rules for various types (more than what LibraryLink supports). But now it's not even clear if this is worth it over just using the more flexible MathLink. $\endgroup$
    – Szabolcs
    Aug 21, 2015 at 9:48
  • $\begingroup$ There's also this C++-side-only solution which people told me just after I started. It's probably better done as my C++ is rusty and not up to date with C++11. $\endgroup$
    – Szabolcs
    Aug 21, 2015 at 9:50
  • $\begingroup$ OK, thanks for the information, that all sounds interesting. I just was wondering, but it is good to know who to ask when having questions :-). I have myself used LibraryLink only to pass around largish numeric arrays in pure C and found that working very well and efficient and I think for that purpose LibraryLink is better suited than MathLink. So far I have no experience with anything else, though... $\endgroup$ Aug 21, 2015 at 10:01

2 Answers 2

7
$\begingroup$

I think the issue is that the demo source file hasn't been properly updated. Originally it used MLCheckFunction, which was later deprecated in favor of MLTestHead. There is, however an incompatible change in the type of the last argument: MLTestHead takes a pointer to int, while MLCheckFunction used to take a pointer to long.

The following test fails

DLLEXPORT int reverseString( WolframLibraryData libData, MLINK mlp)
{
    int res = LIBRARY_FUNCTION_ERROR;
    int i1, i2, sum;
    long len;
    const char *inStr = NULL;
    char* outStr = NULL;

    if ( !MLTestHead( mlp, "List", &len))
        goto retPt;
    if ( len != 1) 
        goto retPt;
    .
    .
    .
}

as explained in the answer by Szabolcs: it would only work correctly on Windows, where long and int are both 32-bit.

After changing the declaration to

int len;

and recompiling, the example works again:

funLink["forward"]

(* "drawrof" *)

The same applies for the other example function, addtwo.

$\endgroup$
3
  • 1
    $\begingroup$ 4 minutes apart :) $\endgroup$
    – Szabolcs
    Aug 21, 2015 at 16:38
  • $\begingroup$ It seems with Interface Version 3 it's also an int, but MLCheckFunction (deprecated in 4) has a long. $\endgroup$
    – Szabolcs
    Aug 21, 2015 at 16:44
  • $\begingroup$ @Szabolcs Yes, that's absolutely right. I've corrected the answer (though perhaps I should just delete it, it doesn't add anything to yours). $\endgroup$
    – ilian
    Aug 21, 2015 at 17:23
7
$\begingroup$

This is due to a bug in the example code. Specifically, in reverseString, the type of variable len should be int and not long because MLTestHead expects an int *. From the docs, the prototype is

int MLTestHead(MLINK link, const char *head, int *n)

On Windows with MSVC long and int are of the same size but on 64-bit OS X they are not, so MLTestHead writes a 4-byte int into len, leaving the remaining 4 bytes alone and causing long len to have an essentially unpredictable value. Then if ( len != 1) fails.

Had I only used "ShellOutputFunction" -> Print with CreateLibrary, I would have seen the compiler warning. But I was stupid and I didn't.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.