Call a foreign-language function: Difference between revisions

From Rosetta Code
Content added Content deleted
m (omit TI-89 BASIC)
(Merge in code from C FFI as prelude to deleting that page)
Line 1: Line 1:
{{task|Programming environment operations}}
{{task|Programming environment operations}}
Show how a [[Foreign function interface|foreign language function]] can be called from the language. As an example, take [[C]] language. Create a string containing "Hello World!" of the string type typical to the language. Pass the string content to [[C]]'s ''strdup''. The content can be copied if necessary. Get the result from ''strdup'' and print it using language means. Do not forget to free the result of ''strdup'' (allocated in the heap).
Show how a [[Foreign function interface|foreign language function]] can be called from the language. As an example, consider calling functions defined in the [[C]] language. Create a string containing "Hello World!" of the string type typical to the language. Pass the string content to [[C]]'s <code>strdup</code>. The content can be copied if necessary. Get the result from <code>strdup</code> and print it using language means. Do not forget to free the result of <code>strdup</code> (allocated in the heap).


Notes
Notes
* It is not mandated if the [[C]] run-time library is to be loaded statically or dynamically. You are free to use either way.
* It is not mandated if the [[C]] run-time library is to be loaded statically or dynamically. You are free to use either way.
* [[C++]] and [[C]] solutions can take some other language to communicate with.
* [[C++]] and [[C]] solutions can take some other language to communicate with.
* It is ''not'' mandatory to use <code>strdup</code>, especially if the foreign function interface being demonstrated makes that uninformative.


=={{header|Ada}}==
=={{header|Ada}}==
Line 37: Line 38:
Hello World!
Hello World!
; No value</lang>
; No value</lang>

=={{header|OCaml}}==
===Outline of what is linked against===
For the hypothetical [[C]] library that contains functions described by a header file with this in:
<lang c>void myfunc_a();
float myfunc_b(int, float);
char *myfunc_c(int *);</lang>

The header file is named "<tt>mylib.h</tt>", and linked against the library with <tt>-lmylib</tt> and compiled with <tt>-I/usr/include/mylib</tt>.
===Required files===
Here are provided all the files, including a Makefile.

====file "mylib.ml":====
<lang ocaml>external myfunc_a: unit -> unit = "caml_myfunc_a"
external myfunc_b: int -> float -> float = "caml_myfunc_b"
external myfunc_c: int array -> string = "caml_myfunc_c"</lang>

====file "wrap_mylib.c":====
<lang C>#include <caml/mlvalues.h>
#include <caml/alloc.h>
#include <mylib.h>

CAMLprim value
caml_myfunc_a(value unit) {
myfunc_a();
return Val_unit;
}

CAMLprim value
caml_myfunc_b(value a; value b) {
float c = myfunc_b(Int_val(a), Double_val(b));
return caml_copy_double(c);
}

CAMLprim value
caml_myfunc_c(value ml_array) {
int i, len;
int *arr;
char *s;
len = Wosize_val(ml_array);
arr = malloc(len * sizeof(int));
for (i=0; i < len; i++) {
arr[i] = Int_val(Field(ml_array, i));
}
char *s = myfunc_c(int *);
free(arr);
return caml_copy_string(s);
}</lang>

====the Makefile:====
<lang Makefile>wrap_mylib.o: wrap_mylib.c
ocamlc -c -ccopt -I/usr/include/mylib $<

dllmylib_stubs.so: wrap_mylib.o
ocamlmklib -o mylib_stubs $< -lmylib

mylib.mli: mylib.ml
ocamlc -i $< > $@

mylib.cmi: mylib.mli
ocamlc -c $<

mylib.cmo: mylib.ml mylib.cmi
ocamlc -c $<

mylib.cma: mylib.cmo dllmylib_stubs.so
ocamlc -a -o $@ $< -dllib -lmylib_stubs -cclib -lmylib

mylib.cmx: mylib.ml mylib.cmi
ocamlopt -c $<

mylib.cmxa: mylib.cmx dllmylib_stubs.so
ocamlopt -a -o $@ $< -cclib -lmylib_stubs -cclib -lmylib

clean:
rm -f *.[oa] *.so *.cm[ixoa] *.cmxa</lang>

the file <tt>mylib.cma</tt> is used for the interpreted and bytecode modes, and <tt>mylib.cmxa</tt> is for the native mode.


{{omit from|TI-89 BASIC}} <!-- Does not have a standard FFI. -->
{{omit from|TI-89 BASIC}} <!-- Does not have a standard FFI. -->

Revision as of 20:34, 17 August 2009

Task
Call a foreign-language function
You are encouraged to solve this task according to the task description, using any language you may know.

Show how a foreign language function can be called from the language. As an example, consider calling functions defined in the C language. Create a string containing "Hello World!" of the string type typical to the language. Pass the string content to C's strdup. The content can be copied if necessary. Get the result from strdup and print it using language means. Do not forget to free the result of strdup (allocated in the heap).

Notes

  • It is not mandated if the C run-time library is to be loaded statically or dynamically. You are free to use either way.
  • C++ and C solutions can take some other language to communicate with.
  • It is not mandatory to use strdup, especially if the foreign function interface being demonstrated makes that uninformative.

Ada

Ada provides standard interfaces to C, C++, Fortran and Cobol. Other language interfaces can be provided as well, but are not mandatory. Usually it is possible to communicate to any language that supports calling conventions standard to the OS (cdecl, stdcall etc). <lang Ada> with Ada.Text_IO; use Ada.Text_IO; with Interfaces.C; use Interfaces.C; with Interfaces.C.Strings; use Interfaces.C.Strings;

procedure Test_C_Interface is

  function strdup (s1 : Char_Array) return Chars_Ptr;
  pragma Import (C, strdup, "_strdup");
  S1 : constant String := "Hello World!";
  S2 : Chars_Ptr;

begin

  S2 := strdup (To_C (S1));
  Put_Line (Value (S2));
  Free (S2);

end Test_C_Interface; </lang>

Common Lisp

Library: CFFI

<lang lisp>CL-USER> (let* ((string "Hello World!")

               (c-string (cffi:foreign-funcall "strdup" :string string :pointer)))
          (unwind-protect (write-line (cffi:foreign-string-to-lisp c-string))
            (cffi:foreign-funcall "free" :pointer c-string :void))
          (values))

Hello World!

No value</lang>

OCaml

Outline of what is linked against

For the hypothetical C library that contains functions described by a header file with this in: <lang c>void myfunc_a(); float myfunc_b(int, float); char *myfunc_c(int *);</lang>

The header file is named "mylib.h", and linked against the library with -lmylib and compiled with -I/usr/include/mylib.

Required files

Here are provided all the files, including a Makefile.

file "mylib.ml":

<lang ocaml>external myfunc_a: unit -> unit = "caml_myfunc_a" external myfunc_b: int -> float -> float = "caml_myfunc_b" external myfunc_c: int array -> string = "caml_myfunc_c"</lang>

file "wrap_mylib.c":

<lang C>#include <caml/mlvalues.h>

  1. include <caml/alloc.h>
  2. include <mylib.h>

CAMLprim value caml_myfunc_a(value unit) {

   myfunc_a();
   return Val_unit;

}

CAMLprim value caml_myfunc_b(value a; value b) {

   float c = myfunc_b(Int_val(a), Double_val(b));
   return caml_copy_double(c);

}

CAMLprim value caml_myfunc_c(value ml_array) {

   int i, len;
   int *arr;
   char *s;
   len = Wosize_val(ml_array);
   arr = malloc(len * sizeof(int));
   for (i=0; i < len; i++) {
       arr[i] = Int_val(Field(ml_array, i));
   }
   char *s = myfunc_c(int *);
   free(arr);
   return caml_copy_string(s);

}</lang>

the Makefile:

<lang Makefile>wrap_mylib.o: wrap_mylib.c

       ocamlc -c -ccopt -I/usr/include/mylib $<

dllmylib_stubs.so: wrap_mylib.o

       ocamlmklib -o mylib_stubs $< -lmylib

mylib.mli: mylib.ml

       ocamlc -i $< > $@

mylib.cmi: mylib.mli

       ocamlc -c $<

mylib.cmo: mylib.ml mylib.cmi

       ocamlc -c $<

mylib.cma: mylib.cmo dllmylib_stubs.so

       ocamlc -a -o $@ $< -dllib -lmylib_stubs -cclib -lmylib

mylib.cmx: mylib.ml mylib.cmi

       ocamlopt -c $<

mylib.cmxa: mylib.cmx dllmylib_stubs.so

       ocamlopt -a -o $@ $< -cclib -lmylib_stubs -cclib -lmylib

clean:

       rm -f *.[oa] *.so *.cm[ixoa] *.cmxa</lang>

the file mylib.cma is used for the interpreted and bytecode modes, and mylib.cmxa is for the native mode.