Skip to content

Relocatable packages #2255

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 33 commits into from
Dec 18, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
06a713e
Start support of relocatable builds
christiaanb Nov 21, 2014
6c9dce4
Enable support for relocatable libraries
christiaanb Nov 24, 2014
859a576
Enable registration of relocatable packages
christiaanb Nov 24, 2014
cf218c7
Fix library documentation paths
christiaanb Nov 24, 2014
a650e8d
Setup correct package registration paths for relocatable packages
christiaanb Nov 25, 2014
da41e21
Relocatable flag not passed to older versions of Cabal
christiaanb Nov 25, 2014
ae56bb3
Correctly set rpaths
christiaanb Nov 25, 2014
a132825
Correctly name flag restriction
christiaanb Nov 25, 2014
717cf35
Correctly calculate relative paths for relocatable packages
christiaanb Nov 26, 2014
aee97a5
Canonicalise rpath library paths
christiaanb Nov 26, 2014
d47cfcb
Add support for relocatable Paths module
christiaanb Nov 26, 2014
ea24975
Wobble whitespace
christiaanb Nov 26, 2014
beaefd2
Whitespace wobble in generated Paths module
christiaanb Nov 26, 2014
1ac8c31
Add support for executables depending on packaged libraries
christiaanb Nov 27, 2014
e2b81b0
Enable installation into empty user package database
christiaanb Nov 27, 2014
0e4e0eb
Wobble layout
christiaanb Nov 27, 2014
9440203
Extend checking whether a relocatable package is feasible
christiaanb Nov 27, 2014
67f608e
Generate absolute rpaths for libraries that are not prefix-relative
christiaanb Nov 28, 2014
b9c698e
Relocatable packages in the same database must share the same prefix
christiaanb Nov 28, 2014
da0a94e
Extend dy(ld)_library_path for relocatable 'cabal run'
christiaanb Dec 2, 2014
52f96e1
Add (DY)LD_LIBRARY_PATH for 'run' and 'test' commands
christiaanb Dec 3, 2014
bb273e7
Don't fail canonicalizePath when libdir doesn't exist
christiaanb Dec 3, 2014
fdcb0d9
Correctly determine location of internal library
christiaanb Dec 3, 2014
7e36443
Split RPath calculation from dependent library calculation
christiaanb Dec 3, 2014
17474f5
Add comment on canonicalizePathNoFail
christiaanb Dec 3, 2014
2dd28dc
Ensure we add overwrite existing (DY)LD_LIBRARY_PATH
christiaanb Dec 4, 2014
5ccaabf
wobble typo
christiaanb Dec 4, 2014
6df1151
Add support for linux
christiaanb Dec 4, 2014
649cffc
Add comment on RPATH support
christiaanb Dec 4, 2014
aa0168b
Cabal handles RPATHs on supported platform.
christiaanb Dec 4, 2014
dd0eaeb
Disable Cabal RPath handling on untested Operating Systems
christiaanb Dec 4, 2014
d53b4fb
Don't use 'lookupEnv' in 'addLibraryPaths'
christiaanb Dec 4, 2014
3f361de
Wobble comment
christiaanb Dec 4, 2014
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions Cabal/Distribution/InstalledPackageInfo.hs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ import Distribution.Text
import Text.PrettyPrint as Disp
import qualified Distribution.Compat.ReadP as Parse

import Data.Binary (Binary)
import Data.Binary (Binary)
import Data.Maybe (fromMaybe)
import GHC.Generics (Generic)

-- -----------------------------------------------------------------------------
Expand Down Expand Up @@ -104,7 +105,8 @@ data InstalledPackageInfo_ m
frameworkDirs :: [FilePath],
frameworks :: [String],
haddockInterfaces :: [FilePath],
haddockHTMLs :: [FilePath]
haddockHTMLs :: [FilePath],
pkgRoot :: Maybe FilePath
}
deriving (Generic, Read, Show)

Expand Down Expand Up @@ -155,7 +157,8 @@ emptyInstalledPackageInfo
frameworkDirs = [],
frameworks = [],
haddockInterfaces = [],
haddockHTMLs = []
haddockHTMLs = [],
pkgRoot = Nothing
}

noVersion :: Version
Expand Down Expand Up @@ -375,6 +378,9 @@ installedFieldDescrs = [
, listField "haddock-html"
showFilePath parseFilePathQ
haddockHTMLs (\xs pkg -> pkg{haddockHTMLs=xs})
, simpleField "pkgroot"
(const Disp.empty) parseFilePathQ
(fromMaybe "" . pkgRoot) (\xs pkg -> pkg{pkgRoot=Just xs})
]

deprecatedFieldDescrs :: [FieldDescr InstalledPackageInfo]
Expand Down
50 changes: 49 additions & 1 deletion Cabal/Distribution/Simple/Build/PathsModule.hs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ import Distribution.Simple.LocalBuildInfo
import Distribution.Simple.Setup ( CopyDest(NoCopyDest) )
import Distribution.Simple.BuildPaths
( autogenModuleName )
import Distribution.Simple.Utils
( shortRelativePath )
import Distribution.Text
( display )
import Distribution.Version
Expand Down Expand Up @@ -62,6 +64,11 @@ generate pkg_descr lbi =
"import Foreign\n"++
"import Foreign.C\n"

reloc_imports
| reloc =
"import System.Environment (getExecutablePath)\n"
| otherwise = ""

header =
pragmas++
"module " ++ display paths_modulename ++ " (\n"++
Expand All @@ -74,16 +81,36 @@ generate pkg_descr lbi =
"import qualified Control.Exception as Exception\n"++
"import Data.Version (Version(..))\n"++
"import System.Environment (getEnv)\n"++
reloc_imports ++
"import Prelude\n"++
"\n"++
"catchIO :: IO a -> (Exception.IOException -> IO a) -> IO a\n"++
"catchIO = Exception.catch\n" ++
"\n"++
"\nversion :: Version"++
"version :: Version"++
"\nversion = Version " ++ show branch ++ " " ++ show tags
where Version branch tags = packageVersion pkg_descr

body
| reloc =
"\n\nbindirrel :: FilePath\n" ++
"bindirrel = " ++ show flat_bindirreloc ++
"\n"++
"\ngetBinDir, getLibDir, getDataDir, getLibexecDir, getSysconfDir :: IO FilePath\n"++
"getBinDir = "++mkGetEnvOrReloc "bindir" flat_bindirreloc++"\n"++
"getLibDir = "++mkGetEnvOrReloc "libdir" flat_libdirreloc++"\n"++
"getDataDir = "++mkGetEnvOrReloc "datadir" flat_datadirreloc++"\n"++
"getLibexecDir = "++mkGetEnvOrReloc "libexecdir" flat_libexecdirreloc++"\n"++
"getSysconfDir = "++mkGetEnvOrReloc "sysconfdir" flat_sysconfdirreloc++"\n"++
"\n"++
"getDataFileName :: FilePath -> IO FilePath\n"++
"getDataFileName name = do\n"++
" dir <- getDataDir\n"++
" return (dir `joinFileName` name)\n"++
"\n"++
get_prefix_reloc_stuff++
"\n"++
filename_stuff
| absolute =
"\nbindir, libdir, datadir, libexecdir, sysconfdir :: FilePath\n"++
"\nbindir = " ++ show flat_bindir ++
Expand Down Expand Up @@ -146,9 +173,20 @@ generate pkg_descr lbi =
sysconfdir = flat_sysconfdirrel
} = prefixRelativeInstallDirs (packageId pkg_descr) lbi

flat_bindirreloc = shortRelativePath flat_prefix flat_bindir
flat_libdirreloc = shortRelativePath flat_prefix flat_libdir
flat_datadirreloc = shortRelativePath flat_prefix flat_datadir
flat_libexecdirreloc = shortRelativePath flat_prefix flat_libexecdir
flat_sysconfdirreloc = shortRelativePath flat_prefix flat_sysconfdir

mkGetDir _ (Just dirrel) = "getPrefixDirRel " ++ show dirrel
mkGetDir dir Nothing = "return " ++ show dir

mkGetEnvOrReloc var dirrel = "catchIO (getEnv \""++var'++"\")" ++
" (\\_ -> getPrefixDirReloc \"" ++ dirrel ++
"\")"
where var' = pkgPathEnvVar pkg_descr var

mkGetEnvOr var expr = "catchIO (getEnv \""++var'++"\")"++
" (\\_ -> "++expr++")"
where var' = pkgPathEnvVar pkg_descr var
Expand All @@ -159,6 +197,8 @@ generate pkg_descr lbi =
|| isNothing flat_bindirrel -- if the bin dir is an absolute path
|| not (supportsRelocatableProgs (compilerFlavor (compiler lbi)))

reloc = relocatable lbi

supportsRelocatableProgs GHC = case buildOS of
Windows -> True
_ -> False
Expand Down Expand Up @@ -188,6 +228,14 @@ pkgPathEnvVar pkg_descr var =
fixchar '-' = '_'
fixchar c = c

get_prefix_reloc_stuff :: String
get_prefix_reloc_stuff =
"getPrefixDirReloc :: FilePath -> IO FilePath\n"++
"getPrefixDirReloc dirRel = do\n"++
" exePath <- getExecutablePath\n"++
" let (bindir,_) = splitFileName exePath\n"++
" return ((bindir `minusFileName` bindirrel) `joinFileName` dirRel)\n"

get_prefix_win32 :: Arch -> String
get_prefix_win32 arch =
"getPrefixDirRel :: FilePath -> IO FilePath\n"++
Expand Down
83 changes: 79 additions & 4 deletions Cabal/Distribution/Simple/Configure.hs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}

-----------------------------------------------------------------------------
-- |
Expand Down Expand Up @@ -104,7 +105,7 @@ import Distribution.Simple.Utils
, writeFileAtomic
, withTempFile )
import Distribution.System
( OS(..), buildOS, Platform, buildPlatform )
( OS(..), buildOS, Platform (..), buildPlatform )
import Distribution.Version
( Version(..), anyVersion, orLaterVersion, withinRange, isAnyVersion )
import Distribution.Verbosity
Expand All @@ -126,9 +127,9 @@ import Data.Binary ( decodeOrFail, encode )
import Data.ByteString.Lazy (ByteString)
import qualified Data.ByteString.Lazy.Char8 as BS
import Data.List
( (\\), nub, partition, isPrefixOf, inits )
( (\\), nub, partition, isPrefixOf, inits, stripPrefix )
import Data.Maybe
( isNothing, catMaybes, fromMaybe )
( isNothing, catMaybes, fromMaybe, isJust )
import Data.Either
( partitionEithers )
import qualified Data.Set as Set
Expand Down Expand Up @@ -601,6 +602,11 @@ configure (pkg_descr0, pbi) cfg
GHC.ghcDynamic comp
_ -> False

reloc <-
if not (fromFlag $ configRelocatable cfg)
then return False
else return True

let lbi = LocalBuildInfo {
configFlags = cfg,
extraConfigArgs = [], -- Currently configure does not
Expand Down Expand Up @@ -631,9 +637,12 @@ configure (pkg_descr0, pbi) cfg
stripLibs = fromFlag $ configStripLibs cfg,
withPackageDB = packageDbs,
progPrefix = fromFlag $ configProgPrefix cfg,
progSuffix = fromFlag $ configProgSuffix cfg
progSuffix = fromFlag $ configProgSuffix cfg,
relocatable = reloc
}

when reloc (checkRelocatable verbosity pkg_descr lbi)

let dirs = absoluteInstallDirs pkg_descr lbi NoCopyDest
relative = prefixRelativeInstallDirs (packageId pkg_descr) lbi

Expand Down Expand Up @@ -1554,3 +1563,69 @@ checkPackageProblems verbosity gpkg pkg = do
if null errors
then mapM_ (warn verbosity) warnings
else die (intercalate "\n\n" errors)

-- | Preform checks if a relocatable build is allowed
checkRelocatable :: Verbosity
-> PackageDescription
-> LocalBuildInfo
-> IO ()
checkRelocatable verbosity pkg lbi
= sequence_ [ checkOS
, checkCompiler
, packagePrefixRelative
, depsPrefixRelative
]
where
-- Check if the OS support relocatable builds.
--
-- If you add new OS' to this list, and your OS supports dynamic libraries
-- and RPATH, make sure you add your OS to RPATH-support list of:
-- Distribution.Simple.GHC.getRPaths
checkOS
= unless (os `elem` [ OSX, Linux ])
$ die $ "Operating system: " ++ display os ++
", does not support relocatable builds"
where
(Platform _ os) = hostPlatform lbi

-- Check if the Compiler support relocatable builds
checkCompiler
= unless (compilerFlavor comp `elem` [ GHC ])
$ die $ "Compiler: " ++ show comp ++
", does not support relocatable builds"
where
comp = compiler lbi

-- Check if all the install dirs are relative to same prefix
packagePrefixRelative
= unless (relativeInstallDirs installDirs)
$ die $ "Installation directories are not prefix_relative:\n" ++
show installDirs
where
installDirs = absoluteInstallDirs pkg lbi NoCopyDest
p = prefix installDirs
relativeInstallDirs (InstallDirs {..}) =
all isJust
(fmap (stripPrefix p)
[ bindir, libdir, dynlibdir, libexecdir, includedir, datadir
, docdir, mandir, htmldir, haddockdir, sysconfdir] )

-- Check if the library dirs of the dependencies that are in the package
-- database to which the package is installed are relative to the
-- prefix of the package
depsPrefixRelative = do
pkgr <- GHC.pkgRoot verbosity lbi (last (withPackageDB lbi))
mapM_ (doCheck pkgr) ipkgs
where
doCheck pkgr ipkg
| maybe False (== pkgr) (Installed.pkgRoot ipkg)
= mapM_ (\l -> when (isNothing $ stripPrefix p l) (die (msg l)))
(Installed.libraryDirs ipkg)
| otherwise
= return ()
installDirs = absoluteInstallDirs pkg lbi NoCopyDest
p = prefix installDirs
ipkgs = PackageIndex.allPackages (installedPkgs lbi)
msg l = "Library directory of a dependency: " ++ show l ++
"\nis not relative to the installation prefix:\n" ++
show p
Loading