diff --git a/Cabal/Distribution/Make.hs b/Cabal/Distribution/Make.hs index 63467c02a91..50491ca2a05 100644 --- a/Cabal/Distribution/Make.hs +++ b/Cabal/Distribution/Make.hs @@ -146,6 +146,8 @@ copyAction flags args = do let destArgs = case fromFlag $ copyDest flags of NoCopyDest -> ["install"] CopyTo path -> ["copy", "destdir=" ++ path] + CopyToDb _ -> error "CopyToDb not supported via Make" + rawSystemExit (fromFlag $ copyVerbosity flags) "make" destArgs installAction :: InstallFlags -> [String] -> IO () diff --git a/Cabal/Distribution/Simple.hs b/Cabal/Distribution/Simple.hs index cb874f42c62..016f4b4cc53 100644 --- a/Cabal/Distribution/Simple.hs +++ b/Cabal/Distribution/Simple.hs @@ -742,7 +742,7 @@ defaultInstallHook :: PackageDescription -> LocalBuildInfo defaultInstallHook pkg_descr localbuildinfo _ flags = do let copyFlags = defaultCopyFlags { copyDistPref = installDistPref flags, - copyDest = toFlag NoCopyDest, + copyDest = installDest flags, copyVerbosity = installVerbosity flags } install pkg_descr localbuildinfo copyFlags diff --git a/Cabal/Distribution/Simple/Configure.hs b/Cabal/Distribution/Simple/Configure.hs index c0210c44ae2..d23b955b1a3 100644 --- a/Cabal/Distribution/Simple/Configure.hs +++ b/Cabal/Distribution/Simple/Configure.hs @@ -747,9 +747,25 @@ configure (pkg_descr0, pbi) cfg = do let dirs = absoluteInstallDirs pkg_descr lbi NoCopyDest relative = prefixRelativeInstallDirs (packageId pkg_descr) lbi - unless (isAbsolute (prefix dirs)) $ die' verbosity $ + -- PKGROOT: allowing ${pkgroot} to be passed as --prefix to + -- cabal configure, is only a hidden option. It allows packages + -- to be relocatable with their package database. This however + -- breaks when the Paths_* or other includes are used that + -- contain hard coded paths. This is still an open TODO. + -- + -- Allowing ${pkgroot} here, however requires less custom hooks + -- in scripts that *really* want ${pkgroot}. See haskell/cabal/#4872 + unless (isAbsolute (prefix dirs) + || "${pkgroot}" `isPrefixOf` prefix dirs) $ die' verbosity $ "expected an absolute directory name for --prefix: " ++ prefix dirs + when ("${pkgroot}" `isPrefixOf` prefix dirs) $ + warn verbosity $ "Using ${pkgroot} in prefix " ++ prefix dirs + ++ " will not work if you rely on the Path_* module " + ++ " or other hard coded paths. Cabal does not yet " + ++ " support fully relocatable builds! " + ++ " See #462 #2302 #2994 #3305 #3473 #3586 #3909 #4097 #4291 #4872" + info verbosity $ "Using " ++ display currentCabalId ++ " compiled by " ++ display currentCompilerId info verbosity $ "Using compiler: " ++ showCompilerId comp diff --git a/Cabal/Distribution/Simple/InstallDirs.hs b/Cabal/Distribution/Simple/InstallDirs.hs index f74bc14d6cd..98e331003c8 100644 --- a/Cabal/Distribution/Simple/InstallDirs.hs +++ b/Cabal/Distribution/Simple/InstallDirs.hs @@ -59,7 +59,8 @@ import Distribution.Text import System.Directory (getAppUserDataDirectory) import System.FilePath ( (), isPathSeparator - , pathSeparator, dropDrive ) + , pathSeparator, dropDrive + , takeDirectory ) #ifdef mingw32_HOST_OS import qualified Prelude @@ -287,19 +288,29 @@ absoluteInstallDirs :: PackageIdentifier absoluteInstallDirs pkgId libname compilerId copydest platform dirs = (case copydest of CopyTo destdir -> fmap ((destdir ) . dropDrive) + CopyToDb dbdir -> fmap (substPrefix "${pkgroot}" (takeDirectory dbdir)) _ -> id) . appendSubdirs () . fmap fromPathTemplate $ substituteInstallDirTemplates env dirs where env = initialPathTemplateEnv pkgId libname compilerId platform + substPrefix pre root path + | pre `isPrefixOf` path = root ++ drop (length pre) path + | otherwise = path -- |The location prefix for the /copy/ command. data CopyDest = NoCopyDest | CopyTo FilePath - deriving (Eq, Show) + | CopyToDb FilePath + -- ^ when using the ${pkgroot} as prefix. The CopyToDb will + -- adjust the paths to be relative to the provided package + -- database when copying / installing. + deriving (Eq, Show, Generic) + +instance Binary CopyDest -- | Check which of the paths are relative to the installation $prefix. -- diff --git a/Cabal/Distribution/Simple/Setup.hs b/Cabal/Distribution/Simple/Setup.hs index 6b016c8d543..eb5fe50605a 100644 --- a/Cabal/Distribution/Simple/Setup.hs +++ b/Cabal/Distribution/Simple/Setup.hs @@ -950,19 +950,35 @@ copyCommand = CommandUI ] , commandDefaultFlags = defaultCopyFlags , commandOptions = \showOrParseArgs -> - [optionVerbosity copyVerbosity (\v flags -> flags { copyVerbosity = v }) + (filter ((`notElem` ["target-package-db"]) + . optionName)) $ copyOptions showOrParseArgs +} - ,optionDistPref - copyDistPref (\d flags -> flags { copyDistPref = d }) - showOrParseArgs +copyOptions :: ShowOrParseArgs -> [OptionField CopyFlags] +copyOptions showOrParseArgs = + [optionVerbosity copyVerbosity (\v flags -> flags { copyVerbosity = v }) - ,option "" ["destdir"] - "directory to copy files to, prepended to installation directories" - copyDest (\v flags -> flags { copyDest = v }) - (reqArg "DIR" (succeedReadE (Flag . CopyTo)) - (\f -> case f of Flag (CopyTo p) -> [p]; _ -> [])) - ] - } + ,optionDistPref + copyDistPref (\d flags -> flags { copyDistPref = d }) + showOrParseArgs + + ,option "" ["destdir"] + "directory to copy files to, prepended to installation directories" + copyDest (\v flags -> case copyDest flags of + Flag (CopyToDb _) -> error "Use either 'destdir' or 'target-package-db'." + _ -> flags { copyDest = v }) + (reqArg "DIR" (succeedReadE (Flag . CopyTo)) + (\f -> case f of Flag (CopyTo p) -> [p]; _ -> [])) + + ,option "" ["target-package-db"] + "package database to copy files into. Required when using ${pkgroot} prefix." + copyDest (\v flags -> case copyDest flags of + NoFlag -> flags { copyDest = v } + Flag NoCopyDest -> flags { copyDest = v } + _ -> error "Use either 'destdir' or 'target-package-db'.") + (reqArg "DATABASE" (succeedReadE (Flag . CopyToDb)) + (\f -> case f of Flag (CopyToDb p) -> [p]; _ -> [])) + ] emptyCopyFlags :: CopyFlags emptyCopyFlags = mempty @@ -981,6 +997,7 @@ instance Semigroup CopyFlags where -- | Flags to @install@: (package db, verbosity) data InstallFlags = InstallFlags { installPackageDB :: Flag PackageDB, + installDest :: Flag CopyDest, installDistPref :: Flag FilePath, installUseWrapper :: Flag Bool, installInPlace :: Flag Bool, @@ -991,6 +1008,7 @@ data InstallFlags = InstallFlags { defaultInstallFlags :: InstallFlags defaultInstallFlags = InstallFlags { installPackageDB = NoFlag, + installDest = Flag NoCopyDest, installDistPref = NoFlag, installUseWrapper = Flag False, installInPlace = Flag False, @@ -1011,30 +1029,40 @@ installCommand = CommandUI "Usage: " ++ pname ++ " install [FLAGS]\n" , commandDefaultFlags = defaultInstallFlags , commandOptions = \showOrParseArgs -> - [optionVerbosity installVerbosity (\v flags -> flags { installVerbosity = v }) - ,optionDistPref - installDistPref (\d flags -> flags { installDistPref = d }) - showOrParseArgs - - ,option "" ["inplace"] - "install the package in the install subdirectory of the dist prefix, so it can be used without being installed" - installInPlace (\v flags -> flags { installInPlace = v }) - trueArg - - ,option "" ["shell-wrappers"] - "using shell script wrappers around executables" - installUseWrapper (\v flags -> flags { installUseWrapper = v }) - (boolOpt [] []) - - ,option "" ["package-db"] "" - installPackageDB (\v flags -> flags { installPackageDB = v }) - (choiceOpt [ (Flag UserPackageDB, ([],["user"]), - "upon configuration register this package in the user's local package database") - , (Flag GlobalPackageDB, ([],["global"]), - "(default) upon configuration register this package in the system-wide package database")]) - ] + (filter ((`notElem` ["target-package-db"]) + . optionName)) $ installOptions showOrParseArgs } +installOptions :: ShowOrParseArgs -> [OptionField InstallFlags] +installOptions showOrParseArgs = + [optionVerbosity installVerbosity (\v flags -> flags { installVerbosity = v }) + ,optionDistPref + installDistPref (\d flags -> flags { installDistPref = d }) + showOrParseArgs + + ,option "" ["inplace"] + "install the package in the install subdirectory of the dist prefix, so it can be used without being installed" + installInPlace (\v flags -> flags { installInPlace = v }) + trueArg + + ,option "" ["shell-wrappers"] + "using shell script wrappers around executables" + installUseWrapper (\v flags -> flags { installUseWrapper = v }) + (boolOpt [] []) + + ,option "" ["package-db"] "" + installPackageDB (\v flags -> flags { installPackageDB = v }) + (choiceOpt [ (Flag UserPackageDB, ([],["user"]), + "upon configuration register this package in the user's local package database") + , (Flag GlobalPackageDB, ([],["global"]), + "(default) upon configuration register this package in the system-wide package database")]) + ,option "" ["target-package-db"] + "package database to install into. Required when using ${pkgroot} prefix." + installDest (\v flags -> flags { installDest = v }) + (reqArg "DATABASE" (succeedReadE (Flag . CopyToDb)) + (\f -> case f of Flag (CopyToDb p) -> [p]; _ -> [])) + ] + emptyInstallFlags :: InstallFlags emptyInstallFlags = mempty diff --git a/cabal-install/Distribution/Client/Config.hs b/cabal-install/Distribution/Client/Config.hs index 257bd7913fe..e17420a20dc 100644 --- a/cabal-install/Distribution/Client/Config.hs +++ b/cabal-install/Distribution/Client/Config.hs @@ -245,6 +245,7 @@ instance Semigroup SavedConfig where installDocumentation = combine installDocumentation, installHaddockIndex = combine installHaddockIndex, installDryRun = combine installDryRun, + installDest = combine installDest, installMaxBackjumps = combine installMaxBackjumps, installReorderGoals = combine installReorderGoals, installCountConflicts = combine installCountConflicts, diff --git a/cabal-install/Distribution/Client/ProjectConfig/Legacy.hs b/cabal-install/Distribution/Client/ProjectConfig/Legacy.hs index 2811a4343a5..1dc7205c3f3 100644 --- a/cabal-install/Distribution/Client/ProjectConfig/Legacy.hs +++ b/cabal-install/Distribution/Client/ProjectConfig/Legacy.hs @@ -41,6 +41,7 @@ import Distribution.PackageDescription.Parse ( sourceRepoFieldDescrs ) import Distribution.Simple.Compiler ( OptimisationLevel(..), DebugInfoLevel(..) ) +import Distribution.Simple.InstallDirs ( CopyDest (NoCopyDest) ) import Distribution.Simple.Setup ( Flag(Flag), toFlag, fromFlagOrDefault , ConfigFlags(..), configureOptions @@ -514,6 +515,7 @@ convertToLegacySharedConfig installFlags = InstallFlags { installDocumentation = mempty, installHaddockIndex = projectConfigHaddockIndex, + installDest = Flag NoCopyDest, installDryRun = projectConfigDryRun, installReinstall = mempty, --projectConfigReinstall, installAvoidReinstalls = mempty, --projectConfigAvoidReinstalls, diff --git a/cabal-install/Distribution/Client/Setup.hs b/cabal-install/Distribution/Client/Setup.hs index 9890b74003a..0dff9aff864 100644 --- a/cabal-install/Distribution/Client/Setup.hs +++ b/cabal-install/Distribution/Client/Setup.hs @@ -1486,6 +1486,7 @@ instance Semigroup InfoFlags where data InstallFlags = InstallFlags { installDocumentation :: Flag Bool, installHaddockIndex :: Flag PathTemplate, + installDest :: Flag Cabal.CopyDest, installDryRun :: Flag Bool, installMaxBackjumps :: Flag Int, installReorderGoals :: Flag ReorderGoals, @@ -1530,6 +1531,7 @@ defaultInstallFlags :: InstallFlags defaultInstallFlags = InstallFlags { installDocumentation = Flag False, installHaddockIndex = Flag docIndexFile, + installDest = Flag Cabal.NoCopyDest, installDryRun = Flag False, installMaxBackjumps = Flag defaultMaxBackjumps, installReorderGoals = Flag (ReorderGoals False), @@ -1628,12 +1630,20 @@ installCommand = CommandUI { commandDefaultFlags = (mempty, mempty, mempty, mempty), commandOptions = \showOrParseArgs -> liftOptions get1 set1 + -- Note: [Hidden Flags] + -- hide "constraint", "dependency", and + -- "exact-configuration" from the configure options. (filter ((`notElem` ["constraint", "dependency" , "exact-configuration"]) . optionName) $ configureOptions showOrParseArgs) ++ liftOptions get2 set2 (configureExOptions showOrParseArgs ConstraintSourceCommandlineFlag) - ++ liftOptions get3 set3 (installOptions showOrParseArgs) + ++ liftOptions get3 set3 + -- hide "target-package-db" flag from the + -- install options. + (filter ((`notElem` ["target-package-db"]) + . optionName) $ + installOptions showOrParseArgs) ++ liftOptions get4 set4 (haddockOptions showOrParseArgs) } where @@ -1678,6 +1688,12 @@ installOptions showOrParseArgs = "Do not install anything, only print what would be installed." installDryRun (\v flags -> flags { installDryRun = v }) trueArg + + , option "" ["target-package-db"] + "package database to install into. Required when using ${pkgroot} prefix." + installDest (\v flags -> flags { installDest = v }) + (reqArg "DATABASE" (succeedReadE (Flag . Cabal.CopyToDb)) + (\f -> case f of Flag (Cabal.CopyToDb p) -> [p]; _ -> [])) ] ++ optionSolverFlags showOrParseArgs