I successfully replicated this example using GHC by itself.
https://wiki.haskell.org/Calling_Haskell_from_C
The end goal is to write 99% of my program in Haskell, and then call it from an event loop written in C:
#include <HsFFI.h>
#ifdef __GLASGOW_HASKELL__
#include "../.stack-work/dist/x86_64-linux/Cabal-2.4.0.1/build/Lib_stub.h"
extern void __stginit_Lib(void);
#endif
#include <stdio.h>
#include <time.h>
extern void hs_add_root (void (*init_root)(void));
int main(int argc, char *argv[])
{
int i;
hs_init(&argc, &argv);
#ifdef __GLASGOW_HASKELL__
hs_add_root(__stginit_Lib);
#endif
for (int m = 0; m < 10; ++m) {
i = fibonacci_hs(42);
printf("Fibonacci: %d\n", i);
}
hs_exit();
return 0;
}
The motivation to run an event loop in C is that, from what I've read, forcing evaluation X times/second is difficult or impossible in Haskell.
Here is package.yaml:
name: c-loop
version: 0.1.0.0
github: "githubuser/c-loop"
license: BSD3
author: "Author name here"
maintainer: "example#example.com"
copyright: "2019 Author name here"
extra-source-files:
- README.md
- ChangeLog.md
# Metadata used when publishing your package
# synopsis: Short description of your package
# category: Web
# To avoid duplicated efforts in documentation and dealing with the
# complications of embedding Haddock markup inside cabal files, it is
# common to point users to the README.md file.
description: Please see the README on GitHub at <https://github.com/githubuser/c-loop#readme>
dependencies:
- base >= 4.7 && < 5
library:
source-dirs: src
executables:
c-loop-exe:
main: Main.hs
source-dirs: app
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
- -fobject-code
# - -no-hs-main
- --make -no-hs-main -optc-O ./c/eventLoop.c Lib -o eventLoop
dependencies:
- c-loop
tests:
c-loop-test:
main: Spec.hs
source-dirs: test
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
dependencies:
- c-loop
When I run:
$ stack build
I get this:
<no location info>: error: module ‘Lib’ cannot be found locally
Does anyone know what is going on?
As an aside, your motivation seems misguided. I don't think there's any benefit to having a C event loop whose only purpose is to "force evaluation" on a regular schedule. You can do that in Haskell just fine.
What's going wrong in your example above is probably the Lib in the ghc-options. However, there are other Cabal fields you should be using instead which will make things work more smoothly.
Here's how to get your minimal example working with Stack. Create a fresh directory with the four files listed below and run stack build, then stack exec c-loop-exe.
A few points:
You might be able to do this with a package.yaml file, but you'll have to convert the Cabal syntax over.
You don't need all that __stginit and hs_add_root garbage anymore, unless you're using GHC < 7.2.
You don't need to hard-code the path for the stub, if you set up the Cabal file correctly (i.e., using c-sources).
The -opt-O2 flag is unnecessary. It's the Stack default.
The contents for the four files:
-- stack.yaml
resolver: lts-13.21
packages:
- .
-- c-loop.cabal
cabal-version: 1.12
name: c-loop
version: 0.1.0.0
build-type: Simple
executable c-loop-exe
main-is: src/Lib.hs
ghc-options: -no-hs-main
c-sources: c/eventLoop.c
build-depends:
base >=4.7 && <5
default-language: Haskell2010
-- c/eventLoop.c
#include <stdio.h>
#include <time.h>
#include "HsFFI.h"
#include "Lib_stub.h"
int main(int argc, char *argv[])
{
int i;
hs_init(&argc, &argv);
for (int m = 0; m < 10; ++m) {
i = fibonacci_hs(42);
printf("Fibonacci: %d\n", i);
}
hs_exit();
return 0;
}
-- src/Lib.hs
{-# LANGUAGE ForeignFunctionInterface #-}
module Lib where
import Foreign.C.Types
fibonacci :: Int -> Int
fibonacci n = fibs !! n
where fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
fibonacci_hs :: CInt -> CInt
fibonacci_hs = fromIntegral . fibonacci . fromIntegral
foreign export ccall fibonacci_hs :: CInt -> CInt
Related
System: Mac OS X Big Sur
ghc : 8.8.4
cabal: 3.2.0.0
I can install all gloss-examples and run without issues.
But when I use makelens ''Foo
It suddenly complains:
<command line>: can't load framework: OpenGL (not found)
I tried with microlens and same behavior.
Why?
Below are the codes I've used:
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens hiding (element)
import Graphics.Gloss
import Graphics.Gloss.Interface.Pure.Game
data ManGame = ManGame {
mgPic :: Picture,
mgX :: Float,
mgY :: Float
-- Add _mgKeyDown to have press and hold function
} deriving Show
--makeLenses ''ManGame
This works. But if I uncommented the last line, it reports error during compilation.
For the cabal file(I've used the same as with other gloss-examples programs):
Executable gloss-game
Main-is: Main.hs
hs-source-dirs: picture/Game
Build-depends:
base >= 4.8 && < 5
, lens
, gloss == 1.13.*
Default-Language:
Haskell2010
ghc-options:
-O2
-Wall
-threaded
-rtsopts
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.
I'd like to build the 32-bit DLL with 64-bit GHC. And here is the minimal example.
Test.hs
{-# LANGUAGE ForeignFunctionInterface #-}
module Test where
import Foreign.C.Types
foreign export ccall c_hello :: IO()
foreign export ccall boo :: CInt
c_hello :: IO()
c_hello = do
print "Hello!"
init_exit.cpp
#include "Test_stub.h"
#include <C:\Program Files\Haskell Platform\8.0.1\lib\include\Rts.h>
#define DLLExport extern "C" __declspec(dllexport)
DLLExport void hello()
{
c_hello();
}
DLLExport int HsStart()
{
int argc = 1;
char* argv[] = {"ghcDLL", NULL};
char** args = argv;
hs_init(&argc, &args);
printf("Haskell library has been initialized!\n");
return 0;
}
DLLExport int HsEnd()
{
hs_exit();
printf("Haskell library has been finalized!\n");
return 0;
}
And then I build the library, using the following commands:
ghc -c -O Test.hs
ghc -c init_exit.cpp
ghc -shared -o Test.dll Test.o init_exit.o
What flags should I pass to ghc or maybe to gcc to build the 32-bit DLL instead of 64-bit? Or maybe there is another way to do this.
A normal Windows 64-bit GHC build (such as the one you can download from the GHC website) is only capable of building 64-bit object files. For example, it doesn't include 32-bit versions of any of the libraries that come with GHC.
Your options are to build a Windows 64-bit to Windows 32-bit cross-compiler, or just run the normal Windows 32-bit build of GHC (probably much easier).
This is the standard Hello World CUDA file:
#include <stdio.h>
#include "hello.h"
const int N = 7;
const int blocksize = 7;
__global__ void hello_kernel(char *a, int *b) {
a[threadIdx.x] += b[threadIdx.x];
}
#define cudaCheckError() { \
cudaError_t e=cudaGetLastError(); \
if(e!=cudaSuccess) { \
printf("Cuda failure %s:%d: '%s'\n",__FILE__,__LINE__,cudaGetErrorString(e)); \
exit(0); \
} \
}
void hello() {
char a[N] = "Hello ";
int b[N] = {15, 10, 6, 0, -11, 1, 0};
char *ad;
int *bd;
const int csize = N*sizeof(char);
const int isize = N*sizeof(int);
printf("%s", a);
cudaMalloc( (void**)&ad, csize );
cudaMemcpy( ad, a, csize, cudaMemcpyHostToDevice );
cudaCheckError();
cudaMalloc( (void**)&bd, isize );
cudaMemcpy( bd, b, isize, cudaMemcpyHostToDevice );
cudaCheckError();
dim3 dimBlock( blocksize, 1 );
dim3 dimGrid( 1, 1 );
hello_kernel<<<dimGrid, dimBlock>>>(ad, bd);
cudaMemcpy( a, ad, csize, cudaMemcpyDeviceToHost );
cudaCheckError();
cudaFree( ad );
cudaCheckError();
printf("%s\n", a);
}
And its header:
-- hello.h
extern "C"
void hello();
That's a Haskell file that calls such function:
-- test.hs
{-# LANGUAGE ForeignFunctionInterface #-}
import Foreign.C
import Foreign.Ptr (Ptr,nullPtr)
foreign import ccall "hello" hello :: IO ()
main = hello
I'm compiling it with:
nvcc hello.c -c -o hello.o
ghc test.hs -o test hello.o -L/usr/local/cuda/lib -optl-lcudart
Running that program with ./test results in:
Hello Cuda failure hello.cu:32: 'no CUDA-capable device is detected'
Running the same program with a C main() that just calls hello produces Hello World, as expected.
How do I make Haskell detect the device correctly?
Maybe unrelated, but I was able to reproduce your error on a Mac with separate on-board and discrete graphics cards. When "Automatic graphics switching" is enabled in System Preferences (and no 3D graphics applications are running), I get the same "no CUDA-capable device is detected" error.
When I turn off automatic graphics switching, it forces the Mac to use the discrete graphics card, and then the program runs as expected.
The purely C/CUDA-based version of the code doesn't seem to be affected by this preference and always works whether automatic switching is enabled or not.
Using ghc 7.8.3 and nvcc V6.5.12, I found that your code works as expected. The only different thing that I did was name hello.c as hello.cu.
/:cuda_haskell> nvcc --version
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2014 NVIDIA Corporation
Built on Thu_Jul_17_19:13:24_CDT_2014
Cuda compilation tools, release 6.5, V6.5.12
/:cuda_haskell> nvcc -o hello.o -c hello.cu
/:cuda_haskell> ghc main.hs -o hello_hs hello.o -L/usr/local/cuda/lib -optl-lcudart
Linking hello_hs ...
/:cuda_haskell> ./hello_hs
Hello World!
/:cuda_haskell> cat main.hs
-- main.hs
{-# LANGUAGE ForeignFunctionInterface #-}
import Foreign.C
import Foreign.Ptr (Ptr,nullPtr)
foreign import ccall "hello" hello :: IO ()
main = hello
I am working through a sample program that uses both C++ source code as well as CUDA. This is the essential content from my four source files.
matrixmul.cu (main CUDA source code):
#include <stdlib.h>
#include <cutil.h>
#include "assist.h"
#include "matrixmul.h"
int main (int argc, char ** argv)
{
...
computeGold(reference, hostM, hostN, Mh, Mw, Nw); //reference to .cpp file
...
}
matrixmul_gold.cpp (C++ source code, single function, no main method):
void computeGold(float * P, const float * M, const float * N, int Mh, int Mw, int Nw)
{
...
}
matrixmul.h (header for matrixmul_gold.cpp file)
#ifndef matrixmul_h
#define matrixmul_h
extern "C"
void computeGold(float * P, const float * M, const float * N, int Mh, int Mw, int Nw);
#endif
assist.h (helper functions)
I am trying to compile and link these files so that they, well, work. So far I can get matrixmul_gold.cpp compiled using:
g++ -c matrixmul_gold.cpp
And I can compile the CUDA source code with out errors using:
nvcc -I/home/sbu/NVIDIA_GPU_Computing_SDK/C/common/inc -L/home/sbu/NVIDIA_GPU_Computing_SDK/C/lib matrixmul.cu -c -lcutil_x86_64
But I just end up with two .O files. I've tried a lot of different ways to link the two .O files but so far it's a no-go. What's the proper approach?
UPDATE: As requested, here is the output of:
nm matrixmul_gold.o matrixmul.o | grep computeGold
nm: 'matrixmul.o': No such file
0000000000000000 T _Z11computeGoldPfPKfS1_iii
I think the 'matrixmul.o' missing error is because I am not actually getting a successful compile when running the suggested compile command:
nvcc -I/home/sbu/NVIDIA_GPU_Computing_SDK/C/common/inc -L/home/sbu/NVIDIA_GPU_Computing_SDK/C/lib -o matrixmul matrixmul.cu matrixmul_gold.o -lcutil_x86_64
UPDATE 2: I was missing an extern "C" from the beginning of matrixmul_gold.cpp. I added that and the suggested compilation command works great. Thank you!
Conventionally you would use whichever compiler you are using to compile the code containing the main subroutine to link the application. In this case you have the main in the .cu, so use nvcc to do the linking. Something like this:
$ g++ -c matrixmul_gold.cpp
$ nvcc -I/home/sbu/NVIDIA_GPU_Computing_SDK/C/common/inc \
-L/home/sbu/NVIDIA_GPU_Computing_SDK/C/lib \
-o matrixmul matrixmul.cu matrixmul_gold.o -lcutil_x86_64
This will link an executable binary called matrimul from matrixmul.cu, matrixmul_gold.o and the cutil library (implicitly nvcc will link the CUDA runtime library and CUDA driver library as well).