Reply to thread

I need to use a C library and I got it to work on the emulator easily, but on an arm64 device only with some strange trickery. The issue is that C functions with … (variadic functions) do not pass values correctly from C# to the library.


This is the C function, with ...


cmd_ln_t *

cmd_ln_init(cmd_ln_t *inout_cmdln, const arg_t *defn, int32 strict, ...)

{

va_list args;

const char *arg, *val;

char **f_argv;

int32 f_argc;


va_start(args, strict);

f_argc = 0;

while ((arg = va_arg(args, const char *))) {

    ++f_argc;

    E_INFO("name: %s   ", arg);

    E_INFO(" retrieving value...");

    val = va_arg(args, const char*);

    E_INFO("value retrieved. \n");

    E_INFO("value: %s \n", val);

    if (val == NULL) {

        E_ERROR("Number of arguments must be even!\n");

        return NULL;

    }

    ++f_argc;

}

va_end(args);

.....................................



I check if the values are correct with the E_INFO()



Approach 1 - The default PARAMS doesn't work:


When I use the following default params expression approuch for c bindings, the ‘arg’ printed in the function shows unknown characters and when ‘val’ is used the function crashes.


[DllImport("__Internal")] public static extern unsafe cmd_ln_t*

cmd_ln_init(cmd_ln_t* inout_cmdln, arg_t* defn, int strict, params string[] arguments);




Approach 2 - a more elaborate approach works:


When I use the a more elaborate approach everything works, on x86_64 architecture normally but for arm64 with a strange work-around. the binding expression in a more elaborate approach.


        [DllImport("__Internal")]

        public static extern unsafe cmd_ln_t* cmd_ln_init(cmd_ln_t* inout_cmdln, arg_t* defn, int strict, string arg1, string arg2);


        [DllImport("__Internal")]

        public static extern unsafe cmd_ln_t* cmd_ln_init(cmd_ln_t* inout_cmdln, arg_t* defn, int strict, string arg1, string arg2, string arg3);


        [DllImport("__Internal")]

        public static extern unsafe cmd_ln_t* cmd_ln_init(cmd_ln_t* inout_cmdln, arg_t* defn, int strict, string arg1, string arg2, string arg3, string arg4);

        //etc etc… for x numbers of arguments




The binding works works the following code


            // works for x86_64

            var cmdPointer = MyBindingLib.cmd_ln_init(null, psArgsPointer, 1,

            "-hmm", hmmFolder,

                "-dict", dictFile,

                "-mmap", "no",

                "-kws_threshold", "1e-80", 

                "-lw", "2.0", 

                null);


            // works for arm64

            var cmdPointer = MyBindingLib.cmd_ln_init(null, psArgsPointer, 1,

                null, null,

                null, null, null,

                "-hmm", hmmFolder,

                "-dict", dictFile,

                "-mmap", "no",

                "-kws_threshold", "1e-80",

                "-lw", "2.0", 

                null);



As you see, the x86_64 works normally to get the values to the C library. But the arm64 version needs to have 5 null values, others half of the values won't make it to the C library (I can check that with the E_INFO function in the C function).



Anyone any idea how to get this Xamarin C binding correct with params or without the 5 prefix null values?


Continue reading...


Back
Top