Call a foreign-language function: Difference between revisions

From Rosetta Code
Content added Content deleted
(→‎{{header|Python}}: add ctypes example)
m (Fixed lang tags.)
Line 14: Line 14:
=={{header|Ada}}==
=={{header|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).
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;
<lang Ada>
with Ada.Text_IO; use Ada.Text_IO;
with Interfaces.C; use Interfaces.C;
with Interfaces.C; use Interfaces.C;
with Interfaces.C.Strings; use Interfaces.C.Strings;
with Interfaces.C.Strings; use Interfaces.C.Strings;
Line 29: Line 28:
Put_Line (Value (S2));
Put_Line (Value (S2));
Free (S2);
Free (S2);
end Test_C_Interface;
end Test_C_Interface;</lang>
</lang>


=={{header|C++}}==
=={{header|C++}}==
Line 36: Line 34:


In addition, this code demonstrates a call to a FORTRAN function defined as
In addition, this code demonstrates a call to a FORTRAN function defined as
<lang cpp>FUNCTION MULTIPLY(X, Y)
<lang fortran>
DOUBLE PRECISION MULTIPLY, X, Y</lang>
FUNCTION MULTIPLY(X, Y)
DOUBLE PRECISION MULTIPLY, X, Y
</lang>
Note that the calling convention of FORTRAN depends on the system and the used FORTRAN compiler, and sometimes even on the command line options used for the compiler; here, GNU Fortran with no options is assumed.
Note that the calling convention of FORTRAN depends on the system and the used FORTRAN compiler, and sometimes even on the command line options used for the compiler; here, GNU Fortran with no options is assumed.
<lang cpp>#include <cstdlib> // for C memory management
<lang cpp>
#include <cstdlib> // for C memory management
#include <string> // for C++ strings
#include <string> // for C++ strings
#include <iostream> // for output
#include <iostream> // for output
Line 83: Line 78:
// free, not delete, nor delete[], nor operator delete
// free, not delete, nor delete[], nor operator delete
std::free(msg2);
std::free(msg2);
}</lang>
}
</lang>


=={{header|Common Lisp}}==
=={{header|Common Lisp}}==
Line 103: Line 97:
Every version of GNU Forth has experimented with a different means to do C foreign function calls. The current implementation resolves various incompatibilities which had plagued earlier mechanisms by parsing C header files and using the host's native toolchain (i.e. gcc and ld) to generate thunks.
Every version of GNU Forth has experimented with a different means to do C foreign function calls. The current implementation resolves various incompatibilities which had plagued earlier mechanisms by parsing C header files and using the host's native toolchain (i.e. gcc and ld) to generate thunks.


<lang forth>
<lang forth>c-library cstrings
c-library cstrings


\c #include <string.h>
\c #include <string.h>
Line 126: Line 119:
duped dup strlen type \ testing
duped dup strlen type \ testing


duped free throw \ gforth ALLOCATE and FREE map directly to C's malloc() and free()
duped free throw \ gforth ALLOCATE and FREE map directly to C's malloc() and free()</lang>
</lang>


=={{header|Lisaac}}==
=={{header|Lisaac}}==
Use backtick notation (`...`) for referencing foreign language (C) features.
Use backtick notation (`...`) for referencing foreign language (C) features.
<lang Lisaac>
<lang Lisaac>Section Header
Section Header


+ name := TEST_C_INTERFACE;
+ name := TEST_C_INTERFACE;
Line 155: Line 146:
// this will also be inserted in-place, expression type disregarded
// this will also be inserted in-place, expression type disregarded
`free(@p)`;
`free(@p)`;
);
);</lang>
</lang>


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


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


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


Line 263: Line 253:
=={{header|Python}}==
=={{header|Python}}==


<lang python>
<lang python>import ctypes
import ctypes
libc = ctypes.CDLL("/lib/libc.so.6")
libc = ctypes.CDLL("/lib/libc.so.6")
libc.strcmp("abc", "def") # -1
libc.strcmp("abc", "def") # -1
libc.strcmp("hello", "hello") # 0
libc.strcmp("hello", "hello") # 0</lang>
</lang>


=={{header|Ruby}}==
=={{header|Ruby}}==

Revision as of 16:01, 19 November 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.

See also:

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>

C++

While calling C functions from C++ is generally almost trivial, strdup illustrates some fine point in communicating with C libraries. However, to illustrate how to generally use C functions, a C function strdup1 is used, which is assumed to have the same interface and behaviour as strdup, but cannot be found in a standard header.

In addition, this code demonstrates a call to a FORTRAN function defined as <lang cpp>FUNCTION MULTIPLY(X, Y) DOUBLE PRECISION MULTIPLY, X, Y</lang> Note that the calling convention of FORTRAN depends on the system and the used FORTRAN compiler, and sometimes even on the command line options used for the compiler; here, GNU Fortran with no options is assumed. <lang cpp>#include <cstdlib> // for C memory management

  1. include <string> // for C++ strings
  2. include <iostream> // for output

// C functions must be defined extern "C" extern "C" char* strdup1(char const*);

// Fortran functions must also be defined extern "C" to prevent name // mangling; in addition, all fortran names are converted to lowercase // and get an undescore appended. Fortran takes all arguments by // reference, which translates to pointers in C and C++ (C++ // references generally work, too, but that may depend on the C++ // compiler) extern "C" double multiply_(double* x, double* y);

// to simplify the use and reduce the probability of errors, a simple // inline forwarder like this can be used: inline double multiply(double x, double y) {

 return multiply_(&x, &y);

}

int main() {

 std::string msg = "The product of 3 and 5 is ";
 // call to C function (note that this should not be assigned
 // directly to a C++ string, because strdup1 allocates memory, and
 // we would leak the memory if we wouldn't save the pointer itself
 char* msg2 = strdup1(msg.c_str());
 // C strings can be directly output to std::cout, so we don't need
 // to put it back into a string to output it.
 std::cout << msg2;
 // call the FORTRAN function (through the wrapper):
 std::cout << multiply(3, 5) << std::endl;
 // since strdup1 allocates with malloc, it must be deallocated with
 // free, not delete, nor delete[], nor operator delete
 std::free(msg2);

}</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>

Forth

Works with: GNU Forth version 0.7.0

Every version of GNU Forth has experimented with a different means to do C foreign function calls. The current implementation resolves various incompatibilities which had plagued earlier mechanisms by parsing C header files and using the host's native toolchain (i.e. gcc and ld) to generate thunks.

<lang forth>c-library cstrings

\c #include <string.h> c-function strdup strdup a -- a ( c-string -- duped string ) c-function strlen strlen a -- n ( c-string -- length )

end-c-library

\ convenience function (not used here)

c-string ( addr u -- addr' )
   tuck  pad swap move  pad + 0 swap c!  pad ;

create test s" testing" mem, 0 c,

test strdup value duped

test . test 7 type \ testing cr duped . \ different address duped dup strlen type \ testing

duped free throw \ gforth ALLOCATE and FREE map directly to C's malloc() and free()</lang>

Lisaac

Use backtick notation (`...`) for referencing foreign language (C) features. <lang Lisaac>Section Header

+ name := TEST_C_INTERFACE;

// this will be inserted in front of the program - external := `#include <string.h>`;

Section Public

- main <- (

 + s : STRING_CONSTANT;
 + p : NATIVE_ARRAY[CHARACTER];
 s := "Hello World!";
 p := s.to_external;
 // this will be inserted in-place
 // use `expr`:type to tell Lisaac what's the type of the external expression
 p := `strdup(@p)` : NATIVE_ARRAY[CHARACTER];
 s.print;
 '='.print;
 p.println;
 // this will also be inserted in-place, expression type disregarded
 `free(@p)`;

);</lang>

Modula-3

Modula-3 provides many predefined interfaces to C files. Here we use Cstring which uses C string functions. Note we have to convert strings of type TEXT into C strings (NULL terminated character arrays). Also note the code requires the UNSAFE keyword because it interfaces with C (which is unsafe). <lang modula3>UNSAFE MODULE Foreign EXPORTS Main;

IMPORT IO, Ctypes, Cstring, M3toC;

VAR string1, string2: Ctypes.const_char_star;

BEGIN

 string1 := M3toC.CopyTtoS("Foobar");
 string2 := M3toC.CopyTtoS("Foobar2");
 IF Cstring.strcmp(string1, string2) = 0 THEN
   IO.Put("string1 = string2\n");
 ELSE
   IO.Put("string1 # string2\n");
 END;
 M3toC.FreeCopiedS(string1);
 M3toC.FreeCopiedS(string2);

END Foreign.</lang> Output:

string1 # string2

OCaml

Outline of what is linked against

For the hypothetical C library that contains functions described by a header file with this in: <lang ocaml>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 ocaml>#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 ocaml>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.

Python

<lang python>import ctypes libc = ctypes.CDLL("/lib/libc.so.6") libc.strcmp("abc", "def") # -1 libc.strcmp("hello", "hello") # 0</lang>

Ruby

Using

Library: RubyGems

package RubyInline

<lang ruby>require 'rubygems' require 'inline'

class InlineTester

 def factorial_ruby(n)
   (1..n).inject(1, :*)
 end
 inline do |builder|
   builder.c <<-'END_C'
     long factorial_c(int max) {
       long result = 1;
       int i;
       for (i = 1; i <= max; ++i)
         result *= i;
       return result;
     }
   END_C
 end
 
 inline do |builder|
   builder.include %q("math.h")
   builder.c <<-'END_C'
     int my_ilogb(double value) {
       return ilogb(value);
     }
   END_C
 end

end

t = InlineTester.new 11.upto(14) {|n| p [n, t.factorial_ruby(n), t.factorial_c(n)]} p t.my_ilogb(1000)</lang>

outputs (note Ruby's implicit use of Bignum past 12!, while C is stuck with a long int):

[11, 39916800, 39916800]
[12, 479001600, 479001600]
[13, 6227020800, 1932053504]
[14, 87178291200, 1278945280]
9

Tcl

Wrapping up the ilogb function from C's math library with

Library: critcl

so that it becomes one of Tcl's normal functions (assuming Tcl 8.5):

<lang tcl>package require critcl critcl::code {

   #include <math.h>

} critcl::cproc tcl::mathfunc::ilogb {double value} int {

   return ilogb(value);

} package provide ilogb 1.0</lang> Note that we do not show strdup here because Tcl manages the memory for strings in complex ways and does not guarantee to preserve string pointers from one call into the C API to the next (e.g., if it has to apply an encoding transformation behind the scenes).