Haskell how to work with extern FILE* from c? [closed] - haskell

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
I want to foreign import a function from some c header, but how to deal with the stderr of type FILE* which defined as:
extern FILE* __stderrp;
#define stderr __stderrp
Maybe not precisely. I use c2hs for my ffi work, and already have:
{#pointer *FILE as File foreign finalizer fclose newtype#}
but I can not import stderr like this:
foreign import ccall "stdio.h stderr" stderr :: File
My c function has the signature:
void func(FILE*);
I can import func with c2hs:
{#fun func as ^ {`File'} -> `()'#}
I need to use stderr to run func:
func(stderr);
I am noob with the foreign import mechanism. It seems I can not import stderr in this way.
ps. Maybe I would wrap my func in a new function
void func2(void){func(stderr);}
This is a workaround, but seems not clean.

It's not unusual to require some kind of "shim" when writing FFI code for Haskell, and I'd encourage you to just write a helper function:
FILE* get_stderr() { return stderr; }
and use that (see example at the bottom of this answer).
However, I was able to get the following minimal example to work by using the vanilla FFI's support for static pointers -- it doesn't import stderr directly, but imports a pointer to the stderr pointer. This kind of import is not directly supported by c2hs, so the interface code is ugly, and I don't think there's any way to avoid having to fetch the stderr pointer value in the IO monad, independent of whether or not you use c2hs.
// file.h
#include <stdio.h>
void func(FILE*);
// file.c
#include "file.h"
void func(FILE *f) {
fputs("Output to stderr!\n", f);
}
// File.chs
{-# LANGUAGE ForeignFunctionInterface #-}
module Main where
import Foreign
#include "file.h"
{#pointer *FILE as File newtype#}
{#fun func as ^ { `File' } -> `()'#}
foreign import ccall "&stderr" stderr_ptr :: Ptr (Ptr File)
main :: IO ()
main = do stderr <- File <$> peek stderr_ptr
func stderr
For comparison, this minimal example with the helper function looks much cleaner at the Haskell level:
// file.h
#include <stdio.h>
void func(FILE*);
FILE* get_stderr(void);
// file.c
#include "file.h"
void func(FILE *f) {
fputs("Output to stderr!\n", f);
}
FILE* get_stderr(void) {return stderr; }
// File.chs
{-# LANGUAGE ForeignFunctionInterface #-}
module Main where
#include "file.h"
{#pointer *FILE as File newtype#}
{#fun func as ^ { `File' } -> `()'#}
{#fun pure get_stderr as ^ {} -> `File'#}
main :: IO ()
main = func getStderr
Note that in both these examples, I removed your fclose finalizer. You probably don't want Haskell arbitrarily deciding it's a good time to close stderr on you.

With c2hs of version 0.28.2, the following code works:
-- lib.chs
{#pointer *FILE as File newtype#}
foreign import ccall "stdio.h &__stderrp" c_stderr :: Ptr (Ptr File) -- can not just use "stdio.h &stderr", this may cause a reference error
-- main.hs
stderr <- File <$> peek c_stderr
func stderr

Related

How do I use a FunPtr from Haskell?

Assuming the following files:
test2.h:
typedef int (*signature) ();
extern const signature lol2;
test2.c:
#include "test2.h"
int lol() {
return 42;
}
const signature lol2 = lol;
Test2.hs:
module Main where
import Foreign.C
import Foreign.Ptr
type Fun =
IO CInt
foreign import ccall
"test2.h lol2"
fun_ptr
:: FunPtr Fun
foreign import ccall "dynamic" mkFun :: FunPtr Fun -> Fun
lol = mkFun fun_ptr
main = do
fortytwo <- lol
putStrLn $ show $ fortytwo
With the following compilation:
gcc -shared test2.c -Wall -Wextra -o libtest2.so -g3 -ggdb3
ghc -o test2 Test2.hs -ltest2 -optl-Wl,-rpath,. -L. -g
(GHC emits a warning about a missing "&" before the lol2 declaration, but I think the warning is wrong, so I ignore it. Also, note that I am not using -dynamic. If I do, the results are the same)
But, I get a SIGSEGV while running:
(gdb) break scheduleWaitThread
Breakpoint 1 at 0x468150: file rts/Schedule.c, line 2509.
(gdb) r
Starting program: [...]/test2
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, scheduleWaitThread (tso=0x4200105388, ret=ret#entry=0x0, pcap=pcap#entry=0x7fffffffd7f8) at rts/Schedule.c:2509
2509 rts/Schedule.c: No such file or directory.
(gdb) bt
#0 scheduleWaitThread (tso=0x4200105388, ret=ret#entry=0x0, pcap=pcap#entry=0x7fffffffd7f8) at rts/Schedule.c:2509
#1 0x0000000000483864 in rts_evalLazyIO (cap=cap#entry=0x7fffffffd7f8, p=p#entry=0x4a5420, ret=ret#entry=0x0) at rts/RtsAPI.c:530
#2 0x00000000004707ae in hs_main (argc=1, argv=0x7fffffffd9e8, main_closure=0x4a5420, rts_config=...) at rts/RtsMain.c:72
#3 0x0000000000406b46 in main ()
(gdb) finish
Run till exit from #0 scheduleWaitThread (tso=0x4200105388, ret=ret#entry=0x0, pcap=pcap#entry=0x7fffffffd7f8) at rts/Schedule.c:2509
Program received signal SIGSEGV, Segmentation fault.
0x00000000004a4d90 in lol2 ()
(gdb)
After the crash the stack seems unusable:
(gdb) bt
#0 0x00000000004a4d90 in lol2 ()
#1 0x000000000040669d in r2ad_info ()
#2 0x0000000000000000 in ?? ()
What am I doing wrong? How can I debug this?
ccall can only import functions, but lol2 is no function. Use a capi import with a value qualification:
{-# LANGUAGE CApiFFI #-}
module Main where
-- ... etc ...
foreign import capi "test2.h value lol2" fun_ptr :: FunPtr Fun
-- ... etc ...
It's not immediately obvious, but the manual says to do this, and it works. The warning message you've seen still comes up; I think you may want to report that as a bug.

Parser error on including a C header file in GHC FFI

I am following examples (e.g. 1 or 2) to construct a data structure to pass to a C program using FFI in GHC (8.0.2). The C file tagger-api.h is:
typedef struct {
int number_of_words; /* number of words to be tagged */
int next_word; /* needed internally */
char **word; /* array of pointers to the words */
char **inputtag; /* array of pointers to the pretagging information */
const char **resulttag;/* array of pointers to the tags */
const char **lemma; /* array of pointers to the lemmas */
} TAGGER_STRUCT;
void init_treetagger(char *param_file_name);
double tag_sentence( TAGGER_STRUCT *ts );
The code is in a MainFFI4TT.hsc file:
{-# LANGUAGE CPP #-}
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE FlexibleInstances, RecordWildCards #-}
module Main where -- must have Main (main) or Main where
import Foreign
import Foreign.C
#include "tagger-api.h"
main = do
withCString parameterFileName c_initTreeTagger
return ()
parameterFileName = "/home/frank/additionalSpace/AF_amd_install/treeTagger/TreeTaggerDaemon/lib/german-utf8.par"
foreign import ccall "tagger-api.h init_treetagger"
c_initTreeTagger :: CString -> IO ()
foreign import ccall "tagger-api.h tag_sentence"
c_tag_sentence :: CString -> IO () -- structure required....
data Struct = Struct -- this requires ccp
{ noOfWords :: !Int
, nextWord :: !Int
, wordsIn :: ![String]
, pretag :: ![String]
, tags :: ![String]
, lemmas :: ![String]
}
{-
type StructPtr = Ptr Struct
instance Storable Struct where
alignement _ = #{alignment TAGGER_STRUCT}
sizeOf _ = #{size TAGGER_STRUCT}
poke p Struct{..} = do
number_of_words <- newCString noOfWords
nextWord <- CInt nextWord
-}
the cabal stanza is:
executable ttclient
main-is: MainFFI4TT.hs
build-depends: base
default-language: Haskell2010
hs-source-dirs: src
other-modules:
Include-dirs: treetaggerSourceC
Includes: tagger-api.h
extra-libraries: treetagger
extra-lib-dirs: /home/frank/Workspace8/repo8/treeTaggerClient/treetaggerSourceC
I was confused whether the file should have the extension .hsc or .cpphs - I was under the erroneous impression, that the .hsc file is automatically produced, now I have one. I assume that cabal is automatically converting the .hsc to a .hs, but it now fails with:
Linking dist/build/ttclient/ttclient ...
dist/build/ttclient/ttclient-tmp/Main.o: In function `c3Lp_info':
(.text+0x49a): undefined reference to `init_treetagger'
dist/build/ttclient/ttclient-tmp/Main.o: In function `c3Nl_info':
(.text+0x762): undefined reference to `tag_sentence'
collect2: error: ld returned 1 exit status
`gcc' failed in phase `Linker'. (Exit code: 1)
The next problem will be how to construct the structure with the array of pointers to strigs.
I appreciated the help in clarifying what preprocessor I have to use and to overcome the first hurdle. Now i am at a different one, help is greatly appreciated.
This new error message suggests that the libtreetagger.a library in the directory /home/frank/Workspace8/repo8/treeTaggerClient/treetaggerSourceC doesn't actually contain definitions for init_treetagger or tag_sentence, whatever tagger-api.h might say.
Can you run nm libtreetagger.a and see if init_treetagger and tag_sentence actually appear as defined symbols in that file? There should be lines like:
00000000000003b0 T init_treetagger
0000000000001c40 T tag_sentence
Specifically, the names should match exactly, the records should include addresses, and the types should be T.

Calling a Clojure Function from Haskell

Is it possible to call a Clojure function from Haskell (on the GHC), using the FFI or some other trick? Here I'm interested in staying within the bounds of GHC (i.e., not using Frege). I'm also interested in keeping the central program in Haskell (meaning that the Clojure function should be called from Haskell, and not vice versa).
How to do this?
Let me start by advertising inline-java which should make it pretty easy to call Clojure by just writing the Java code that calls the Clojure API. That said, as I am not running the bleeding edge GHC 8.0.2 (and had a variety of other install issues) I haven't been able to use this. When (if) I get inline-java running, I'll update this solution.
My solution below starts by creating a C interface to the Java methods in the Clojure API for Java via the JNI. Then, it calls that C interface using Haskell FFI support. You may need to adjust the library and include file paths depending on where your JDK and JRE are installed. If everything works right, you should see 7 printed to stdout. This is 3 plus 4 calculated by Clojure.
Setup
Download the Clojure 1.8.0 jar if you don't already have it. We'll be using the Java Clojure API. Make sure you've defined LD_LIBRARY_PATH. On the machine I used, that means exporting
export LD_LIBRARY_PATH="/usr/lib64/jvm/java/jre/lib/amd64/server/"
Finally, here is a makefile to make compiling a bit easier. You may need to adjust some library and include paths.
# makefile
all:
gcc -O -c \
-I /usr/lib64/jvm/java/include/ \
-I /usr/lib64/jvm/java/include/linux/ \
java.c
ghc -O2 -Wall \
-L/usr/lib64/jvm/java/jre/lib/amd64/server/ \
-ljvm \
clojure.hs \
java.o
run:
./clojure
clean:
rm -f java.o
rm -f clojure clojure.o clojure.hi
C Interface to Clojure functions
Now, we will make a C interface for the JVM and Clojure functionality we need. For this, we will be using the JNI. I choose to expose a pretty limited interface:
create_vm initializes a new JVM with the Clojure jar on the classpath (make sure you adjust this if you put your Clojure jar somewhere other than in the same folder)
load_methods looks up the Clojure methods we will need. Thankfully the Java Clojure API is pretty small, so we can wrap almost all of the functions there without to much difficulty. We also need to have functions that convert things like numbers or strings to and from their corresponding Clojure representation. I've only done this for java.lang.Long (which is Clojure's default integral number type).
readObj wraps clojure.java.api.Clojure.read (with C strings)
varObj wraps the one arg version of clojure.java.api.Clojure.var (with C strings)
varObjQualified wraps the two arg version of clojure.java.api.Clojure.read (with C strings)
longValue converts a Clojure long to a C long
newLong converts a C long to a Clojure long
invokeFn dispatches to the clojure.lang.IFn.invoke of the right arity. Here, I only bother to expose this up to arity 2, but nothing is stopping you from going further.
Here is the code:
// java.c
#include <stdio.h>
#include <stdbool.h>
#include <jni.h>
// Uninitialized Java natural interface
JNIEnv *env;
JavaVM *jvm;
// JClass for Clojure
jclass clojure, ifn, longClass;
jmethodID readM, varM, varQualM, // defined on 'clojure.java.api.Clojure'
invoke[2], // defined on 'closure.lang.IFn'
longValueM, longC; // defined on 'java.lang.Long'
// Initialize the JVM with the Clojure JAR on classpath.
bool create_vm() {
// Configuration options for the JVM
JavaVMOption opts = {
.optionString = "-Djava.class.path=./clojure-1.8.0.jar",
};
JavaVMInitArgs args = {
.version = JNI_VERSION_1_6,
.nOptions = 1,
.options = &opts,
.ignoreUnrecognized = false,
};
// Make the VM
int rv = JNI_CreateJavaVM(&jvm, (void**)&env, &args);
if (rv < 0 || !env) {
printf("Unable to Launch JVM %d\n",rv);
return false;
}
return true;
}
// Lookup the classes and objects we need to interact with Clojure.
void load_methods() {
clojure = (*env)->FindClass(env, "clojure/java/api/Clojure");
readM = (*env)->GetStaticMethodID(env, clojure, "read", "(Ljava/lang/String;)Ljava/lang/Object;");
varM = (*env)->GetStaticMethodID(env, clojure, "var", "(Ljava/lang/Object;)Lclojure/lang/IFn;");
varQualM = (*env)->GetStaticMethodID(env, clojure, "var", "(Ljava/lang/Object;Ljava/lang/Object;)Lclojure/lang/IFn;");
ifn = (*env)->FindClass(env, "clojure/lang/IFn");
invoke[0] = (*env)->GetMethodID(env, ifn, "invoke", "()Ljava/lang/Object;");
invoke[1] = (*env)->GetMethodID(env, ifn, "invoke", "(Ljava/lang/Object;)Ljava/lang/Object;");
invoke[2] = (*env)->GetMethodID(env, ifn, "invoke", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
// Obviously we could keep going here. The Clojure API has 'invoke' for up to 20 arguments...
longClass = (*env)->FindClass(env, "java/lang/Long");
longValueM = (*env)->GetMethodID(env, longClass, "longValue", "()J");
longC = (*env)->GetMethodID(env, longClass, "<init>", "(J)V");
}
// call the 'invoke' function of the right arity on 'IFn'.
jobject invokeFn(jobject obj, unsigned n, jobject *args) {
return (*env)->CallObjectMethodA(env, obj, invoke[n], (jvalue*)args);
}
// 'read' static method from 'Clojure' object.
jobject readObj(const char *cStr) {
jstring str = (*env)->NewStringUTF(env, cStr);
return (*env)->CallStaticObjectMethod(env, clojure, readM, str);
}
// 'var' static method from 'Clojure' object.
jobject varObj(const char* fnCStr) {
jstring fn = (*env)->NewStringUTF(env, fnCStr);
return (*env)->CallStaticObjectMethod(env, clojure, varM, fn);
}
// qualified 'var' static method from 'Clojure' object.
jobject varObjQualified(const char* nsCStr, const char* fnCStr) {
jstring ns = (*env)->NewStringUTF(env, nsCStr);
jstring fn = (*env)->NewStringUTF(env, fnCStr);
return (*env)->CallStaticObjectMethod(env, clojure, varQualM, ns, fn);
}
Haskell Interface to C functions
Finally, we use Haskell's FFI to plug into the C functions we just made. This compiles to an executable which adds 3 and 4 using Clojure's add function. Here, I lost the motivation to make functions for readObj and varObj (mostly because I don't happen to need them for my example).
-- clojure.hs
{-# LANGUAGE GeneralizedNewtypeDeriving, ForeignFunctionInterface #-}
import Foreign
import Foreign.C.Types
import Foreign.C.String
-- Clojure objects are just Java objects, and jsvalue is a union with size 64
-- bits. Since we are cutting corners, we might as well just derive 'Storable'
-- from something else that has the same size - 'CLong'.
newtype ClojureObject = ClojureObject CLong deriving (Storable)
foreign import ccall "load_methods" load_methods :: IO ()
foreign import ccall "create_vm" create_vm :: IO ()
foreign import ccall "invokeFn" invokeFn :: ClojureObject -> CUInt -> Ptr ClojureObject -> IO ClojureObject
-- foreign import ccall "readObj" readObj :: CString -> IO ClojureObject
-- foreign import ccall "varObj" varObj :: CString -> IO ClojureObject
foreign import ccall "varObjQualified" varObjQualified :: CString -> CString -> IO ClojureObject
foreign import ccall "newLong" newLong :: CLong -> ClojureObject
foreign import ccall "longValue" longValue :: ClojureObject -> CLong
-- | In order for anything to work, this needs to be called first.
loadClojure :: IO ()
loadClojure = create_vm *> load_methods
-- | Make a Clojure function call
invoke :: ClojureObject -> [ClojureObject] -> IO ClojureObject
invoke fn args = do
args' <- newArray args
let n = fromIntegral (length args)
invokeFn fn n args'
-- | Make a Clojure number from a Haskell one
long :: Int64 -> ClojureObject
long l = newLong (CLong l)
-- | Make a Haskell number from a Clojure one
unLong :: ClojureObject -> Int64
unLong cl = let CLong l = longValue cl in l
-- | Look up a var in Clojure based on the namespace and name
varQual :: String -> String -> IO ClojureObject
varQual ns fn = withCString ns (\nsCStr ->
withCString fn (\fnCStr -> varObjQualified nsCStr fnCStr))
main :: IO ()
main = do
loadClojure
putStrLn "Clojure loaded"
plus <- varQual "clojure.core" "+"
out <- invoke plus [long 3, long 4]
print $ unLong out -- prints "7" on my tests
Try it!
Compiling should be just make all and running make run.
Limitations
Since this is only a proof of concept, there are a bunch of things that should be fixed:
proper conversion for all of Clojure's primitive types
tear down the JVM after you are done!
make sure we aren't introducing memory leaks anywhere (which we might be doing with newArray)
represent Clojure objects properly in Haskell
many more!
That said, it works!
An easy way would be to launch your Clojure process with a socket REPL or NRepl server.
This enables a socket based REPL, so you could then use sockets to call your Clojure function.

How to change the name of a haskell process under linux

I am trying to change the name of a running process under linux. In C, I would just modify argv[0] in-place, but how can I do that from haskell? I noticed that ghc has a primitive called getProgArgv:
foreign import ccall unsafe "getProgArgv"
getProgArgv :: Ptr CInt -> Ptr (Ptr CString) -> IO ()
but I tried with that and it didn't work. Also, I am aware of prctl(PR_SET_NAME,"...") but that only changes the current thread's name, and most tools (such as ps and htop) do not use that name.
Ok, so I came up with an ugly hack that seems to work. It based on a idea borrowed from here. We have to use an auxiliary c file:
#include <string.h>
#include <sys/prctl.h>
char *argv0 = 0;
static void capture_argv0(int argc, char *argv[]) {
argv0 = argv[0];
}
__attribute__((section(".init_array"))) void (*p_capture_argv0)(int, char*[]) = &capture_argv0;
void set_prog_name(char *name) {
if (!argv0) return;
size_t len = strlen(argv0);
strncpy(argv0, name, len);
prctl(PR_SET_NAME, name);
}
This relies on the section(".init_array") attribute that tells gcc to register capture_argv0 as an initialization function. This means that it will be executed before main. We use it to make a copy of the argv[0] pointer and store it as a global variable. Now we can call set_prog_name from haskell.

Importing 'C' Delay function into Haskell using FFI

There is a function in the wiringPi 'C' library called delay with type
void delay(unsigned int howLong);
This function delays execution of code for howLong milliseconds. I wrote the binding code in haskell to be able to call this function. The haskell code is as follows,
foreign import ccall "wiringPi.h delay" c_delay :: CUInt -> IO ()
hdelay :: Int -> IO ()
hdelay howlong = c_delay (fromIntegral howlong)
After this, I wrote a simple haskell program to call this function. The simply haskell code is as follows..
--After importing relavent libraries I did
main = wiringPiSetup
>> delay 5000
But the delay does not happen or rather the executable generated by the ghc compiler exits right away.
Could someone tell me what could possibly go wrong here? A small nudge in the right direction would help.
Cheers and Regards.
Please ignore the part in block quote, and see update below - I am preserving the original non-solution because of comments associated with it.
You should mark the import as unsafe since you want the main
thread to block while the function is executing (see comment below by
#carl). By default, import is safe, not unsafe. So, changing
the function signature to this should make the main thread block:
foreign import ccall unsafe "wiring.h delay" c_delay :: CUInt -> IO ()
Also, if you plan to write multi-threaded code, GHC docs for multi-threaded FFI is >very useful. This also seems a good starter.
Update
The behavior seems to be due to signal interrupt handling (if I recall correctly, this was added in GHC 7.4+ to fix some bugs). More details here:
http://hackage.haskell.org/trac/ghc/wiki/Commentary/Rts/Signals
Please note the comment on the above page: Signal handling differs between the threaded version of the runtime and the non-threaded version.
Approach 1 - Handle signal interrupt in FFI code:
A toy code is below which handles the interrupt in sleep. I tested it on Linux 2.6.18 with ghc 7.6.1.
C code:
/** ctest.c **/
#include <unistd.h>
#include <stdio.h>
#include <time.h>
unsigned delay(unsigned sec)
{
struct timespec req={0};
req.tv_sec = sec;
req.tv_nsec = 0;
while (nanosleep(&req, &req) == -1) {
printf("Got interrupt, continuing\n");
continue;
}
return 1;
}
Haskell code:
{-# LANGUAGE ForeignFunctionInterface #-}
-- Filename Test.hs
module Main (main) where
import Foreign.C.Types
foreign import ccall safe "delay" delay :: CUInt -> IO CUInt
main = do
putStrLn "Sleeping"
n <- delay 2000
putStrLn $ "Got return code from sleep: " ++ show n
Now, after compiling with ghc 7.6.1 (command: ghc Test.hs ctest.c), it waits until sleep finishes, and prints a message every time it gets an interrupt signal during sleep:
./Test
Sleeping
Got interrupt, continuing
Got interrupt, continuing
Got interrupt, continuing
Got interrupt, continuing
....
....
Got return code from sleep: 1
Approach 2 - Disable SIGVTALRM before calling FFI code, and re-enable:
I am not sure what the implications are for disabling SIGVTALRM. This is alternative approach which disables SIGVTALRM during FFI call, if you can't alter FFI code. So, FFI code is not interrupted during sleep (assuming it is SIGVTALRM that is causing the interrupt).
{-# LANGUAGE ForeignFunctionInterface #-}
-- Test.hs
module Main (main) where
import Foreign.C.Types
import System.Posix.Signals
foreign import ccall safe "delay" delay :: CUInt -> IO CUInt
main = do
putStrLn "Sleeping"
-- Block SIGVTALRM temporarily to avoid interrupts while sleeping
blockSignals $ addSignal sigVTALRM emptySignalSet
n <- delay 2
putStrLn $ "Got return code from sleep: " ++ show n
-- Unblock SIGVTALRM
unblockSignals $ addSignal sigVTALRM emptySignalSet
return ()

Resources