25

I've created a Haskell package that makes FFI calls to functions defined in CUDA code. I'd like to compile .cu file to an object (.o) file during package build and force linker to link it in.

So far, I tried to use a technique found this question. I've customized buildHook to:

  1. run nvcc
  2. run default buildHook
  3. create ar library file with nvcc compiled code.

Setup.hs is available here.

This solution has a major disadvantage in restricting this package to static linking. Although cabal produces a shared library, it won't work because it has no way of resolving symbols located in the object file.

Is there a simpler way to link custom code during building?

Community
  • 1
  • 1

1 Answers1

3

I do a similar thing. I have a Haskell file which calls CUDA code.

Here's how I compile CUDA libraries and link with Haskell:

$(NVCC) -c -E  $(NVCC_OPTS) -o build/file.i file.cu
$(NVCC) -c  $(NVCC_OPTS) -o build/file.o file.cu

I then link everything into a C++ Shared Library called LibSO with Haskell options

$(CXX) -shared -Wl,-rpath=\$$$$ORIGIN $(CXX_LINK_LIBS) $(PACKAGE_RPATH) -Lbuild -rdynamic -L/usr/local/lib/ghc-7.6.3 -lHSrts-ghc7.6.3 -o build/LibSO.so build/file.o

where

CXX_LINK_LIBS = -Lbuild -lcudart -lcuda -lpthread -lcupti -lcurand -lnvidia-ml
NVCC_OPTS = --compiler-options -fPIC -maxrregcount=0 --machine 64 --DCUDA

I then take my Haskell files and compile them into o and hi files. (I compile twice because of TemplateHaskell)

ghc -v0 -Wall -rtsopts -threaded -stubdir build -ibuild/ -no-hs-main  -o build/iop.o -ohi build/iop.hi -c haskell/iop.lhs
ghc -v0 -Wall -rtsopts -threaded -stubdir build -ibuild/ -no-hs-main  -fPIC -dynamic -osuf dyn_o -hisuf dyn_hi -o build/iop.dyn_o -ohi build/iop.dyn_hi -c haskell/iop.lhs

So now we have haskell dynamic objects and a C++ shared library. In the end, I link a main haskell file with everything:

ghc -optl "-Wl,-rpath=\$$ORIGIN" $(CXX_LINK_LIBS) -Lbuild -rtsopts -threaded -lstdc++ -lLibSO -o build/Main build/iop.dyn_o

Does this sort of help?

Arnon
  • 2,237
  • 15
  • 23
  • 1
    It's not really useful, because you are assuming that the final result is an executable. My project needs to depend on another packages specified in .cabal file, so manually passing them as arguments to ghc/g++ is not an option. What's more, other packages will depend on my package so I can't just build an executable at the end. It's essential that Cabal can build the project by itself and be able to use it as dependency. – Marcin Mikołajczyk Sep 04 '14 at 15:24
  • So you're using Cabal and not linking directly? Do you pre-compile NVCC into objects and then pass them to Cabal? What arguments are you passing to Cabal to begin with? – Arnon Sep 04 '14 at 18:41
  • I use a custom Setup.hs file that I attached to the original question. NVCC is called during build phase and resulting object files are later archived with other Haskell objects to .a file. Building doesn't require additional command line arguments, everything is specified in Setup.hs. – Marcin Mikołajczyk Sep 04 '14 at 19:08
  • I'm quite confident Cabal wasn't designed for such a complex scheme. I'd consider alternative compilation methods. – Arnon Sep 07 '14 at 13:27