FFI proposal: allow some control over the scope of C header files

Manuel M T Chakravarty chak at cse.unsw.edu.au
Fri Apr 21 09:32:11 EDT 2006


Duncan Coutts:
> One problem that people writing FFI bindings often run into is that they
> do not understand exactly where C header files are required to be
> available.
> 
> The easy case is importing some C function defined in a well known and
> widely available C header file (eg gtk/gtk.h). In this case we just make
> sure that header is available for compiling every module in the package
> and add that header file to the package info file (or .cabal file) so
> that every module that uses the package will have the C header
> available. In this case there is no problem with C calls being inlined
> outside of the module which imported them since the C header file will
> be available everywhere.
> 
> The tricky case is that people often use "private" header files that are
> #included when compiling a module/package but are not installed along
> with that package and so are not #included when compiling client
> modules. Most of the time this works, however the Haskell compiler is
> allowed to inline across modules and if it chooses to inline the C call
> into a client module then things will break. Sadly it still compiles and
> sometimes even works since C allows calling a C function without a
> prototype. However occasionally it's going to break horribly.
>
> Allowing us to limit where the C headers will be required would be very
> useful. Sometimes it is very convenient to have private header files
> that will not be installed with the package. It is also sometimes the
> case that it's much more convenient to not require that the user has a
> set of C header files installed to be able to use a library package.
> Examples of this include some windows packages, eg DriectX where it's
> rather inconvenient to require that users have the MS DirectX SDK
> installed.

I understand these concerns, but they are tightly coupled to two
mechanisms that are currently not really standardised: (1) cross-module
function inlining and (2) command line options.

> Currently GHC has a de-facto way of limiting the required scope of C
> header files to a module - by using the standard FFI syntax (!). I know
> people are already using this trick to allow the use of private header
> files.
> 
> This issue also touches on the related issue that the way of specifying
> C header files in the FFI spec is not really optimal. GHC implements a
> couple other methods and these are probably used more that the method in
> the FFI spec.
> 
> So I suggest that we briefly consider some possibilities for extending
> control over where C header files will be needed and perhaps also for
> specifying what C header files are needed in the first place.
> 
> I think we'd want to be able to specify that a C header file not
> "escape" a module boundary and probably we'd also want to be able to ask
> that it not escape a package boundary (though this may be beyond the H'
> spec since Haskell does not talk about packages).

The H98 standard already specifies a NOINLINE pragma for any function:

  http://haskell.org/onlinereport/pragmas.html

The simplest solution is to ensure that all Haskell compilers implement
this pragma properly for foreign imported functions.  If you want finer
control over where inlining takes place, then maybe the pragma should be
extended to provide that finer control.

> It would also be convenient to be able to specify that a module needs a
> particular C header file rather than having to specify it in each
> foreign import decl. Currently this can be done by cabal in a
> compiler-specific way (it uses ghc's -#include command line mechanism)

If you don't specify it in every import declaration, the compiler won't
know what to include if you allow inlining and the compiler does perform
cross-module inlining.

Besides, the standard so far doesn't cover command line options at all.
So, there is the more general question of whether it should.

> It's a reasonable question to ask if specifying a C header file should
> go in the module source code or elsewhere (eg a .cabal file) since
> afterall we don't specify search paths etc in the module. I'd say that
> it is right that the name of the header file be in the module source
> code and that the search paths etc be external.
> 
> So some syntax off the top of my head:
> 
> foreign import cheader module-local "foo/bar.h"
> 
> I think there are 3 possibilities for the C header escape/scope setting
> (which should probably be manditory rather than optional):
> module-local
> package-local (extension for compilers that have a notion of a package)
> global

Is this additional complexity really necessary or would the use of
NOINLINE pragmas not suffice?  It's really in a library context where
you want to restrict the inlining of foreign functions, but there the
foreign functions are probably not much used inside the library itself,
but mainly exported, so I doubt that you would get much of a performance
loss by just tagging all foreign imported functions that you don't want
to escape as NOINLINE.

Manuel




More information about the Haskell-prime mailing list