I was following some FFI tutorials and examples (here and here), and I was wondering what should change when using stack?
In the examples, the source C file is compiled to an object file using gcc -c -o termops.o termops.c and included in the gcc compilation using ghc --make -main-is FfiEx -o ffi_ex FfiEx.hs termops.o. How can the equivalent be accomplished using stack?
Here is as minimal an FFI C project as I could imagine.
$ cd c-proj
c-proj$ ls
Main.hs c-proj.cabal c_file.c
The contents of these files:
c-proj.cabal: describes the
name: c-proj
version: 0.1.0.0
cabal-version: >= 1.22
build-type: Simple
executable main
main-is: Main.hs
build-depends: base >= 4.9
c-sources: c_file.c
Main.hs: the only Haskell source file
{-# LANGUAGE ForeignFunctionInterface #-}
module Main where
foreign import ccall "plus_ten" plusTen :: Int -> IO Int
main = do
n <- plusTen 2
print n
c_file.c: the C source file
#include<stdio.h>
int plus_ten(int n) {
printf("%d + 10\n", n);
return n + 10;
}
Then, if you want to use Stack, you can run stack init.
$ stack init
<< Shell output snipped >>
$ stack build
<< Shell output snipped >>
$ stack exec main
2 + 10
12
Related
I just started with c development and I need to compile and link a program which uses the Accelerate Framework from Apple:
Simple example accelerate.c:
#include <stdio.h>
#include <Accelerate/Accelerate.h>
double vectorvector_product(double * a, double * b, int dim){
// This function returns in res the elementwiseproduct between a and b,
// a and b must have the same dimension dim.
return cblas_ddot(dim,a,1,b,1);
}
int main(){
double a[4] = {1.0,2.0,3.0,4.0};
double b[4] = {1.0,2.0,3.0,4.0};
double res = vectorvector_product(a,b,4);
printf("Res: %f",res);
}
I compiled it with clang:
>>> cc -Wall -g -c accelerate.c
And obtained a new file accelerate.o
What would I do now in order to properly link it?
All I know is that this Accelerate framework is located at /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/Accelerate.framework
>>> ls /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/Accelerate.framework
Accelerate.tbd Frameworks Headers Modules Versions
p.s.: If I Run this program with Xcode it magically works, but I need to do it from the command line and I would like to know what I'm doing.
Apparently the correct way to link Accelerate.h is by passing -framework Accelerate as argument e.g.
>>> cc -framework Accelerate accelerate.c
will compile and link accelerate.c by generating an executable a.out.
I wish to call OCaml code through C++ by compiling OCaml to a static or shared library that contains a C interface. This page seems to explain how to create a C interface for OCaml. But how do I do it and compile it? And how do I obtain the .h file to load in my C++ code?
Also, could someone explain to be this part:
The OCaml runtime system comprises three main parts: the bytecode
interpreter, the memory manager, and a set of C functions that
implement the primitive operations. Some bytecode instructions are
provided to call these C functions, designated by their offset in a
table of functions (the table of primitives).
I thougth OCaml could be compiled to native machine language. Why it is compiled to bytecode and interpreted at runtime? Is it always like that, or only for OCaml libraries compiled with C interface?
Most of that page describes how to call C from OCaml. You want to do the reverse, which is described in Advanced Topics: callbacks from C to OCaml, closer to the bottom of the page.
When you do native compilation there is no bytecode involved, just as you say. The native compiler (ocamlopt) produces ordinary object (.o in Unix) files and extra files containing OCaml metadata.
If you look at Advanced Example with callbacks, you'll see an example where the main program is in C, with calls to two functions defined in OCaml. Things should work similarly in C++. (I have only done this in C myself, however.)
Update
Here is the worked-out example using the code from Advanced example with callbacks. I am running this code on Ubuntu 18.04.4 (x86_64).
The OCaml code looks like this:
$ cat mod.ml
let rec fib n = if n < 2 then 1 else fib (n - 1) + fib (n - 1)
let format_result n = Printf.sprintf "Result is: %d\n" n
let () = Callback.register "fib" fib
let () = Callback.register "format_result" format_result
Compile this code and ask for a complete object file:
$ ocamlopt -output-obj -o bigmod.o mod.ml
Rename the C code to modwrap.cc. (The code is given in the OCaml manual section.)
$ head -6 modwrap.cc
#include <stdio.h>
#include <string.h>
#include <caml/mlvalues.h>
#include <caml/callback.h>
int fib(int n)
Note that the OCaml include files are conditionalized as to whether they're being included from C or C++ (as are almost all header files these days).
The main function from the OCaml manual section is also valid C++; rename it to main.cc:
$ head -7 main.cc
#include <stdio.h>
#include <caml/callback.h>
extern int fib(int n);
extern char * format_result(int n);
int main(int argc, char ** argv)
Now compile and link everything:
$ g++ -c modwrap.cc
$ g++ -o myprog -I $(ocamlopt -where) \
main.cc modwrap.o bigmod.o $(ocamlopt -where)/libasmrun.a -ldl
$
Now run the program
$ ./myprog
fib(10) = Result is: 89
There is no automatic generation of header files. In this example the extern lines of main.cc are the header file in essence. If you want a header file you'll have to write something like this yourself.
Update 2
Here are the commands for creating an actual static library containing the OCaml functions and their wrappers. This assumes that you have done the compiles above to create bigmod.o and modwrap.o:
$ cp $(ocamlopt -where)/libasmrun.a libmyoc.a
$ ar r libmyoc.a bigmod.o modwrap.o
Now you can use this library in your C++ code (represented by main.cc):
$ g++ -o myprog -I $(ocamlopt -where) main.cc -L . -lmyoc -ldl
$ ./myprog
fib(10) = Result is: 89
Update 3
(I updated the above commands to work on Unbuntu.)
I am trying to call a C function from Haskell using the FFI and I keep getting this error :
ghc.exe: ^^ Could not load 'getSize', dependency unresolved. See top
entry above.
main: ByteCodeLink: can't find label During interactive linking, GHCi
couldn't find the following symbol: getSize This may be due to you
not asking GHCi to load extra object files, archives or DLLs needed by
your current session. Restart GHCi, specifying the missing library
using the -L/path/to/object/dir and -lmissinglibname flags, or simply
by naming the relevant files on the GHCi command line. Alternatively,
this link failure might indicate a bug in GHCi. If you suspect the
latter, please send a bug report to:
glasgow-haskell-bugs#haskell.org
I am using the stdio.h library in my C library:
C library
// lib.h
#include <stdio.h>
double getSize() {
double size = 0;
scanf("$f", &size);
return size;
}
FFI module
{-# LANGUAGE ForeignFunctionInterface #-}
module Ffi where
import Foreign
import Foreign.C.Types
foreign import ccall "lib.h getSize" c_size :: IO Double
Main
module Main where
import Ffi
main :: IO ()
main = do a <- getLine
b <- c_size
print $ "got from C: " ++ show b
Running script
gcc -o lib -lib.h
runghc main
P.S. Could this be because I somehow have to specify the dependency stdio.h somewhere else too?
Okay, there are several things to do here:
Rename "lib.h" to "lib.c". It's a C source file (containing code), not a C header file.
Ideally, add a separate "lib.h" header file with the prototype for getSize.
Fix the bug in "lib.c". You want "%lf" in place of "$f" to read in a double.
Compile the program with ghc instead of running it with runghc. A single ghc command can compile and link both Haskell modules and C code.
In other words, your files should look like:
// lib.c
#include "lib.h"
#include <stdio.h>
double getSize() {
double size = 0;
scanf("%lf", &size);
return size;
}
// lib.h
double getSize(void);
-- Ffi.hs
{-# LANGUAGE ForeignFunctionInterface #-}
module Ffi where
import Foreign
import Foreign.C.Types
foreign import ccall "lib.h getSize" c_size :: IO Double
-- Main.hs
module Main where
import Ffi
main :: IO ()
main = do a <- getLine
b <- c_size
print $ "got from C: " ++ show b
and you should compile it with:
$ ghc Main.hs lib.c
[1 of 2] Compiling Ffi ( Ffi.hs, Ffi.o )
[2 of 2] Compiling Main ( Main.hs, Main.o )
Linking Main ...
Then you can run it, supply a line for the Haskell getLine and a second line for the C scanf, and it should work fine:
$ ./Main
hello world!! -- line for Haskell
135.0 -- line for C
"got from C: 135.0"
I'm trying to learn how to call routines in C directly from OCaml code, using the Ctypes library.
I have this basic example with two files: hello.ml and hello.c.
hello.ml looks like this:
open Ctypes
open Foreign
let hello =
foreign "hello" (float # -> returning void)
;;
let () =
hello 3.15
;;
hello.c looks like this:
#include <stdio.h>
void hello(double x)
{
if ( x > 0)
printf("hello!\n");
}
How do I compile these two files into one executable?
The process of manually compiling/linking code is scary to me and I don't understand it very well. I usually use a Makefile template to compile my code because that's really easy.
Here's an example that I use on OS X.
in simple.c
int adder(int a, int b)
{
return a + b;
}
and in simple.ml
open Ctypes
open Foreign
let adder_ = foreign
"adder" (int #-> int #-> returning int)
let () =
print_endline (string_of_int (adder_ 1 2))
Then I do
clang -shared simple.c -o simple.so
ocamlfind ocamlopt -package ctypes.foreign -cclib simple.so -linkpkg simple.ml -o Test
./Test
And that should print out 3 on the terminal.
"R.h" and "Rmath.h" are header files for an interface between R.app and C. But, they seems to be readable only through a R command 'R CMD SHLIB something.c'
I wish to compile my native C program to include them using gcc. I'm using Snow Leopard where I'm not able to locate those header files!
Any help?
Please see the 'Writing R Extensions' manual about details, you can easily compile and link against Rmath.h and the standalone R Math library -- but not R.h. (Which you can use via Rcpp / RInside but that is a different story.)
There are a number of examples floating around for use of libRmath, one is in the manual itself. Here is one I ship in the Debian package r-mathlib containing this standalone math library:
/* copyright header omitted here for brevity */
#define MATHLIB_STANDALONE 1
#include <Rmath.h>
#include <stdio.h>
typedef enum {
BUGGY_KINDERMAN_RAMAGE,
AHRENS_DIETER,
BOX_MULLER,
USER_NORM,
INVERSION,
KINDERMAN_RAMAGE
} N01type;
int
main(int argc, char** argv)
{
/* something to force the library to be included */
qnorm(0.7, 0.0, 1.0, 0, 0);
printf("*** loaded '%s'\n", argv[0]);
set_seed(123, 456);
N01_kind = AHRENS_DIETER;
printf("one normal %f\n", norm_rand());
set_seed(123, 456);
N01_kind = BOX_MULLER;
printf("normal via BM %f\n", norm_rand());
return 0;
}
and on Linux you simply build like this (as I place the library and header in standard locations in the package; add -I and -L as needed on OS X)
/tmp $ cp -vax /usr/share/doc/r-mathlib/examples/test.c mathlibtest.c
`/usr/share/doc/r-mathlib/examples/test.c' -> `mathlibtest.c'
/tmp $ gcc -o mathlibtest mathlibtest.c -lRmath -lm
/tmp $ ./mathlibtest
*** loaded '/tmp/mathlibtest'
one normal 1.119638
normal via BM -1.734578
/tmp $