C compiler selection in cabal package

2020-07-03 07:13发布

问题:

I decided to add some flags to control the way that C source file is compiled (i.e. something like use-clang, use-intel etc.).

      C-Sources:    c_lib/tiger.c
      Include-Dirs: c_lib
      Install-Includes: tiger.h

      if flag(debug)
          GHC-Options: -debug -Wall -fno-warn-orphans
          CPP-Options: -DDEBUG
          CC-Options: -DDEBUG -g
      else
          GHC-Options: -Wall -fno-warn-orphans

Question is: which options in descritpion file need to be modified to change C compiler? I did found only CC-Options.

回答1:

There really doesn't seem to be any way to specify this in a .cabal file; the only thing we seem to have at the moment that would be even remotely useful here is --with-<prog>=path.

I suggest you try filing a ticket against Cabal on the trac.



回答2:

There is no straightforward way, but it is possible.

Assuming that you are using Distribution.Simple, you basically need to add a user hook to the build stage.

All of the following changes need to appear in Setup.hs:

Change main to use a build hook, something like:

main :: IO ()
main = defaultMainWithHooks simpleUserHooks { buildHook = myBuildHook }

Next you need a build hook. It will likely look something like the following:

myBuildHook pkg_descr local_bld_info user_hooks bld_flags =
    do
    let lib       = fromJust (library pkg_descr)
        lib_bi    = libBuildInfo lib
        custom_bi = customFieldsBI lib_bi
        cpp_name  = fromJust (lookup "x-cc-name" custom_bi)
        c_srcs    = cSources lib_bi
        cc_opts   = ccOptions lib_bi
        inc_dirs  = includeDirs lib_bi
        lib_dirs  = extraLibDirs lib_bi
        bld_dir   = buildDir local_bld_info
    -- Compile C/C++ sources
    putStrLn "invoking my compile phase"
    objs <- mapM (compileCxx cpp_name cc_opts inc_dirs bld_dir) c_srcs
    -- Remove C/C++ source code from the hooked build (don't change libs)
    let lib_bi'    = lib_bi { cSources = [] }
        lib'       = lib    { libBuildInfo = lib_bi' }
        pkg_descr' = pkg_descr { library = Just lib' }
    -- The following line invokes the standard build behaviour
    putStrLn "Invoke default build hook"
    bh <- buildHook simpleUserHooks pkg_descr' local_bld_info user_hooks bld_flags
    return bh

The code above probably needs unpacking a bit. The let clauses are basically about unpacking the required data fields from the structures passed to the build hook. Notice that you can create custom stanzas in your foo.cabal. I have provided the code to support a stanza something like:

x-cc-name: icc

As a means to specify your compiler. Having extracted all of the source files, you map over them using a function to compile a single file (NB: this is sub-optimal in some cases, e.g. those compilers which can efficiently compile multiple source files to produce a single object output and benefit from large scale optimizations, but we'll leave that aside for now).

Last of all, as we've now compiled the C/C++ code, remove it from the build structures before you pass everything on to the default build hook.

Sorry that this is more of a 'HOWTO' than a canned answer, but it should help you to get going.

I should mention that the code is untested. I have adapted it from some work I have been doing on the wxHaskell build system, so I know the idea works fine. The Cabal API is actually pretty well documented - it suffers mainly from being somewhat unstable around some of these areas.



回答3:

4.10.1. Replacing the program for one or more phases

-pgmc cmd
        Use cmd as the C compiler.

This works for ghc --make, but I'm not sure how to get Cabal to apply this to the C file compilation.



标签: haskell cabal