On Tue, Jun 5, 2012 at 4:28 AM, Ketil Malde <ke...@malde.org> wrote: > Rogan Creswick <cresw...@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).
I'm not sure if/when copy hooks are used during the typical cabal configure/build/install process; I suspect they are not used. There is, however, a `cabal copy` command, which I believe does. Not that that helps you right now, but that may explain the behavior you saw. >> LocalBuildInfo /probably/ has the details you need (eg: installDirTemplates). This was harder than I thought. Here's an example (I hacked an example on to the cabal-dev Setup.hs, so there are extra imports you won't necessarily need -- full Setup.hs is in the linked gist, the email only contains the relevant exceprts): Gist: https://gist.github.com/2876277 main = defaultMainWithHooks $ simpleUserHooks { hookedPrograms = [cabalInstallProgram] , postInst = postInstCp (postInst simpleUserHooks) } type PostInstHook = Args -> InstallFlags -> PackageDescription -> LocalBuildInfo -> IO () postInstCp :: PostInstHook -> Args -> InstallFlags -> PackageDescription -> LocalBuildInfo -> IO () postInstCp oldHook args iflags pDesc lbi = do let -- The filename to copy from: inFile :: FilePath inFile = "srcFileName.sh" -- The filename to copy to: outFile :: FilePath outFile = "destFileName.sh" prefix = fromFlag $ installDistPref iflags -- Make a concrete binDir from the LocalBuildInfo & PackageDescription: instBinDir :: FilePath instBinDir = bindir $ absoluteInstallDirs pDesc lbi (fromFlag $ copyDest defaultCopyFlags) -- layer of indirection, in case we wanted to get a specific -- src directory from the cabal file: src :: FilePath src = inFile -- qualify the destination. dest :: FilePath dest = instBinDir </> outFile -- Do the copy, creating outFile in the bin dir: copyFile src dest -- now invoke the old hook: oldHook args iflags pDesc lbi --Rogan > > 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@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe