Description
I’m trying to port IHaskell to MacPorts. IHaskell uses hlint
. The issue is that both stack
and cabal
builds create binaries with an hlint_datadir
that points to the build directory in .stack
or .cabal-sandbox
, not the install directory with prefix, say, /opt/local/share/hlint
. After the build, these temporary build directories are discarded, and neither ihaskell
nor hlint
binaries work.
This issue has been opened at ndmitchell/hlint#699 and IHaskell/IHaskell#1061, and we all agree that it's an upstream issue with cabal
.
Before I get to the issue, please let me recap the background:
- The
cabal
build ofhlint
hardcodes the build path into the binaries because of well-known issue with the waycabal
handlesdata-files
. - This behavior breaks package managers like MacPorts and Brew because they cannot destroot properly.
- Brew has hacked around this by reluctantly modifying
prefix
. See idris: install using haskell-stack Homebrew/homebrew-core#1630 (comment). - I hacked around this by adding a temporary symbolic link to
prefix
(ihaskell binary fromstack install
not independent of .stack root, not destroot'd IHaskell/IHaskell#1061 (comment)), and have been discussing this approach with the MacPorts maintainers for packages like this one that have thedata-files
issue. There's also been reasonable reluctance and push-back against this practice, which is one reason we haven't mergedihaskell
yet. - To address these reasonable concerns, I found
hlint
author's @ndmitchell'sPaths_packagename.hs
solution to the issue of hardcodedcabal
data-files
in the binary, for which no uglyDESTDIR
hack is necessary. All that's required is to specify the path within a file calledPaths_packagename.hs
, which is normally automatically generated bycabal
with its own paths. See stack datadir option writes to datadir during build, breaking DESTDIR, unlike cabal commercialhaskell/stack#5026 - Side note:
pandoc
's author addressed this issue by using file-embed. See: Addstack build --prefix
option commercialhaskell/stack#848 (comment)
Now that we have a working fix to stack
and cabal
's data-files
issues, I'd like to use it for the MacPorts port. I haven't gotten this working with ihaskell
's more complicated build, including its dependencies like hlint
.
Would you please help figure out an hlint
(within ihaskell
) build recipe that produces a relocatable, properly prefix
-ed binary?
The src/Paths_*.hs
approach works for the ihaskell
binary, but not for hlint_datadir
in either the ihaskell
or hlint
binaries. I’ve tried many things:
- Put a copy of
Paths_hlint.hs
both insrc
andsrc/IHaskell
, without success. - Tried setting Cabal’s global
datadir
setting in a variety ways. - Adding the
ghc
option-ipathtoPaths_hlint
, several different ways. - Played around with
--enable-relocatable
, which I believe tickles thatreloc
guard in https://github.com/haskell/cabal/blob/master/Cabal/Distribution/Simple/Build/PathsModule.hs.
Nothing is working. ghc
always finds the Paths_hlint.hs
that Cabal generates, not the one I provided.
Would you all please indicate a Cabal build recipe that reads my version of Paths_hlint.hs
—not Cabal's autogen
version—so that we can get a properly DESTDIR
-ed and PREFIXED
-ed binary for a packaged install?
Cabal-based build recipe:
cabal update
cabal install cpphs happy
cabal sandbox init
cabal sandbox add-source . ./ghc-parser ./ipython-kernel
cabal install --only-dependencies
cabal configure --extra-lib-dir=/usr/lib
cabal install --extra-lib-dir=/usr/lib
Alternate stack
-based build recipe:
rm -fr ~/.stack ./.stack-work stack.yaml.lock
stack setup
stack build
Here's aPaths_hlint.hs
that should work. A successful build recipe will just stick this in a place where it will be found by ghc
before the Cabal’s autogen
Paths_*.hs file.
{- Cabal data-files hardcoded path in binary fix.
This file replaces the `Paths_hlint.hs` automatically created by Cabal.
See:
* https://github.com/commercialhaskell/stack/issues/848
* https://github.com/commercialhaskell/stack/issues/4857
* https://github.com/haskell/cabal/issues/462
* https://github.com/haskell/cabal/issues/3586
-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE NoRebindableSyntax #-}
{-# OPTIONS_GHC -fno-warn-missing-import-lists #-}
module Paths_hlint (
version,
getBinDir, getLibDir, getDynLibDir, getDataDir, getLibexecDir,
getDataFileName, getSysconfDir
) where
import qualified Control.Exception as Exception
import Data.Version (Version(..))
import System.Environment (getEnv)
import Prelude
#if defined(VERSION_base)
#if MIN_VERSION_base(4,0,0)
catchIO :: IO a -> (Exception.IOException -> IO a) -> IO a
#else
catchIO :: IO a -> (Exception.Exception -> IO a) -> IO a
#endif
#else
catchIO :: IO a -> (Exception.IOException -> IO a) -> IO a
#endif
catchIO = Exception.catch
version :: Version
version = Version [2,0,1] []
bindir, libdir, dynlibdir, datadir, libexecdir, sysconfdir :: FilePath
bindir = "/opt/local/bin"
libdir = "/opt/local/lib/ihaskell"
dynlibdir = "/opt/local/lib/ihaskell"
datadir = "/opt/local/share/ihaskell"
libexecdir = "/opt/local/lib/ihaskell"
sysconfdir = "/opt/local/etc"
getBinDir, getLibDir, getDynLibDir, getDataDir, getLibexecDir, getSysconfDir :: IO FilePath
getBinDir = catchIO (getEnv "hlint_bindir") (\_ -> return bindir)
getLibDir = catchIO (getEnv "hlint_libdir") (\_ -> return libdir)
getDynLibDir = catchIO (getEnv "hlint_dynlibdir") (\_ -> return dynlibdir)
getDataDir = catchIO (getEnv "hlint_datadir") (\_ -> return datadir)
getLibexecDir = catchIO (getEnv "hlint_libexecdir") (\_ -> return libexecdir)
getSysconfDir = catchIO (getEnv "hlint_sysconfdir") (\_ -> return sysconfdir)
getDataFileName :: FilePath -> IO FilePath
getDataFileName name = do
dir <- getDataDir
return (dir ++ "/" ++ name)