Cabal should support hsc2hs's stub .c feature #238

bos opened this Issue May 24, 2012 · 9 comments

3 participants


(Imported from Trac #245, reported by guest on 2008-02-21)

The Pugs project recently uncovered a bit of a problem with GHC 6.8.x.

To quote:

  • {-# INCLUDE -} seems to require either a very relative or an absolute path. That is, you have to make the path listed inside an INCLUDE ('dist/build/Pugs/Embed/Parrot_hsc.h') in the file dist/build/Pugs/Embed/Parrot.hs absolute or completely relative - that is, the first line needs to look like either '{-# INCLUDE "Parrot_hsc.h" #-}' or '{-# INCLUDE
"/home/gwern/bin/pugs/dist/build/Pugs/Embed/Parrot_hsc.h" #-}'.

The particular problem is that 'dist/build/Pugs/Embed/Parrot_hsc.c:#include "Parrot_hsc.h"' is being translated to the (broken) 'dist/build/Pugs/Embed/Parrot.hs:{-# INCLUDE "dist/build/Pugs/Embed/Parrot_hsc.h" #-}'.

The relevant files and notes can be found in the Pugs SVN repo, in src/Pugs/Embed/, and the files of interest are Haskell.hs Parrot.hsc Parrot_hsc.c Parrot_hsc.h Perl5.hs Pugs.hs



(Imported comment by @dcoutts on 2008-02-21)

hsc2hs has a little used feature which is that you can use #def directives to spit bits of C code into a generated .c and .h file. The build system is supposed to notice this .c file and compile and link it into the system in question. Cabal does not do this (presumably because nobody implementing hsc2hs support had ever seen the feature).

Turns out that people were making use of this hsc2hs feature despite the lack of support in Cabal by relying on the fact that Cabal used to put pre-processor output into the src dirs so instead of asking for proper support people worked around the issue by using things like:

c-sources: src/Foo_hsc.c
and relying on Cabal to run hsc2hs on src/Foo.hsc to generate src/Foo_hsc.c before compiling any .c files. Of course when Cabal-1.2 changed to put all generated files under dist/ this workaround broke.

The right thing obviously is for Cabal to notice the .c files that hsc2hs generates and to compile and link them in. There may be a problem with paths however since hsc2hs will be putting the generated .c file under dist/build/ and hsc2hs embeds a '#include to the .h file with the full dist/build/ prefix, but we do not put . on the include search path, only dist/build/, so the header file should really be relative to that. This may require changes in hsc2hs to support properly. We got this working correctly for c2hs` which does similar things, embedding relative links between generated files.


(Imported comment by ross on 2008-02-21)

There's a good reason that this feature is little used (see the Note in the description of this feature in the GHC User's Guide). Because of GHC's cross-module inlining, to do it right you'd need to treat the _hsc.h files as both includes and install-includes, to be included in the compilation of dependent packages.


(Imported comment by @dcoutts on 2008-02-22)

I've filed a ticket with pugs:


(Imported comment by @dons on 2008-02-22)

This breaks Tuomov's 'riot' too,

where his Makefile build system compiles and links in,

ghc -c -fglasgow-exts -cpp -fasm -funbox-strict-fields -fignore-asserts -cpp -DCF_CHARSET_SUPPORT -DCF_WCHAR_SUPPORT -DHAVE_WADDNWSTR -DHAVE_RESIZETERM -DGHC64 -I. -Icbits Ginsu/CWString_hsc.c -o Ginsu/CWString_hsc.o
ghc -c -fglasgow-exts -cpp -fasm -funbox-strict-fields -fignore-asserts -cpp -DCF_CHARSET_SUPPORT -DCF_WCHAR_SUPPORT -DHAVE_WADDNWSTR -DHAVE_RESIZETERM -DGHC64 -I. -Icbits Curses/Curses_hsc.c -o Curses/Curses_hsc.o

But with a .cabal file, we can't get those linked, leading to errors:
(.text+0xc087): undefined reference to hs_curses_acs_ulcorner'
dist/build/riot/riot-tmp/Curses/Curses.o: In function
(.text+0x12fd4): undefined reference to hs_curses_color_pair'
dist/build/riot/riot-tmp/Ginsu/CWString.o: In function
(.text+0x24ff): undefined reference to hs_get_mb_cur_max'
collect2: ld returned 1 exit status
cabal: Error: some packages failed to install:
riot-1.20080618 failed during the building phase. The exception was:
ExitFailure?` 1


(Imported comment by guest on 2008-08-26)

This bug just bit me. Is there a workaround yet?


(Imported comment by acowley on 2011-04-02)

I've also run into this issue. Using #def is very convenient for wrapping a C interface (e.g. to handle passing structs by value). To work around the cabal limitation, one can either use a Makefile or a custom Setup.hs to manually invoke hsc2hs in the src directory before running the usual cabal install. This requires that the generated *_hsc.c files be specified in the .cabal file.


The workaround described by Duncan still seems to work (but now with a path to dist/):

c-sources: dist/build/Path/To/Module_hsc.c

@nh2 note that this workaround will break in the presence of sandboxes (the path would look like dist/dist-foobar/build/Path/To/Module_hsc.c instead)

@23Skidoo 23Skidoo referenced this issue in ian-ross/cabal Mar 28, 2015
@ian-ross ian-ross Allow preprocessors to specify extra C sources
Add functionality to allow preprocessors like hsc2hs and C2HS to inform
Cabal of extra C sources that they create that need to be compiled and
linked.  Includes hsc2hs-based test case.
@23Skidoo 23Skidoo closed this in #2467 Mar 29, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment