4

I am exploring some adventurous ideas.

TL:DR; gnumake is able to use loadable modules, I am trying to use that C barrier to use OCaml but have trouble with the OCaml runtime initializing.

I have this OCaml code:

(* This is speak_ocaml.ml *)
let do_speak () =
  print_endline "This called from OCaml!!";
  flush stdout;
  "Some return value from OCaml"

let () =
  Callback.register "speak" do_speak

and I also have this C code: (Yes, needs to use extra CAML macros but not relevant here)

#include <stdlib.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

#include <gnumake.h>
#include <caml/mlvalues.h>
#include <caml/callback.h>
#include <caml/memory.h>
#include <caml/alloc.h>

int plugin_is_GPL_compatible;

char *ocaml_speaker(const char *func_name, int argc, char **argv)
{
  char *answer =
    String_val(caml_callback(*caml_named_value("speak"), Val_unit));

  printf("Speaking and got: %s\n", answer);
  char *buf = gmk_alloc(strlen(answer) + 1);
  strcpy(buf, answer);
  /* receive_arg */
  return buf;
}

int do_speak_gmk_setup()
{
  printf("Getting Called by Make\n");
  // This is pretty critical, will explain below
  char **argv = {"/home/Edgar/foo", NULL};
  caml_startup(argv);
  printf("Called caml_startup\n");
  gmk_add_function("speak", ocaml_speaker, 1, (unsigned int)1, 1);
  return 1;
}

and I'm compiling it with this Makefile

all:
    ocamlopt -c speak_ocaml.ml
    ocamlopt -output-obj -o caml_code.o speak_ocaml.cmx
    clang -I`ocamlc -where` -c do_speak.c -o do_speak.o

    clang -shared -undefined dynamic_lookup -fPIC -L`ocamlc -where` -ldl \
    -lasmrun do_speak.o caml_code.o -o do_speak.so

show_off:
    echo "Speaker?"
    ${speak 123}

clean:
    @rm -rf *.{cmi,cmt,cmi,cmx,o,cmo,so}

And my problem is that only printf("Getting Called by Make\n"); is going off when I add the appropriate load do_speak.so in the Makefile, caml_startup is not going off correctly. Now I am calling caml_startup because if I don't then I get an error of

Makefile:9: dlopen(do_speak.so, 9): Symbol not found: _caml_atom_table
  Referenced from: do_speak.so
  Expected in: flat namespace
 in do_speak.so
Makefile:9: *** do_speak.so: failed to load.  Stop.

And this is because of the way that clang on OS X does linking, see here for more details: http://psellos.com/2014/10/2014.10.atom-table-undef.html

I am kind of out of ideas... I need to create a C shared library out of OCaml code which then needs to be part of another C shared library from which I obviously don't have the original argv pointers that caml_startup wants. As my code sample show, I've tried faking it out, and also used caml_startup(NULL) and char **argv = {NULL}; caml_startup(argv) with similar lack of success. I don't know how else to initialize the runtime correctly.

1 Answers1

2

I actually can't tell very well what you're asking. However, here's a comment on this part of your question:

I've tried faking it out, and also used caml_startup(NULL) and char **argv = {NULL}; caml_startup(argv) with similar lack of success. I don't know how else to initialize the runtime correctly.

As far as I know, the only reason for the argv argument of caml_startup is to establish the command-line arguments (for Sys.argv). If you don't need command-line arguments it should be OK to call like this:

char *arg = NULL;
caml_startup(&arg);

Technically argv is supposed to contain at least one string (the name of the program). So maybe it would be better to call like this:

char *argv[] = { "program", NULL };
caml_startup(argv);
Jeffrey Scofield
  • 65,646
  • 2
  • 72
  • 108
  • The point is that I'm trying to use OCaml code as a C lib for C code that is intended to be compiled as a C lib itself rather than as a C executable, kind of doesn't matter as much now since I dropped OCaml and picked C++ for this task because of this problem. –  Feb 15 '16 at 05:48