Call a foreign-language function: Difference between revisions
(→{{header|Lisaac}}: Explain backtick notation) |
|||
Line 76: | Line 76: | ||
=={{header|Lisaac}}== |
=={{header|Lisaac}}== |
||
Use backtick notation (`...`) for referencing foreign language (C) features. |
|||
<lang Lisaac> |
<lang Lisaac> |
||
Section Header |
Section Header |
||
Line 81: | Line 82: | ||
+ name := TEST_C_INTERFACE; |
+ name := TEST_C_INTERFACE; |
||
// this will be inserted in front of the program |
|||
- external := `#include <string.h>`; |
- external := `#include <string.h>`; |
||
Line 91: | Line 93: | ||
s := "Hello World!"; |
s := "Hello World!"; |
||
p := s.to_external; |
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]; |
p := `strdup(@p)` : NATIVE_ARRAY[CHARACTER]; |
||
s.print; |
s.print; |
||
'='.print; |
'='.print; |
||
p.println; |
p.println; |
||
// this will also be inserted in-place, expression type disregarded |
|||
`free(@p)`; |
`free(@p)`; |
||
); |
); |
Revision as of 15:11, 19 September 2009
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>
Common Lisp
<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
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 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>
- 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 mylib.cma is used for the interpreted and bytecode modes, and mylib.cmxa is for the native mode.
Ruby
Using
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
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).