------------------------------------------------------------------------------- |-- Module : Distribution.Simple.Configure-- Copyright : Isaac Jones 2003-2005---- Maintainer : cabal-devel@haskell.org-- Portability : portable---- This deals with the /configure/ phase. It provides the 'configure' action-- which is given the package description and configure flags. It then tries-- to: configure the compiler; resolves any conditionals in the package-- description; resolve the package dependencies; check if all the extensions-- used by this package are supported by the compiler; check that all the build-- tools are available (including version checks if appropriate); checks for-- any required @pkg-config@ packages (updating the 'BuildInfo' with the-- results)---- Then based on all this it saves the info in the 'LocalBuildInfo' and writes-- it out to the @dist\/setup-config@ file. It also displays various details to-- the user, the amount of information displayed depending on the verbosity-- level.{- All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Isaac Jones nor the names of other
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -}moduleDistribution.Simple.Configure(configure,writePersistBuildConfig,getPersistBuildConfig,checkPersistBuildConfigOutdated,maybeGetPersistBuildConfig,localBuildInfoFile,getInstalledPackages,configCompiler,configCompilerAux,ccLdOptionsBuildInfo,tryGetConfigStateFile,checkForeignDeps,interpretPackageDbFlags,)whereimportDistribution.Simple.Compiler(CompilerFlavor(..),Compiler(compilerId),compilerFlavor,compilerVersion,showCompilerId,unsupportedLanguages,unsupportedExtensions,PackageDB(..),PackageDBStack)importDistribution.Package(PackageName(PackageName),PackageIdentifier(..),PackageId,packageName,packageVersion,Package(..),Dependency(Dependency),simplifyDependency,InstalledPackageId(..))importDistribution.InstalledPackageInfoasInstalled(InstalledPackageInfo,InstalledPackageInfo_(..),emptyInstalledPackageInfo)importqualifiedDistribution.Simple.PackageIndexasPackageIndeximportDistribution.Simple.PackageIndex(PackageIndex)importDistribution.PackageDescriptionasPD(PackageDescription(..),specVersion,GenericPackageDescription(..),Library(..),hasLibs,Executable(..),BuildInfo(..),allExtensions,HookedBuildInfo,updatePackageDescription,allBuildInfo,FlagName(..),TestSuite(..),Benchmark(..))importDistribution.PackageDescription.Configuration(finalizePackageDescription,mapTreeData)importDistribution.PackageDescription.Check(PackageCheck(..),checkPackage,checkPackageFiles)importDistribution.Simple.Hpc(enableCoverage)importDistribution.Simple.Program(Program(..),ProgramLocation(..),ConfiguredProgram(..),ProgramConfiguration,defaultProgramConfiguration,configureAllKnownPrograms,knownPrograms,lookupKnownProgram,userSpecifyArgss,userSpecifyPaths,requireProgram,requireProgramVersion,pkgConfigProgram,gccProgram,rawSystemProgramStdoutConf)importDistribution.Simple.Setup(ConfigFlags(..),CopyDest(..),fromFlag,fromFlagOrDefault,flagToMaybe)importDistribution.Simple.InstallDirs(InstallDirs(..),defaultInstallDirs,combineInstallDirs)importDistribution.Simple.LocalBuildInfo(LocalBuildInfo(..),ComponentLocalBuildInfo(..),absoluteInstallDirs,prefixRelativeInstallDirs,inplacePackageId,allComponentsBy,Component(..),foldComponent,ComponentName(..))importDistribution.Simple.BuildPaths(autogenModulesDir)importDistribution.Simple.Utils(die,warn,info,setupMessage,createDirectoryIfMissingVerbose,intercalate,cabalVersion,withFileContents,writeFileAtomic,withTempFile)importDistribution.System(OS(..),buildOS,Arch(..),buildArch,buildPlatform)importDistribution.Version(Version(..),anyVersion,orLaterVersion,withinRange,isAnyVersion)importDistribution.Verbosity(Verbosity,lessVerbose)importqualifiedDistribution.Simple.GHCasGHCimportqualifiedDistribution.Simple.JHCasJHCimportqualifiedDistribution.Simple.LHCasLHCimportqualifiedDistribution.Simple.NHCasNHCimportqualifiedDistribution.Simple.HugsasHugsimportqualifiedDistribution.Simple.UHCasUHCimportControl.Monad(when,unless,foldM,filterM,forM)importData.List(nub,partition,isPrefixOf,inits,find)importData.Maybe(isNothing,catMaybes,mapMaybe)importData.Monoid(Monoid(..))importData.Graph(SCC(..),graphFromEdges,transposeG,vertices,stronglyConnCompR)importSystem.Directory(doesFileExist,getModificationTime,createDirectoryIfMissing,getTemporaryDirectory)importSystem.Exit(ExitCode(..),exitWith)importSystem.FilePath((</>),isAbsolute)importqualifiedSystem.Info(compilerName,compilerVersion)importSystem.IO(hPutStrLn,stderr,hClose)importDistribution.Text(Text(disp),display,simpleParse)importText.PrettyPrint(comma,punctuate,render,nest,sep)importDistribution.Compat.Exception(catchExit,catchIO)tryGetConfigStateFile::(Reada)=>FilePath->IO(EitherStringa)tryGetConfigStateFilefilename=doexists<-doesFileExistfilenameifnotexiststhenreturn(Leftmissing)elsewithFileContentsfilename$\str->caselinesstrof[headder,rest]->casecheckHeaderheadderofJustmsg->return(Leftmsg)Nothing->casereadsrestof[(bi,_)]->return(Rightbi)_->return(LeftcantParse)_->return(LeftcantParse)wherecheckHeader::String->MaybeStringcheckHeaderheader=caseparseHeaderheaderofJust(cabalId,compId)|cabalId==currentCabalId->Nothing|otherwise->Just(badVersioncabalIdcompId)Nothing->JustcantParsemissing="Run the 'configure' command first."cantParse="Saved package config file seems to be corrupt. "++"Try re-running the 'configure' command."badVersioncabalIdcompId="You need to re-run the 'configure' command. "++"The version of Cabal being used has changed (was "++displaycabalId++", now "++displaycurrentCabalId++")."++badcompilercompIdbadcompilercompId|compId==currentCompilerId=""|otherwise=" Additionally the compiler is different (was "++displaycompId++", now "++displaycurrentCompilerId++") which is probably the cause of the problem."-- internal functiontryGetPersistBuildConfig::FilePath->IO(EitherStringLocalBuildInfo)tryGetPersistBuildConfigdistPref=tryGetConfigStateFile(localBuildInfoFiledistPref)-- |Read the 'localBuildInfoFile'. Error if it doesn't exist. Also-- fail if the file containing LocalBuildInfo is older than the .cabal-- file, indicating that a re-configure is required.getPersistBuildConfig::FilePath->IOLocalBuildInfogetPersistBuildConfigdistPref=dolbi<-tryGetPersistBuildConfigdistPrefeitherdiereturnlbi-- |Try to read the 'localBuildInfoFile'.maybeGetPersistBuildConfig::FilePath->IO(MaybeLocalBuildInfo)maybeGetPersistBuildConfigdistPref=dolbi<-tryGetPersistBuildConfigdistPrefreturn$either(constNothing)Justlbi-- |After running configure, output the 'LocalBuildInfo' to the-- 'localBuildInfoFile'.writePersistBuildConfig::FilePath->LocalBuildInfo->IO()writePersistBuildConfigdistPreflbi=docreateDirectoryIfMissingFalsedistPrefwriteFileAtomic(localBuildInfoFiledistPref)(showHeaderpkgid++'\n':showlbi)wherepkgid=packageId(localPkgDescrlbi)showHeader::PackageIdentifier->StringshowHeaderpkgid="Saved package config for "++displaypkgid++" written by "++displaycurrentCabalId++" using "++displaycurrentCompilerIdwherecurrentCabalId::PackageIdentifiercurrentCabalId=PackageIdentifier(PackageName"Cabal")cabalVersioncurrentCompilerId::PackageIdentifiercurrentCompilerId=PackageIdentifier(PackageNameSystem.Info.compilerName)System.Info.compilerVersionparseHeader::String->Maybe(PackageIdentifier,PackageIdentifier)parseHeaderheader=casewordsheaderof["Saved","package","config","for",pkgid,"written","by",cabalid,"using",compilerid]->case(simpleParsepkgid::MaybePackageIdentifier,simpleParsecabalid,simpleParsecompilerid)of(Just_,Justcabalid',Justcompilerid')->Just(cabalid',compilerid')_->Nothing_->Nothing-- |Check that localBuildInfoFile is up-to-date with respect to the-- .cabal file.checkPersistBuildConfigOutdated::FilePath->FilePath->IOBoolcheckPersistBuildConfigOutdateddistPrefpkg_descr_file=dot0<-getModificationTimepkg_descr_filet1<-getModificationTime$localBuildInfoFiledistPrefreturn(t0>t1)-- |@dist\/setup-config@localBuildInfoFile::FilePath->FilePathlocalBuildInfoFiledistPref=distPref</>"setup-config"-- ------------------------------------------------------------------------------- * Configuration-- ------------------------------------------------------------------------------- |Perform the \"@.\/setup configure@\" action.-- Returns the @.setup-config@ file.configure::(GenericPackageDescription,HookedBuildInfo)->ConfigFlags->IOLocalBuildInfoconfigure(pkg_descr0,pbi)cfg=doletdistPref=fromFlag(configDistPrefcfg)buildDir'=distPref</>"build"verbosity=fromFlag(configVerbositycfg)setupMessageverbosity"Configuring"(packageIdpkg_descr0)createDirectoryIfMissingVerbose(lessVerboseverbosity)TruedistPrefletprogramsConfig=userSpecifyArgss(configProgramArgscfg).userSpecifyPaths(configProgramPathscfg)$configProgramscfguserInstall=fromFlag(configUserInstallcfg)packageDbs=interpretPackageDbFlagsuserInstall(configPackageDBscfg)-- detect compiler(comp,programsConfig')<-configCompiler(flagToMaybe$configHcFlavorcfg)(flagToMaybe$configHcPathcfg)(flagToMaybe$configHcPkgcfg)programsConfig(lessVerboseverbosity)letversion=compilerVersioncompflavor=compilerFlavorcomp-- Create a PackageIndex that makes *any libraries that might be*-- defined internally to this package look like installed packages, in-- case an executable should refer to any of them as dependencies.---- It must be *any libraries that might be* defined rather than the-- actual definitions, because these depend on conditionals in the .cabal-- file, and we haven't resolved them yet. finalizePackageDescription-- does the resolution of conditionals, and it takes internalPackageSet-- as part of its input.---- Currently a package can define no more than one library (which has-- the same name as the package) but we could extend this later.-- If we later allowed private internal libraries, then here we would-- need to pre-scan the conditional data to make a list of all private-- libraries that could possibly be defined by the .cabal file.letpid=packageIdpkg_descr0internalPackage=emptyInstalledPackageInfo{--TODO: should use a per-compiler method to map the source-- package ID into an installed package id we can use-- for the internal package set. The open-codes use of-- InstalledPackageId . display here is a hack.Installed.installedPackageId=InstalledPackageId$display$pid,Installed.sourcePackageId=pid}internalPackageSet=PackageIndex.fromList[internalPackage]installedPackageSet<-getInstalledPackages(lessVerboseverbosity)comppackageDbsprogramsConfig'let-- Constraint test function for the solverdependencySatisfiable=not.null.PackageIndex.lookupDependencypkgs'wherepkgs'=PackageIndex.insertinternalPackageinstalledPackageSetenableTestt=t{testEnabled=fromFlag(configTestscfg)}flaggedTests=map(\(n,t)->(n,mapTreeDataenableTestt))(condTestSuitespkg_descr0)enableBenchmarkbm=bm{benchmarkEnabled=fromFlag(configBenchmarkscfg)}flaggedBenchmarks=map(\(n,bm)->(n,mapTreeDataenableBenchmarkbm))(condBenchmarkspkg_descr0)pkg_descr0''=pkg_descr0{condTestSuites=flaggedTests,condBenchmarks=flaggedBenchmarks}(pkg_descr0',flags)<-casefinalizePackageDescription(configConfigurationsFlagscfg)dependencySatisfiableDistribution.System.buildPlatform(compilerIdcomp)(configConstraintscfg)pkg_descr0''ofRightr->returnrLeftmissing->die$"At least the following dependencies are missing:\n"++(render.nest4.sep.punctuatecomma.map(disp.simplifyDependency)$missing)-- add extra include/lib dirs as specified in cfg-- we do it here so that those get checked tooletpkg_descr=enableCoverage(fromFlag(configLibCoveragecfg))distPref$addExtraIncludeLibDirspkg_descr0'when(not(nullflags))$infoverbosity$"Flags chosen: "++intercalate", "[name++"="++displayvalue|(FlagNamename,value)<-flags]checkPackageProblemsverbositypkg_descr0(updatePackageDescriptionpbipkg_descr)letselectDependencies=(\xs->([x|Leftx<-xs],[x|Rightx<-xs])).map(selectDependencyinternalPackageSetinstalledPackageSet)(failedDeps,allPkgDeps)=selectDependencies(buildDependspkg_descr)internalPkgDeps=[pkgid|InternalDependency_pkgid<-allPkgDeps]externalPkgDeps=[pkg|ExternalDependency_pkg<-allPkgDeps]when(not(nullinternalPkgDeps)&&not(newPackageDepsBehaviourpkg_descr))$die$"The field 'build-depends: "++intercalate", "(map(display.packageName)internalPkgDeps)++"' refers to a library which is defined within the same "++"package. To use this feature the package must specify at "++"least 'cabal-version: >= 1.8'."reportFailedDependenciesfailedDepsreportSelectedDependenciesverbosityallPkgDepspackageDependsIndex<-casePackageIndex.dependencyClosureinstalledPackageSet(mapInstalled.installedPackageIdexternalPkgDeps)ofLeftpackageDependsIndex->returnpackageDependsIndexRightbroken->die$"The following installed packages are broken because other"++" packages they depend on are missing. These broken "++"packages must be rebuilt before they can be used.\n"++unlines["package "++display(packageIdpkg)++" is broken due to missing package "++intercalate", "(mapdisplaydeps)|(pkg,deps)<-broken]letpseudoTopPkg=emptyInstalledPackageInfo{Installed.installedPackageId=InstalledPackageId(display(packageIdpkg_descr)),Installed.sourcePackageId=packageIdpkg_descr,Installed.depends=mapInstalled.installedPackageIdexternalPkgDeps}casePackageIndex.dependencyInconsistencies.PackageIndex.insertpseudoTopPkg$packageDependsIndexof[]->return()inconsistencies->warnverbosity$"This package indirectly depends on multiple versions of the same "++"package. This is highly likely to cause a compile failure.\n"++unlines["package "++displaypkg++" requires "++display(PackageIdentifiernamever)|(name,uses)<-inconsistencies,(pkg,ver)<-uses]-- installation directoriesdefaultDirs<-defaultInstallDirsflavoruserInstall(hasLibspkg_descr)letinstallDirs=combineInstallDirsfromFlagOrDefaultdefaultDirs(configInstallDirscfg)-- check languages and extensionsletlanglist=nub$catMaybes$mapdefaultLanguage(allBuildInfopkg_descr)letlangs=unsupportedLanguagescomplanglistwhen(not(nulllangs))$die$"The package "++display(packageIdpkg_descr0)++" requires the following languages which are not "++"supported by "++display(compilerIdcomp)++": "++intercalate", "(mapdisplaylangs)letextlist=nub$concatMapallExtensions(allBuildInfopkg_descr)letexts=unsupportedExtensionscompextlistwhen(not(nullexts))$die$"The package "++display(packageIdpkg_descr0)++" requires the following language extensions which are not "++"supported by "++display(compilerIdcomp)++": "++intercalate", "(mapdisplayexts)-- configured known/required programs & external build tools-- exclude build-tool deps on "internal" exes in the same packageletrequiredBuildTools=[buildTool|letexeNames=mapexeName(executablespkg_descr),bi<-allBuildInfopkg_descr,buildTool@(Dependency(PackageNametoolName)reqVer)<-buildToolsbi,letisInternal=toolName`elem`exeNames-- we assume all internal build-tools are-- versioned with the package:&&packageVersionpkg_descr`withinRange`reqVer,notisInternal]programsConfig''<-configureAllKnownPrograms(lessVerboseverbosity)programsConfig'>>=configureRequiredProgramsverbosityrequiredBuildTools(pkg_descr',programsConfig''')<-configurePkgconfigPackagesverbositypkg_descrprogramsConfig''split_objs<-ifnot(fromFlag$configSplitObjscfg)thenreturnFalseelsecaseflavorofGHC|version>=Version[6,5][]->returnTrue_->dowarnverbosity("this compiler does not support "++"--enable-split-objs; ignoring")returnFalse-- The allPkgDeps contains all the package deps for the whole package-- but we need to select the subset for this specific component.-- we just take the subset for the package names this component-- needs. Note, this only works because we cannot yet depend on two-- versions of the same package.letconfigLiblib=configComponent(libBuildInfolib)configExeexe=(exeNameexe,configComponent(buildInfoexe))configTesttest=(testNametest,configComponent(testBuildInfotest))configBenchmarkbm=(benchmarkNamebm,configComponent(benchmarkBuildInfobm))configComponentbi=ComponentLocalBuildInfo{componentPackageDeps=ifnewPackageDepsBehaviourpkg_descr'then[(installedPackageIdpkg,packageIdpkg)|pkg<-selectSubsetbiexternalPkgDeps]++[(inplacePackageIdpkgid,pkgid)|pkgid<-selectSubsetbiinternalPkgDeps]else[(installedPackageIdpkg,packageIdpkg)|pkg<-externalPkgDeps]}selectSubset::Packagepkg=>BuildInfo->[pkg]->[pkg]selectSubsetbipkgs=[pkg|pkg<-pkgs,packageNamepkg`elem`names]wherenames=[name|Dependencyname_<-targetBuildDependsbi]-- Obtains the intrapackage dependencies for the given componentletipDepscomponent=mapMaybeexeDepToComp(buildToolsbi)++mapMaybelibDepToComp(targetBuildDependsbi)wherebi=foldComponentlibBuildInfobuildInfotestBuildInfobenchmarkBuildInfocomponentexeDepToComp(Dependency(PackageNamename)_)=CExe`fmap`find((==)name.exeName)(executablespkg_descr')libDepToComp(Dependencypn_)|pn`elem`mappackageNameinternalPkgDeps=CLib`fmap`librarypkg_descr'libDepToComp_=Nothingletsccs=(stronglyConnCompR.maplkup.vertices.transposeG)gwhere(g,lkup,_)=graphFromEdges$allComponentsBypkg_descr'$\c->(c,keyc,mapkey(ipDepsc))key=foldComponent(const"library")exeNametestNamebenchmarkName-- check for cycles in the dependency graphbuildOrder<-forMsccs$\scc->casesccofAcyclicSCC(c,_,_)->return(foldComponent(constCLibName)(CExeName.exeName)(CTestName.testName)(CBenchName.benchmarkName)c)CyclicSCCvs->die$"Found cycle in intrapackage dependency graph:\n "++intercalate" depends on "(map(\(_,k,_)->"'"++k++"'")(vs++[headvs]))letlbi=LocalBuildInfo{configFlags=cfg,extraConfigArgs=[],-- Currently configure does not-- take extra args, but if it-- did they would go here.installDirTemplates=installDirs,compiler=comp,buildDir=buildDir',scratchDir=fromFlagOrDefault(distPref</>"scratch")(configScratchDircfg),libraryConfig=configLib`fmap`librarypkg_descr',executableConfigs=configExe`fmap`executablespkg_descr',testSuiteConfigs=configTest`fmap`testSuitespkg_descr',benchmarkConfigs=configBenchmark`fmap`benchmarkspkg_descr',compBuildOrder=buildOrder,installedPkgs=packageDependsIndex,pkgDescrFile=Nothing,localPkgDescr=pkg_descr',withPrograms=programsConfig''',withVanillaLib=fromFlag$configVanillaLibcfg,withProfLib=fromFlag$configProfLibcfg,withSharedLib=fromFlag$configSharedLibcfg,withDynExe=fromFlag$configDynExecfg,withProfExe=fromFlag$configProfExecfg,withOptimization=fromFlag$configOptimizationcfg,withGHCiLib=fromFlag$configGHCiLibcfg,splitObjs=split_objs,stripExes=fromFlag$configStripExescfg,withPackageDB=packageDbs,progPrefix=fromFlag$configProgPrefixcfg,progSuffix=fromFlag$configProgSuffixcfg}letdirs=absoluteInstallDirspkg_descrlbiNoCopyDestrelative=prefixRelativeInstallDirs(packageIdpkg_descr)lbiunless(isAbsolute(prefixdirs))$die$"expected an absolute directory name for --prefix: "++prefixdirsinfoverbosity$"Using "++displaycurrentCabalId++" compiled by "++displaycurrentCompilerIdinfoverbosity$"Using compiler: "++showCompilerIdcompinfoverbosity$"Using install prefix: "++prefixdirsletdirinfonamedirisPrefixRelative=infoverbosity$name++" installed in: "++dir++relNotewhererelNote=casebuildOSofWindows|not(hasLibspkg_descr)&&isNothingisPrefixRelative->" (fixed location)"_->""dirinfo"Binaries"(bindirdirs)(bindirrelative)dirinfo"Libraries"(libdirdirs)(libdirrelative)dirinfo"Private binaries"(libexecdirdirs)(libexecdirrelative)dirinfo"Data files"(datadirdirs)(datadirrelative)dirinfo"Documentation"(docdirdirs)(docdirrelative)sequence_[reportProgramverbosityprogconfiguredProg|(prog,configuredProg)<-knownProgramsprogramsConfig''']returnlbiwhereaddExtraIncludeLibDirspkg_descr=letextraBi=mempty{extraLibDirs=configExtraLibDirscfg,PD.includeDirs=configExtraIncludeDirscfg}modifyLibl=l{libBuildInfo=libBuildInfol`mappend`extraBi}modifyExecutablee=e{buildInfo=buildInfoe`mappend`extraBi}inpkg_descr{library=modifyLib`fmap`librarypkg_descr,executables=modifyExecutable`map`executablespkg_descr}-- ------------------------------------------------------------------------------- Configuring package dependenciesreportProgram::Verbosity->Program->MaybeConfiguredProgram->IO()reportProgramverbosityprogNothing=infoverbosity$"No "++programNameprog++" found"reportProgramverbosityprog(JustconfiguredProg)=infoverbosity$"Using "++programNameprog++version++locationwherelocation=caseprogramLocationconfiguredProgofFoundOnSystemp->" found on system at: "++pUserSpecifiedp->" given by user at: "++pversion=caseprogramVersionconfiguredProgofNothing->""Justv->" version "++displayvhackageUrl::StringhackageUrl="http://hackage.haskell.org/package/"dataResolvedDependency=ExternalDependencyDependencyInstalledPackageInfo|InternalDependencyDependencyPackageId-- should be a lib namedataFailedDependency=DependencyNotExistsPackageName|DependencyNoVersionDependency-- | Test for a package dependency and record the version we have installed.selectDependency::PackageIndex-- ^ Internally defined packages->PackageIndex-- ^ Installed packages->Dependency->EitherFailedDependencyResolvedDependencyselectDependencyinternalIndexinstalledIndexdep@(Dependencypkgnamevr)=-- If the dependency specification matches anything in the internal package-- index, then we prefer that match to anything in the second.-- For example:---- Name: MyLibrary-- Version: 0.1-- Library-- ..-- Executable my-exec-- build-depends: MyLibrary---- We want "build-depends: MyLibrary" always to match the internal library-- even if there is a newer installed library "MyLibrary-0.2".-- However, "build-depends: MyLibrary >= 0.2" should match the installed one.casePackageIndex.lookupPackageNameinternalIndexpkgnameof[(_,[pkg])]|packageVersionpkg`withinRange`vr->Right$InternalDependencydep(packageIdpkg)_->casePackageIndex.lookupDependencyinstalledIndexdepof[]->Left$DependencyNotExistspkgnamepkgs->Right$ExternalDependencydep$-- by default we just pick the latestcaselastpkgsof(_ver,instances)->headinstances-- the first preferencereportSelectedDependencies::Verbosity->[ResolvedDependency]->IO()reportSelectedDependenciesverbositydeps=infoverbosity$unlines["Dependency "++display(simplifyDependencydep)++": using "++displaypkgid|resolved<-deps,let(dep,pkgid)=caseresolvedofExternalDependencydep'pkg'->(dep',packageIdpkg')InternalDependencydep'pkgid'->(dep',pkgid')]reportFailedDependencies::[FailedDependency]->IO()reportFailedDependencies[]=return()reportFailedDependenciesfailed=die(intercalate"\n\n"(mapreportFailedDependencyfailed))wherereportFailedDependency(DependencyNotExistspkgname)="there is no version of "++displaypkgname++" installed.\n"++"Perhaps you need to download and install it from\n"++hackageUrl++displaypkgname++"?"reportFailedDependency(DependencyNoVersiondep)="cannot satisfy dependency "++display(simplifyDependencydep)++"\n"getInstalledPackages::Verbosity->Compiler->PackageDBStack->ProgramConfiguration->IOPackageIndexgetInstalledPackagesverbositycomppackageDBsprogconf=dowhen(nullpackageDBs)$die$"No package databases have been specified. If you use "++"--package-db=clear, you must follow it with --package-db= "++"with 'global', 'user' or a specific file."infoverbosity"Reading installed packages..."casecompilerFlavorcompofGHC->GHC.getInstalledPackagesverbositypackageDBsprogconfHugs->Hugs.getInstalledPackagesverbositypackageDBsprogconfJHC->JHC.getInstalledPackagesverbositypackageDBsprogconfLHC->LHC.getInstalledPackagesverbositypackageDBsprogconfNHC->NHC.getInstalledPackagesverbositypackageDBsprogconfUHC->UHC.getInstalledPackagesverbositycomppackageDBsprogconfflv->die$"don't know how to find the installed packages for "++displayflv-- | The user interface specifies the package dbs to use with a combination of-- @--global@, @--user@ and @--package-db=global|user|clear|$file@.-- This function combines the global/user flag and interprets the package-db-- flag into a single package db stack.--interpretPackageDbFlags::Bool->[MaybePackageDB]->PackageDBStackinterpretPackageDbFlagsuserInstallspecificDBs=extrainitialStackspecificDBswhereinitialStack|userInstall=[GlobalPackageDB,UserPackageDB]|otherwise=[GlobalPackageDB]extradbs'[]=dbs'extra_(Nothing:dbs)=extra[]dbsextradbs'(Justdb:dbs)=extra(dbs'++[db])dbsnewPackageDepsBehaviourMinVersion::VersionnewPackageDepsBehaviourMinVersion=Version{versionBranch=[1,7,1],versionTags=[]}-- In older cabal versions, there was only one set of package dependencies for-- the whole package. In this version, we can have separate dependencies per-- target, but we only enable this behaviour if the minimum cabal version-- specified is >= a certain minimum. Otherwise, for compatibility we use the-- old behaviour.newPackageDepsBehaviour::PackageDescription->BoolnewPackageDepsBehaviourpkg=specVersionpkg>=newPackageDepsBehaviourMinVersion-- ------------------------------------------------------------------------------- Configuring program dependenciesconfigureRequiredPrograms::Verbosity->[Dependency]->ProgramConfiguration->IOProgramConfigurationconfigureRequiredProgramsverbositydepsconf=foldM(configureRequiredProgramverbosity)confdepsconfigureRequiredProgram::Verbosity->ProgramConfiguration->Dependency->IOProgramConfigurationconfigureRequiredProgramverbosityconf(Dependency(PackageNameprogName)verRange)=caselookupKnownProgramprogNameconfofNothing->die("Unknown build tool "++progName)Justprog-- requireProgramVersion always requires the program have a version-- but if the user says "build-depends: foo" ie no version constraint-- then we should not fail if we cannot discover the program version.|verRange==anyVersion->do(_,conf')<-requireProgramverbosityprogconfreturnconf'|otherwise->do(_,_,conf')<-requireProgramVersionverbosityprogverRangeconfreturnconf'-- ------------------------------------------------------------------------------- Configuring pkg-config package dependenciesconfigurePkgconfigPackages::Verbosity->PackageDescription->ProgramConfiguration->IO(PackageDescription,ProgramConfiguration)configurePkgconfigPackagesverbositypkg_descrconf|nullallpkgs=return(pkg_descr,conf)|otherwise=do(_,_,conf')<-requireProgramVersion(lessVerboseverbosity)pkgConfigProgram(orLaterVersion$Version[0,9,0][])confmapM_requirePkgallpkgslib'<-updateLibrary(librarypkg_descr)exes'<-mapMupdateExecutable(executablespkg_descr)letpkg_descr'=pkg_descr{library=lib',executables=exes'}return(pkg_descr',conf')whereallpkgs=concatMappkgconfigDepends(allBuildInfopkg_descr)pkgconfig=rawSystemProgramStdoutConf(lessVerboseverbosity)pkgConfigProgramconfrequirePkgdep@(Dependency(PackageNamepkg)range)=doversion<-pkgconfig["--modversion",pkg]`catchIO`(\_->dienotFound)`catchExit`(\_->dienotFound)casesimpleParseversionofNothing->die"parsing output of pkg-config --modversion failed"Justv|not(withinRangevrange)->die(badVersionv)|otherwise->infoverbosity(depSatisfiedv)wherenotFound="The pkg-config package "++pkg++versionRequirement++" is required but it could not be found."badVersionv="The pkg-config package "++pkg++versionRequirement++" is required but the version installed on the"++" system is version "++displayvdepSatisfiedv="Dependency "++displaydep++": using version "++displayvversionRequirement|isAnyVersionrange=""|otherwise=" version "++displayrangeupdateLibraryNothing=returnNothingupdateLibrary(Justlib)=dobi<-pkgconfigBuildInfo(pkgconfigDepends(libBuildInfolib))return$Justlib{libBuildInfo=libBuildInfolib`mappend`bi}updateExecutableexe=dobi<-pkgconfigBuildInfo(pkgconfigDepends(buildInfoexe))returnexe{buildInfo=buildInfoexe`mappend`bi}pkgconfigBuildInfo::[Dependency]->IOBuildInfopkgconfigBuildInfo[]=returnmemptypkgconfigBuildInfopkgdeps=doletpkgs=nub[displaypkg|Dependencypkg_<-pkgdeps]ccflags<-pkgconfig("--cflags":pkgs)ldflags<-pkgconfig("--libs":pkgs)return(ccLdOptionsBuildInfo(wordsccflags)(wordsldflags))-- | Makes a 'BuildInfo' from C compiler and linker flags.---- This can be used with the output from configuration programs like pkg-config-- and similar package-specific programs like mysql-config, freealut-config etc.-- For example:---- > ccflags <- rawSystemProgramStdoutConf verbosity prog conf ["--cflags"]-- > ldflags <- rawSystemProgramStdoutConf verbosity prog conf ["--libs"]-- > return (ccldOptionsBuildInfo (words ccflags) (words ldflags))--ccLdOptionsBuildInfo::[String]->[String]->BuildInfoccLdOptionsBuildInfocflagsldflags=let(includeDirs',cflags')=partition("-I"`isPrefixOf`)cflags(extraLibs',ldflags')=partition("-l"`isPrefixOf`)ldflags(extraLibDirs',ldflags'')=partition("-L"`isPrefixOf`)ldflags'inmempty{PD.includeDirs=map(drop2)includeDirs',PD.extraLibs=map(drop2)extraLibs',PD.extraLibDirs=map(drop2)extraLibDirs',PD.ccOptions=cflags',PD.ldOptions=ldflags''}-- ------------------------------------------------------------------------------- Determining the compiler detailsconfigCompilerAux::ConfigFlags->IO(Compiler,ProgramConfiguration)configCompilerAuxcfg=configCompiler(flagToMaybe$configHcFlavorcfg)(flagToMaybe$configHcPathcfg)(flagToMaybe$configHcPkgcfg)programsConfig(fromFlag(configVerbositycfg))whereprogramsConfig=userSpecifyArgss(configProgramArgscfg).userSpecifyPaths(configProgramPathscfg)$defaultProgramConfigurationconfigCompiler::MaybeCompilerFlavor->MaybeFilePath->MaybeFilePath->ProgramConfiguration->Verbosity->IO(Compiler,ProgramConfiguration)configCompilerNothing____=die"Unknown compiler"configCompiler(JusthcFlavor)hcPathhcPkgconfverbosity=docasehcFlavorofGHC->GHC.configureverbosityhcPathhcPkgconfJHC->JHC.configureverbosityhcPathhcPkgconfLHC->do(_,ghcConf)<-GHC.configureverbosityNothinghcPkgconfLHC.configureverbosityhcPathNothingghcConfHugs->Hugs.configureverbosityhcPathhcPkgconfNHC->NHC.configureverbosityhcPathhcPkgconfUHC->UHC.configureverbosityhcPathhcPkgconf_->die"Unknown compiler"-- Try to build a test C program which includes every header and links every-- lib. If that fails, try to narrow it down by preprocessing (only) and linking-- with individual headers and libs. If none is the obvious culprit then give a-- generic error message.-- TODO: produce a log file from the compiler errors, if any.checkForeignDeps::PackageDescription->LocalBuildInfo->Verbosity->IO()checkForeignDepspkglbiverbosity=doifBuildsWithallHeaders(commonCcArgs++makeLdArgsallLibs)-- I'm feeling lucky(return())(domissingLibs<-findMissingLibsmissingHdr<-findOffendingHdrexplainErrorsmissingHdrmissingLibs)whereallHeaders=collectFieldPD.includesallLibs=collectFieldPD.extraLibsifBuildsWithheadersargssuccessfailure=dook<-builds(makeProgramheaders)argsifokthensuccesselsefailurefindOffendingHdr=ifBuildsWithallHeadersccArgs(returnNothing)(go.tail.inits$allHeaders)wherego[]=returnNothing-- cannot happengo(hdrs:hdrsInits)=-- Try just preprocessing firstifBuildsWithhdrscppArgs-- If that works, try compiling too(ifBuildsWithhdrsccArgs(gohdrsInits)(return.Just.Right.last$hdrs))(return.Just.Left.last$hdrs)cppArgs="-E":commonCppArgs-- preprocess onlyccArgs="-c":commonCcArgs-- don't try to linkfindMissingLibs=ifBuildsWith[](makeLdArgsallLibs)(return[])(filterM(fmapnot.libExists)allLibs)libExistslib=builds(makeProgram[])(makeLdArgs[lib])commonCppArgs=hcDefines(compilerlbi)++["-I"++autogenModulesDirlbi]++["-I"++dir|dir<-collectFieldPD.includeDirs]++["-I."]++collectFieldPD.cppOptions++collectFieldPD.ccOptions++["-I"++dir|dep<-deps,dir<-Installed.includeDirsdep]++[opt|dep<-deps,opt<-Installed.ccOptionsdep]commonCcArgs=commonCppArgs++collectFieldPD.ccOptions++[opt|dep<-deps,opt<-Installed.ccOptionsdep]commonLdArgs=["-L"++dir|dir<-collectFieldPD.extraLibDirs]++collectFieldPD.ldOptions++["-L"++dir|dep<-deps,dir<-Installed.libraryDirsdep]--TODO: do we also need dependent packages' ld options?makeLdArgslibs=["-l"++lib|lib<-libs]++commonLdArgsmakeProgramhdrs=unlines$["#include \""++hdr++"\""|hdr<-hdrs]++["int main(int argc, char** argv) { return 0; }"]collectFieldf=concatMapfallBiallBi=allBuildInfopkgdeps=PackageIndex.topologicalOrder(installedPkgslbi)buildsprogramargs=dotempDir<-getTemporaryDirectorywithTempFiletempDir".c"$\cNamecHnd->withTempFiletempDir""$\oNnameoHnd->dohPutStrLncHndprogramhClosecHndhCloseoHnd_<-rawSystemProgramStdoutConfverbositygccProgram(withProgramslbi)(cName:"-o":oNname:args)returnTrue`catchIO`(\_->returnFalse)`catchExit`(\_->returnFalse)explainErrorsNothing[]=return()-- should be impossible!explainErrorshdrlibs=die$unlines$[ifpluralthen"Missing dependencies on foreign libraries:"else"Missing dependency on a foreign library:"|missing]++casehdrofJust(Lefth)->["* Missing (or bad) header file: "++h]_->[]++caselibsof[]->[][lib]->["* Missing C library: "++lib]_->["* Missing C libraries: "++intercalate", "libs]++[ifpluralthenmessagePluralelsemessageSingular|missing]++casehdrofJust(Left_)->[headerCppMessage]Just(Righth)->[(ifmissingthen"* "else"")++"Bad header file: "++h,headerCcMessage]_->[]whereplural=lengthlibs>=2-- Is there something missing? (as opposed to broken)missing=not(nulllibs)||casehdrofJust(Left_)->True;_->FalsemessageSingular="This problem can usually be solved by installing the system "++"package that provides this library (you may need the "++"\"-dev\" version). If the library is already installed "++"but in a non-standard location then you can use the flags "++"--extra-include-dirs= and --extra-lib-dirs= to specify "++"where it is."messagePlural="This problem can usually be solved by installing the system "++"packages that provide these libraries (you may need the "++"\"-dev\" versions). If the libraries are already installed "++"but in a non-standard location then you can use the flags "++"--extra-include-dirs= and --extra-lib-dirs= to specify "++"where they are."headerCppMessage="If the header file does exist, it may contain errors that "++"are caught by the C compiler at the preprocessing stage. "++"In this case you can re-run configure with the verbosity "++"flag -v3 to see the error messages."headerCcMessage="The header file contains a compile error. "++"You can re-run configure with the verbosity flag "++"-v3 to see the error messages from the C compiler."--FIXME: share this with the PreProcessor modulehcDefines::Compiler->[String]hcDefinescomp=casecompilerFlavorcompofGHC->letghcOS=casebuildOSofLinux->["linux"]Windows->["mingw32"]OSX->["darwin"]FreeBSD->["freebsd"]OpenBSD->["openbsd"]NetBSD->["netbsd"]Solaris->["solaris2"]AIX->["aix"]HPUX->["hpux"]IRIX->["irix"]HaLVM->[]OtherOS_->[]ghcArch=casebuildArchofI386->["i386"]X86_64->["x86_64"]PPC->["powerpc"]PPC64->["powerpc64"]Sparc->["sparc"]Arm->["arm"]Mips->["mips"]SH->[]IA64->["ia64"]S390->["s390"]Alpha->["alpha"]Hppa->["hppa"]Rs6000->["rs6000"]M68k->["m68k"]Vax->["vax"]OtherArch_->[]in["-D__GLASGOW_HASKELL__="++versionIntversion]++map(\os->"-D"++os++"_HOST_OS=1")ghcOS++map(\arch->"-D"++arch++"_HOST_ARCH=1")ghcArchJHC->["-D__JHC__="++versionIntversion]NHC->["-D__NHC__="++versionIntversion]Hugs->["-D__HUGS__"]_->[]whereversion=compilerVersioncomp-- TODO: move this into the compiler abstraction-- FIXME: this forces GHC's crazy 4.8.2 -> 408 convention on all-- the other compilers. Check if that's really what they want.versionInt::Version->StringversionInt(Version{versionBranch=[]})="1"versionInt(Version{versionBranch=[n]})=shownversionInt(Version{versionBranch=n1:n2:_})=-- 6.8.x -> 608-- 6.10.x -> 610lets1=shown1s2=shown2middle=cases2of_:_:_->""_->"0"ins1++middle++s2-- | Output package check warnings and errors. Exit if any errors.checkPackageProblems::Verbosity->GenericPackageDescription->PackageDescription->IO()checkPackageProblemsverbositygpkgpkg=doioChecks<-checkPackageFilespkg"."letpureChecks=checkPackagegpkg(Justpkg)errors=[e|PackageBuildImpossiblee<-pureChecks++ioChecks]warnings=[w|PackageBuildWarningw<-pureChecks++ioChecks]ifnullerrorsthenmapM_(warnverbosity)warningselsedomapM_(hPutStrLnstderr.("Error: "++))errorsexitWith(ExitFailure1)