[Haskell-cafe] Install a script with Cabal?

Ivan Perez ivanperezdominguez at gmail.com
Tue Jun 5 15:41:41 CEST 2012

I spent quite some time going through the cabal docs to generate some
files automatically with hails. I totally feel your pain :)

What I'm going to suggest is not really a solution to your problem,
but since modifying the hooks to install specific programs is not the
best solution either, you might want to try and write your script in
Haskell (using HSH, for instance). That way you would have a
multi-platform "script" that can be installed just like any other
Haskell program.

Regarding the general problem, the best I can think of would be adding
a field "Bin-files:" to the cabal file format, and have Cabal process
it properly. Maybe some of the maintainers of cabal can comment on

Two more suggestions. If you are going to modify the hooks:
1) Do not call cp directly. Use copyFile if possible. "cp" is *nix dependent.
2) Read the name of the file to be copied from a configuration file.
It is much more likely that others (and you) will be able to reuse
your code if you do.


[1] http://hackage.haskell.org/package/HSH

On 5 June 2012 12:28, Ketil Malde <ketil at malde.org> wrote:
> Rogan Creswick <creswick at gmail.com> writes:
>>> I have a small project that installs a couple of Haskell tools and a
>>> script that uses these. Cabal will of course build and install the
>>> Haskell programs, but how can I get Cabal to install the script as
>>> well? There's a host of UserHooks available¹, but it'd probably be
>>> better to have an example than to try to experiment with the right
>>> configuration.
>> I don't have an example handy, but I think you'll want preInts,
>> instHook, or postInst.  I'd probably go with postInst unless you need
>> data provided by instHook's type that isn't passed to preInst or
>> postInst.
> I found an example¹ using copyHook. However, this seems to be the wrong
> thing, at least I am unable to get cabal to ever call this hook (or
> preCopy, etc).
>> LocalBuildInfo /probably/ has the details you need (eg: installDirTemplates).
> I just printed out the contents of LocalBuildInfo, but that's 33 pages
> (I counted) of output.  Redirected to a file, it makes it easier to
> search to find the relevant needles in this haystack.
> Okay, looking at installDirTemplates, I see `bindir` can extract this
> data member.  It's of course an InstallDirTemplate, not a FilePath, but
> I found 'fromPathTemplate', which has the right type.  Except it only
> dumps the template, with $prefix and all.
> Hoogle doesn't seem to know about any of the Cabal stuff, Hayoo has a *very*
> annoying behavior where it cleans out everything you did if you use the
> "back" button, and the "source" links it advertises seem to point into
> the wide blue 404.  But using the latter, I managed to find a link to
> 'substPathTemplate', worked out that the PackageIdentifier it needs is a
> member of PackageDescription, and tried to use that.  Except it gives
> the same result, and doesn't appear to substitute anything.  I guess the
> fact that it is undocumented is a hint that it's the wrong thing to use.
> Reading some more, maybe 'absoluteInstallDirs' is what I'm looking for?
> In addition to the usual heap of huge config structs, it needs a
> "CopyDest", though.  Since I have no idea what to use, I just put
> NoCopyDest there.  Does that make sense?  Okay, it works now, in the
> sense that I ran it once on my laptop, and it copied the file to
> ~/.cabal/bin.  Here is the code, comments welcome:
>  #!/usr/bin/env runhaskell
>  import Distribution.Simple (defaultMainWithHooks, simpleUserHooks,UserHooks(..))
>  import Distribution.Simple.Setup (InstallFlags,CopyDest(..))
>  import Distribution.Simple.Utils (rawSystemExit)
>  import Distribution.PackageDescription (PackageDescription())
>  import Distribution.Simple.LocalBuildInfo (LocalBuildInfo(..), InstallDirs(..), absoluteInstallDirs)
>  import Distribution.Verbosity (normal)
>  main :: IO ()
>  main = defaultMainWithHooks simpleUserHooks
>      { instHook = \pd lbi uh ifs -> myinst pd lbi uh ifs >> instHook simpleUserHooks pd lbi uh ifs }
>  myinst :: PackageDescription -> LocalBuildInfo -> UserHooks -> InstallFlags -> IO ()
>  myinst pd lbi _uh _fs = do
>      let bin = bindir $ absoluteInstallDirs pd lbi NoCopyDest
>      rawSystemExit normal "cp" ["asmeval", bin]
> PS: This was a rather frustrating excercise, and after wallowing through
> a wilderness of modules, types, records and functions, I can't help but
> feel that Cabal is a bit overengineered. Surely including a script or
> similar in a package isn't all that outlandish? Could there conceivably
> have been a simpler way?  Or at least, better documented?  I suspect the
> fact that - with the sole exception of the link below -- I could find *no*
> examples to help me out indicates that it is a bit too complicated.
> -k
> ¹ http://blog.ezyang.com/2010/06/setting-up-cabal-the-ffi-and-c2hs/
> --
> If I haven't seen further, it is by standing in the footprints of giants
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe at haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe

More information about the Haskell-Cafe mailing list