
Simon Marlow
Libraries and executables in the same package are not well supported by Cabal.
I'm starting to believe the situation is not as bad as you suggest. I recently realized a post configuration hook can be used to generate the needed package configuration information, so that it is easy to write packages in which executables are linked to the library in the package. I have enclosed the code that does so. There is one remaining problem, you have to figure out how to force executables to be rebuilt when only the library changes. I use a makefile to delete all the binaries before I run Setup.hs build. John $ make find dist -type f -perm /u+x -delete runghc Setup.hs build Preprocessing library a-1.0... Preprocessing executables for a-1.0... Building a-1.0... [1 of 1] Compiling A ( A.hs, dist/build/A.o ) /usr/bin/ar: creating dist/build/libHSa-1.0.a [1 of 1] Compiling Main ( exec/Main.hs, dist/build/b/b-tmp/Main.o ) Linking dist/build/b/b ... $ make clean runghc Setup.hs clean cleaning... $ rm package.conf $ more `find . -type f ` > ../a.txt $ cat ../a.txt :::::::::::::: ./a.cabal :::::::::::::: Name: a Version: 1.0 Build-Depends: base Exposed-Modules: A Executable: b Main-Is: Main.hs Hs-Source-Dirs: exec ghc-options: -package-conf package.conf -package a :::::::::::::: ./Setup.hs :::::::::::::: -- Provide support for executables that link with the library defined -- within a package. The trick is to generate a package description -- that supports the linking phase. import Distribution.Simple import qualified Distribution.InstalledPackageInfo as I import Distribution.PackageDescription import Distribution.Setup import Distribution.Simple.LocalBuildInfo import System.IO import System.Exit -- The package description is generated using a post configuration hook. main = defaultMainWithHooks userHooks userHooks = defaultUserHooks { postConf = conf } -- The hook always runs the old actions last. old = postConf defaultUserHooks -- If the package defines no library, do nothing. conf :: Args -> ConfigFlags -> PackageDescription -> LocalBuildInfo -> IO ExitCode conf args flags pkg bld = case library pkg of Nothing -> old args flags pkg bld Just lib -> confLib lib args flags pkg bld -- Create package descriptions and then print it. confLib :: Library -> Args -> ConfigFlags -> PackageDescription -> LocalBuildInfo -> IO ExitCode confLib lib args flags pkg bld = do let hsLib = "HS" ++ showPackageId (package pkg) let info0 = I.emptyInstalledPackageInfo let info1 = info0 { I.package = package pkg, I.exposed = True, I.exposedModules = exposedModules lib, I.importDirs = [buildDir bld], I.libraryDirs = [buildDir bld], I.hsLibraries = [hsLib] } writeFile "package.conf" (show [info1]) old args flags pkg bld -- A clean hook should be written that deletes package.conf. :::::::::::::: ./Makefile :::::::::::::: SETUP = runghc Setup.hs CONFIGURE = $(SETUP) configure --ghc all: @if test ! -f .setup-config; \ then echo $(CONFIGURE); $(CONFIGURE); fi find dist -type f -perm /u+x -delete $(SETUP) build Makefile: @echo make $@ %: force $(SETUP) $@ .PHONY: all force :::::::::::::: ./A.hs :::::::::::::: module A where a :: Int a = 3 :::::::::::::: ./exec/Main.hs :::::::::::::: module Main (main) where import A main :: IO () main = print a