├── Makefile ├── .hspec ├── cabal.project ├── .gitignore ├── bash ├── profile-install ├── haddocks ├── pre-commit ├── tests └── builds ├── .gitattributes ├── src ├── Package │ ├── C │ │ ├── Db │ │ │ ├── Monad.hs │ │ │ ├── Memory.hs │ │ │ ├── Type.hs │ │ │ ├── GarbageCollect.hs │ │ │ └── Register.hs │ │ ├── Type │ │ │ ├── Verbosity.hs │ │ │ ├── Version.hs │ │ │ ├── Shared.hs │ │ │ ├── Vars.hs │ │ │ └── Tree.hs │ │ ├── Triple.hs │ │ ├── Dhall.hs │ │ ├── Monad.hs │ │ ├── Build │ │ │ ├── OS.hs │ │ │ └── Tree.hs │ │ ├── Logging.hs │ │ ├── Unpack.hs │ │ ├── Error.hs │ │ ├── Fetch.hs │ │ ├── Triple │ │ │ ├── Parse.hs │ │ │ └── Type.hs │ │ ├── Dhall │ │ │ └── Type.hs │ │ ├── PackageSet.hs │ │ ├── Type.hs │ │ └── Build.hs │ └── C.hs ├── System │ ├── Directory │ │ └── Executable.cpphs │ └── Process │ │ └── Ext.hs ├── Data │ └── Text │ │ └── Prettyprint │ │ └── Doc │ │ └── Custom.hs └── CPkgPrelude.hs ├── .ctags ├── cabal.project.cross ├── pkgs └── patches │ ├── make.patch │ ├── xproto.patch │ ├── xextproto.patch │ ├── scrnsaverproto.patch │ ├── xineramaproto.patch │ ├── renderproto.patch │ ├── intltool.patch │ ├── pHash.patch │ └── m4.patch ├── .stylish-haskell.yaml ├── test └── Spec.hs ├── .hlint.yaml ├── LICENSE ├── CHANGELOG.md ├── dhall ├── cpkg-types.dhall └── cpkg-prelude.dhall ├── cpkg.cabal ├── app └── Main.hs ├── TODO.md └── README.md /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: docs 2 | 3 | docs: 4 | dhall-docs --input dhall --output-link docs 5 | -------------------------------------------------------------------------------- /.hspec: -------------------------------------------------------------------------------- 1 | --fail-fast 2 | --failure-report .hspec-failures 3 | --rerun 4 | --rerun-all-on-success 5 | -------------------------------------------------------------------------------- /cabal.project: -------------------------------------------------------------------------------- 1 | packages: ./ 2 | constraints: cpkg +development 3 | , zlib +pkg-config 4 | 5 | max-backjumps: 40000 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | .ghc.environment.* 3 | .hspec-failures 4 | tags 5 | dist 6 | dist-* 7 | doc 8 | *.prof 9 | *.hp 10 | *.eventlog 11 | -------------------------------------------------------------------------------- /bash/profile-install: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cabal build exe:cpkg -w ghc-8.8.2 --enable-profiling 4 | cp $(fd cpkg$ -t x -I) ~/.local/bin/cpkg-prof 5 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.cpphs linguist-language=Haskell 2 | *.hsc2hs linguist-language=Haskell 3 | *.c2hs linguist-language=Haskell 4 | *.gc linguist-language=Haskell 5 | -------------------------------------------------------------------------------- /bash/haddocks: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e pipefail 4 | DOCS_PATH=$(PKG_CONFIG_PATH=$(cpkg dump pkg-config libarchive) cabal haddock -w ghc-8.6.5 --haddock-for-hackage | tail -n1) 5 | cabal upload --publish -d "$DOCS_PATH" 6 | -------------------------------------------------------------------------------- /src/Package/C/Db/Monad.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE ConstraintKinds #-} 2 | 3 | module Package.C.Db.Monad ( MonadDb 4 | ) where 5 | 6 | import Control.Monad.State 7 | import Package.C.Db.Type 8 | 9 | type MonadDb = MonadState InstallDb 10 | -------------------------------------------------------------------------------- /.ctags: -------------------------------------------------------------------------------- 1 | --langdef=DHALL 2 | --langmap=DHALL:.dhall 3 | --regex-DHALL=/let *([[:lower:]][[:alnum:]_]+)/\1/f,function/ 4 | --regex-DHALL=/let *([[:upper:]][[:alnum:]_]+)/\1/t,type/ 5 | --regex-DHALL=/< *([[:upper:]][[:alnum:]_]+)/\1/t,type/ 6 | --regex-DHALL=/\| *([[:upper:]][[:alnum:]_]+)/\1/t,type/ 7 | -------------------------------------------------------------------------------- /cabal.project.cross: -------------------------------------------------------------------------------- 1 | packages: ./ 2 | 3 | constraints: dhall +cross 4 | , half +cross 5 | , libarchive +cross 6 | , libarchive >= 1.0.5.1 7 | 8 | source-repository-package 9 | type: git 10 | tag: 2cb1e838620dbcedaa5e1d461c6c67dd56d6343d 11 | location: https://github.com/ekmett/half.git 12 | -------------------------------------------------------------------------------- /pkgs/patches/make.patch: -------------------------------------------------------------------------------- 1 | --- glob/glob.c 2013-10-20 17:14:38.000000000 +0000 2 | +++ glob/glob.c 2018-09-18 10:16:03.860886356 +0000 3 | @@ -208,7 +208,7 @@ 4 | #endif /* __GNU_LIBRARY__ || __DJGPP__ */ 5 | 6 | 7 | -#if !defined __alloca && !defined __GNU_LIBRARY__ 8 | +#if !defined __alloca && defined __GNU_LIBRARY__ 9 | 10 | # ifdef __GNUC__ 11 | # undef alloca 12 | -------------------------------------------------------------------------------- /src/System/Directory/Executable.cpphs: -------------------------------------------------------------------------------- 1 | module System.Directory.Executable ( mkExecutable ) where 2 | 3 | import System.Directory 4 | 5 | #ifdef mingw32_HOST_OS 6 | mkExecutable :: FilePath -> IO () 7 | mkExecutable = mempty 8 | #else 9 | mkExecutable :: FilePath -> IO () 10 | mkExecutable fp = do 11 | perms <- getPermissions fp 12 | setPermissions fp (setOwnerExecutable True perms) 13 | #endif 14 | -------------------------------------------------------------------------------- /bash/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # This is the pre-commit hook I use, provided for sake of other users here 4 | # It includes one check (viz., Dhall typechecking) and a perl one-liner to 5 | # update the repository's linecount 6 | 7 | set -e 8 | cabal new-run cpkg -w ghc-8.6.5 -- check-set pkgs/pkg-set.dhall 9 | cabal new-test -w ghc-8.6.5 10 | echo ':ctags' | cabal new-repl -w ghc-8.6.5 11 | perl -0777 -i -pe 's/```\n----.*```/```\n'"$(poly -c)"'\n```/igs' README.md 12 | -------------------------------------------------------------------------------- /src/Package/C/Type/Verbosity.hs: -------------------------------------------------------------------------------- 1 | module Package.C.Type.Verbosity ( Verbosity (..) 2 | ) where 3 | 4 | data Verbosity = Silent -- ^ Display nothing 5 | | Normal -- ^ Display progress information 6 | | Verbose -- ^ Display stderr from builds 7 | | Loud -- ^ Display stdout and stderr from builds 8 | | Diagnostic -- ^ Display stdout and stderr from builds, and display debug information 9 | deriving (Eq, Ord) 10 | -------------------------------------------------------------------------------- /pkgs/patches/xproto.patch: -------------------------------------------------------------------------------- 1 | --- config.sub 2019-04-27 16:40:36.266089495 -0500 2 | +++ config.sub 2019-04-27 16:41:44.593275058 -0500 3 | @@ -240,7 +240,7 @@ 4 | | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ 5 | | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ 6 | | am33_2.0 \ 7 | - | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ 8 | + | arc | aarch64 | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ 9 | | bfin \ 10 | | c4x | clipper \ 11 | | d10v | d30v | dlx | dsp16xx \ 12 | -------------------------------------------------------------------------------- /src/Package/C/Triple.hs: -------------------------------------------------------------------------------- 1 | module Package.C.Triple ( -- * Types 2 | TargetTriple (..) 3 | , Arch (..) 4 | , OS (..) 5 | , Manufacturer (..) 6 | , ABI (..) 7 | -- * Parsers 8 | , parseTriple 9 | -- * Helper functions 10 | , parseTripleIO 11 | ) where 12 | 13 | import Package.C.Triple.Parse 14 | import Package.C.Triple.Type 15 | -------------------------------------------------------------------------------- /pkgs/patches/xextproto.patch: -------------------------------------------------------------------------------- 1 | --- config.sub 2019-04-27 17:01:47.137694014 -0500 2 | +++ config.sub 2019-04-27 17:02:05.329622757 -0500 3 | @@ -249,7 +249,7 @@ 4 | | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ 5 | | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ 6 | | am33_2.0 \ 7 | - | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ 8 | + | arc | aarch64 | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ 9 | | bfin \ 10 | | c4x | clipper \ 11 | | d10v | d30v | dlx | dsp16xx \ 12 | -------------------------------------------------------------------------------- /pkgs/patches/scrnsaverproto.patch: -------------------------------------------------------------------------------- 1 | --- config.sub 2012-03-22 22:49:47.000000000 -0500 2 | +++ config.sub 2019-04-28 04:52:47.247723846 -0500 3 | @@ -250,7 +250,7 @@ 4 | | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ 5 | | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ 6 | | am33_2.0 \ 7 | - | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ 8 | + | arc | aarch64 | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ 9 | | bfin \ 10 | | c4x | clipper \ 11 | | d10v | d30v | dlx | dsp16xx \ 12 | -------------------------------------------------------------------------------- /pkgs/patches/xineramaproto.patch: -------------------------------------------------------------------------------- 1 | --- config.sub 2009-10-01 05:35:23.000000000 -0500 2 | +++ config.sub 2019-04-28 04:57:15.837809557 -0500 3 | @@ -242,7 +242,7 @@ 4 | | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ 5 | | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ 6 | | am33_2.0 \ 7 | - | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ 8 | + | arc | aarch64 | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ 9 | | bfin \ 10 | | c4x | clipper \ 11 | | d10v | d30v | dlx | dsp16xx \ 12 | -------------------------------------------------------------------------------- /pkgs/patches/renderproto.patch: -------------------------------------------------------------------------------- 1 | --- config.sub 2010-08-10 09:11:53.000000000 -0500 2 | +++ config.sub.new 2019-04-27 17:18:57.730988579 -0500 3 | @@ -248,7 +248,7 @@ 4 | | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ 5 | | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ 6 | | am33_2.0 \ 7 | - | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ 8 | + | arc | aarch64 | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ 9 | | bfin \ 10 | | c4x | clipper \ 11 | | d10v | d30v | dlx | dsp16xx \ 12 | -------------------------------------------------------------------------------- /.stylish-haskell.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | steps: 3 | - simple_align: 4 | cases: true 5 | top_level_patterns: true 6 | records: true 7 | - imports: 8 | align: global 9 | list_align: after_alias 10 | pad_module_names: true 11 | long_list_align: inline 12 | empty_list_align: inherit 13 | list_padding: 4 14 | separate_lists: true 15 | space_surround: false 16 | - language_pragmas: 17 | style: vertical 18 | align: true 19 | remove_redundant: false 20 | 21 | - trailing_whitespace: {} 22 | columns: 160 23 | newline: native 24 | language_extensions: [CPP] 25 | -------------------------------------------------------------------------------- /src/Package/C/Dhall.hs: -------------------------------------------------------------------------------- 1 | module Package.C.Dhall ( getCPkg 2 | , getPkgs 3 | ) where 4 | 5 | import Dhall 6 | import Package.C.Dhall.Type 7 | import Package.C.Type.Verbosity 8 | 9 | maybeMod :: Verbosity -> IO a -> IO a 10 | maybeMod v | v >= Verbose = detailed 11 | | otherwise = id 12 | 13 | getDhall :: FromDhall a => Verbosity -> FilePath -> IO a 14 | getDhall v = maybeMod v . inputFile auto 15 | 16 | getCPkg :: Verbosity -> FilePath -> IO CPkg 17 | getCPkg = getDhall 18 | 19 | getPkgs :: Verbosity -> FilePath -> IO [CPkg] 20 | getPkgs = getDhall 21 | -------------------------------------------------------------------------------- /src/Package/C/Type/Version.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE GeneralizedNewtypeDeriving #-} 2 | {-# LANGUAGE OverloadedStrings #-} 3 | 4 | module Package.C.Type.Version ( Version (..) 5 | , showVersion 6 | ) where 7 | 8 | import CPkgPrelude 9 | import Data.List (intercalate) 10 | 11 | newtype Version = Version [ Natural ] 12 | deriving (Eq, Ord, FromDhall, Binary, Hashable) 13 | 14 | showVersion :: Version -> String 15 | showVersion (Version v) = intercalate "." (show <$> v) 16 | 17 | instance Pretty Version where 18 | pretty (Version v) = fold (punctuate "." (pretty <$> v)) 19 | -------------------------------------------------------------------------------- /src/Data/Text/Prettyprint/Doc/Custom.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | 3 | module Data.Text.Prettyprint.Doc.Custom ( (<#>) 4 | , (<##>) 5 | , vdisplay 6 | , dashed 7 | ) where 8 | 9 | import Data.Foldable (foldl') 10 | import Data.Text.Prettyprint.Doc 11 | 12 | infixr 5 <#> 13 | infixr 5 <##> 14 | 15 | (<#>) :: Doc a -> Doc a -> Doc a 16 | (<#>) a b = a <> line <> b 17 | 18 | (<##>) :: Doc a -> Doc a -> Doc a 19 | (<##>) a b = a <> hardline <> b 20 | 21 | vdisplay :: [Doc a] -> Doc a 22 | vdisplay = foldl' (<#>) mempty 23 | 24 | dashed :: [Doc a] -> Doc a 25 | dashed = concatWith (\x y -> x <> "-" <> y) 26 | -------------------------------------------------------------------------------- /src/Package/C/Monad.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE ConstraintKinds #-} 2 | {-# LANGUAGE FlexibleContexts #-} 3 | 4 | module Package.C.Monad ( PkgM 5 | , MonadPkg 6 | , runPkgM 7 | ) where 8 | 9 | import Control.Monad.Reader 10 | import Control.Monad.State 11 | import Package.C.Db.Memory 12 | import Package.C.Db.Type 13 | import Package.C.Type.Verbosity 14 | 15 | -- TODO: should this take a 'Maybe Platform' as well? 16 | type PkgM = StateT InstallDb (ReaderT Verbosity IO) 17 | 18 | type MonadPkg m = (MonadState InstallDb m, MonadReader Verbosity m, MonadIO m) 19 | 20 | runPkgM :: Verbosity -> PkgM a -> IO a 21 | runPkgM v act = do 22 | pSet <- strictIndex 23 | flip runReaderT v $ evalStateT act pSet 24 | -------------------------------------------------------------------------------- /src/Package/C/Build/OS.hs: -------------------------------------------------------------------------------- 1 | module Package.C.Build.OS ( dhallOS 2 | , dhallArch 3 | ) where 4 | 5 | import Package.C.Triple.Type hiding (arch, os) 6 | import System.Info (arch, os) 7 | 8 | dhallArch :: Arch 9 | dhallArch = case arch of 10 | "x86_64" -> X64 11 | "x86" -> X86 12 | "arm" -> Arm 13 | "aarch64" -> AArch 14 | _ -> error "unrecognized architecture" 15 | 16 | dhallOS :: OS 17 | dhallOS = case os of 18 | "freebsd" -> FreeBSD 19 | "openbsd" -> OpenBSD 20 | "netbsd" -> NetBSD 21 | "solaris" -> Solaris 22 | "dragonfly" -> Dragonfly 23 | "linux" -> Linux 24 | "darwin" -> Darwin 25 | "mingw32" -> Windows 26 | _ -> error "unrecognized OS" 27 | -------------------------------------------------------------------------------- /src/Package/C/Type/Shared.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DeriveAnyClass #-} 2 | {-# LANGUAGE DeriveGeneric #-} 3 | {-# LANGUAGE DerivingStrategies #-} 4 | 5 | 6 | module Package.C.Type.Shared ( VersionBound (..) 7 | , Dep (..) 8 | ) where 9 | 10 | import qualified Data.Text as T 11 | import Dhall 12 | import Package.C.Type.Version 13 | 14 | data VersionBound = Lower { lower :: Version } 15 | | Upper { upper :: Version } 16 | | LowerUpper { lower :: Version, upper :: Version } 17 | | NoBound 18 | deriving (Generic, FromDhall) 19 | 20 | data Dep = Dep { name :: T.Text 21 | , bound :: VersionBound 22 | } deriving (Generic, FromDhall) 23 | -------------------------------------------------------------------------------- /src/Package/C/Logging.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE FlexibleContexts #-} 2 | 3 | module Package.C.Logging ( putNormal 4 | , putDiagnostic 5 | , putLoud 6 | ) where 7 | 8 | import Control.Monad.Reader 9 | import Package.C.Type.Verbosity 10 | 11 | putVerbosity :: (MonadReader Verbosity m, MonadIO m) => Verbosity -> String -> m () 12 | putVerbosity verb s = do 13 | v <- ask 14 | when (v >= verb) 15 | (liftIO (putStrLn s)) 16 | 17 | putNormal :: (MonadReader Verbosity m, MonadIO m) => String -> m () 18 | putNormal = putVerbosity Normal 19 | 20 | putDiagnostic :: (MonadReader Verbosity m, MonadIO m) => String -> m () 21 | putDiagnostic = putVerbosity Diagnostic 22 | 23 | putLoud :: (MonadReader Verbosity m, MonadIO m) => String -> m () 24 | putLoud = putVerbosity Loud 25 | -------------------------------------------------------------------------------- /test/Spec.hs: -------------------------------------------------------------------------------- 1 | import Package.C 2 | import Test.Hspec 3 | import Test.Hspec.Megaparsec 4 | import Text.Megaparsec 5 | 6 | parseHelper :: String -> TargetTriple -> SpecWith () 7 | parseHelper str tgt' = 8 | parallel $ it "should work on arm-linux-gnueabihf" $ 9 | parse parseTriple "(none)" str 10 | `shouldParse` tgt' 11 | 12 | main :: IO () 13 | main = hspec $ 14 | describe "parseTriple" $ do 15 | parseHelper "arm-linux-gnueabihf" $ TargetTriple Arm Nothing Linux (Just GNUeabihf) 16 | parseHelper "mips64el-linux-gnuabi64" $ TargetTriple Mips64El Nothing Linux (Just GNUabi64) 17 | parseHelper "mips64-linux-gnu" $ TargetTriple Mips64 Nothing Linux (Just GNU) 18 | parseHelper "x86_64-unknown-redox" $ TargetTriple X64 (Just Unknown) Redox Nothing 19 | parseHelper "mipsisa64r6el-linux-gnuabi64" $ TargetTriple MipsIsa64r6El Nothing Linux (Just GNUabi64) 20 | -------------------------------------------------------------------------------- /bash/tests: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | cabal new-test 6 | cabal new-run cpkg -w ghc-8.2.2 -- check-set './pkgs/pkg-set.dhall' 7 | cabal new-run cpkg -- install feh -vv --pkg-set './pkgs/pkg-set.dhall' --target=arm-linux-gnueabihf 8 | cabal new-run cpkg -- install emacs -vv --pkg-set './pkgs/pkg-set.dhall' 9 | cabal new-run cpkg -- install glibc -vv --pkg-set './pkgs/pkg-set.dhall' 10 | cabal new-run cpkg -- install pHash -vv --pkg-set './pkgs/pkg-set.dhall' 11 | cabal new-run cpkg -- install gnupg -vv --pkg-set './pkgs/pkg-set.dhall' 12 | cabal new-run cpkg -- install qt -vv --pkg-set './pkgs/pkg-set.dhall' 13 | cabal new-run cpkg -- install lapack -vv --pkg-set './pkgs/pkg-set.dhall' 14 | cabal new-run cpkg -- install pdfgrep -vv --pkg-set './pkgs/pkg-set.dhall' 15 | cabal new-run cpkg -- install wget -vv --pkg-set './pkgs/pkg-set.dhall' --target=arm-linux-gnueabihf 16 | cabal new-run cpkg -- install hugs -vv --pkg-set './pkgs/pkg-set.dhall' --target=arm-linux-gnueabihf 17 | -------------------------------------------------------------------------------- /src/System/Process/Ext.hs: -------------------------------------------------------------------------------- 1 | module System.Process.Ext ( waitProcess 2 | ) where 3 | 4 | import Control.Monad.Reader (ask) 5 | import CPkgPrelude 6 | import Package.C.Monad 7 | import Package.C.Type.Verbosity 8 | import System.Exit (ExitCode (ExitSuccess), exitWith) 9 | import System.Process 10 | 11 | handleExit :: ExitCode -> IO () 12 | handleExit ExitSuccess = mempty 13 | handleExit x = exitWith x 14 | 15 | verbosityErr :: Verbosity -> StdStream 16 | verbosityErr v | v >= Verbose = Inherit 17 | verbosityErr _ = CreatePipe 18 | 19 | waitProcess :: CreateProcess -> PkgM () 20 | waitProcess proc' = do 21 | v <- ask 22 | if v >= Loud 23 | then do 24 | (_, _, _, r) <- liftIO $ createProcess (proc' { std_out = Inherit, std_err = Inherit }) 25 | liftIO (handleExit =<< waitForProcess r) 26 | else void $ liftIO $ readCreateProcess (proc' { std_err = verbosityErr v }) mempty 27 | 28 | -------------------------------------------------------------------------------- /bash/builds: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | cpkg install gc 5 | cpkg install gc --target=i686-linux-gnu 6 | cpkg install gc --target=x86_64-w64-mingw32 7 | cpkg install gc --target=s390x-linux-gnu 8 | cpkg install gc --target=arm-linux-gnueabihf 9 | cpkg install gc --target=powerpc64-linux-gnu 10 | cpkg install gc --target=powerpc64le-linux-gnu 11 | cpkg install gc --target=powerpc-linux-gnu 12 | cpkg install gc --target=powerpc-linux-gnuspe 13 | cpkg install gc --target=aarch64-linux-gnu 14 | cpkg install gc --target=alpha-linux-gnu 15 | cpkg install gc --target=m68k-linux-gnu 16 | cpkg install gc --target=mips-linux-gnu 17 | cpkg install gc --target=mipsel-linux-gnu 18 | cpkg install gc --target=mips64-linux-gnu 19 | cpkg install gc --target=mips64el-linux-gnu 20 | cpkg install gc --target=sh4-linux-gnu 21 | cpkg install gc --target=arm-linux-gnueabi 22 | cpkg install gc --target=riscv64-linux-gnu 23 | cpkg install gc --target=hppa-linux-gnu 24 | cpkg install gc --target=sparc64-linux-gnu 25 | cpkg install gc --target=hppa64-linux-gnu 26 | cpkg install gc --target=i686-w64-mingw32 27 | -------------------------------------------------------------------------------- /src/Package/C/Type/Vars.hs: -------------------------------------------------------------------------------- 1 | module Package.C.Type.Vars ( BuildVars (..) 2 | ) where 3 | 4 | import Package.C.Triple.Type 5 | 6 | data BuildVars = BuildVars { installDir :: FilePath 7 | , currentDir :: FilePath 8 | , targetTriple :: Maybe TargetTriple 9 | , isCross :: Bool 10 | , includeDirs :: [ FilePath ] 11 | , preloadLibs :: [ FilePath ] 12 | , shareDirs :: [ FilePath ] 13 | , linkDirs :: [ FilePath ] 14 | , binDirs :: [ FilePath ] 15 | , buildOS :: OS -- ^ See [here](https://gcc.gnu.org/onlinedocs/gccint/Configure-Terms.html) for terminology. This is the OS of the system we are building on. 16 | , buildArch :: Arch 17 | , static :: Bool 18 | , cpus :: Int 19 | } 20 | -------------------------------------------------------------------------------- /src/Package/C/Type/Tree.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DeriveAnyClass #-} 2 | {-# LANGUAGE DeriveFoldable #-} 3 | {-# LANGUAGE DeriveGeneric #-} 4 | {-# LANGUAGE DeriveTraversable #-} 5 | {-# LANGUAGE TypeFamilies #-} 6 | 7 | module Package.C.Type.Tree ( DepTree (..) 8 | , DepTreeF (..) 9 | , asBldDep 10 | ) where 11 | 12 | import Control.Recursion 13 | import GHC.Generics (Generic) 14 | 15 | data DepTree p = DepNode p Bool [DepTree p] 16 | | BldDepNode p [DepTree p] 17 | deriving (Functor, Foldable, Traversable, Generic, Recursive) 18 | 19 | data DepTreeF p x = DepNodeF { self :: p, man :: Bool, deps :: [x] } 20 | | BldDepNodeF { self :: p, deps :: [x] } 21 | deriving (Functor, Foldable, Traversable, Generic) 22 | 23 | type instance Base (DepTree a) = DepTreeF a 24 | 25 | asBldDep :: DepTree p -> DepTree p 26 | asBldDep (DepNode p _ ps) = BldDepNode p (fmap asBldDep ps) 27 | asBldDep (BldDepNode p ps) = BldDepNode p (fmap asBldDep ps) 28 | -------------------------------------------------------------------------------- /.hlint.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - functions: 3 | - {name: unsafePerformIO, within: []} 4 | - {name: undefined, within: [Package.C.Db.Register]} 5 | - {name: fromJust, within: []} 6 | - {name: foldl, within: []} 7 | - {name: traceShowId, within: []} 8 | - {name: traceShow, within: []} 9 | - {name: diagnosticDirectory, within: []} 10 | 11 | - ignore: {name: "Avoid lambda using `infix`"} 12 | - ignore: {name: "Use section"} 13 | - ignore: {name: "Redundant lambda"} 14 | - ignore: {name: "Replace case with fromMaybe"} 15 | 16 | - error: {lhs: "f *> pure ()", rhs: "void f", name: "Use void"} 17 | - error: {lhs: "over _1 f x", rhs: "first f x", name: "Use arrows"} 18 | - error: {lhs: "over _2 f x", rhs: "second f x", name: "Use arrows"} 19 | - error: {lhs: "bool x x p", rhs: "x", name: "Redundant bool"} 20 | - error: {lhs: "maybe mempty", rhs: "foldMap", name: "Use foldMap"} 21 | - error: {lhs: "if p then x else pure ()", rhs: "when p x"} 22 | - error: {lhs: "fmap (pure ())", rhs: "void", name: "Use void"} 23 | 24 | - fixity: infixr 3 *** 25 | - fixity: infixr 3 &&& 26 | - fixity: infixr 1 <=< 27 | - fixity: infixr 1 <=*< 28 | -------------------------------------------------------------------------------- /src/Package/C/Db/Memory.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE FlexibleContexts #-} 2 | 3 | module Package.C.Db.Memory ( strictIndex 4 | , pkgIndex 5 | , globalPkgDir 6 | , memIndex 7 | ) where 8 | 9 | import Control.Monad.State.Class 10 | import CPkgPrelude 11 | import Data.Binary (decode) 12 | import qualified Data.ByteString as BS 13 | import qualified Data.ByteString.Lazy as BSL 14 | import Package.C.Db.Monad 15 | import Package.C.Db.Type 16 | 17 | pkgIndex :: MonadIO m => m FilePath 18 | pkgIndex = ( "index.bin") <$> globalPkgDir 19 | 20 | globalPkgDir :: MonadIO m => m FilePath 21 | globalPkgDir = liftIO (getAppUserDataDirectory "cpkg") 22 | 23 | memIndex :: MonadDb m => m InstallDb 24 | memIndex = get 25 | 26 | strictIndex :: MonadIO m => m InstallDb 27 | strictIndex = do 28 | 29 | indexFile <- pkgIndex 30 | -- Add some proper error handling here 31 | existsIndex <- liftIO (doesFileExist indexFile) 32 | 33 | if existsIndex 34 | then decode . BSL.fromStrict <$> liftIO (BS.readFile indexFile) 35 | else pure mempty 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright Vanessa McHale (c) 2018-2020 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 7 | 2. 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. 8 | 9 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | 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 HOLDER 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. 12 | -------------------------------------------------------------------------------- /src/Package/C/Db/Type.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DeriveAnyClass #-} 2 | {-# LANGUAGE DeriveGeneric #-} 3 | {-# LANGUAGE DerivingStrategies #-} 4 | {-# LANGUAGE GeneralizedNewtypeDeriving #-} 5 | 6 | module Package.C.Db.Type ( BuildCfg (..) 7 | , InstallDb (..) 8 | -- * Lenses 9 | , installedPackages 10 | ) where 11 | 12 | import CPkgPrelude 13 | import Data.Semigroup 14 | import qualified Data.Set as S 15 | import qualified Data.Text as T 16 | import Package.C.Type 17 | 18 | -- TODO: we definitely want something different here - it should allow garbage 19 | -- collection, for one 20 | newtype InstallDb = InstallDb { _installedPackages :: S.Set BuildCfg } 21 | deriving newtype (Semigroup, Monoid, Binary) 22 | 23 | installedPackages :: Lens' InstallDb (S.Set BuildCfg) 24 | installedPackages f s = fmap (\x -> s { _installedPackages = x }) (f (_installedPackages s)) 25 | 26 | data BuildCfg = BuildCfg { buildName :: String 27 | , buildVersion :: Version 28 | , pinnedBuildDeps :: [(T.Text, Version)] 29 | , pinnedDeps :: [(T.Text, Version)] 30 | , targetArch :: Maybe TargetTriple 31 | , global :: Bool 32 | , configureCmds :: [ Command ] 33 | , buildCmds :: [ Command ] 34 | , installCmds :: [ Command ] 35 | -- , tarball :: FilePath 36 | , manual :: Bool -- ^ Was this package manually installed? 37 | } deriving (Eq, Ord, Generic, Binary, Hashable) 38 | -------------------------------------------------------------------------------- /src/Package/C/Unpack.hs: -------------------------------------------------------------------------------- 1 | module Package.C.Unpack ( unpackResponse 2 | , Compression (..) 3 | , TarCompress (..) 4 | ) where 5 | 6 | import qualified Codec.Archive as Archive 7 | import Codec.Archive.Zip (ZipOption (..), extractFilesFromArchive, toArchive) 8 | import qualified Codec.Compression.BZip as Bzip 9 | import qualified Codec.Compression.GZip as Gzip 10 | import qualified Codec.Compression.Lzma as Lzma 11 | import qualified Codec.Compression.Zstd.Lazy as Zstd 12 | import qualified Codec.Lzip as Lzip 13 | import Control.Exception (throw) 14 | import qualified Data.ByteString.Lazy as BSL 15 | import System.Directory 16 | 17 | data TarCompress = Gz 18 | | Xz 19 | | Bz2 20 | | Lz 21 | | Zstd 22 | | None 23 | 24 | data Compression = Tar TarCompress 25 | | Zip 26 | 27 | 28 | getCompressor :: TarCompress -> BSL.ByteString -> BSL.ByteString 29 | getCompressor Gz = Gzip.decompress 30 | getCompressor None = id 31 | getCompressor Xz = Lzma.decompress 32 | getCompressor Bz2 = Bzip.decompress 33 | getCompressor Lz = Lzip.decompress 34 | getCompressor Zstd = Zstd.decompress 35 | 36 | archiveResponse :: TarCompress -> FilePath -> BSL.ByteString -> IO () 37 | archiveResponse compressScheme dirName = 38 | Archive.throwArchiveM . Archive.unpackToDirLazy dirName . getCompressor compressScheme 39 | 40 | zipResponse :: FilePath -> BSL.ByteString -> IO () 41 | zipResponse dirName response = withCurrentDirectory dirName $ do 42 | let options = OptDestination dirName 43 | extractFilesFromArchive [options] (toArchive response) 44 | 45 | unpackResponse :: Compression -> FilePath -> BSL.ByteString -> IO () 46 | unpackResponse (Tar tarCmp) fp response = archiveResponse tarCmp fp response 47 | unpackResponse Zip fp response = zipResponse fp response 48 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # cpkg 2 | 3 | ## 0.2.5.0 4 | 5 | * Add `package set:` info to `dhall --version` 6 | 7 | ## 0.2.4.2 8 | 9 | * Support `aarch64` 10 | 11 | ## 0.2.4.1 12 | 13 | * Use `bz2` in place of `bzlib` for now 14 | 15 | ## 0.2.4.0 16 | 17 | * Use [`libarchive`](http://hackage.haskell.org/package/libarchive) exclusively 18 | 19 | ## 0.2.3.8 20 | 21 | * Support `.zst` via [zstd](http://hackage.haskell.org/package/zstd) library 22 | * Pin new Dhall package set 23 | 24 | ## 0.2.3.7 25 | 26 | * Pin package 27 | 28 | ## 0.2.3.6 29 | 30 | * Use `dhall` 1.27.0 31 | 32 | ## 0.2.3.5 33 | 34 | * Use `lzlib` 0.3.0.0 35 | 36 | ## 0.2.3.4 37 | 38 | * Use `libarchive` 2.0.0.0 39 | 40 | ## 0.2.3.3 41 | 42 | * Add `find` subcommand 43 | 44 | ## 0.2.3.2 45 | 46 | * Add `.lz` support 47 | 48 | ## 0.2.3.1 49 | 50 | * Now works with Dhall 1.25.0 on a sufficiently new GHC 51 | 52 | ## 0.2.3.0 53 | 54 | * Add `garbage-collect` subcommand 55 | * Add `uninstall` subcommand 56 | * Add `nuke-cache` subcommand 57 | 58 | ## 0.2.2.0 59 | 60 | * Add `printLdLibFlags` function and add functionality to CLI interface 61 | * `cfg.installDir` is now absolute 62 | 63 | ## 0.2.1.0 64 | 65 | * Add `SymlinkManpage` command 66 | 67 | ## 0.2.0.1 68 | 69 | * Pass `-p0` option to `patch` 70 | 71 | ## 0.2.0.0 72 | 73 | * Support more MIPS architectures 74 | 75 | ## 0.1.3.1 76 | 77 | * Don't install build-tool dependencies globally 78 | 79 | ## 0.1.3.0 80 | 81 | * Add ability to patch libraries 82 | 83 | ## 0.1.2.1 84 | 85 | * Add `--global` flag 86 | 87 | ## 0.1.2.0 88 | 89 | * Export `Dep` 90 | 91 | ## 0.1.1.1 92 | 93 | * Stream using `libarchive` lazily 94 | 95 | ## 0.1.1.0 96 | 97 | * Export `EnvVar` 98 | * Better diagnostic output 99 | * Fix bug where cross dependencies' `bin/` directory was added to `PATH` for 100 | subsequent package builds 101 | * Allow use of `libarchive` for packages that cannot be handled with the `tar` 102 | library 103 | 104 | ## 0.1.0.0 105 | 106 | Initial release 107 | -------------------------------------------------------------------------------- /src/CPkgPrelude.hs: -------------------------------------------------------------------------------- 1 | module CPkgPrelude ( -- * Base reëxports 2 | Generic 3 | , Natural 4 | , void 5 | , when 6 | , unless 7 | , traverse_ 8 | , fold 9 | , toList 10 | , filterM 11 | , forM_ 12 | , ($>) 13 | , (<=<) 14 | , (<=*<) 15 | , MonadIO (..) 16 | , Void 17 | -- * Dhall reëxports 18 | , ToDhall 19 | , FromDhall 20 | -- * hashable reëxports 21 | , Hashable 22 | -- * Exports from "Data.Binary" 23 | , Binary 24 | -- prettyprinter reëxports 25 | , Doc 26 | , Pretty (..) 27 | , punctuate 28 | -- * microlens reëxports 29 | , Lens' 30 | , over 31 | -- * Exports from "System.FilePath" 32 | , () 33 | -- * Exports from "System.Directory" 34 | , doesFileExist 35 | , removeDirectoryRecursive 36 | , getAppUserDataDirectory 37 | ) where 38 | 39 | import Control.Composition ((<=*<)) 40 | import Control.Monad 41 | import Control.Monad.IO.Class (MonadIO (..)) 42 | import Data.Binary (Binary) 43 | import Data.Foldable 44 | import Data.Functor (($>)) 45 | import Data.Hashable (Hashable) 46 | import Data.Text.Prettyprint.Doc 47 | import Data.Void (Void) 48 | import Dhall (FromDhall, ToDhall) 49 | import GHC.Generics (Generic) 50 | import GHC.Natural (Natural) 51 | import Lens.Micro (Lens', over) 52 | import System.Directory 53 | import System.FilePath (()) 54 | -------------------------------------------------------------------------------- /src/Package/C.hs: -------------------------------------------------------------------------------- 1 | module Package.C ( 2 | -- * Types 3 | CPkg (..) 4 | , BuildVars (..) 5 | , Version (..) 6 | , Verbosity (..) 7 | , TargetTriple (..) 8 | , Command (..) 9 | , OS (..) 10 | , Arch (..) 11 | , Manufacturer (..) 12 | , ABI (..) 13 | , InstallDb (..) 14 | , BuildCfg (..) 15 | , EnvVar (..) 16 | , MonadDb 17 | , PkgM 18 | , Platform 19 | , Dep (..) 20 | -- * Functions 21 | , buildCPkg 22 | , runPkgM 23 | , globalPkgDir 24 | , printLinkerFlags 25 | , printCompilerFlags 26 | , printPkgConfigPath 27 | , printIncludePath 28 | , printLibPath 29 | , printLdLibPath 30 | , printCabalFlags 31 | , buildByName 32 | , uninstallPkgByName 33 | , garbageCollect 34 | , cleanCache 35 | -- * Dhall functionality 36 | , cPkgDhallToCPkg 37 | , getCPkg 38 | , getPkgs 39 | -- * Packaging 40 | , displayPackageSet 41 | , displayPackage 42 | , allPackages 43 | -- * Parsers 44 | , parseTriple 45 | , parseTripleIO 46 | , parseHostIO 47 | -- * Version 48 | , defaultPackageSetHash 49 | ) where 50 | 51 | import Package.C.Build 52 | import Package.C.Build.Tree 53 | import Package.C.Db.GarbageCollect 54 | import Package.C.Db.Monad 55 | import Package.C.Db.Register 56 | import Package.C.Db.Type 57 | import Package.C.Dhall 58 | import Package.C.Monad 59 | import Package.C.PackageSet 60 | import Package.C.Triple 61 | import Package.C.Type 62 | -------------------------------------------------------------------------------- /src/Package/C/Error.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | 3 | module Package.C.Error ( printErr 4 | , unrecognized 5 | , indexError 6 | , corruptedDatabase 7 | , unfoundPackage 8 | , parseErr 9 | , notInstalled 10 | , PackageError (..) 11 | ) where 12 | 13 | import CPkgPrelude 14 | import Data.Text.Prettyprint.Doc 15 | import Data.Text.Prettyprint.Doc.Custom 16 | import Data.Text.Prettyprint.Doc.Render.Text 17 | import System.Exit 18 | 19 | data PackageError = Unrecognized String 20 | | IndexError String -- package name 21 | | CorruptedDatabase 22 | | UnfoundPackage -- TODO: this should take the package name as an argument 23 | | NotInstalled String 24 | | ParseFailed String 25 | -- TODO: libarchive error 26 | 27 | instance Pretty PackageError where 28 | pretty (Unrecognized t) = "Error: Unrecognized archive format when unpacking" <#> hang 2 (pretty t) <> hardline 29 | pretty (IndexError str) = "Error: Package" <+> pretty str <+> "not found in your indices. Try 'cpkg install" <+> pretty str <> "'." <> hardline 30 | pretty CorruptedDatabase = "Error: Package database corrupted. Please try 'cpkg nuke'" <> hardline 31 | pretty UnfoundPackage = "Error: Package not found" <> hardline 32 | pretty (ParseFailed str) = "Parse error:" <+> pretty str 33 | pretty (NotInstalled pkg) = "Package" <+> pretty pkg <+> "is not installed, so not removed." <> hardline 34 | 35 | printErr :: MonadIO m => PackageError -> m a 36 | printErr e = liftIO (putDoc (pretty e) *> exitFailure) 37 | 38 | notInstalled :: MonadIO m => String -> m a 39 | notInstalled = printErr . NotInstalled 40 | 41 | unrecognized :: MonadIO m => String -> m a 42 | unrecognized = printErr . Unrecognized 43 | 44 | indexError :: MonadIO m => String -> m a 45 | indexError = printErr . IndexError 46 | 47 | corruptedDatabase :: MonadIO m => m a 48 | corruptedDatabase = printErr CorruptedDatabase 49 | 50 | unfoundPackage :: MonadIO m => m a 51 | unfoundPackage = printErr UnfoundPackage 52 | 53 | parseErr :: MonadIO m => String -> m a 54 | parseErr = printErr . ParseFailed 55 | -------------------------------------------------------------------------------- /pkgs/patches/intltool.patch: -------------------------------------------------------------------------------- 1 | --- intltool-update.in 2015-03-08 20:39:54.000000000 -0500 2 | +++ intltool-update.in 2019-06-19 20:58:02.349782444 -0500 3 | @@ -1062,13 +1062,13 @@ 4 | } 5 | } 6 | 7 | - if ($str =~ /^(.*)\${?([A-Z_]+)}?(.*)$/) 8 | + if ($str =~ /^(.*)\$\{?([A-Z_]+)}?(.*)$/) 9 | { 10 | my $rest = $3; 11 | my $untouched = $1; 12 | my $sub = ""; 13 | # Ignore recursive definitions of variables 14 | - $sub = $varhash{$2} if defined $varhash{$2} and $varhash{$2} !~ /\${?$2}?/; 15 | + $sub = $varhash{$2} if defined $varhash{$2} and $varhash{$2} !~ /\$\{?$2}?/; 16 | 17 | return SubstituteVariable ("$untouched$sub$rest"); 18 | } 19 | @@ -1190,10 +1190,10 @@ 20 | $name =~ s/\(+$//g; 21 | $version =~ s/\(+$//g; 22 | 23 | - $varhash{"PACKAGE_NAME"} = $name if (not $name =~ /\${?AC_PACKAGE_NAME}?/); 24 | - $varhash{"PACKAGE"} = $name if (not $name =~ /\${?PACKAGE}?/); 25 | - $varhash{"PACKAGE_VERSION"} = $version if (not $name =~ /\${?AC_PACKAGE_VERSION}?/); 26 | - $varhash{"VERSION"} = $version if (not $name =~ /\${?VERSION}?/); 27 | + $varhash{"PACKAGE_NAME"} = $name if (not $name =~ /\$\{?AC_PACKAGE_NAME}?/); 28 | + $varhash{"PACKAGE"} = $name if (not $name =~ /\$\{?PACKAGE}?/); 29 | + $varhash{"PACKAGE_VERSION"} = $version if (not $name =~ /\$\{?AC_PACKAGE_VERSION}?/); 30 | + $varhash{"VERSION"} = $version if (not $name =~ /\$\{?VERSION}?/); 31 | } 32 | 33 | if ($conf_source =~ /^AC_INIT\(([^,\)]+),([^,\)]+)[,]?([^,\)]+)?/m) 34 | @@ -1219,11 +1219,11 @@ 35 | $version =~ s/\(+$//g; 36 | $bugurl =~ s/\(+$//g if (defined $bugurl); 37 | 38 | - $varhash{"PACKAGE_NAME"} = $name if (not $name =~ /\${?AC_PACKAGE_NAME}?/); 39 | - $varhash{"PACKAGE"} = $name if (not $name =~ /\${?PACKAGE}?/); 40 | - $varhash{"PACKAGE_VERSION"} = $version if (not $name =~ /\${?AC_PACKAGE_VERSION}?/); 41 | - $varhash{"VERSION"} = $version if (not $name =~ /\${?VERSION}?/); 42 | - $varhash{"PACKAGE_BUGREPORT"} = $bugurl if (defined $bugurl and not $bugurl =~ /\${?\w+}?/); 43 | + $varhash{"PACKAGE_NAME"} = $name if (not $name =~ /\$\{?AC_PACKAGE_NAME}?/); 44 | + $varhash{"PACKAGE"} = $name if (not $name =~ /\$\{?PACKAGE}?/); 45 | + $varhash{"PACKAGE_VERSION"} = $version if (not $name =~ /\$\{?AC_PACKAGE_VERSION}?/); 46 | + $varhash{"VERSION"} = $version if (not $name =~ /\$\{?VERSION}?/); 47 | + $varhash{"PACKAGE_BUGREPORT"} = $bugurl if (defined $bugurl and not $bugurl =~ /\$\{?\w+}?/); 48 | } 49 | 50 | # \s makes this not work, why? 51 | -------------------------------------------------------------------------------- /dhall/cpkg-types.dhall: -------------------------------------------------------------------------------- 1 | let OS = 2 | < FreeBSD 3 | | OpenBSD 4 | | NetBSD 5 | | Solaris 6 | | Dragonfly 7 | | Linux 8 | | Darwin 9 | | Windows 10 | | Redox 11 | | Haiku 12 | | IOS 13 | | AIX 14 | | Hurd 15 | | Android 16 | | NoOs 17 | > 18 | 19 | let Arch = 20 | < X64 21 | | AArch 22 | | Arm 23 | | RISCV64 24 | | PowerPC 25 | | PowerPC64 26 | | PowerPC64le 27 | | Sparc64 28 | | S390x 29 | | Alpha 30 | | M68k 31 | | Mips 32 | | MipsEl 33 | | Mips64 34 | | Mips64El 35 | | X86 36 | | SH4 37 | | HPPA 38 | | HPPA64 39 | | MipsIsa32r6El 40 | | MipsIsa32r6 41 | | MipsIsa64r6El 42 | | MipsIsa64r6 43 | > 44 | 45 | let Manufacturer = < Unknown | Apple | IBM | PC > 46 | 47 | let ABI = < GNU | GNUabi64 | GNUeabi | GNUeabihf | GNUspe | MinGw > 48 | 49 | let TargetTriple = 50 | { arch : Arch 51 | , manufacturer : Optional Manufacturer 52 | , os : OS 53 | , abi : Optional ABI 54 | } 55 | 56 | let BuildVars = 57 | { installDir : Text 58 | , currentDir : Text 59 | , targetTriple : Optional TargetTriple 60 | , isCross : Bool 61 | , includeDirs : List Text 62 | , preloadLibs : List Text 63 | , shareDirs : List Text 64 | , linkDirs : List Text 65 | , binDirs : List Text 66 | , buildOS : OS 67 | , buildArch : Arch 68 | , static : Bool 69 | , cpus : Natural 70 | } 71 | 72 | let VersionBound = 73 | < Lower : { lower : List Natural } 74 | | Upper : { upper : List Natural } 75 | | LowerUpper : { lower : List Natural, upper : List Natural } 76 | | NoBound 77 | > 78 | 79 | let Dep = { name : Text, bound : VersionBound } 80 | 81 | let EnvVar = { var : Text, value : Text } 82 | 83 | let Proc = 84 | { program : Text 85 | , arguments : List Text 86 | , environment : Optional (List EnvVar) 87 | , procDir : Optional Text 88 | } 89 | 90 | let Command = 91 | < CreateDirectory : { dir : Text } 92 | | MakeExecutable : { file : Text } 93 | | Call : Proc 94 | | SymlinkBinary : { file : Text } 95 | | SymlinkManpage : { file : Text, section : Natural } 96 | | Symlink : { tgt : Text, linkName : Text } 97 | | Write : { file : Text, contents : Text } 98 | | CopyFile : { src : Text, dest : Text } 99 | | Patch : { patchContents : Text } 100 | > 101 | 102 | in { OS 103 | , BuildVars 104 | , VersionBound 105 | , Dep 106 | , Arch 107 | , Manufacturer 108 | , ABI 109 | , TargetTriple 110 | , Command 111 | , EnvVar 112 | , Proc 113 | } 114 | -------------------------------------------------------------------------------- /src/Package/C/Fetch.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | 3 | module Package.C.Fetch ( fetchUrl 4 | ) where 5 | 6 | import CPkgPrelude 7 | import qualified Data.ByteString.Lazy as BSL 8 | import Data.List (isSuffixOf) 9 | import Data.Maybe (fromJust) 10 | import Network.HTTP.Client 11 | import Network.HTTP.Client.TLS (tlsManagerSettings) 12 | import Network.URI 13 | import Package.C.Db.Register 14 | import Package.C.Error 15 | import Package.C.Logging 16 | import Package.C.Monad 17 | import Package.C.Unpack 18 | import System.Directory (createDirectoryIfMissing) 19 | import System.FilePath (takeFileName) 20 | 21 | urlToCompression :: MonadIO m => String -> m Compression 22 | urlToCompression s | ".tar.gz" `isSuffixOf` s || ".tgz" `isSuffixOf` s = pure $ Tar Gz 23 | | ".tar.xz" `isSuffixOf` s || ".txz" `isSuffixOf` s = pure $ Tar Xz 24 | | ".tar.bz2" `isSuffixOf` s = pure $ Tar Bz2 25 | | ".tar.lz" `isSuffixOf` s = pure $ Tar Lz 26 | | ".tar.zst" `isSuffixOf` s = pure $ Tar Zstd 27 | | ".tar" `isSuffixOf` s = pure $ Tar None 28 | | ".zip" `isSuffixOf` s = pure Zip 29 | | otherwise = unrecognized s 30 | 31 | asFilename :: String -> Maybe String 32 | asFilename = fmap (takeFileName . uriPath) . parseURI 33 | 34 | cacheDir :: MonadIO m => m FilePath 35 | cacheDir = ( "cache") <$> globalPkgDir 36 | 37 | fetchUrl :: String -- ^ URL 38 | -> String -- ^ Package name 39 | -> FilePath -- ^ Directory to unpack to 40 | -> PkgM () 41 | fetchUrl url name dirName = do 42 | 43 | let tarballName = fromJust (asFilename url) 44 | tarballDir <- ( tarballName) <$> cacheDir 45 | shouldDownload <- not <$> liftIO (doesFileExist tarballDir) 46 | 47 | compression <- urlToCompression url 48 | 49 | response <- 50 | if shouldDownload 51 | then do 52 | putNormal ("Downloading " ++ name) 53 | 54 | putLoud ("from URL " ++ url) 55 | 56 | manager <- liftIO $ newManager tlsManagerSettings 57 | initialRequest <- liftIO $ parseRequest url 58 | liftIO $ responseBody <$> httpLbs (initialRequest { method = "GET" }) manager 59 | else do 60 | putDiagnostic ("Using cached tarball at " ++ tarballDir) 61 | liftIO $ BSL.readFile tarballDir 62 | 63 | cacheDirExists <- liftIO (doesFileExist =<< cacheDir) 64 | unless cacheDirExists 65 | (liftIO $ createDirectoryIfMissing True =<< cacheDir) 66 | 67 | when shouldDownload $ do 68 | -- TODO: should cache/compress to .tar.xz? 69 | putLoud ("Caching " ++ tarballName) 70 | liftIO $ BSL.writeFile tarballDir response 71 | 72 | putNormal ("Unpacking " ++ name) 73 | 74 | liftIO $ unpackResponse compression dirName response 75 | -------------------------------------------------------------------------------- /src/Package/C/Triple/Parse.hs: -------------------------------------------------------------------------------- 1 | module Package.C.Triple.Parse ( parseTriple 2 | , parseTripleIO 3 | ) where 4 | 5 | import CPkgPrelude 6 | import Package.C.Error 7 | import Package.C.Triple.Type 8 | import Text.Megaparsec 9 | import Text.Megaparsec.Char 10 | 11 | type Parser = Parsec Void String 12 | 13 | parseTripleIO :: MonadIO m => String -> m TargetTriple 14 | parseTripleIO = parseIO parseTriple 15 | 16 | parseIO :: MonadIO m => Parser a -> String -> m a 17 | parseIO p str = 18 | case parse p "(none)" str of 19 | Right x -> pure x 20 | Left err -> parseErr (errorBundlePretty err) 21 | 22 | parseTriple :: Parser TargetTriple 23 | parseTriple = TargetTriple 24 | <$> parseArch 25 | <*> optional (try (char '-' *> parseManufacturer)) 26 | <*> (char '-' *> parseOS) 27 | <*> optional (char '-' *> parseABI) 28 | 29 | tryString :: String -> Parser String 30 | tryString = try . string 31 | 32 | parseArch :: Parser Arch 33 | parseArch = 34 | (tryString "x86_64" $> X64) 35 | <|> (tryString "armv7l" $> Arm) 36 | <|> (tryString "arm" $> Arm) 37 | <|> (tryString "aarch64" $> AArch) 38 | <|> (tryString "riscv64" $> RISCV64) 39 | <|> (tryString "powerpc64le" $> PowerPC64le) 40 | <|> (tryString "powerpc64" $> PowerPC64) 41 | <|> (tryString "powerpc" $> PowerPC) 42 | <|> (tryString "sparc64" $> Sparc64) 43 | <|> (tryString "s390x" $> S390x) 44 | <|> (tryString "alpha" $> Alpha) 45 | <|> (tryString "m68k" $> M68k) 46 | <|> (tryString "mipsisa32r6el" $> MipsIsa32r6El) 47 | <|> (tryString "mipsisa32r6" $> MipsIsa32r6) 48 | <|> (tryString "mipsisa64r6el" $> MipsIsa64r6El) 49 | <|> (tryString "mipsisa64r6" $> MipsIsa64r6) 50 | <|> (tryString "mips64el" $> Mips64El) 51 | <|> (tryString "mips64" $> Mips64) 52 | <|> (tryString "mipsel" $> MipsEl) 53 | <|> (tryString "mips" $> Mips) 54 | <|> (tryString "i686" $> X86) 55 | <|> (tryString "sh4" $> SH4) 56 | <|> (tryString "hppa64" $> HPPA64) 57 | <|> (tryString "hppa" $> HPPA) 58 | 59 | parseManufacturer :: Parser Manufacturer 60 | parseManufacturer = 61 | (tryString "unknown" $> Unknown) 62 | <|> (tryString "apple" $> Apple) 63 | <|> (tryString "ibm" $> IBM) 64 | <|> (tryString "pc" $> PC) 65 | 66 | parseOS :: Parser OS 67 | parseOS = 68 | (tryString "darwin" $> Darwin) 69 | <|> (tryString "dragonfly" $> Dragonfly) 70 | <|> (tryString "freebsd" $> FreeBSD) 71 | <|> (tryString "linux" $> Linux) 72 | <|> (tryString "openbsd" $> OpenBSD) 73 | <|> (tryString "netbsd" $> NetBSD) 74 | <|> (tryString "solaris" $> Solaris) 75 | <|> (tryString "w64" $> Windows) 76 | <|> (tryString "redox" $> Redox) 77 | <|> (tryString "haiku" $> Haiku) 78 | <|> (tryString "ios" $> IOS) 79 | <|> (tryString "aix" $> AIX) 80 | <|> (tryString "hurd" $> Hurd) 81 | <|> (tryString "android" $> Android) 82 | <|> (tryString "none" $> NoOs) 83 | 84 | parseABI :: Parser ABI 85 | parseABI = 86 | (tryString "gnueabihf" $> GNUeabihf) 87 | <|> (tryString "gnuabi64" $> GNUabi64) 88 | <|> (tryString "gnueabi" $> GNUeabi) 89 | <|> (tryString "gnuspe" $> GNUspe) 90 | <|> (tryString "gnu" $> GNU) 91 | <|> (tryString "mingw32" $> MinGw) 92 | -------------------------------------------------------------------------------- /src/Package/C/Db/GarbageCollect.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE FlexibleContexts #-} 2 | 3 | module Package.C.Db.GarbageCollect ( cleanSymlinks 4 | , cleanCache 5 | , garbageCollect 6 | ) where 7 | 8 | import Control.Monad.Reader (MonadReader) 9 | import CPkgPrelude 10 | import qualified Data.Set as S 11 | import qualified Data.Text as T 12 | import Package.C.Db.Memory (globalPkgDir) 13 | import Package.C.Db.Monad (MonadDb) 14 | import Package.C.Db.Register 15 | import Package.C.Db.Type 16 | import Package.C.Logging (putDiagnostic) 17 | import Package.C.Type (TargetTriple, Verbosity) 18 | import System.Directory (doesDirectoryExist, doesFileExist, getSymbolicLinkTarget, listDirectory, removeDirectoryRecursive, removeFile) 19 | import System.FilePath (()) 20 | 21 | getTransitiveDepsByName :: (MonadIO m, MonadDb m) => String -> Maybe TargetTriple -> m (S.Set BuildCfg) 22 | getTransitiveDepsByName = getTransitiveDeps <=*< lookupOrFail 23 | 24 | garbageCollect :: (MonadIO m, MonadDb m, MonadReader Verbosity m) 25 | => m () 26 | garbageCollect = garbageCollectPkgs *> cleanSymlinks 27 | 28 | -- TODO: garbage collect old packages as well, and things which are broken b/c 29 | -- their dependencies are gone 30 | -- 31 | -- | @since 0.2.3.0 32 | garbageCollectPkgs :: (MonadIO m, MonadDb m, MonadReader Verbosity m) 33 | => m () 34 | garbageCollectPkgs = do 35 | allPkgs <- installedDb 36 | let manuals = (toList . S.filter manual) allPkgs 37 | putDiagnostic ("Manually installed packages: " ++ show (buildName <$> manuals)) 38 | allDeps <- S.unions <$> traverse getTransitiveDeps manuals 39 | let redundant = allPkgs S.\\ allDeps 40 | putDiagnostic ("Redundant packages: " ++ show (buildName <$> toList redundant)) 41 | traverse_ uninstallPkg redundant 42 | 43 | getTransitiveDeps :: (MonadIO m, MonadDb m) => BuildCfg -> m (S.Set BuildCfg) 44 | getTransitiveDeps cfg = do 45 | let names = fst <$> pinnedDeps cfg 46 | host = targetArch cfg 47 | next <- traverse (\n -> getTransitiveDepsByName n host) (T.unpack <$> names) 48 | pure $ S.insert cfg (S.unions next) 49 | 50 | -- | @since 0.2.3.0 51 | cleanCache :: MonadIO m => m () 52 | cleanCache = liftIO $ do 53 | ccDir <- ( "cache") <$> globalPkgDir 54 | exists <- doesDirectoryExist ccDir 55 | when exists $ 56 | removeDirectoryRecursive ccDir 57 | 58 | cleanSymlinks :: (MonadReader Verbosity m, MonadIO m) => m () 59 | cleanSymlinks = do 60 | pkDir <- liftIO globalPkgDir 61 | let binDir = pkDir "bin" 62 | manDir = pkDir "share" "man" 63 | man1Dir = manDir "man1" 64 | man3Dir = manDir "man3" 65 | traverse_ cleanDir 66 | [binDir, man1Dir, man3Dir] 67 | 68 | 69 | cleanDir :: (MonadReader Verbosity m, MonadIO m) => FilePath -> m () 70 | cleanDir dir = do 71 | exists <- liftIO $ doesDirectoryExist dir 72 | when exists $ do 73 | links <- liftIO $ listDirectory dir 74 | forM_ links $ \link -> do 75 | let linkAbs = dir link 76 | brk <- liftIO $ isBroken linkAbs 77 | when brk $ 78 | putDiagnostic ("Removing link " ++ linkAbs ++ "...") *> 79 | liftIO (removeFile linkAbs) 80 | 81 | isBroken :: FilePath -> IO Bool 82 | isBroken = (fmap not . doesFileExist) <=< getSymbolicLinkTarget 83 | 84 | -- getSymbolicLinkTarget 85 | -------------------------------------------------------------------------------- /src/Package/C/Dhall/Type.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DeriveAnyClass #-} 2 | {-# LANGUAGE DeriveGeneric #-} 3 | {-# LANGUAGE OverloadedStrings #-} 4 | 5 | module Package.C.Dhall.Type ( CPkg (..) 6 | , BuildVars (..) 7 | , EnvVar (..) 8 | , Command (..) 9 | ) where 10 | 11 | import qualified Data.Text as T 12 | import Data.Text.Prettyprint.Doc 13 | import Data.Text.Prettyprint.Doc.Custom 14 | import Dhall 15 | import GHC.Natural (Natural) 16 | import Package.C.Triple.Type 17 | import Package.C.Type.Shared 18 | import Package.C.Type.Version 19 | 20 | data BuildVars = BuildVars { installDir :: T.Text 21 | , currentDir :: T.Text 22 | , targetTriple :: Maybe TargetTriple 23 | , isCross :: Bool 24 | , includeDirs :: [ T.Text ] 25 | , preloadLibs :: [ T.Text ] 26 | -- TODO: nameToLinkDir function?? 27 | , shareDirs :: [ T.Text ] 28 | , linkDirs :: [ T.Text ] 29 | , binDirs :: [ T.Text ] 30 | , buildOS :: OS 31 | , buildArch :: Arch 32 | , static :: Bool 33 | , cpus :: Natural 34 | } deriving (Generic, ToDhall) 35 | 36 | data EnvVar = EnvVar { var :: T.Text, value :: T.Text } 37 | deriving (Generic, FromDhall) 38 | 39 | data Command = CreateDirectory { dir :: T.Text } 40 | | MakeExecutable { file :: T.Text } 41 | | Call { program :: T.Text 42 | , arguments :: [T.Text] 43 | , environment :: Maybe [EnvVar] 44 | , procDir :: Maybe T.Text 45 | } 46 | | SymlinkBinary { file :: T.Text } 47 | | SymlinkManpage { file :: T.Text, section :: Natural } 48 | | Symlink { tgt :: T.Text, linkName :: T.Text } 49 | | Write { contents :: T.Text, file :: T.Text } 50 | | CopyFile { src :: T.Text, dest :: T.Text } 51 | | Patch { patchContents :: T.Text } 52 | deriving (Generic, FromDhall) 53 | 54 | data CPkg = CPkg { pkgName :: T.Text 55 | , pkgVersion :: [ Natural ] 56 | , pkgUrl :: T.Text 57 | , pkgSubdir :: T.Text 58 | , pkgBuildDeps :: [ Dep ] -- TODO: depend on target? 59 | , pkgDeps :: [ Dep ] 60 | , configureCommand :: BuildVars -> [ Command ] 61 | , buildCommand :: BuildVars -> [ Command ] 62 | , installCommand :: BuildVars -> [ Command ] 63 | -- TODO: add "description" field for printing 64 | -- TODO: add "test" command for e.g. `make check` 65 | } deriving (Generic, FromDhall) 66 | 67 | preDeps :: Doc a -> [ Dep ] -> Doc a 68 | preDeps _ [] = "" 69 | preDeps dep ds = hardline <> dep <+> hsep (punctuate "," (pretty . name <$> ds)) 70 | 71 | prettyDeps :: [ Dep ] -> Doc a 72 | prettyDeps = preDeps "dependencies:" 73 | 74 | prettyBldDeps :: [ Dep ] -> Doc a 75 | prettyBldDeps = preDeps "build dependencies:" 76 | 77 | instance Pretty CPkg where 78 | pretty (CPkg nam v url _ bds ds _ _ _) = pretty nam <##> indent 4 ("url:" <+> pretty url <##> "version:" <+> pretty (Version v) <> prettyDeps ds <> prettyBldDeps bds) 79 | -------------------------------------------------------------------------------- /src/Package/C/PackageSet.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE GeneralizedNewtypeDeriving #-} 2 | {-# LANGUAGE OverloadedStrings #-} 3 | 4 | module Package.C.PackageSet ( PackageSet (..) 5 | , PackId 6 | , pkgsM 7 | , displayPackageSet 8 | , displayPackage 9 | , defaultPackageSetHash 10 | ) where 11 | 12 | import CPkgPrelude 13 | import Data.Containers.ListUtils 14 | import Data.List (find, intersperse) 15 | import qualified Data.Map as M 16 | import qualified Data.Text as T 17 | import Data.Text.Prettyprint.Doc 18 | import Data.Text.Prettyprint.Doc.Custom 19 | import Data.Text.Prettyprint.Doc.Render.Text 20 | import Dhall hiding (maybe) 21 | import qualified Package.C.Dhall.Type as Dhall 22 | import Package.C.Error 23 | import Package.C.Type 24 | import Package.C.Type.Tree 25 | 26 | defaultPackageSetHash :: T.Text 27 | defaultPackageSetHash = "sha256:172035e1adc2b2f0e4035e943125f6c7afb53e2e0055313709d0c4208eb83850" 28 | 29 | defaultPackageSetDhall :: Maybe String -> IO PackageSetDhall 30 | defaultPackageSetDhall (Just pkSet) = input auto (T.pack pkSet) 31 | defaultPackageSetDhall Nothing = input auto ("https://raw.githubusercontent.com/vmchale/cpkg/a82629bc65449b66c0ab337faaeb0d12096675f6/pkgs/pkg-set.dhall " <> defaultPackageSetHash) 32 | 33 | 34 | displayPackageSet :: Maybe String -> IO () 35 | displayPackageSet = putDoc . pretty <=< defaultPackageSetDhall 36 | 37 | displayPackage :: String -> IO () 38 | displayPackage str = do 39 | pk <- find (\ps -> T.unpack (Dhall.pkgName ps) == str) . listPackages <$> defaultPackageSetDhall Nothing 40 | case pk of 41 | Just p -> putDoc (pretty p <> hardline) 42 | Nothing -> unfoundPackage 43 | 44 | newtype PackageSetDhall = PackageSetDhall { listPackages :: [ Dhall.CPkg ] } 45 | deriving FromDhall 46 | 47 | instance Pretty PackageSetDhall where 48 | pretty (PackageSetDhall set) = vdisplay (intersperse hardline (pretty <$> set)) <> hardline 49 | 50 | newtype PackageSet = PackageSet (M.Map T.Text CPkg) 51 | 52 | type PackId = T.Text 53 | 54 | packageSetDhallToPackageSet :: PackageSetDhall -> PackageSet 55 | packageSetDhallToPackageSet (PackageSetDhall pkgs'') = 56 | let names = Dhall.pkgName <$> pkgs'' 57 | pkgs' = cPkgDhallToCPkg <$> pkgs'' 58 | 59 | in PackageSet $ M.fromList (zip names pkgs') 60 | 61 | getDeps :: PackId -> Bool -> PackageSet -> Maybe (DepTree PackId) 62 | getDeps pkgName' usr set@(PackageSet ps) = do 63 | cpkg <- M.lookup pkgName' ps 64 | let depNames = name <$> pkgDeps cpkg 65 | bldDepNames = name <$> pkgBuildDeps cpkg 66 | ds = nubOrd depNames 67 | bds = nubOrd bldDepNames 68 | nextDeps <- traverse (\p -> getDeps p False set) ds 69 | nextBldDeps <- traverse (\p -> asBldDep <$> getDeps p False set) bds 70 | pure $ DepNode pkgName' usr (nextDeps ++ nextBldDeps) 71 | 72 | -- TODO: use dfsForest but check for cycles 73 | pkgPlan :: PackId -> PackageSet -> Maybe (DepTree PackId) 74 | pkgPlan pkId = getDeps pkId True -- manually installed 75 | 76 | pkgs :: PackId -> PackageSet -> Maybe (DepTree CPkg) 77 | pkgs pkId set@(PackageSet pset) = do 78 | plan <- pkgPlan pkId set 79 | traverse (`M.lookup` pset) plan 80 | 81 | pkgsM :: PackId -> Maybe String -> IO (DepTree CPkg) 82 | pkgsM pkId pkSet = do 83 | pks <- pkgs pkId . packageSetDhallToPackageSet <$> defaultPackageSetDhall pkSet 84 | maybe unfoundPackage pure pks 85 | -------------------------------------------------------------------------------- /pkgs/patches/pHash.patch: -------------------------------------------------------------------------------- 1 | --- src/cimgffmpeg.cpp 2019-06-22 20:18:05.632517868 -0500 2 | +++ src/cimgffmpeg.cpp 2019-06-22 20:18:45.569003435 -0500 3 | @@ -100,12 +100,12 @@ 4 | AVFrame *pFrame; 5 | 6 | // Allocate video frame 7 | - pFrame=avcodec_alloc_frame(); 8 | + pFrame=av_frame_alloc(); 9 | if (pFrame==NULL) 10 | return -1; 11 | 12 | // Allocate an AVFrame structure 13 | - AVFrame *pConvertedFrame = avcodec_alloc_frame(); 14 | + AVFrame *pConvertedFrame = av_frame_alloc(); 15 | if(pConvertedFrame==NULL) 16 | return -1; 17 | 18 | @@ -254,10 +254,10 @@ 19 | AVFrame *pFrame; 20 | 21 | // Allocate video frame 22 | - pFrame=avcodec_alloc_frame(); 23 | + pFrame=av_frame_alloc(); 24 | 25 | // Allocate an AVFrame structure 26 | - AVFrame *pConvertedFrame = avcodec_alloc_frame(); 27 | + AVFrame *pConvertedFrame = av_frame_alloc(); 28 | if(pConvertedFrame==NULL){ 29 | return -1; 30 | } 31 | --- configure.ac 2019-06-22 21:22:10.582842002 -0500 32 | +++ configure.ac 2019-06-22 21:21:48.962982961 -0500 33 | @@ -122,7 +122,7 @@ 34 | AC_DEFUN([AC_CHECK_FFMPEG], 35 | [ 36 | AC_MSG_CHECKING([whether FFmpeg is present]) 37 | -AC_CHECK_LIB([avcodec], [avcodec_alloc_frame], [], [AC_MSG_ERROR([ 38 | +AC_CHECK_LIB([avutil], [av_frame_alloc], [], [AC_MSG_ERROR([ 39 | 40 | *** libavcodec not found. 41 | You need FFmpeg. Get it at ])]) 42 | --- src/pHash.h 2019-06-23 11:31:15.678771295 -0500 43 | +++ src/pHash.h 2019-06-23 11:31:31.754816275 -0500 44 | @@ -47,6 +47,8 @@ 45 | #if defined(HAVE_IMAGE_HASH) || defined(HAVE_VIDEO_HASH) 46 | #define cimg_debug 0 47 | #define cimg_display 0 48 | +#define cimg_use_png 49 | +#define cimg_use_jpeg 50 | #include "CImg.h" 51 | using namespace cimg_library; 52 | #endif 53 | --- src/cimgffmpeg.cpp 2019-06-22 21:50:15.060403190 -0500 54 | +++ src/cimgffmpeg.cpp 2019-06-22 21:56:50.839827371 -0500 55 | @@ -39,11 +39,11 @@ 56 | int ReadFrames(VFInfo *st_info, CImgList *pFrameList, unsigned int low_index, unsigned int hi_index) 57 | { 58 | //target pixel format 59 | - PixelFormat ffmpeg_pixfmt; 60 | + AVPixelFormat ffmpeg_pixfmt; 61 | if (st_info->pixelformat == 0) 62 | - ffmpeg_pixfmt = PIX_FMT_GRAY8; 63 | + ffmpeg_pixfmt = AV_PIX_FMT_GRAY8; 64 | else 65 | - ffmpeg_pixfmt = PIX_FMT_RGB24; 66 | + ffmpeg_pixfmt = AV_PIX_FMT_RGB24; 67 | 68 | st_info->next_index = low_index; 69 | 70 | @@ -123,7 +123,7 @@ 71 | int size = 0; 72 | 73 | 74 | - int channels = ffmpeg_pixfmt == PIX_FMT_GRAY8 ? 1 : 3; 75 | + int channels = ffmpeg_pixfmt == AV_PIX_FMT_GRAY8 ? 1 : 3; 76 | 77 | AVPacket packet; 78 | int result = 1; 79 | @@ -189,11 +189,11 @@ 80 | 81 | int NextFrames(VFInfo *st_info, CImgList *pFrameList) 82 | { 83 | - PixelFormat ffmpeg_pixfmt; 84 | + AVPixelFormat ffmpeg_pixfmt; 85 | if (st_info->pixelformat == 0) 86 | - ffmpeg_pixfmt = PIX_FMT_GRAY8; 87 | + ffmpeg_pixfmt = AV_PIX_FMT_GRAY8; 88 | else 89 | - ffmpeg_pixfmt = PIX_FMT_RGB24; 90 | + ffmpeg_pixfmt = AV_PIX_FMT_RGB24; 91 | 92 | if (st_info->pFormatCtx == NULL) 93 | { 94 | @@ -287,7 +287,7 @@ 95 | break; 96 | if(packet.stream_index == st_info->videoStream) { 97 | 98 | - int channels = ffmpeg_pixfmt == PIX_FMT_GRAY8 ? 1 : 3; 99 | + int channels = ffmpeg_pixfmt == AV_PIX_FMT_GRAY8 ? 1 : 3; 100 | AVPacket avpkt; 101 | av_init_packet(&avpkt); 102 | avpkt.data = packet.data; 103 | --- src/cimgffmpeg.h 2019-06-23 11:47:59.046307628 -0500 104 | +++ src/cimgffmpeg.h 2019-06-23 11:32:14.754956444 -0500 105 | @@ -30,6 +30,8 @@ 106 | #define cimg_display 0 107 | #define cimg_debug 0 108 | 109 | +#define cimg_use_png 110 | +#define cimg_use_jpeg 111 | #include "CImg.h" 112 | 113 | #define __STDC_CONSTANT_MACROS 114 | -------------------------------------------------------------------------------- /src/Package/C/Type.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DeriveAnyClass #-} 2 | {-# LANGUAGE DeriveGeneric #-} 3 | 4 | module Package.C.Type ( CPkg (..) 5 | , BuildVars (..) 6 | , Verbosity (..) 7 | , EnvVar (..) 8 | , Command (..) 9 | , Dep (..) 10 | , Version (..) 11 | , OS (..) 12 | , TargetTriple (..) 13 | -- * Helper functions 14 | , cPkgDhallToCPkg 15 | , showVersion 16 | ) where 17 | 18 | import CPkgPrelude 19 | import qualified Data.Text as T 20 | import GHC.Generics (Generic) 21 | import qualified Package.C.Dhall.Type as Dhall 22 | import Package.C.Triple.Type 23 | import Package.C.Type.Shared 24 | import Package.C.Type.Vars 25 | import Package.C.Type.Verbosity 26 | import Package.C.Type.Version 27 | 28 | data EnvVar = EnvVar { var :: String, value :: String } 29 | deriving (Eq, Ord, Generic, Binary, Hashable) 30 | 31 | data Command = CreateDirectory { dir :: String } 32 | | MakeExecutable { file :: String } 33 | | Call { program :: String 34 | , arguments :: [String] 35 | , environment :: Maybe [EnvVar] 36 | , procDir :: Maybe String 37 | } 38 | | SymlinkBinary { file :: String } 39 | | SymlinkManpage { file :: String, section :: Int } 40 | | Symlink { tgt :: String, linkName :: String } 41 | | Write { contents :: T.Text, file :: FilePath } 42 | | CopyFile { src :: FilePath, dest :: FilePath } 43 | | Patch { patchContents :: T.Text } 44 | deriving (Eq, Ord, Generic, Binary, Hashable) 45 | 46 | -- TODO: build script should take OS as an argument? 47 | -- That way we can use make/gmake where we want it 48 | data CPkg = CPkg { pkgName :: String 49 | , pkgVersion :: Version 50 | , pkgUrl :: String 51 | , pkgSubdir :: String 52 | , pkgBuildDeps :: [ Dep ] 53 | , pkgDeps :: [ Dep ] 54 | , configureCommand :: BuildVars -> [ Command ] 55 | , buildCommand :: BuildVars -> [ Command ] 56 | , installCommand :: BuildVars -> [ Command ] 57 | } 58 | 59 | envVarDhallToEnvVar :: Dhall.EnvVar -> EnvVar 60 | envVarDhallToEnvVar (Dhall.EnvVar ev x) = EnvVar (T.unpack ev) (T.unpack x) 61 | 62 | commandDhallToCommand :: Dhall.Command -> Command 63 | commandDhallToCommand (Dhall.CreateDirectory d) = CreateDirectory (T.unpack d) 64 | commandDhallToCommand (Dhall.MakeExecutable exe) = MakeExecutable (T.unpack exe) 65 | commandDhallToCommand (Dhall.Call p as env proc) = Call (T.unpack p) (T.unpack <$> as) (fmap envVarDhallToEnvVar <$> env) (T.unpack <$> proc) 66 | commandDhallToCommand (Dhall.SymlinkBinary b) = SymlinkBinary (T.unpack b) 67 | commandDhallToCommand (Dhall.SymlinkManpage b s) = SymlinkManpage (T.unpack b) (fromIntegral s) 68 | commandDhallToCommand (Dhall.Write out fp) = Write out (T.unpack fp) 69 | commandDhallToCommand (Dhall.CopyFile src' dest') = CopyFile (T.unpack src') (T.unpack dest') 70 | commandDhallToCommand (Dhall.Symlink t l) = Symlink (T.unpack t) (T.unpack l) 71 | commandDhallToCommand (Dhall.Patch c) = Patch c 72 | 73 | buildVarsToDhallBuildVars :: BuildVars -> Dhall.BuildVars 74 | buildVarsToDhallBuildVars (BuildVars dir' cd tgt' cross incls prelds shr lds bins os' arch' sta nproc) = Dhall.BuildVars (T.pack dir') (T.pack cd) tgt' cross (T.pack <$> incls) (T.pack <$> prelds) (T.pack <$> shr) (T.pack <$> lds) (T.pack <$> bins) os' arch' sta (fromIntegral nproc) 75 | 76 | cPkgDhallToCPkg :: Dhall.CPkg -> CPkg 77 | cPkgDhallToCPkg (Dhall.CPkg n v url subdir bldDeps deps cfgCmd buildCmd installCmd) = 78 | CPkg (T.unpack n) (Version v) (T.unpack url) (T.unpack subdir) bldDeps deps configure build install 79 | 80 | where configure cfg = commandDhallToCommand <$> cfgCmd (buildVarsToDhallBuildVars cfg) 81 | build cfg = commandDhallToCommand <$> buildCmd (buildVarsToDhallBuildVars cfg) 82 | install cfg = commandDhallToCommand <$> installCmd (buildVarsToDhallBuildVars cfg) 83 | -------------------------------------------------------------------------------- /src/Package/C/Triple/Type.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DeriveAnyClass #-} 2 | {-# LANGUAGE DeriveGeneric #-} 3 | {-# LANGUAGE OverloadedStrings #-} 4 | 5 | module Package.C.Triple.Type ( TargetTriple (..) 6 | , Manufacturer (..) 7 | , Arch (..) 8 | , ABI (..) 9 | , OS (..) 10 | ) where 11 | 12 | import CPkgPrelude 13 | import Data.Text.Prettyprint.Doc.Custom 14 | 15 | -- TODO: are the derived Binary instances inefficient? possibly replace them 16 | -- with handwritten instances... 17 | data TargetTriple = TargetTriple { arch :: Arch 18 | , manufacturer :: Maybe Manufacturer 19 | , os :: OS 20 | , abi :: Maybe ABI 21 | } 22 | deriving (Eq, Ord, Hashable, Binary, Generic, ToDhall) 23 | 24 | instance Pretty TargetTriple where 25 | pretty (TargetTriple a (Just m) o (Just ab)) = dashed [pretty a, pretty m, pretty o, pretty ab] 26 | pretty (TargetTriple a Nothing o (Just ab)) = dashed [pretty a, pretty o, pretty ab] 27 | pretty (TargetTriple a (Just m) o Nothing) = dashed [pretty a, pretty m, pretty o] 28 | pretty (TargetTriple a Nothing o Nothing) = dashed [pretty a, pretty o] 29 | 30 | instance Show TargetTriple where 31 | show = show . pretty 32 | 33 | data Manufacturer = Unknown 34 | | Apple 35 | | IBM 36 | | PC 37 | deriving (Eq, Ord, Hashable, Binary, Generic, ToDhall) 38 | 39 | instance Pretty Manufacturer where 40 | pretty Unknown = "unknown" 41 | pretty Apple = "apple" 42 | pretty IBM = "ibm" 43 | pretty PC = "pc" 44 | 45 | data Arch = X64 46 | | AArch 47 | | Arm 48 | | RISCV64 49 | | PowerPC 50 | | PowerPC64 51 | | PowerPC64le 52 | | Sparc64 53 | | S390x 54 | | Alpha 55 | | M68k 56 | | Mips 57 | | MipsEl 58 | | Mips64 59 | | Mips64El 60 | | X86 61 | | SH4 62 | | HPPA 63 | | HPPA64 64 | | MipsIsa32r6El 65 | | MipsIsa32r6 66 | | MipsIsa64r6El 67 | | MipsIsa64r6 68 | deriving (Eq, Ord, Hashable, Binary, Generic, ToDhall) 69 | 70 | instance Pretty Arch where 71 | pretty X64 = "x86_64" 72 | pretty AArch = "aarch64" 73 | pretty Arm = "arm" 74 | pretty RISCV64 = "riscv64" 75 | pretty PowerPC = "powerpc" 76 | pretty PowerPC64 = "powerpc64" 77 | pretty PowerPC64le = "powerpc64le" 78 | pretty Sparc64 = "sparc64" 79 | pretty S390x = "s390x" 80 | pretty Alpha = "alpha" 81 | pretty M68k = "m68k" 82 | pretty Mips = "mips" 83 | pretty MipsEl = "mipsel" 84 | pretty Mips64 = "mips64" 85 | pretty Mips64El = "mips64el" 86 | pretty X86 = "i686" 87 | pretty SH4 = "sh4" 88 | pretty HPPA = "hppa" 89 | pretty HPPA64 = "hppa64" 90 | pretty MipsIsa32r6El = "mipsisa32r6el" 91 | pretty MipsIsa32r6 = "mipsisa32r6" 92 | pretty MipsIsa64r6El = "mipsisa64r6el" 93 | pretty MipsIsa64r6 = "mipsisa64r6" 94 | 95 | data ABI = GNU 96 | | GNUabi64 97 | | GNUeabi 98 | | GNUeabihf 99 | | GNUspe 100 | | MinGw 101 | deriving (Eq, Ord, Hashable, Binary, Generic, ToDhall) 102 | 103 | instance Pretty ABI where 104 | pretty GNU = "gnu" 105 | pretty GNUabi64 = "gnuabi64" 106 | pretty GNUeabi = "gnueabi" 107 | pretty GNUeabihf = "gnueabihf" 108 | pretty GNUspe = "gnuspe" 109 | pretty MinGw = "mingw32" 110 | 111 | data OS = Darwin 112 | | Dragonfly 113 | | FreeBSD 114 | | Linux 115 | | OpenBSD 116 | | NetBSD 117 | | Solaris 118 | | Windows 119 | | Redox 120 | | Haiku 121 | | IOS 122 | | AIX 123 | | Hurd 124 | | Android 125 | | NoOs 126 | deriving (Eq, Ord, Hashable, Binary, Generic, ToDhall) 127 | -- IRIX? HP UX? 128 | 129 | instance Pretty OS where 130 | pretty Darwin = "darwin" 131 | pretty Dragonfly = "dragonfly" 132 | pretty FreeBSD = "freebsd" 133 | pretty Linux = "linux" 134 | pretty OpenBSD = "openbsd" 135 | pretty NetBSD = "netbsd" 136 | pretty Solaris = "solaris" 137 | pretty Windows = "w64" 138 | pretty Redox = "redox" 139 | pretty Haiku = "haiku" 140 | pretty IOS = "ios" 141 | pretty AIX = "aix" 142 | pretty Hurd = "hurd" 143 | pretty Android = "android" 144 | pretty NoOs = "none" 145 | -------------------------------------------------------------------------------- /cpkg.cabal: -------------------------------------------------------------------------------- 1 | cabal-version: 1.18 2 | name: cpkg 3 | version: 0.2.5.7 4 | license: BSD3 5 | license-file: LICENSE 6 | copyright: Copyright: (c) 2018-2020 Vanessa McHale 7 | maintainer: vamchale@gmail.com 8 | author: Vanessa McHale 9 | synopsis: Build tool for C 10 | description: 11 | A build tool and package manager configured using [Dhall](https://github.com/dhall-lang/dhall-haskell). 12 | 13 | category: Packaging, Package Management, Dhall, C 14 | build-type: Simple 15 | extra-source-files: 16 | cabal.project 17 | dhall/cpkg-prelude.dhall 18 | dhall/cpkg-types.dhall 19 | pkgs/pkg-set.dhall 20 | pkgs/patches/*.patch 21 | 22 | extra-doc-files: 23 | README.md 24 | CHANGELOG.md 25 | 26 | source-repository head 27 | type: git 28 | location: https://github.com/vmchale/cpkg 29 | 30 | flag development 31 | description: Enable `-Werror` 32 | default: False 33 | manual: True 34 | 35 | library 36 | exposed-modules: Package.C 37 | build-tools: cpphs -any 38 | hs-source-dirs: src 39 | other-modules: 40 | Package.C.Dhall 41 | Package.C.Dhall.Type 42 | Package.C.Type 43 | Package.C.Type.Shared 44 | Package.C.Type.Tree 45 | Package.C.Type.Verbosity 46 | Package.C.Type.Version 47 | Package.C.Type.Vars 48 | Package.C.Triple 49 | Package.C.Triple.Type 50 | Package.C.Triple.Parse 51 | Package.C.Build 52 | Package.C.Build.OS 53 | Package.C.Build.Tree 54 | Package.C.Unpack 55 | Package.C.Error 56 | Package.C.Fetch 57 | Package.C.Monad 58 | Package.C.Db.Type 59 | Package.C.Db.Register 60 | Package.C.Db.Monad 61 | Package.C.Db.Memory 62 | Package.C.Db.GarbageCollect 63 | Package.C.PackageSet 64 | Package.C.Logging 65 | System.Process.Ext 66 | System.Directory.Executable 67 | Data.Text.Prettyprint.Doc.Custom 68 | CPkgPrelude 69 | 70 | default-language: Haskell2010 71 | other-extensions: 72 | DeriveGeneric DeriveAnyClass OverloadedStrings DerivingStrategies 73 | GeneralizedNewtypeDeriving RankNTypes 74 | 75 | ghc-options: -Wall 76 | build-depends: 77 | base >=4.11 && <5, 78 | containers >=0.6.0.0, 79 | text -any, 80 | temporary -any, 81 | bytestring -any, 82 | zlib -any, 83 | bz2 >=0.1.1.0, 84 | lzma -any, 85 | zip-archive -any, 86 | prettyprinter -any, 87 | http-client -any, 88 | http-client-tls -any, 89 | directory >=1.3.1.0, 90 | filepath -any, 91 | process -any, 92 | mtl -any, 93 | hashable -any, 94 | binary -any, 95 | microlens -any, 96 | recursion >=2.2.3.0, 97 | filemanip -any, 98 | network-uri -any, 99 | megaparsec -any, 100 | libarchive >=2.2.5.0, 101 | dir-traverse >=0.2.1.0, 102 | composition-prelude >=1.5.2.0, 103 | lzlib >=0.3.0.0, 104 | dhall >=1.29.0, 105 | zstd -any 106 | 107 | if (flag(development) && impl(ghc <=8.2)) 108 | ghc-options: -Werror 109 | 110 | if impl(ghc >=8.0) 111 | ghc-options: 112 | -Wincomplete-uni-patterns -Wincomplete-record-updates 113 | -Wredundant-constraints -Widentities 114 | 115 | if impl(ghc >=8.4) 116 | ghc-options: -Wmissing-export-lists 117 | 118 | executable cpkg 119 | main-is: Main.hs 120 | hs-source-dirs: app 121 | other-modules: Paths_cpkg 122 | default-language: Haskell2010 123 | ghc-options: -threaded -rtsopts "-with-rtsopts=-N -qg" -Wall 124 | build-depends: 125 | base -any, 126 | cpkg -any, 127 | optparse-applicative -any, 128 | directory -any, 129 | text -any, 130 | dhall >=1.29.0 131 | 132 | if (flag(development) && impl(ghc <=8.2)) 133 | ghc-options: -Werror 134 | 135 | if impl(ghc >=8.0) 136 | ghc-options: 137 | -Wincomplete-uni-patterns -Wincomplete-record-updates 138 | -Wredundant-constraints -Widentities 139 | 140 | if impl(ghc >=8.4) 141 | ghc-options: -Wmissing-export-lists 142 | 143 | test-suite cpkg-test 144 | type: exitcode-stdio-1.0 145 | main-is: Spec.hs 146 | hs-source-dirs: test 147 | default-language: Haskell2010 148 | ghc-options: -threaded -rtsopts "-with-rtsopts=-N -K1K" -Wall 149 | build-depends: 150 | base -any, 151 | cpkg -any, 152 | hspec -any, 153 | hspec-megaparsec -any, 154 | megaparsec -any 155 | 156 | if flag(development) 157 | ghc-options: -Werror 158 | 159 | if impl(ghc >=8.0) 160 | ghc-options: 161 | -Wincomplete-uni-patterns -Wincomplete-record-updates 162 | -Wredundant-constraints -Widentities 163 | 164 | if impl(ghc >=8.4) 165 | ghc-options: -Wmissing-export-lists 166 | -------------------------------------------------------------------------------- /pkgs/patches/m4.patch: -------------------------------------------------------------------------------- 1 | diff --color -u lib/fflush.c lib/fflush.c 2 | --- lib/fflush.c 2016-12-31 07:54:41.000000000 -0600 3 | +++ lib/fflush.c 2019-05-24 15:43:00.800903010 -0500 4 | @@ -33,7 +33,7 @@ 5 | #undef fflush 6 | 7 | 8 | -#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ 9 | +#if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ 10 | 11 | /* Clear the stream's ungetc buffer, preserving the value of ftello (fp). */ 12 | static void 13 | @@ -72,7 +72,7 @@ 14 | 15 | #endif 16 | 17 | -#if ! (defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */) 18 | +#if ! (defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */) 19 | 20 | # if (defined __sferror || defined __DragonFly__ || defined __ANDROID__) && defined __SNPT 21 | /* FreeBSD, NetBSD, OpenBSD, DragonFly, Mac OS X, Cygwin, Android */ 22 | @@ -148,7 +148,7 @@ 23 | if (stream == NULL || ! freading (stream)) 24 | return fflush (stream); 25 | 26 | -#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ 27 | +#if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ 28 | 29 | clear_ungetc_buffer_preserving_position (stream); 30 | 31 | diff --color -u lib/fpending.c lib/fpending.c 32 | --- lib/fpending.c 2016-12-31 07:54:41.000000000 -0600 33 | +++ lib/fpending.c 2019-05-24 15:43:00.800903010 -0500 34 | @@ -32,7 +32,7 @@ 35 | /* Most systems provide FILE as a struct and the necessary bitmask in 36 | , because they need it for implementing getc() and putc() as 37 | fast macros. */ 38 | -#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ 39 | +#if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ 40 | return fp->_IO_write_ptr - fp->_IO_write_base; 41 | #elif defined __sferror || defined __DragonFly__ || defined __ANDROID__ 42 | /* FreeBSD, NetBSD, OpenBSD, DragonFly, Mac OS X, Cygwin, Android */ 43 | diff --color -u lib/fpurge.c lib/fpurge.c 44 | --- lib/fpurge.c 2016-12-31 07:54:41.000000000 -0600 45 | +++ lib/fpurge.c 2019-05-24 15:43:00.800903010 -0500 46 | @@ -62,7 +62,7 @@ 47 | /* Most systems provide FILE as a struct and the necessary bitmask in 48 | , because they need it for implementing getc() and putc() as 49 | fast macros. */ 50 | -# if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ 51 | +# if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ 52 | fp->_IO_read_end = fp->_IO_read_ptr; 53 | fp->_IO_write_ptr = fp->_IO_write_base; 54 | /* Avoid memory leak when there is an active ungetc buffer. */ 55 | diff --color -u lib/freadahead.c lib/freadahead.c 56 | --- lib/freadahead.c 2016-12-31 07:54:41.000000000 -0600 57 | +++ lib/freadahead.c 2019-05-24 15:43:00.800903010 -0500 58 | @@ -25,7 +25,7 @@ 59 | size_t 60 | freadahead (FILE *fp) 61 | { 62 | -#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ 63 | +#if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ 64 | if (fp->_IO_write_ptr > fp->_IO_write_base) 65 | return 0; 66 | return (fp->_IO_read_end - fp->_IO_read_ptr) 67 | diff --color -u lib/freading.c lib/freading.c 68 | --- lib/freading.c 2016-12-31 07:54:41.000000000 -0600 69 | +++ lib/freading.c 2019-05-24 15:43:00.800903010 -0500 70 | @@ -31,7 +31,7 @@ 71 | /* Most systems provide FILE as a struct and the necessary bitmask in 72 | , because they need it for implementing getc() and putc() as 73 | fast macros. */ 74 | -# if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ 75 | +# if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ 76 | return ((fp->_flags & _IO_NO_WRITES) != 0 77 | || ((fp->_flags & (_IO_NO_READS | _IO_CURRENTLY_PUTTING)) == 0 78 | && fp->_IO_read_base != NULL)); 79 | diff --color -u lib/fseeko.c lib/fseeko.c 80 | --- lib/fseeko.c 2016-12-31 07:54:41.000000000 -0600 81 | +++ lib/fseeko.c 2019-05-24 15:43:00.800903010 -0500 82 | @@ -47,7 +47,7 @@ 83 | #endif 84 | 85 | /* These tests are based on fpurge.c. */ 86 | -#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ 87 | +#if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ 88 | if (fp->_IO_read_end == fp->_IO_read_ptr 89 | && fp->_IO_write_ptr == fp->_IO_write_base 90 | && fp->_IO_save_base == NULL) 91 | @@ -123,7 +123,7 @@ 92 | return -1; 93 | } 94 | 95 | -#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ 96 | +#if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ 97 | fp->_flags &= ~_IO_EOF_SEEN; 98 | fp->_offset = pos; 99 | #elif defined __sferror || defined __DragonFly__ || defined __ANDROID__ 100 | Common subdirectories: lib/glthread and lib/glthread 101 | diff --color -u lib/stdio-impl.h lib/stdio-impl.h 102 | --- lib/stdio-impl.h 2016-12-31 07:54:42.000000000 -0600 103 | +++ lib/stdio-impl.h 2019-05-24 15:43:10.885006876 -0500 104 | @@ -138,3 +138,4 @@ 105 | # define _IOERR 0x10 106 | 107 | #endif 108 | +#define _IO_IN_BACKUP 0x100 109 | -------------------------------------------------------------------------------- /src/Package/C/Build/Tree.hs: -------------------------------------------------------------------------------- 1 | module Package.C.Build.Tree ( buildByName 2 | ) where 3 | 4 | import Control.Recursion 5 | import CPkgPrelude 6 | import Data.Containers.ListUtils (nubOrd) 7 | import Data.List (isInfixOf) 8 | import Package.C.Build 9 | import Package.C.Monad 10 | import Package.C.PackageSet 11 | import Package.C.Type 12 | import Package.C.Type.Tree 13 | import System.Directory (doesDirectoryExist) 14 | import System.FilePath (()) 15 | 16 | data BuildDirs = BuildDirs { libraries :: [FilePath] 17 | , share :: [FilePath] 18 | , include :: [FilePath] 19 | , binaries :: [FilePath] 20 | } 21 | 22 | getAll :: [BuildDirs] -> BuildDirs 23 | getAll bds = 24 | let go f = concat (f <$> bds) 25 | in BuildDirs (go libraries) (go share) (go include) (go binaries) 26 | 27 | -- in order to prevent the "vanilla" libffi from preceding the *cross* libffi, 28 | -- we filter out any directory that doesn't contain the target triple. this 29 | -- causes further bugs and it's slow 30 | -- 31 | -- Really we should allow *all* libdirs for Python/Perl here, since they won't 32 | -- (hopefully) pollute the pkg-config path... 33 | immoralFilter :: Maybe TargetTriple -> [FilePath] -> [FilePath] 34 | immoralFilter Nothing fps = fps 35 | immoralFilter (Just tgt') fps = 36 | let infixDir = show tgt' 37 | in filter (\fp -> infixDir `isInfixOf` fp || "meson" `isInfixOf` fp || "XML-Parser" `isInfixOf` fp || "python3" `isInfixOf` fp) fps -- FIXME: more principled approach 38 | 39 | -- filter out stuff from the path 40 | filterCross :: Maybe TargetTriple -> [FilePath] -> [FilePath] 41 | filterCross Nothing = id 42 | filterCross (Just tgt') = 43 | let infixDir = show tgt' 44 | in filter (\fp -> not (infixDir `isInfixOf` fp) || "ncurses" `isInfixOf` fp) 45 | 46 | buildWithContext :: DepTree CPkg 47 | -> Maybe TargetTriple 48 | -> Bool -- ^ Should we build static libraries? 49 | -> Bool -- ^ Install globally 50 | -> PkgM () 51 | buildWithContext cTree host sta glob = zygoM' dirAlg buildAlg cTree 52 | 53 | where buildAlg :: DepTreeF CPkg (BuildDirs, ()) -> PkgM () 54 | buildAlg (DepNodeF c usr preBds) = 55 | buildCPkg c host sta glob usr ds (immoralFilter host ls) is (filterCross host bs) 56 | where (BuildDirs ls ds is bs) = getAll (fst <$> preBds) 57 | buildAlg (BldDepNodeF c preBds) = 58 | buildCPkg c Nothing False False False ds ls is bs -- don't use static libraries for build dependencies 59 | -- also don't install them globally 60 | -- build dependencies are not manual! 61 | where (BuildDirs ls ds is bs) = getAll (fst <$> preBds) 62 | 63 | mkBuildDirs :: MonadIO m => FilePath -> BuildDirs -> m BuildDirs 64 | mkBuildDirs pkgDir (BuildDirs ls ds is bs) = do 65 | let linkDir = pkgDir "lib" 66 | linkDir64 = pkgDir "lib64" 67 | includeDir = pkgDir "include" 68 | dataDir = pkgDir "share" 69 | binDir = pkgDir "bin" 70 | 71 | binExists <- liftIO (doesDirectoryExist binDir) 72 | let bins = if binExists 73 | then binDir : bs 74 | else bs 75 | 76 | shareExists <- liftIO (doesDirectoryExist dataDir) 77 | let shares = if shareExists 78 | then dataDir : ds 79 | else ds 80 | 81 | linkExists <- liftIO (doesDirectoryExist linkDir) 82 | link64Exists <- liftIO (doesDirectoryExist linkDir64) 83 | 84 | let linkAppend = if linkExists 85 | then (linkDir :) 86 | else id 87 | let link64Append = if link64Exists 88 | then (linkDir64 :) 89 | else id 90 | 91 | let links = link64Append (linkAppend ls) 92 | 93 | includeExists <- liftIO (doesDirectoryExist includeDir) 94 | let includes = if includeExists 95 | then includeDir : is 96 | else is 97 | 98 | pure (BuildDirs (nubOrd links) (nubOrd shares) (nubOrd includes) (nubOrd bins)) 99 | 100 | dirAlg :: DepTreeF CPkg BuildDirs -> PkgM BuildDirs 101 | dirAlg (DepNodeF c _ bds) = do 102 | 103 | let bldDirs@(BuildDirs ls ds is bs) = getAll bds 104 | 105 | buildVars <- getVars host sta ds (immoralFilter host ls) is (filterCross host bs) 106 | 107 | pkgDir <- cPkgToDir c host glob buildVars 108 | 109 | mkBuildDirs pkgDir bldDirs 110 | 111 | dirAlg (BldDepNodeF c bds) = do 112 | 113 | let bldDirs@(BuildDirs ls ds is bs) = getAll bds 114 | 115 | buildVars <- getVars Nothing False ds ls is bs 116 | 117 | pkgDir <- cPkgToDir c Nothing False buildVars 118 | 119 | mkBuildDirs pkgDir bldDirs 120 | 121 | -- TODO: should this parse a string into a TargetTriple instead? 122 | -- | Manually install a package 123 | buildByName :: PackId -> Maybe TargetTriple -> Maybe String -> Bool -> Bool -> PkgM () 124 | buildByName pkId host pkSet sta glob = do 125 | allPkgs <- liftIO (pkgsM pkId pkSet) 126 | buildWithContext allPkgs host sta glob 127 | -------------------------------------------------------------------------------- /app/Main.hs: -------------------------------------------------------------------------------- 1 | module Main (main) where 2 | 3 | import Control.Monad (void, when) 4 | import Data.Semigroup 5 | import qualified Data.Text as T 6 | import qualified Data.Version as V 7 | import Dhall.Version (dhallVersionString) 8 | import Options.Applicative hiding (auto) 9 | import Package.C hiding (Command, name) 10 | import qualified Paths_cpkg as P 11 | import System.Directory (doesDirectoryExist, removeDirectoryRecursive) 12 | 13 | cpkgVersion :: V.Version 14 | cpkgVersion = P.version 15 | 16 | data DumpTarget = Linker { _pkgGet :: String } 17 | | Compiler { _pkgGet :: String } 18 | | PkgConfig { _pkgGets :: [String] } 19 | | IncludePath { _pkgGet :: String } 20 | | LibPath { _pkgGet :: String } 21 | | LdLibPath { _pkgGets :: [String] } 22 | 23 | data Command = Install { _pkgName :: String, _verbosity :: Verbosity, _target :: Maybe Platform, _static :: Bool, _global :: Bool, _packageSet :: Maybe String } 24 | | Uninstall { _pkgStr :: String, _verbosity :: Verbosity, _target :: Maybe Platform } 25 | | Check { _dhallFile :: String, _verbosity :: Verbosity } 26 | | CheckSet { _dhallFile :: String, _verbosity :: Verbosity } 27 | | Dump { _dumpTarget :: DumpTarget, _host :: Maybe Platform } 28 | | DumpCabal { _pkgGetsCabal :: [String], _host :: Maybe Platform } 29 | | List { _packageSet :: Maybe String } 30 | | Find { _findPkg :: String } 31 | | Nuke 32 | | NukeCache 33 | | GarbageCollect { _verbosity :: Verbosity } 34 | 35 | verbosityInt :: Parser Int 36 | verbosityInt = length <$> 37 | many (flag' () (short 'v' <> long "verbose" <> help "Turn up verbosity")) 38 | 39 | verbosity :: Parser Verbosity 40 | verbosity = fmap intToVerbosity verbosityInt 41 | 42 | intToVerbosity :: Int -> Verbosity 43 | intToVerbosity 0 = Normal 44 | intToVerbosity 1 = Verbose 45 | intToVerbosity 2 = Loud 46 | intToVerbosity 3 = Diagnostic 47 | intToVerbosity _ = Normal 48 | 49 | wrapper :: ParserInfo Command 50 | wrapper = info (helper <*> versionInfo <*> userCmd) 51 | (fullDesc 52 | <> progDesc "The cpkg build tool and package manager." 53 | <> header "cpkg - a build tool for C") 54 | 55 | versionInfo :: Parser (a -> a) 56 | versionInfo = infoOption vStr (short 'V' <> long "version" <> help "Show version") 57 | where vStr = "cpkg version: " ++ V.showVersion cpkgVersion ++ "\ndhall version: " ++ dhallVersionString ++ "\npackage set: " ++ T.unpack defaultPackageSetHash 58 | 59 | dumpTarget :: Parser DumpTarget 60 | dumpTarget = hsubparser 61 | (command "linker" (info (Linker <$> package) (progDesc "Dump linker flags for a package")) 62 | <> command "compiler" (info (Compiler <$> package) (progDesc "Dump compiler flags for a package")) 63 | <> command "pkg-config" (info (PkgConfig <$> some package) (progDesc "Dump pkg-config path for a package")) -- TODO: make pkg-config recursive or something? 64 | <> command "include" (info (IncludePath <$> package) (progDesc "Dump C_INCLUDE_PATH for a package")) 65 | <> command "library" (info (LibPath <$> package) (progDesc "Dump LD_LIBRARY_PATH or LIBRARY_PATH info for a package")) 66 | <> command "ld-path" (info (LdLibPath <$> some package) (progDesc "Dump LD_LIBRARY_PATH or LIBRARY_PATH for a package")) 67 | ) 68 | 69 | userCmd :: Parser Command 70 | userCmd = hsubparser 71 | (command "install" (info install (progDesc "Install a package from the global package set")) 72 | <> command "uninstall" (info uninstall (progDesc "Uninstall a package")) 73 | <> command "check" (info check (progDesc "Check a Dhall expression to ensure it can be used to build a package")) 74 | <> command "check-set" (info checkSet (progDesc "Check a package set defined in Dhall")) 75 | <> command "dump" (info dump (progDesc "Display flags to link against a particular library")) 76 | <> command "dump-cabal" (info dumpCabal (progDesc "Display flags to use with cabal new-build")) 77 | <> command "list" (info list (progDesc "List all available packages")) 78 | <> command "find" (info find (progDesc "Find a package and list information")) 79 | <> command "nuke" (info (pure Nuke) (progDesc "Remove all globally installed libraries")) 80 | <> command "nuke-cache" (info (pure NukeCache) (progDesc "Remove cached soure tarballs")) 81 | <> command "garbage-collect" (info garbageCollect' (progDesc "Garbage collect redundant packages")) 82 | ) 83 | 84 | list :: Parser Command 85 | list = List <$> packageSet 86 | 87 | find :: Parser Command 88 | find = Find 89 | <$> argument str 90 | (metavar "PACKAGE" 91 | <> help "Name of package" 92 | ) 93 | 94 | ftypeCompletions :: String -> Mod ArgumentFields a 95 | ftypeCompletions ext = completer . bashCompleter $ "file -X '!*." ++ ext ++ "' -o plusdirs" 96 | 97 | dhallCompletions :: Mod ArgumentFields a 98 | dhallCompletions = ftypeCompletions "dhall" 99 | 100 | uninstall :: Parser Command 101 | uninstall = Uninstall 102 | <$> argument str 103 | (metavar "PACKAGE" 104 | <> help "Name of package to uninstall" 105 | <> completer (listIOCompleter allPackages)) 106 | <*> verbosity 107 | <*> target 108 | 109 | install :: Parser Command 110 | install = Install 111 | <$> argument str 112 | (metavar "PACKAGE" 113 | <> help "Name of package to install") 114 | <*> verbosity 115 | <*> target 116 | <*> static' 117 | <*> switch 118 | (long "global" 119 | <> short 'g' 120 | <> help "Install globally") 121 | <*> packageSet 122 | 123 | packageSet :: Parser (Maybe String) 124 | packageSet = optional 125 | (strOption 126 | (metavar "EXPRESSION" 127 | <> long "pkg-set" 128 | <> help "Dhall expression for the package set to be used" 129 | )) 130 | 131 | static' :: Parser Bool 132 | static' = 133 | switch 134 | (long "static" 135 | <> help "Build static libaries") 136 | 137 | garbageCollect' :: Parser Command 138 | garbageCollect' = GarbageCollect <$> verbosity 139 | 140 | check :: Parser Command 141 | check = Check <$> dhallFile <*> verbosity 142 | 143 | checkSet :: Parser Command 144 | checkSet = CheckSet <$> dhallFile <*> verbosity 145 | 146 | target :: Parser (Maybe Platform) 147 | target = optional 148 | (strOption 149 | (metavar "TARGET" 150 | <> long "target" 151 | <> help "Host platform, e.g. arm-linux-gnueabihf" 152 | )) 153 | 154 | package :: Parser String 155 | package = 156 | argument str 157 | (metavar "PACKAGE" 158 | <> help "Name of package you want to link against" 159 | <> completer (listIOCompleter allPackages) 160 | ) 161 | 162 | dumpCabal :: Parser Command 163 | dumpCabal = DumpCabal 164 | <$> some package 165 | <*> target 166 | 167 | dump :: Parser Command 168 | dump = Dump 169 | <$> dumpTarget 170 | <*> target 171 | 172 | dhallFile :: Parser String 173 | dhallFile = 174 | argument str 175 | (metavar "EXPRESSION" 176 | <> help "File containing a Dhall expression" 177 | <> dhallCompletions 178 | ) 179 | 180 | run :: Command -> IO () 181 | run (Uninstall pkId v host') = do 182 | parsedHost <- parseHostIO host' 183 | runPkgM v $ uninstallPkgByName pkId parsedHost 184 | run (Install pkId v host' sta glob pkSet) = do 185 | parsedHost <- parseHostIO host' 186 | runPkgM v $ buildByName (T.pack pkId) parsedHost pkSet sta glob 187 | run (Check file' v) = void $ getCPkg v file' 188 | run (CheckSet file' v) = void $ getPkgs v file' 189 | run (Dump (Linker name) host) = runPkgM Normal $ printLinkerFlags name host 190 | run (Dump (Compiler name) host) = runPkgM Normal $ printCompilerFlags name host 191 | run (Dump (PkgConfig names) host) = runPkgM Normal $ printPkgConfigPath names host 192 | run (Dump (IncludePath name) host) = runPkgM Normal $ printIncludePath name host 193 | run (Dump (LibPath name) host) = runPkgM Normal $ printLibPath name host 194 | run (Dump (LdLibPath names) host) = runPkgM Normal $ printLdLibPath names host 195 | run (DumpCabal names host) = runPkgM Normal $ printCabalFlags names host 196 | run Nuke = do 197 | pkgDir <- globalPkgDir 198 | exists <- doesDirectoryExist pkgDir 199 | when exists $ 200 | removeDirectoryRecursive pkgDir 201 | run NukeCache = cleanCache 202 | run (List pkSet) = displayPackageSet pkSet 203 | run (Find pk) = displayPackage pk 204 | run (GarbageCollect v) = runPkgM v garbageCollect 205 | 206 | main :: IO () 207 | main = run =<< execParser wrapper 208 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # Upstream 2 | - [ ] Report CBOR decoding? 3 | - [ ] Fix Dhall parser 4 | - [ ] Add typechecking benchmarks 5 | - [ ] Ask how to implement `init`/`tail` in Dhall 6 | - [ ] Also find & replace on strings 7 | - [ ] Maybe fix `acid-state`? 8 | - [ ] Investigate possible upstream bug when downloading `fltk` and unpacking 9 | the `.tar.gz` 10 | - [x] Fix tar library and/or rewrite it 11 | - [x] Dhall space leak 12 | - [ ] Dhall performance problems 13 | - [ ] Fix `hp2pretty` completions to work with `.hp` files alone 14 | - [ ] Investigate performance problems while decoding `index.bin` 15 | - [ ] complain about ncurses 6.1 not cross-compiling 16 | - [ ] complain about Xorg libraries and bad defaults (malloc) related to 17 | cross-compiling 18 | - [ ] definitely complain about intltool 19 | - [ ] complain about m4 (?) 20 | - [ ] Figure out why `libX11` stalls when not watched (i.e. when `-vv` is not 21 | passed...) 22 | - [ ] figure out why `libsepol` doesn't cross-compile 23 | - [ ] `xextproto` doesn't like `aarch64` 24 | - [ ] ImageMagick fails on ARM 25 | - [ ] `wget` doesn't work with latest gnutls 26 | - [ ] Report bug to LFS: libevent depends on openssl as they have configured it... 27 | - [ ] OpenSSH fails to cross-compile 28 | - [ ] bz2 fails to unpack glu? 29 | # Libraries 30 | - [ ] Consider splitting off library for parsing triples &c. 31 | # Code Maintenance 32 | - [ ] Use a more sensible monad 33 | - [ ] Stop being a mess 34 | # Documentation 35 | - [ ] Document use of `cabal.project` files (which is simpler...) 36 | # Features 37 | - [ ] Source depends like `CImg` 38 | - [ ] Something like cabal flags - enable exif with feh, for example... 39 | - [ ] Pass verbosity to configuration/build script 40 | - [ ] Constraint solver 41 | - [ ] Build/handle preprocessors 42 | - [ ] Don't try to use cross-compiler on preprocessors 43 | - [x] Nix-style builds 44 | - [x] Garbage collection 45 | - [ ] Make it less crappy 46 | - [ ] Caching 47 | - [ ] Cache global package set? 48 | - [ ] `unpack` subcommand for packages 49 | - [ ] Cabal integration? Make it usable as a package for `Setup.hs` files :o 50 | - [ ] Better Haddock API; expose more types 51 | - [ ] Allow a package's function to specify a `pkg-config` dir, etc. 52 | - [ ] Bootstrap "fancy" tar? 53 | - [ ] Package "components"? Like cabal: build executables or not... 54 | - [ ] Symlink manpages 55 | - [ ] Completions 56 | - [ ] `cpkg install` should use `cpkg list`? 57 | - [ ] Custom package sets 58 | - [ ] Haskell library API should be better 59 | - [ ] `cpkg list` should show what binaries it provides 60 | - [ ] `test` should map to commands such as `make check`; should not be run when 61 | cross-compiling 62 | - [ ] `pkgRuntimeDeps` field? 63 | - [ ] append to `cabal.project` file 64 | - [ ] pass `pi@32.32.43.00` or whatever on the command-line? 65 | - [ ] Add IA64 (itanium) support 66 | - [ ] Add HPUX/HPUX64 support 67 | - [ ] Store build logs - options/environment variables, etc. 68 | # Performance 69 | - [ ] Dhall is slow 70 | # Bugs 71 | - [ ] Shouldn't be able to `cpkg dump compiler sed` since it provides no 72 | libraries 73 | - [ ] Figure out `ACLOCAL_PATH` 74 | - [ ] Fails when symlink already exists 75 | - [ ] Cross-compile shouldn't symlink 76 | - [ ] If X depends on Y, Z and Y depends on Z, then it will not link things 77 | correctly... 78 | - [ ] Figure out `PERL5LIB` variable 79 | # Deficiencies 80 | - [ ] Get rid of `symlinkLibrary`? And just use `symlink`... 81 | - [ ] Cache package downloads globally 82 | - [ ] No database w/ graph right now 83 | - [ ] Build step should take OS as an argument 84 | - [ ] Make e.g. `vim` depend on `glibc` 85 | - [ ] Get rid of annoying `LD_PRELOAD` hack? 86 | - [ ] dhall library should prefer `symlink` to `copyFile` when possible? hmm 87 | # Testing 88 | - [ ] Maintainer subcommand to build every single package 89 | # Packages 90 | - [ ] bash 91 | - [ ] librsvg 92 | - [ ] https://github.com/linux-noah/noah 93 | - [ ] GHC cross-compiler? 94 | - [ ] https://sourceforge.net/projects/infozip/files/ 95 | - [ ] fdupes 96 | - [ ] Figlet 97 | - [ ] http://www.linuxfromscratch.org/blfs/view/7.5/postlfs/acl.html 98 | - [ ] GHC (`https://downloads.haskell.org/~ghc/8.6.3/ghc-8.6.3-src.tar.xz`) 99 | & cross-compiler 100 | - [ ] weighttp 101 | - [ ] `patscc` 102 | - [ ] http://www.qhull.org/download/qhull-2019-src-7.3.2.tgz 103 | - [ ] `rustc` 104 | - [ ] https://github.com/ZBar/ZBar 105 | - [ ] Doxygen 106 | - [ ] libXcursor 107 | - [ ] exif, libexif-gtk, gexif (https://libexif.github.io/) 108 | - [ ] nomacs 109 | - [ ] FFmpeg 110 | - [ ] https://ftp.gnu.org/gnu/texinfo/ ? 111 | - [ ] charset (?) 112 | - [ ] weighttpd https://github.com/lighttpd/weighttp 113 | - [ ] https://sourceware.org/newlib/ 114 | - [ ] https://labs.tomasino.org/gnu-recutils/ 115 | - [ ] fish 116 | - [ ] libtizcore 117 | - [ ] ghostscript http://www.linuxfromscratch.org/blfs/view/svn/pst/gs.html 118 | - [ ] https://github.com/yaml/libyaml 119 | - [ ] https://mosh.org/mosh-1.3.2.tar.gz 120 | - [ ] http://www.linuxfromscratch.org/blfs/view/svn/general/boost.html 121 | - [ ] brlcad https://jaist.dl.sourceforge.net/project/brlcad/BRL-CAD%20Source/7.28.0/brlcad-7.28.0.tar.bz2 122 | - [ ] gstreamer-video 123 | - [ ] ragel 124 | - [ ] https://ftp.gnu.org/gnu/parallel/parallel-20181222.tar.bz2 125 | - [ ] http://savannah.gnu.org/projects/patch/ 126 | - [ ] Blender https://download.blender.org/source/blender-2.79b.tar.gz 127 | - [ ] http://www.ibiblio.org/pub/Linux/utils/file/symlinks-1.4.tar.gz 128 | - [ ] http://www.linuxfromscratch.org/blfs/view/8.2/general/tree.html 129 | - [ ] libsigsegv 130 | - [ ] pyqt5 131 | - [ ] weirdo levenshtein distance in ATS 132 | - [ ] https://github.com/jmcnamara/libxlsxwriter/archive/RELEASE_0.8.4.tar.gz 133 | - [ ] http://www.linuxfromscratch.org/blfs/view/8.3/postlfs/cracklib.html 134 | - [ ] https://github.com/gildor2/fast_zlib 135 | - [ ] grep 136 | - [ ] https://github.com/chapel-lang/chapel/releases/download/1.18.0/chapel-1.18.0.tar.gz (https://chapel-lang.org/docs/usingchapel/QUICKSTART.html) 137 | - [ ] ed 138 | - [ ] cloc 139 | - [ ] libpeas 140 | - [ ] libcaca 141 | - [ ] alarm, pread, top, htop, kill, grep 142 | - [ ] http://www.linuxfromscratch.org/blfs/view/8.1/pst/xmlto.html 143 | - [ ] https://liquidtelecom.dl.sourceforge.net/project/schilytools/schily-2018-12-21.tar.bz2 144 | - [ ] https://ftp.gnu.org/gnu/autogen/rel5.18.16/ 145 | - [ ] https://github.com/pkgconf/pkgconf 146 | - [ ] http://www.linuxfromscratch.org/lfs/view/6.6/appendices/dependencies.html 147 | - [ ] https://github.com/scipy/scipy/releases/download/v1.2.0/scipy-1.2.0.tar.xz 148 | - [ ] Perl wrapper like `mkPy3Wrapper` 149 | - [ ] http://www.linuxfromscratch.org/blfs/view/cvs/basicnet/glib-networking.html 150 | - [ ] http://www.linuxfromscratch.org/blfs/view/cvs/gnome/gexiv2.html 151 | - [ ] http://www.linuxfromscratch.org/blfs/view/8.3/x/x7driver.html#libinput 152 | - [ ] http://luajit.org/index.html 153 | - [ ] https://github.com/mquinson/po4a 154 | - [ ] texinfo/help2man 155 | - [ ] libutemper 156 | - [ ] https://www.gimp.org/source/#gimp-requirements 157 | - [ ] https://github.com/GNOME/cheese 158 | - [ ] http://trousers.sourceforge.net/ 159 | - [ ] https://www.gnu.org/software/libidn/#libidn2 160 | - [ ] https://nlnetlabs.nl/projects/unbound/about/ 161 | - [ ] https://www.gnupg.org/ftp/gcrypt/pinentry/pinentry-1.1.0.tar.bz2 162 | - [ ] http://aa-project.sourceforge.net/aalib/ 163 | - [ ] https://www.gnupg.org/ftp/gcrypt/ntbtls/ntbtls-0.1.2.tar.bz2 164 | - [ ] https://github.com/GNOME/libgudev 165 | - [ ] nss? 166 | - [ ] libXcursor 167 | - [ ] scrot (https://github.com/dreamer/scrot/releases) 168 | - [ ] http://download.redis.io/releases/redis-5.0.3.tar.gz 169 | - [ ] Rarian 170 | - [ ] https://github.com/garabik/unicode/releases 171 | - [ ] evince 172 | - [ ] https://github.com/GNOME/libgweather 173 | - [ ] GIMP 174 | - [ ] libav cross-compile 175 | - [ ] https://github.com/mtoyoda/sl/releases 176 | - [ ] libsocketcap 177 | - [ ] https://github.com/pinard/paxutils/releases 178 | - [ ] https://github.com/aperezdc/signify 179 | - [ ] zstd 180 | - [ ] lz4 181 | - [ ] oclint 182 | - [ ] https://www.cs.ubc.ca/research/flann/ 183 | - [ ] pdftotext http://www.xpdfreader.com/download.html 184 | - [ ] Firefox 185 | - [ ] github-linguist (??) 186 | - [ ] https://github.com/microsoft/mimalloc 187 | - [ ] http://www.linuxfromscratch.org/blfs/view/8.3/kde/okular5.html 188 | - [ ] http://cimg.eu/links.shtml 189 | - [ ] http://www.linuxfromscratch.org/blfs/view/svn/gnome/nautilus.html 190 | - [ ] wxWidgets/erlang 191 | - [ ] http://download.savannah.gnu.org/releases/lzip/tarlz/ 192 | - [ ] https://github.com/NLnetLabs/unbound 193 | - [ ] https://github.com/google/brotli/releases 194 | - [ ] https://www.gnu.org/software/gsl/ 195 | # Documentation 196 | - [ ] Write a manpage 197 | - [ ] Documentation in 198 | - [ ] French 199 | - [ ] German 200 | - [ ] Write `info` thing like `info sed` 201 | # Dhall Libraries 202 | - [ ] `mkExe` and `makeExe` are too similar 203 | # Tests 204 | -------------------------------------------------------------------------------- /src/Package/C/Build.hs: -------------------------------------------------------------------------------- 1 | module Package.C.Build ( buildCPkg 2 | , getVars 3 | , cPkgToDir 4 | ) where 5 | 6 | import Control.Concurrent (getNumCapabilities) 7 | import CPkgPrelude 8 | import Data.List (isInfixOf) 9 | import Data.Maybe (isJust) 10 | import qualified Data.Text as T 11 | import qualified Data.Text.IO as TIO 12 | import Package.C.Build.OS 13 | import Package.C.Db.Register 14 | import Package.C.Fetch 15 | import Package.C.Logging 16 | import Package.C.Monad 17 | import Package.C.Type 18 | import System.Directory 19 | import System.Directory.Executable (mkExecutable) 20 | import System.Directory.Recursive (getSubdirsRecursive) 21 | import System.FilePath (takeDirectory, takeFileName, ()) 22 | import System.FilePath.Glob 23 | import System.IO.Temp (withSystemTempDirectory) 24 | import System.Process 25 | import System.Process.Ext 26 | 27 | envVarSplit :: EnvVar -> (String, String) 28 | envVarSplit (EnvVar ev x) = (ev, x) 29 | 30 | replaceSymlink :: FilePath -> FilePath -> IO () 31 | replaceSymlink actual link = do 32 | bf <- doesFileExist link 33 | if bf 34 | then removeFile link 35 | else do 36 | bd <- doesDirectoryExist link 37 | when bd $ removeDirectoryLink link 38 | createFileLink actual link 39 | 40 | stepToProc :: FilePath -- ^ Package build directory 41 | -> FilePath -- ^ Package install directory 42 | -> Command 43 | -> PkgM () 44 | stepToProc fp _ (Call p as envs dir') = do 45 | let dir'' = maybe fp (fp ) dir' 46 | envVars = fmap envVarSplit <$> envs 47 | putDiagnostic ("Running " ++ p ++ " with arguments " ++ unwords as ++ " in directory " ++ dir'' ++ " with environment " ++ show envVars) 48 | waitProcess $ (proc p as) { cwd = Just dir'', std_in = CreatePipe, env = envVars } 49 | stepToProc dir' _ (MakeExecutable fp) = do 50 | putDiagnostic ("Marking " ++ (dir' fp) ++ " as executable...") 51 | liftIO $ mkExecutable (dir' fp) 52 | stepToProc dir' _ (CreateDirectory d) = do 53 | putDiagnostic ("Creating directory " ++ (dir' d) ++ "...") 54 | liftIO $ createDirectoryIfMissing True (dir' d) 55 | stepToProc _ p (SymlinkBinary file') = do 56 | binDir <- ( "bin") <$> globalPkgDir 57 | let actualBin = p file' 58 | liftIO $ createDirectoryIfMissing True binDir 59 | liftIO $ replaceSymlink actualBin (binDir takeFileName file') 60 | stepToProc _ p (SymlinkManpage file' sec) = do 61 | manDir <- ( ("share" "man" "man" ++ show sec)) <$> globalPkgDir 62 | let actualMan = p file' 63 | liftIO $ createDirectoryIfMissing True manDir 64 | liftIO $ replaceSymlink actualMan (manDir takeFileName file') 65 | stepToProc _ p (Symlink tgt' lnk) = do 66 | let linkAbs = p lnk 67 | putDiagnostic ("Creating directory" ++ takeDirectory linkAbs ++ "...") 68 | liftIO $ createDirectoryIfMissing True (takeDirectory linkAbs) 69 | -- TODO: diagnostics for symlinks 70 | liftIO $ replaceSymlink (p tgt') linkAbs 71 | stepToProc dir' _ (Write out fp) = do 72 | let fpAbs = dir' fp 73 | putDiagnostic ("Writing\n" ++ T.unpack out ++ "\n in file" ++ fpAbs) 74 | liftIO (TIO.writeFile fpAbs out) 75 | stepToProc dir' p (CopyFile src' dest') = do 76 | let absSrc = dir' src' 77 | absDest = p dest' 78 | putDiagnostic ("Copying file " ++ absSrc ++ " to " ++ absDest ++ "...") 79 | liftIO $ createDirectoryIfMissing True (takeDirectory absDest) 80 | liftIO $ copyFileWithMetadata absSrc absDest 81 | stepToProc dir' _ (Patch contents') = do 82 | liftIO $ TIO.writeFile (dir' "step.patch") contents' 83 | waitProcess $ (proc "patch" ["-p0", "-i", "step.patch"]) { cwd = Just dir' } 84 | 85 | processSteps :: (Traversable t) 86 | => FilePath -- ^ Build directory 87 | -> FilePath -- ^ Install directory 88 | -> t Command 89 | -> PkgM () 90 | processSteps pkgDir instDir = traverse_ (stepToProc pkgDir instDir) 91 | 92 | configureInDir :: CPkg 93 | -> BuildVars 94 | -> FilePath -- ^ Build directory 95 | -> PkgM () 96 | configureInDir cpkg cfg p = 97 | 98 | let steps = configureCommand cpkg cfg 99 | in 100 | putNormal ("Configuring " ++ pkgName cpkg) *> 101 | processSteps p (installDir cfg) steps 102 | 103 | buildInDir :: CPkg 104 | -> BuildVars 105 | -> FilePath -- ^ Build directory 106 | -> FilePath -- ^ Install directory 107 | -> PkgM () 108 | buildInDir cpkg cfg p p' = do 109 | putNormal ("Building " ++ pkgName cpkg) 110 | processSteps p p' (buildCommand cpkg cfg) 111 | 112 | installInDir :: CPkg 113 | -> BuildVars 114 | -> FilePath -- ^ Build directory 115 | -> FilePath -- ^ Install directory 116 | -> PkgM () 117 | installInDir cpkg cfg p p' = 118 | putNormal ("Installing " ++ pkgName cpkg) *> 119 | processSteps p p' (installCommand cpkg cfg) 120 | 121 | fetchCPkg :: CPkg 122 | -> FilePath -- ^ Directory for intermediate build files 123 | -> PkgM () 124 | fetchCPkg cpkg = fetchUrl (pkgUrl cpkg) (pkgName cpkg) 125 | 126 | buildCPkg :: CPkg 127 | -> Maybe TargetTriple 128 | -> Bool -- ^ Should we build static libraries? 129 | -> Bool -- ^ Should we install globally? 130 | -> Bool -- ^ Was this package installed manually? 131 | -> [FilePath] -- ^ Shared data directories 132 | -> [FilePath] -- ^ Library directories 133 | -> [FilePath] -- ^ Include directories 134 | -> [FilePath] -- ^ Directories to add to @PATH@ 135 | -> PkgM () 136 | buildCPkg cpkg host sta glob usr shr libs incls bins = do 137 | 138 | buildVars <- getVars host sta shr libs incls bins 139 | 140 | -- TODO: use a real database 141 | installed <- packageInstalled cpkg host glob buildVars 142 | 143 | when installed $ 144 | putDiagnostic ("Package " ++ pkgName cpkg ++ " already installed, skipping.") 145 | 146 | unless installed $ 147 | forceBuildCPkg cpkg host glob usr buildVars 148 | 149 | getPreloads :: [ FilePath ] -> IO [ FilePath ] 150 | getPreloads = 151 | fmap concat . traverse (\fp -> namesMatching (fp "*.so")) 152 | 153 | -- only really suitable for hashing at this point, since we use @""@ as the 154 | -- install directory. we use this to get a hash which we then use to get the 155 | -- *real* install directory, which we then use with @configureVars@ to set 156 | -- things up correctly - otherwise we would have a circularity 157 | getVars :: Maybe TargetTriple 158 | -> Bool -- ^ Should we build static libraries? 159 | -> [FilePath] -- ^ Shared data directories 160 | -> [FilePath] -- ^ Library directories 161 | -> [FilePath] -- ^ Include directories 162 | -> [FilePath] -- ^ Directories to add to @PATH@ 163 | -> PkgM BuildVars 164 | getVars host sta shr links incls bins = do 165 | nproc <- liftIO getNumCapabilities 166 | pure (BuildVars "" "" host (isJust host) incls [] shr links bins dhallOS dhallArch sta nproc) 167 | -- we don't run getPreloads until later because that might be slow 168 | 169 | -- diagnosticDirectory :: String -> (FilePath -> m a) -> m a 170 | -- diagnosticDirectory s f = f (s ++ "-diagnostic") 171 | 172 | getSubdirsWrap :: FilePath -> IO [FilePath] 173 | getSubdirsWrap fp = do 174 | b <- doesDirectoryExist fp 175 | if b 176 | then (fp:) <$> getSubdirsRecursive fp 177 | else pure [] 178 | 179 | -- TODO: more complicated solver, garbage collector, and all that. 180 | -- Basically nix-style builds for C libraries 181 | forceBuildCPkg :: CPkg 182 | -> Maybe TargetTriple 183 | -> Bool 184 | -> Bool -- ^ Manually installed? 185 | -> BuildVars 186 | -> PkgM () 187 | forceBuildCPkg cpkg host glob usr buildVars = do 188 | 189 | pkgDir <- cPkgToDir cpkg host glob buildVars 190 | 191 | liftIO $ createDirectoryIfMissing True pkgDir 192 | 193 | withSystemTempDirectory "cpkg" $ \p -> do 194 | -- diagnosticDirectory "cpkg" $ \p -> do 195 | 196 | putDiagnostic ("Setting up temporary directory in " ++ p) 197 | 198 | fetchCPkg cpkg p 199 | 200 | pAbs <- liftIO (makeAbsolute p) 201 | 202 | let p' = pAbs pkgSubdir cpkg 203 | 204 | lds <- liftIO $ do 205 | linkSubdirs <- concat <$> traverse getSubdirsWrap (linkDirs buildVars) 206 | -- FIXME: this seems stupid 207 | let curses = not . ("curses" `isInfixOf`) 208 | getPreloads $ filter curses linkSubdirs 209 | 210 | let buildConfigured = buildVars { installDir = pkgDir, currentDir = pAbs, preloadLibs = lds } 211 | 212 | configureInDir cpkg buildConfigured p' 213 | 214 | buildInDir cpkg buildConfigured p' pkgDir 215 | 216 | installInDir cpkg buildConfigured p' pkgDir 217 | 218 | registerPkg cpkg host glob usr buildVars -- not configured 219 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cpkg 2 | 3 | [![Hackage CI](https://matrix.hackage.haskell.org/api/v2/packages/cpkg/badge)](https://matrix.hackage.haskell.org/package/cpkg) 4 | [![Hackage](https://img.shields.io/hackage/v/cpkg.svg)](http://hackage.haskell.org/package/cpkg) 5 | [![Dependencies of latest version on Hackage](https://img.shields.io/hackage-deps/v/cpkg.svg)](https://hackage.haskell.org/package/cpkg) 6 | 7 | `cpkg` is a build tool for C with a particular emphasis on cross compilation. 8 | It is configured using 9 | [Dhall](http://github.com/dhall-lang/dhall-haskell). 10 | 11 | By considering a package to be a *function* taking a `cpkg`-supplied 12 | installation directory to a series of steps, we can effectively package 13 | C projects with diverse build systems and handle dependencies between them. 14 | 15 | This tool provides reasonably good support for cross-compilation of C projects 16 | and packages. It is not a full-fledged package manager. 17 | 18 | - [Installation](#installation) 19 | - [Shell Completions](#shell-completions) 20 | - [Packages](#packages) 21 | - [Example](#example) 22 | - [Configuration](#configuration) 23 | - [Dhall Prelude](#dhall-prelude) 24 | - [Cabal Integration](#cabal-integration) 25 | - [Known Deficiencies](#known-deficiences) 26 | - [Security](#security) 27 | - [Performance](#performance) 28 | - [Dependency Solver](#dependency-solver) 29 | - [Garbage Collection](#garbage-collection) 30 | - [Contents](#contents) 31 | 32 | ## Installation 33 | 34 | ``` 35 | cabal new-install cpkg 36 | ``` 37 | 38 | ### Shell Completions 39 | 40 | Add the following to your `~/.bashrc` for shell completions: 41 | 42 | ``` 43 | eval "$(cpkg --bash-completion-script cpkg)" 44 | ``` 45 | 46 | ### Packages 47 | 48 | To view available packages, use `cpkg list` 49 | 50 | ``` 51 | vanessa@thinkpad ~/programming/haskell/done/cpkg 🌸 cpkg list 52 | 53 | autoconf 54 | url: https://ftp.gnu.org/gnu/autoconf/autoconf-2.69.tar.xz 55 | version: 2.69 56 | build dependencies: m4 57 | 58 | 59 | automake 60 | url: https://ftp.gnu.org/gnu/automake/automake-1.16.1.tar.xz 61 | version: 1.16.1 62 | build dependencies: autoconf 63 | 64 | 65 | at-spi2-atk 66 | url: http://ftp.gnome.org/pub/gnome/sources/at-spi2-atk/2.30/at-spi2-atk-2.30.0.tar.xz 67 | version: 2.30.0 68 | dependencies: at-spi2-core, atk, libxml2 69 | build dependencies: meson, ninja 70 | 71 | 72 | at-spi2-core 73 | url: http://ftp.gnome.org/pub/gnome/sources/at-spi2-core/2.30/at-spi2-core-2.30.0.tar.xz 74 | version: 2.30.0 75 | dependencies: libXtst, glib 76 | build dependencies: meson, ninja 77 | 78 | 79 | atk 80 | url: https://ftp.gnome.org/pub/gnome/sources/atk/2.30/atk-2.30.0.tar.xz 81 | version: 2.30.0 82 | build dependencies: gobject-introspection 83 | ⋮ 84 | ``` 85 | 86 | 87 | ## Example 88 | 89 | To install `tar`: 90 | 91 | ``` 92 | cpkg install tar 93 | ``` 94 | 95 | To install `emacs`: 96 | 97 | ``` 98 | cpkg install emacs 99 | ``` 100 | 101 | ### Configuration 102 | 103 | Here is the configuration for Lua: 104 | 105 | ```dhall 106 | let prelude = https://raw.githubusercontent.com/vmchale/cpkg/master/dhall/cpkg-prelude.dhall 107 | in 108 | 109 | let lua = 110 | λ(v : List Natural) → 111 | let printLuaOS = 112 | λ(os : types.OS) → 113 | merge 114 | { FreeBSD = λ(_ : {}) → "freebsd" 115 | , OpenBSD = λ(_ : {}) → "bsd" 116 | , NetBSD = λ(_ : {}) → "bsd" 117 | , Solaris = λ(_ : {}) → "solaris" 118 | , Dragonfly = λ(_ : {}) → "bsd" 119 | , Linux = λ(_ : {}) → "linux" 120 | , Darwin = λ(_ : {}) → "macosx" 121 | , Windows = λ(_ : {}) → "mingw" 122 | , Redox = λ(_ : {}) → "generic" 123 | , Haiku = λ(_ : {}) → "generic" 124 | , IOS = λ(_ : {}) → "generic" 125 | , AIX = λ(_ : {}) → "generic" 126 | , Hurd = λ(_ : {}) → "generic" 127 | , Android = λ(_ : {}) → "generic" 128 | , NoOs = λ(_ : {}) → "c89" 129 | } 130 | os 131 | in 132 | 133 | let luaBuild = 134 | λ(cfg : types.BuildVars) → 135 | let cc = prelude.mkCCArg cfg 136 | in 137 | 138 | let ldflags = 139 | (prelude.mkLDFlags cfg.linkDirs).value 140 | in 141 | 142 | let cflags = 143 | (prelude.mkCFlags cfg.includeDirs).value 144 | in 145 | 146 | let os = 147 | prelude.osCfg cfg 148 | in 149 | 150 | [ prelude.call (prelude.defaultCall ⫽ { program = "make" 151 | , arguments = cc # [ printLuaOS os, "MYLDFLAGS=${ldflags}", "MYCFLAGS=${cflags}", "MYLIBS=-lncurses" ] 152 | }) 153 | ] 154 | in 155 | 156 | let luaInstall = 157 | λ(cfg : types.BuildVars) → 158 | [ prelude.call (prelude.defaultCall ⫽ { program = "make" 159 | , arguments = [ "install", "INSTALL_TOP=${cfg.installDir}" ] 160 | }) ] 161 | # prelude.symlinkBinaries [ "bin/lua", "bin/luac" ] 162 | in 163 | 164 | prelude.simplePackage { name = "lua", version = v } ⫽ 165 | { pkgUrl = "http://www.lua.org/ftp/lua-${prelude.showVersion v}.tar.gz" 166 | , configureCommand = prelude.doNothing 167 | , buildCommand = luaBuild 168 | , installCommand = luaInstall 169 | , pkgDeps = [ prelude.unbounded "readline" 170 | , prelude.unbounded "ncurses" 171 | ] 172 | } 173 | in 174 | 175 | lua [5,3,5] 176 | ``` 177 | 178 | ### Cabal Integration 179 | 180 | After running 181 | 182 | ``` 183 | cpkg install libX11 --target=arm-linux-gnueabihf 184 | cpkg install libXext --target=arm-linux-gnueabihf 185 | cpkg install libXrandr --target=arm-linux-gnueabihf 186 | cpkg install libXinerama --target=arm-linux-gnueabihf 187 | cpkg install libXScrnSaver --target=arm-linux-gnueabihf 188 | ``` 189 | 190 | You can dump flags to be passed to cabal with 191 | 192 | ``` 193 | cpkg dump-cabal libX11 libXext libXrandr libXinerama libXScrnSaver --target=arm-linux-gnueabihf 194 | ``` 195 | 196 | which will produce something like 197 | 198 | ``` 199 | --extra-lib-dirs=/home/vanessa/.cpkg/arm-linux-gnueabihf/libX11-1.6.7-820c8166b4caadb/lib --extra-lib-dirs=/home/vanessa/.cpkg/arm-linux-gnueabihf/libXext-1.3.3-1bad0a89c6794a53/lib --extra-lib-dirs=/home/vanessa/.cpkg/arm-linux-gnueabihf/libXrandr-1.5.1-f58f951a622e5c2/lib --extra-lib-dirs=/home/vanessa/.cpkg/arm-linux-gnueabihf/libXinerama-1.1.4-516496f7e04d34be/lib --extra-lib-dirs=/home/vanessa/.cpkg/arm-linux-gnueabihf/libXScrnSaver-1.2.3-60f6993b79a87725/lib 200 | ``` 201 | 202 | This could be used, for example, to cross-compile `xmonad`, viz. 203 | 204 | ``` 205 | cabal new-install xmonad --with-ghc arm-linux-gnueabihf-ghc --with-ghc-pkg arm-linux-gnueabihf-ghc-pkg $(cpkg dump-cabal libX11 libXext libXrandr libXinerama libXScrnSaver --target=arm-linux-gnueabihf) 206 | ``` 207 | 208 | ### Dhall Prelude 209 | 210 | There is 211 | a [prelude](https://github.com/vmchale/cpkg/blob/master/dhall/cpkg-prelude.dhall) 212 | available containing functions which simplify the process of writing package 213 | descriptions. As an example, we can install `sed` 214 | 215 | ```dhall 216 | let prelude = https://raw.githubusercontent.com/vmchale/cpkg/master/dhall/cpkg-prelude.dhall 217 | in 218 | 219 | let sed = 220 | λ(v : List Natural) → 221 | prelude.makeGnuExe { name = "sed", version = v } 222 | in 223 | 224 | sed [4,5] 225 | ``` 226 | 227 | ## Known Deficiencies 228 | 229 | ### Security 230 | 231 | This tool is insecure. 232 | 233 | ### Performance 234 | 235 | This tool is not performant. 236 | 237 | ### Dependency Solver 238 | 239 | Currently, there is no dependency solver. It should be relatively easy to add 240 | a version-based dependency solver to the code. 241 | 242 | ### Garbage Collection 243 | 244 | Currently, there is no garbage collector à la `$ nix-collect-garbage`. This will 245 | *not* be relatively easy to add, because it will require that the global package 246 | index be re-implemented (ideally using a proper database). 247 | 248 | ## Contents 249 | 250 | Lovingly provided by [polyglot](https://github.com/vmchale/polyglot): 251 | 252 | ``` 253 | ─────────────────────────────────────────────────────────────────────────────── 254 | Language Files Lines Code Comments Blanks 255 | ─────────────────────────────────────────────────────────────────────────────── 256 | Bash 4 58 49 3 6 257 | Cabal 1 165 147 0 18 258 | Cabal Project 1 4 3 0 1 259 | Dhall 5 6412 5724 0 688 260 | Haskell 32 1999 1643 37 319 261 | Makefile 1 12 8 0 4 262 | Markdown 3 556 448 0 108 263 | YAML 4 114 110 0 4 264 | ─────────────────────────────────────────────────────────────────────────────── 265 | Total 51 9320 8132 40 1148 266 | ─────────────────────────────────────────────────────────────────────────────── 267 | ``` 268 | -------------------------------------------------------------------------------- /src/Package/C/Db/Register.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE FlexibleContexts #-} 2 | {-# LANGUAGE RankNTypes #-} 3 | 4 | -- TODO: a lot of the stuff in this module could be made pure so that it only 5 | -- gets called once 6 | module Package.C.Db.Register ( registerPkg 7 | , unregisterPkg 8 | , uninstallPkg 9 | , uninstallPkgByName 10 | , installedDb 11 | , lookupOrFail 12 | , cPkgToDir 13 | , globalPkgDir 14 | , printCompilerFlags 15 | , printLinkerFlags 16 | , printPkgConfigPath 17 | , printIncludePath 18 | , printLibPath 19 | , printCabalFlags 20 | , printLdLibPath 21 | , packageInstalled 22 | , allPackages 23 | , parseHostIO 24 | , Platform 25 | ) where 26 | 27 | import Control.Monad.Reader 28 | import Control.Monad.State (modify) 29 | import CPkgPrelude 30 | import Data.Binary (encode) 31 | import qualified Data.ByteString.Lazy as BSL 32 | import Data.Hashable (Hashable (..)) 33 | import Data.List (intercalate) 34 | import qualified Data.Set as S 35 | import Numeric (showHex) 36 | import Package.C.Db.Memory 37 | import Package.C.Db.Monad 38 | import Package.C.Db.Type 39 | import Package.C.Error 40 | import Package.C.Logging 41 | import Package.C.Triple 42 | import Package.C.Type hiding (Dep (name)) 43 | 44 | type Platform = String 45 | type FlagPrint = forall m. MonadIO m => BuildCfg -> m String 46 | 47 | allPackages :: IO [String] 48 | allPackages = do 49 | (InstallDb index) <- strictIndex 50 | pure (buildName <$> toList index) 51 | 52 | printCompilerFlags :: (MonadIO m, MonadDb m) => String -> Maybe Platform -> m () 53 | printCompilerFlags = printFlagsWith buildCfgToCFlags 54 | 55 | printLinkerFlags :: (MonadIO m, MonadDb m) => String -> Maybe Platform -> m () 56 | printLinkerFlags = printFlagsWith buildCfgToLinkerFlags 57 | 58 | printPkgConfigPath :: (MonadIO m, MonadDb m) => [String] -> Maybe Platform -> m () 59 | printPkgConfigPath = printMany (liftIO . putStrLn <=< (fmap (intercalate ":") . traverse buildCfgToPkgConfigPath)) 60 | 61 | printIncludePath :: (MonadIO m, MonadDb m) => String -> Maybe Platform -> m () 62 | printIncludePath = printFlagsWith buildCfgToIncludePath 63 | 64 | printLibPath :: (MonadIO m, MonadDb m) => String -> Maybe Platform -> m () 65 | printLibPath = printFlagsWith buildCfgToLibPath 66 | 67 | parseHostIO :: MonadIO m => Maybe Platform -> m (Maybe TargetTriple) 68 | parseHostIO (Just x) = fmap Just (parseTripleIO x) 69 | parseHostIO Nothing = pure Nothing 70 | 71 | printFlagsWith :: (MonadIO m, MonadDb m) => FlagPrint -> String -> Maybe Platform -> m () 72 | printFlagsWith f name host = do 73 | 74 | parsedHost <- parseHostIO host 75 | 76 | maybePackage <- lookupPackage name parsedHost 77 | 78 | case maybePackage of 79 | Nothing -> indexError name 80 | Just p -> liftIO (putStrLn =<< f p) 81 | 82 | printMany :: (MonadIO m, MonadDb m) => ([BuildCfg] -> m ()) -> [String] -> Maybe Platform -> m () 83 | printMany f names host = do 84 | 85 | parsedHost <- parseHostIO host 86 | 87 | maybePackages <- sequenceA <$> traverse (\n -> lookupPackage n parsedHost) names 88 | 89 | case maybePackages of 90 | Nothing -> indexError (head names) 91 | Just ps -> f ps 92 | 93 | printLdLibPath :: (MonadIO m, MonadDb m) => [String] -> Maybe Platform -> m () 94 | printLdLibPath = printMany (liftIO . putStrLn <=< (fmap (intercalate ":") . traverse buildCfgToLibPath)) 95 | 96 | printCabalFlags :: (MonadIO m, MonadDb m) => [String] -> Maybe Platform -> m () 97 | printCabalFlags = printMany (liftIO . putStrLn <=< (fmap unwords . traverse buildCfgToCabalFlag)) 98 | 99 | buildCfgToCabalFlag :: MonadIO m => BuildCfg -> m String 100 | buildCfgToCabalFlag = fmap (("--extra-lib-dirs=" ++) . ( "lib")) . buildCfgToDir 101 | 102 | -- TODO: do something more sophisticated; allow packages to return their own 103 | -- dir? 104 | buildCfgToLinkerFlags :: MonadIO m => BuildCfg -> m String 105 | buildCfgToLinkerFlags = fmap (("-L" ++) . ( "lib")) . buildCfgToDir 106 | 107 | buildCfgToCFlags :: MonadIO m => BuildCfg -> m String 108 | buildCfgToCFlags = fmap (("-I" ++) . ( "include")) . buildCfgToDir 109 | 110 | buildCfgToPkgConfigPath :: MonadIO m => BuildCfg -> m String 111 | buildCfgToPkgConfigPath = fmap ( "lib" "pkgconfig") . buildCfgToDir 112 | 113 | buildCfgToLibPath :: MonadIO m => BuildCfg -> m String 114 | buildCfgToLibPath = fmap ( "lib") . buildCfgToDir 115 | 116 | buildCfgToIncludePath :: MonadIO m => BuildCfg -> m String 117 | buildCfgToIncludePath = fmap ( "include") . buildCfgToDir 118 | 119 | installedDb :: (MonadIO m, MonadDb m) 120 | => m (S.Set BuildCfg) 121 | installedDb = 122 | _installedPackages <$> memIndex 123 | 124 | packageInstalled :: (MonadIO m, MonadDb m) 125 | => CPkg 126 | -> Maybe TargetTriple 127 | -> Bool 128 | -> BuildVars 129 | -> m Bool 130 | packageInstalled pkg host glob b = do 131 | 132 | packs <- installedDb 133 | 134 | pure $ 135 | (pkgToBuildCfg pkg host glob True b `S.member` packs) 136 | || (pkgToBuildCfg pkg host glob False b `S.member` packs) 137 | 138 | lookupPackage :: (MonadIO m, MonadDb m) => String -> Maybe TargetTriple -> m (Maybe BuildCfg) 139 | lookupPackage name host = do 140 | 141 | packs <- installedDb 142 | 143 | let matches = S.filter (\pkg -> buildName pkg == name && targetArch pkg == host) packs 144 | 145 | pure (S.lookupMax matches) 146 | 147 | lookupOrFail :: (MonadIO m, MonadDb m) => String -> Maybe TargetTriple -> m BuildCfg 148 | lookupOrFail name host = do 149 | pk <- lookupPackage name host 150 | case pk of 151 | Just cfg -> pure cfg 152 | Nothing -> notInstalled name 153 | 154 | -- | @since 0.2.3.0 155 | uninstallPkgByName :: (MonadReader Verbosity m, MonadIO m, MonadDb m) 156 | => String 157 | -> Maybe TargetTriple 158 | -> m () 159 | uninstallPkgByName name host = 160 | uninstallPkg =<< lookupOrFail name host 161 | 162 | uninstallPkg :: (MonadIO m, MonadDb m, MonadReader Verbosity m) 163 | => BuildCfg 164 | -> m () 165 | uninstallPkg cpkg = do 166 | unregisterPkg cpkg 167 | (liftIO . removeDirectoryRecursive) 168 | =<< buildCfgToDir cpkg 169 | 170 | unregisterPkg :: (MonadIO m, MonadDb m, MonadReader Verbosity m) 171 | => BuildCfg 172 | -> m () 173 | unregisterPkg buildCfg = do 174 | 175 | putLoud ("Unregistering package " ++ buildName buildCfg ++ "...") 176 | 177 | indexFile <- pkgIndex 178 | indexContents <- memIndex 179 | 180 | let modIndex = over installedPackages (S.delete buildCfg) 181 | newIndex = modIndex indexContents 182 | 183 | modify modIndex 184 | 185 | liftIO $ BSL.writeFile indexFile (encode newIndex) 186 | 187 | -- TODO: replace this with a proper/sensible database 188 | registerPkg :: (MonadIO m, MonadDb m, MonadReader Verbosity m) 189 | => CPkg 190 | -> Maybe TargetTriple 191 | -> Bool -- ^ Globally installed? 192 | -> Bool -- ^ Manually installed? 193 | -> BuildVars 194 | -> m () 195 | registerPkg cpkg host glob usr b = do 196 | 197 | putDiagnostic ("Registering package " ++ pkgName cpkg ++ "...") 198 | 199 | indexFile <- pkgIndex 200 | indexContents <- memIndex 201 | 202 | let buildCfg = pkgToBuildCfg cpkg host glob usr b 203 | modIndex = over installedPackages (S.insert buildCfg) 204 | newIndex = modIndex indexContents 205 | 206 | modify modIndex 207 | 208 | liftIO $ BSL.writeFile indexFile (encode newIndex) 209 | 210 | pkgToBuildCfg :: CPkg 211 | -> Maybe TargetTriple 212 | -> Bool 213 | -> Bool -- ^ Was this package manually installed? 214 | -> BuildVars 215 | -> BuildCfg 216 | pkgToBuildCfg (CPkg n v _ _ bds ds cCmd bCmd iCmd) host glob usr bVar = 217 | BuildCfg n v (go <$> bds) (go <$> ds) host glob (cCmd bVar) (bCmd bVar) (iCmd bVar) usr -- TODO: fix pinned build deps &c. 218 | where placeholderVersion = Version [0,1,0,0] 219 | go (Dep n' _) = (n', placeholderVersion) 220 | 221 | platformString :: Maybe TargetTriple -> (FilePath -> FilePath -> FilePath) 222 | platformString Nothing = () 223 | platformString (Just p) = \x y -> x show p y 224 | 225 | buildCfgToDir :: MonadIO m => BuildCfg -> m FilePath 226 | buildCfgToDir buildCfg = do 227 | global' <- globalPkgDir 228 | -- when hashing, pretend everything has was NOT manually installed so they 229 | -- all have the same hash 230 | let hashed = showHex (abs (hash (buildCfg { manual = False}))) mempty 231 | () = platformString (targetArch buildCfg) 232 | pure (global' buildName buildCfg ++ "-" ++ showVersion (buildVersion buildCfg) ++ "-" ++ hashed) 233 | 234 | globDir :: Maybe TargetTriple -> FilePath 235 | globDir Nothing = "/usr/local" 236 | globDir (Just arch') = "/usr" show arch' 237 | 238 | cPkgToDir :: MonadIO m 239 | => CPkg 240 | -> Maybe TargetTriple 241 | -> Bool 242 | -> BuildVars 243 | -> m FilePath 244 | cPkgToDir pk host False bv = buildCfgToDir (pkgToBuildCfg pk host False undefined bv) 245 | cPkgToDir _ host _ _ = pure (globDir host) 246 | -------------------------------------------------------------------------------- /dhall/cpkg-prelude.dhall: -------------------------------------------------------------------------------- 1 | {- Dhall prelude imports -} 2 | let concatMapSep = 3 | https://raw.githubusercontent.com/dhall-lang/dhall-lang/9f259cd68870b912fbf2f2a08cd63dc3ccba9dc3/Prelude/Text/concatMapSep sha256:c272aca80a607bc5963d1fcb38819e7e0d3e72ac4d02b1183b1afb6a91340840 4 | 5 | let concatMapText = 6 | https://raw.githubusercontent.com/dhall-lang/dhall-lang/9f259cd68870b912fbf2f2a08cd63dc3ccba9dc3/Prelude/Text/concatMap sha256:7a0b0b99643de69d6f94ba49441cd0fa0507cbdfa8ace0295f16097af37e226f 7 | 8 | let concatMap = 9 | https://raw.githubusercontent.com/dhall-lang/dhall-lang/9f259cd68870b912fbf2f2a08cd63dc3ccba9dc3/Prelude/List/concatMap sha256:3b2167061d11fda1e4f6de0522cbe83e0d5ac4ef5ddf6bb0b2064470c5d3fb64 10 | 11 | let map = 12 | https://raw.githubusercontent.com/dhall-lang/dhall-lang/9f259cd68870b912fbf2f2a08cd63dc3ccba9dc3/Prelude/List/map sha256:dd845ffb4568d40327f2a817eb42d1c6138b929ca758d50bc33112ef3c885680 13 | 14 | let mapOptional = 15 | https://raw.githubusercontent.com/dhall-lang/dhall-lang/bf757ba1ee526714278568012c6bc98d7ea9757e/Prelude/Optional/map sha256:501534192d988218d43261c299cc1d1e0b13d25df388937add784778ab0054fa 16 | 17 | let not = 18 | https://raw.githubusercontent.com/dhall-lang/dhall-lang/9f259cd68870b912fbf2f2a08cd63dc3ccba9dc3/Prelude/Bool/not sha256:723df402df24377d8a853afed08d9d69a0a6d86e2e5b2bac8960b0d4756c7dc4 19 | 20 | let types = ../dhall/cpkg-types.dhall 21 | 22 | let showVersion = concatMapSep "." Natural Natural/show 23 | 24 | let maybeAppend = 25 | λ(a : Type) → 26 | λ(x : Optional a) → 27 | λ(xs : List a) → 28 | merge { Some = λ(x : a) → xs # [ x ], None = xs } x 29 | 30 | let printArch = 31 | λ(arch : types.Arch) → 32 | merge 33 | { X64 = "x86_64" 34 | , AArch = "aarch64" 35 | , Arm = "arm" 36 | , RISCV64 = "riscv64" 37 | , PowerPC = "powerpc" 38 | , PowerPC64 = "powerpc64" 39 | , PowerPC64le = "powerpc64le" 40 | , Sparc64 = "sparc64" 41 | , S390x = "s390x" 42 | , Alpha = "alpha" 43 | , M68k = "m68k" 44 | , Mips = "mips" 45 | , MipsEl = "mipsel" 46 | , Mips64 = "mips64" 47 | , Mips64El = "mips64el" 48 | , X86 = "i686" 49 | , SH4 = "sh4" 50 | , HPPA = "hppa" 51 | , HPPA64 = "hppa64" 52 | , MipsIsa32r6El = "mipsisa32r6el" 53 | , MipsIsa32r6 = "mipsisa32r6" 54 | , MipsIsa64r6El = "mipsisa64r6el" 55 | , MipsIsa64r6 = "mipsisa64r6" 56 | } 57 | arch 58 | 59 | let printManufacturer = 60 | λ(x : types.Manufacturer) → 61 | merge { Unknown = "unknown", Apple = "apple", IBM = "ibm", PC = "pc" } x 62 | 63 | let libSuffix = 64 | λ(os : types.OS) → 65 | merge 66 | { FreeBSD = "so" 67 | , OpenBSD = "so" 68 | , NetBSD = "so" 69 | , Solaris = "so" 70 | , Dragonfly = "so" 71 | , Linux = "so" 72 | , Darwin = "dylib" 73 | , Windows = "dll" 74 | , Redox = "so" 75 | , Haiku = "so" 76 | , IOS = "dylib" 77 | , AIX = "so" 78 | , Hurd = "so" 79 | , Android = "so" 80 | , NoOs = "so" 81 | } 82 | os 83 | 84 | let printOS = 85 | λ(os : types.OS) → 86 | merge 87 | { FreeBSD = "freebsd" 88 | , OpenBSD = "openbsd" 89 | , NetBSD = "netbsd" 90 | , Solaris = "solaris" 91 | , Dragonfly = "dragonfly" 92 | , Linux = "linux" 93 | , Darwin = "darwin" 94 | , Windows = "w64" 95 | , Redox = "redox" 96 | , Haiku = "haiku" 97 | , IOS = "darwin" 98 | , AIX = "aix" 99 | , Hurd = "hurd" 100 | , Android = "android" 101 | , NoOs = "none" 102 | } 103 | os 104 | 105 | let printABI = 106 | λ(os : types.ABI) → 107 | merge 108 | { GNU = "gnu" 109 | , GNUabi64 = "gnuabi64" 110 | , GNUeabi = "gnueabi" 111 | , GNUeabihf = "gnueabihf" 112 | , GNUspe = "gnuspe" 113 | , MinGw = "mingw32" 114 | } 115 | os 116 | 117 | let printTargetTriple = 118 | λ(t : types.TargetTriple) → 119 | "${printArch t.arch}-${printOS t.os}" 120 | ++ merge 121 | { Some = λ(abi : types.ABI) → "-${printABI abi}", None = "" } 122 | t.abi 123 | 124 | let mkHost = 125 | mapOptional 126 | types.TargetTriple 127 | Text 128 | (λ(tgt : types.TargetTriple) → "--host=${printTargetTriple tgt}") 129 | 130 | let makeExe = 131 | λ(os : types.OS) → 132 | merge 133 | { FreeBSD = "gmake" 134 | , OpenBSD = "gmake" 135 | , NetBSD = "gmake" 136 | , Solaris = "gmake" 137 | , Dragonfly = "gmake" 138 | , Linux = "make" 139 | , Darwin = "make" 140 | , Windows = "make" 141 | , Redox = "make" 142 | , Haiku = "make" 143 | , IOS = "make" 144 | , AIX = "make" 145 | , Hurd = "make" 146 | , Android = "make" 147 | , NoOs = "make" 148 | } 149 | os 150 | 151 | let mkExe = λ(x : Text) → types.Command.MakeExecutable { file = x } 152 | 153 | let mkExes = map Text types.Command mkExe 154 | 155 | let writeFile = types.Command.Write 156 | 157 | let patch = λ(x : Text) → types.Command.Patch { patchContents = x } 158 | 159 | let defaultEnv = None (List types.EnvVar) 160 | 161 | let defaultCall = 162 | { arguments = [] : List Text 163 | , environment = defaultEnv 164 | , procDir = None Text 165 | } 166 | 167 | let call = types.Command.Call 168 | 169 | let symlinkBinary = λ(file : Text) → types.Command.SymlinkBinary { file } 170 | 171 | let symlinkManpage = types.Command.SymlinkManpage 172 | 173 | let symlink = 174 | λ(tgt : Text) → 175 | λ(lnk : Text) → 176 | types.Command.Symlink { tgt, linkName = lnk } 177 | 178 | let copyFile = 179 | λ(src : Text) → λ(dest : Text) → types.Command.CopyFile { src, dest } 180 | 181 | let symlinkBinaries = map Text types.Command symlinkBinary 182 | 183 | let symlinkManpages = 184 | map { file : Text, section : Natural } types.Command symlinkManpage 185 | 186 | let isUnix = 187 | λ(os : types.OS) → 188 | merge 189 | { FreeBSD = True 190 | , OpenBSD = True 191 | , NetBSD = True 192 | , Solaris = True 193 | , Dragonfly = True 194 | , Linux = True 195 | , Darwin = True 196 | , Windows = False 197 | , Redox = False 198 | , Haiku = False 199 | , IOS = True 200 | , AIX = True 201 | , Hurd = True 202 | , Android = True 203 | , NoOs = False 204 | } 205 | os 206 | 207 | let isMac = 208 | λ(os : types.OS) → 209 | merge 210 | { FreeBSD = False 211 | , OpenBSD = False 212 | , NetBSD = False 213 | , Solaris = False 214 | , Dragonfly = False 215 | , Linux = False 216 | , Darwin = True 217 | , Windows = False 218 | , Redox = False 219 | , Haiku = False 220 | , IOS = False 221 | , AIX = False 222 | , Hurd = False 223 | , Android = False 224 | , NoOs = False 225 | } 226 | os 227 | 228 | let mkLDFlagsGeneral = 229 | λ(libDirs : List Text) → 230 | λ(linkLibs : List Text) → 231 | λ(cfg : types.BuildVars) → 232 | let flag0 = concatMapSep " " Text (λ(dir : Text) → "-L${dir}") libDirs 233 | 234 | let flag1 = concatMapText Text (λ(dir : Text) → " -l${dir}") linkLibs 235 | 236 | let flag2 = 237 | concatMapText 238 | Text 239 | ( λ(dir : Text) → 240 | if isMac cfg.buildOS then "" else " -Wl,-rpath-link,${dir}" 241 | ) 242 | libDirs 243 | 244 | in { var = "LDFLAGS", value = flag0 ++ flag1 ++ flag2 } 245 | 246 | let mkLDFlags = 247 | λ(libDirs : List Text) → mkLDFlagsGeneral libDirs ([] : List Text) 248 | 249 | let mkLDPath = 250 | λ(libDirs : List Text) → 251 | let flag = concatMapSep ":" Text (λ(dir : Text) → dir) libDirs 252 | 253 | in { var = "LD_LIBRARY_PATH", value = flag } 254 | 255 | let mkLDRunPath = 256 | λ(libDirs : List Text) → 257 | let flag = concatMapSep ":" Text (λ(dir : Text) → dir) libDirs 258 | 259 | in { var = "LD_RUN_PATH", value = flag } 260 | 261 | let mkStaPath = 262 | λ(libDirs : List Text) → 263 | let flag = concatMapText Text (λ(dir : Text) → "${dir}:") libDirs 264 | 265 | in { var = "LIBRARY_PATH" 266 | , value = flag ++ "/usr/local/lib:/lib:/usr/lib" 267 | } 268 | 269 | let osCfg = 270 | λ(cfg : types.BuildVars) → 271 | merge 272 | { Some = λ(tgt : types.TargetTriple) → tgt.os, None = cfg.buildOS } 273 | cfg.targetTriple 274 | 275 | let archCfg = 276 | λ(cfg : types.BuildVars) → 277 | merge 278 | { Some = λ(tgt : types.TargetTriple) → tgt.arch 279 | , None = cfg.buildArch 280 | } 281 | cfg.targetTriple 282 | 283 | let mkPerlLib = 284 | λ ( x 285 | : { libDirs : List Text 286 | , perlVersion : List Natural 287 | , cfg : types.BuildVars 288 | } 289 | ) → 290 | let os = x.cfg.buildOS 291 | 292 | let arch = x.cfg.buildArch 293 | 294 | let flag = 295 | concatMapSep 296 | ":" 297 | Text 298 | ( λ(dir : Text) → 299 | "${dir}/site_perl/${showVersion 300 | x.perlVersion}/${printArch 301 | arch}-${printOS 302 | os}/" 303 | ) 304 | x.libDirs 305 | 306 | let major = 307 | merge 308 | { Some = Natural/show, None = "" } 309 | (List/head Natural x.perlVersion) 310 | 311 | in { var = "PERL${major}LIB", value = flag } 312 | 313 | let mkIncludePath = 314 | λ(incls : List Text) → 315 | let flag = concatMapSep ":" Text (λ(dir : Text) → dir) incls 316 | 317 | in { var = "C_INCLUDE_PATH", value = flag } 318 | 319 | let mkCFlags = 320 | λ(cfg : types.BuildVars) → 321 | let flag = 322 | concatMapSep " " Text (λ(dir : Text) → "-I${dir}") cfg.includeDirs 323 | 324 | let staFlag = if cfg.static then " -static" else "" 325 | 326 | in { var = "CPPFLAGS", value = flag ++ staFlag } 327 | 328 | let mkPkgConfigVar = 329 | λ(libDirs : List Text) → 330 | let flag = 331 | concatMapSep ":" Text (λ(dir : Text) → "${dir}/pkgconfig") libDirs 332 | 333 | in { var = "PKG_CONFIG_PATH", value = flag } 334 | 335 | let mkXdgDataDirs = 336 | λ(shareDirs : List Text) → 337 | let flag = concatMapSep ":" Text (λ(dir : Text) → dir) shareDirs 338 | 339 | in { var = "XDG_DATA_DIRS", value = flag } 340 | 341 | let mkPathVar = 342 | λ(binDirs : List Text) → 343 | concatMapText Text (λ(dir : Text) → "${dir}:") binDirs 344 | 345 | let unixPath = 346 | λ(binDirs : List Text) → 347 | { var = "PATH" 348 | , value = 349 | mkPathVar binDirs 350 | ++ "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" 351 | } 352 | 353 | let defaultPath = 354 | λ(cfg : types.BuildVars) → 355 | if isUnix cfg.buildOS 356 | then [ unixPath cfg.binDirs ] : List types.EnvVar 357 | else [] : List types.EnvVar 358 | 359 | let libPath = 360 | λ(cfg : types.BuildVars) → 361 | if cfg.static then mkStaPath cfg.linkDirs else mkLDPath cfg.linkDirs 362 | 363 | let mkLDPreload = 364 | λ(libs : List Text) → 365 | let flag = concatMapSep " " Text (λ(lib : Text) → lib) libs 366 | 367 | in { var = "LD_PRELOAD", value = flag } 368 | 369 | let mkGuileEnv = 370 | λ(libs : List Text) → 371 | λ(share : List Text) → 372 | let flag0 = 373 | concatMapSep 374 | ":" 375 | Text 376 | (λ(lib : Text) → "${lib}/guile/3.0/site-ccache") 377 | libs 378 | 379 | let flag1 = 380 | concatMapSep 381 | ":" 382 | Text 383 | (λ(dir : Text) → "${dir}/guile/site/3.0") 384 | share 385 | 386 | in [ { var = "GUILE_LOAD_COMPILED_PATH", value = flag0 } 387 | , { var = "GUILE_LOAD_PATH", value = flag1 } 388 | ] 389 | 390 | let configEnv = 391 | λ(linkLibs : List Text) → 392 | λ(cfg : types.BuildVars) → 393 | defaultPath cfg 394 | # [ mkLDFlagsGeneral cfg.linkDirs linkLibs cfg 395 | , mkCFlags cfg 396 | , mkPkgConfigVar (cfg.shareDirs # cfg.linkDirs) 397 | , libPath cfg 398 | , mkLDRunPath cfg.linkDirs 399 | , mkPerlLib 400 | { libDirs = cfg.linkDirs, perlVersion = [ 5, 30, 2 ], cfg } 401 | ] 402 | # mkGuileEnv cfg.linkDirs cfg.shareDirs 403 | 404 | let buildEnv = 405 | λ(cfg : types.BuildVars) → 406 | defaultPath cfg 407 | # [ mkPkgConfigVar (cfg.shareDirs # cfg.linkDirs) 408 | , mkPerlLib 409 | { libDirs = cfg.linkDirs, perlVersion = [ 5, 30, 2 ], cfg } 410 | , mkLDPath cfg.linkDirs 411 | , mkLDFlagsGeneral cfg.linkDirs ([] : List Text) cfg 412 | ] 413 | # mkGuileEnv cfg.linkDirs cfg.shareDirs 414 | 415 | let configSome = 416 | λ(linkLibs : List Text) → 417 | λ(cfg : types.BuildVars) → 418 | Some (configEnv linkLibs cfg) 419 | 420 | let generalConfigure = 421 | λ(envVars : List Text → types.BuildVars → Optional (List types.EnvVar)) → 422 | λ(filename : Text) → 423 | λ(linkLibs : List Text) → 424 | λ(extraFlags : List Text) → 425 | λ(cfg : types.BuildVars) → 426 | let maybeHost = mkHost cfg.targetTriple 427 | 428 | let modifyArgs = maybeAppend Text maybeHost 429 | 430 | let mac = isMac cfg.buildOS 431 | 432 | let modifyProg = 433 | if mac 434 | then λ(x : List Text) → [ "${filename}" ] # x 435 | else λ(x : List Text) → x 436 | 437 | let program = if mac then "sh" else "./${filename}" 438 | 439 | in [ call 440 | ( defaultCall 441 | ⫽ { program 442 | , arguments = 443 | modifyProg 444 | ( modifyArgs [ "--prefix=${cfg.installDir}" ] 445 | # extraFlags 446 | ) 447 | , environment = envVars linkLibs cfg 448 | } 449 | ) 450 | ] 451 | 452 | let configWithEnv = 453 | λ(envVars : List Text → types.BuildVars → Optional (List types.EnvVar)) → 454 | generalConfigure envVars "configure" ([] : List Text) ([] : List Text) 455 | 456 | let configureWithFlags = 457 | generalConfigure configSome "configure" ([] : List Text) 458 | 459 | let defaultConfigure = configureWithFlags ([] : List Text) 460 | 461 | let configureLinkExtraLibs = 462 | λ(linkLibs : List Text) → 463 | generalConfigure configSome "configure" linkLibs ([] : List Text) 464 | 465 | let mkAclocalPath = 466 | λ(shareDirs : List Text) → 467 | let flag = 468 | concatMapSep 469 | ":" 470 | Text 471 | (λ(dir : Text) → "${dir}/aclocal:${dir}/autoconf") 472 | shareDirs 473 | 474 | in { var = "ACLOCAL_PATH", value = flag } 475 | 476 | let configureMkExesExtraFlags = 477 | λ(x : { bins : List Text, extraFlags : List Text }) → 478 | λ(cfg : types.BuildVars) → 479 | mkExes x.bins # configureWithFlags x.extraFlags cfg 480 | 481 | let configureMkExes = 482 | λ(bins : List Text) → 483 | configureMkExesExtraFlags { bins, extraFlags = [] : List Text } 484 | 485 | let generalBuild = 486 | λ(cpus : types.BuildVars → Natural) → 487 | λ(envs : List types.EnvVar) → 488 | λ(cfg : types.BuildVars) → 489 | [ call 490 | ( defaultCall 491 | ⫽ { program = makeExe cfg.buildOS 492 | , arguments = [ "-j${Natural/show (cpus cfg)}" ] 493 | , environment = Some envs 494 | } 495 | ) 496 | ] 497 | 498 | let defaultCpus = λ(cfg : types.BuildVars) → cfg.cpus 499 | 500 | let singleThreaded = λ(_ : types.BuildVars) → 1 501 | 502 | let buildWith = generalBuild defaultCpus 503 | 504 | let defaultBuild = λ(cfg : types.BuildVars) → buildWith (buildEnv cfg) cfg 505 | 506 | let installWith = 507 | λ(envs : List types.EnvVar) → 508 | λ(cfg : types.BuildVars) → 509 | [ call 510 | ( defaultCall 511 | ⫽ { program = makeExe cfg.buildOS 512 | , arguments = [ "install" ] 513 | , environment = Some envs 514 | } 515 | ) 516 | ] 517 | 518 | let defaultInstall = λ(cfg : types.BuildVars) → installWith (buildEnv cfg) cfg 519 | 520 | let installWithBinaries = 521 | λ(bins : List Text) → 522 | λ(installVars : types.BuildVars) → 523 | defaultInstall installVars 524 | # ( if not installVars.isCross 525 | then symlinkBinaries bins 526 | else [] : List types.Command 527 | ) 528 | 529 | let installWithManpages = 530 | λ(mans : List { file : Text, section : Natural }) → 531 | λ(installVars : types.BuildVars) → 532 | defaultInstall installVars 533 | # ( if not installVars.isCross 534 | then symlinkManpages mans 535 | else [] : List types.Command 536 | ) 537 | 538 | let unbounded = λ(x : Text) → { name = x, bound = types.VersionBound.NoBound } 539 | 540 | let lowerBound = 541 | λ(pkg : { name : Text, lower : List Natural }) → 542 | { name = pkg.name 543 | , bound = types.VersionBound.Lower { lower = pkg.lower } 544 | } 545 | 546 | let upperBound = 547 | λ(pkg : { name : Text, upper : List Natural }) → 548 | { name = pkg.name 549 | , bound = types.VersionBound.Upper { upper = pkg.upper } 550 | } 551 | 552 | let defaultPackage = 553 | { configureCommand = defaultConfigure 554 | , buildCommand = defaultBuild 555 | , installCommand = defaultInstall 556 | , pkgBuildDeps = [] : List types.Dep 557 | , pkgDeps = [] : List types.Dep 558 | } 559 | 560 | let simplePackage = 561 | λ(pkg : { name : Text, version : List Natural }) → 562 | defaultPackage 563 | ⫽ { pkgName = pkg.name 564 | , pkgVersion = pkg.version 565 | , pkgSubdir = "${pkg.name}-${showVersion pkg.version}" 566 | } 567 | 568 | let makeGnuExe = 569 | λ(pkg : { name : Text, version : List Natural }) → 570 | simplePackage pkg 571 | ⫽ { pkgUrl = 572 | "https://ftp.gnu.org/gnu/${pkg.name}/${pkg.name}-${showVersion 573 | pkg.version}.tar.xz" 574 | , installCommand = installWithBinaries [ "bin/${pkg.name}" ] 575 | } 576 | 577 | let makeGnuLibrary = 578 | λ(pkg : { name : Text, version : List Natural }) → 579 | simplePackage pkg 580 | ⫽ { pkgUrl = 581 | "https://ftp.gnu.org/pub/gnu/lib${pkg.name}/lib${pkg.name}-${showVersion 582 | pkg.version}.tar.xz" 583 | , pkgSubdir = "lib${pkg.name}-${showVersion pkg.version}" 584 | } 585 | 586 | let createDir = λ(x : Text) → types.Command.CreateDirectory { dir = x } 587 | 588 | let printCMakeOS = 589 | λ(os : types.OS) → 590 | merge 591 | { FreeBSD = "BSD" 592 | , OpenBSD = "BSD" 593 | , NetBSD = "BSD" 594 | , Solaris = "Solaris" 595 | , Dragonfly = "BSD" 596 | , Linux = "Linux" 597 | , Darwin = "Darwin" 598 | , Windows = "Windows" 599 | , Redox = "Redox" 600 | , Haiku = "Haiku" 601 | , IOS = "Darwin" 602 | , AIX = "AIX" 603 | , Hurd = "Hurd" 604 | , Android = "Android" 605 | , NoOs = "Generic" 606 | } 607 | os 608 | 609 | let cmakeConfigureGeneral = 610 | λ(envVars : types.BuildVars → Optional (List types.EnvVar)) → 611 | λ(flags : List Text) → 612 | λ(cfg : types.BuildVars) → 613 | let host = 614 | merge 615 | { Some = 616 | λ(tgt : types.TargetTriple) → 617 | [ "-DCMAKE_C_COMPILER=${printTargetTriple tgt}-gcc" 618 | , "-DCMAKE_CXX_COMPILER=${printTargetTriple tgt}-g++" 619 | ] 620 | , None = 621 | [ "-DCMAKE_C_COMPILER=gcc", "-DCMAKE_CXX_COMPILER=g++" ] 622 | } 623 | cfg.targetTriple 624 | 625 | let system = 626 | merge 627 | { Some = 628 | λ(tgt : types.TargetTriple) → 629 | [ "-DCMAKE_SYSTEM_NAME=${printCMakeOS tgt.os}" ] 630 | , None = [] : List Text 631 | } 632 | cfg.targetTriple 633 | 634 | in [ createDir "build" 635 | , call 636 | { program = "cmake" 637 | , arguments = 638 | [ "../" 639 | , "-DCMAKE_INSTALL_PREFIX:PATH=${cfg.installDir}" 640 | , "-DCMAKE_MAKE_PROGRAM=${makeExe cfg.buildOS}" 641 | ] 642 | # host 643 | # system 644 | # flags 645 | , environment = envVars cfg 646 | , procDir = Some "build" 647 | } 648 | ] 649 | 650 | let cmakeEnv = 651 | λ(cfg : types.BuildVars) → 652 | [ mkPkgConfigVar (cfg.shareDirs # cfg.linkDirs) 653 | , { var = "CMAKE_INCLUDE_PATH" 654 | , value = (mkIncludePath cfg.includeDirs).value 655 | } 656 | , { var = "CMAKE_LIBRARY_PATH", value = (libPath cfg).value } 657 | ] 658 | # defaultPath cfg 659 | 660 | let cmakeSome = λ(cfg : types.BuildVars) → Some (cmakeEnv cfg) 661 | 662 | let cmakeConfigureWithFlags = cmakeConfigureGeneral cmakeSome 663 | 664 | let cmakeConfigure = cmakeConfigureWithFlags ([] : List Text) 665 | 666 | let cmakeConfigureNinja = 667 | λ(cfg : types.BuildVars) → 668 | let host = 669 | merge 670 | { Some = 671 | λ(tgt : types.TargetTriple) → 672 | [ "-DCMAKE_C_COMPILER=${printTargetTriple tgt}-gcc" 673 | , "-DCMAKE_CXX_COMPILER=${printTargetTriple tgt}-g++" 674 | ] 675 | , None = [] : List Text 676 | } 677 | cfg.targetTriple 678 | 679 | let system = 680 | merge 681 | { Some = 682 | λ(tgt : types.TargetTriple) → 683 | [ "-DCMAKE_SYSTEM_NAME=${printCMakeOS tgt.os}" ] 684 | , None = [] : List Text 685 | } 686 | cfg.targetTriple 687 | 688 | in [ createDir "build" 689 | , call 690 | { program = "cmake" 691 | , arguments = 692 | [ "../" 693 | , "-DCMAKE_INSTALL_PREFIX:PATH=${cfg.installDir}" 694 | , "-G" 695 | , "Ninja" 696 | ] 697 | # host 698 | # system 699 | , environment = Some (cmakeEnv cfg) 700 | , procDir = Some "build" 701 | } 702 | ] 703 | 704 | let cmakeBuild = 705 | λ(cfg : types.BuildVars) → 706 | [ call 707 | { program = "cmake" 708 | , arguments = 709 | [ "--build" 710 | , "." 711 | , "--config" 712 | , "Release" 713 | , "--" 714 | , "-j" 715 | , Natural/show cfg.cpus 716 | ] 717 | , environment = Some (cmakeEnv cfg) 718 | , procDir = Some "build" 719 | } 720 | ] 721 | 722 | let cmakeInstall = 723 | λ(cfg : types.BuildVars) → 724 | [ call 725 | { program = "cmake" 726 | , arguments = 727 | [ "--build", ".", "--target", "install", "--config", "Release" ] 728 | , environment = Some (cmakeEnv cfg) 729 | , procDir = Some "build" 730 | } 731 | ] 732 | 733 | let cmakeInstallWithBinaries = 734 | λ(bins : List Text) → 735 | λ(installVars : types.BuildVars) → 736 | cmakeInstall installVars # symlinkBinaries bins 737 | 738 | let cmakePackage = 739 | defaultPackage 740 | ⫽ { configureCommand = cmakeConfigure 741 | , buildCommand = cmakeBuild 742 | , installCommand = cmakeInstall 743 | , pkgBuildDeps = [ unbounded "cmake" ] 744 | } 745 | 746 | let autogenConfigure = 747 | λ(cfg : types.BuildVars) → 748 | [ call 749 | ( defaultCall 750 | ⫽ { program = "./autogen.sh" 751 | , environment = Some 752 | ( [ mkAclocalPath cfg.shareDirs 753 | , mkPkgConfigVar (cfg.shareDirs # cfg.linkDirs) 754 | ] 755 | # defaultPath cfg 756 | ) 757 | } 758 | ) 759 | ] 760 | # defaultConfigure cfg 761 | 762 | let fullVersion = 763 | λ(x : { version : List Natural, patch : Natural }) → 764 | x.version # [ x.patch ] 765 | 766 | let mkPyPath = 767 | λ(version : List Natural) → 768 | λ(libDirs : List Text) → 769 | let flag = 770 | concatMapSep 771 | ":" 772 | Text 773 | ( λ(dir : Text) → 774 | "${dir}/python${showVersion version}/site-packages" 775 | ) 776 | libDirs 777 | 778 | in { var = "PYTHONPATH", value = flag } 779 | 780 | let mkPy3Path = mkPyPath [ 3, 9 ] 781 | 782 | let mesonCfgFile = 783 | λ(cfg : types.BuildVars) → 784 | let prefix = 785 | merge 786 | { Some = 787 | λ(tgt : types.TargetTriple) → "${printTargetTriple tgt}-" 788 | , None = "" 789 | } 790 | cfg.targetTriple 791 | 792 | in '' 793 | [binaries] 794 | '' 795 | ++ '' 796 | c = '${prefix}gcc' 797 | '' 798 | ++ '' 799 | cpp = '${prefix}g++' 800 | '' 801 | ++ '' 802 | ar = '${prefix}ar' 803 | '' 804 | ++ '' 805 | strip = '${prefix}strip' 806 | '' 807 | ++ '' 808 | pkgconfig = 'pkg-config' 809 | '' 810 | ++ '' 811 | [host_machine] 812 | '' 813 | ++ '' 814 | system = '${printOS (osCfg cfg)}' 815 | '' 816 | ++ '' 817 | cpu_family = '${printArch (archCfg cfg)}' 818 | '' 819 | ++ '' 820 | cpu = '${printArch (archCfg cfg)}' 821 | '' 822 | ++ "endian = 'little'" 823 | 824 | let mesonEnv = 825 | λ(cfg : types.BuildVars) → 826 | Some 827 | ( [ mkPkgConfigVar (cfg.linkDirs # cfg.shareDirs) 828 | , mkPy3Path cfg.linkDirs 829 | , libPath cfg 830 | , mkLDRunPath cfg.linkDirs 831 | , mkLDFlags cfg.linkDirs cfg 832 | , mkCFlags cfg 833 | , mkLDPreload cfg.preloadLibs 834 | ] 835 | # defaultPath cfg 836 | ) 837 | 838 | let mesonConfigureGeneral = 839 | λ(envs : types.BuildVars → Optional (List types.EnvVar)) → 840 | λ(flags : List Text) → 841 | λ(cfg : types.BuildVars) → 842 | let crossArgs = 843 | if cfg.isCross 844 | then [ "--cross-file", "cross.txt" ] 845 | else [] : List Text 846 | 847 | in [ createDir "build" 848 | , writeFile 849 | { file = "build/cross.txt", contents = mesonCfgFile cfg } 850 | , call 851 | { program = "meson" 852 | , arguments = 853 | [ "--prefix=${cfg.installDir}", ".." ] # crossArgs # flags 854 | , environment = envs cfg 855 | , procDir = Some "build" 856 | } 857 | ] 858 | 859 | let mesonConfigureWithFlags = mesonConfigureGeneral mesonEnv 860 | 861 | let mesonConfigure = mesonConfigureWithFlags ([] : List Text) 862 | 863 | let ninjaBuildWith = 864 | λ(linkLibs : List Text) → 865 | λ(cfg : types.BuildVars) → 866 | let ldPreload = 867 | if cfg.isCross 868 | then [] : List types.EnvVar 869 | else [ mkLDPreload cfg.preloadLibs ] 870 | 871 | in [ call 872 | ( defaultCall 873 | ⫽ { program = "ninja" 874 | , environment = Some 875 | ( [ mkPkgConfigVar cfg.linkDirs 876 | , mkPy3Path cfg.linkDirs 877 | , libPath cfg 878 | , mkLDRunPath cfg.linkDirs 879 | , mkLDFlagsGeneral cfg.linkDirs linkLibs cfg 880 | , mkCFlags cfg 881 | ] 882 | # defaultPath cfg 883 | # ldPreload 884 | ) 885 | , procDir = Some "build" 886 | } 887 | ) 888 | ] 889 | 890 | let ninjaBuild = ninjaBuildWith ([] : List Text) 891 | 892 | let ninjaInstall = 893 | λ(cfg : types.BuildVars) → 894 | [ call 895 | ( defaultCall 896 | ⫽ { program = "ninja" 897 | , environment = Some 898 | ( [ mkPkgConfigVar cfg.linkDirs 899 | , mkPy3Path cfg.linkDirs 900 | , libPath cfg 901 | , mkLDRunPath cfg.linkDirs 902 | , mkLDFlags cfg.linkDirs cfg 903 | , mkCFlags cfg 904 | ] 905 | # defaultPath cfg 906 | ) 907 | , arguments = [ "install" ] 908 | , procDir = Some "build" 909 | } 910 | ) 911 | ] 912 | 913 | let ninjaPackage = 914 | λ(x : { name : Text, version : List Natural }) → 915 | simplePackage x 916 | ⫽ { configureCommand = mesonConfigure 917 | , buildCommand = ninjaBuild 918 | , installCommand = ninjaInstall 919 | , pkgBuildDeps = [ unbounded "meson", unbounded "ninja" ] 920 | } 921 | 922 | let copyFiles = 923 | map { src : Text, dest : Text } types.Command types.Command.CopyFile 924 | 925 | let ninjaInstallWithPkgConfig = 926 | λ(fs : List { src : Text, dest : Text }) → 927 | λ(cfg : types.BuildVars) → 928 | ninjaInstall cfg # copyFiles fs 929 | 930 | let doNothing = λ(_ : types.BuildVars) → [] : List types.Command 931 | 932 | let mesonMoves = 933 | map 934 | Text 935 | { src : Text, dest : Text } 936 | ( λ(pcFile : Text) → 937 | { src = "build/meson-private/${pcFile}" 938 | , dest = "lib/pkgconfig/${pcFile}" 939 | } 940 | ) 941 | 942 | let pythonBuild = 943 | λ(version : List Natural) → 944 | λ(cfg : types.BuildVars) → 945 | let major = 946 | merge 947 | { Some = Natural/show, None = "" } 948 | (List/head Natural version) 949 | 950 | let versionString = showVersion version 951 | 952 | in [ createDir 953 | "${cfg.installDir}/lib/python${versionString}/site-packages" 954 | , call 955 | ( defaultCall 956 | ⫽ { program = "python${major}" 957 | , arguments = [ "setup.py", "build" ] 958 | , environment = Some 959 | ( [ { var = "PYTHONPATH" 960 | , value = 961 | "${cfg.installDir}/lib/python${versionString}/site-packages" 962 | } 963 | , mkPkgConfigVar cfg.linkDirs 964 | , libPath cfg 965 | ] 966 | # defaultPath cfg 967 | ) 968 | } 969 | ) 970 | ] 971 | 972 | let pythonInstall = 973 | λ(version : List Natural) → 974 | λ(cfg : types.BuildVars) → 975 | let major = 976 | merge 977 | { Some = Natural/show, None = "" } 978 | (List/head Natural version) 979 | 980 | let versionString = showVersion version 981 | 982 | in [ createDir 983 | "${cfg.installDir}/lib/python${versionString}/site-packages" 984 | , call 985 | ( defaultCall 986 | ⫽ { program = "python${major}" 987 | , arguments = 988 | [ "setup.py" 989 | , "install" 990 | , "--prefix=${cfg.installDir}" 991 | , "--optimize=1" 992 | ] 993 | , environment = Some 994 | ( [ { var = "PYTHONPATH" 995 | , value = 996 | "${cfg.installDir}/lib/python${versionString}/site-packages" 997 | } 998 | , mkPkgConfigVar cfg.linkDirs 999 | , libPath cfg 1000 | ] 1001 | # defaultPath cfg 1002 | ) 1003 | } 1004 | ) 1005 | ] 1006 | 1007 | let pythonPackage = 1008 | λ(pyVersion : List Natural) → 1009 | λ(x : { name : Text, version : List Natural }) → 1010 | let major = 1011 | merge 1012 | { Some = Natural/show, None = "" } 1013 | (List/head Natural pyVersion) 1014 | 1015 | in simplePackage x 1016 | ⫽ { configureCommand = doNothing 1017 | , buildCommand = pythonBuild pyVersion 1018 | , installCommand = pythonInstall pyVersion 1019 | , pkgBuildDeps = [ unbounded "python${major}" ] 1020 | } 1021 | 1022 | let python3Build = pythonBuild [ 3, 9 ] 1023 | 1024 | let python3Install = pythonInstall [ 3, 9 ] 1025 | 1026 | let python3Package = pythonPackage [ 3, 9 ] 1027 | 1028 | let python2Package = pythonPackage [ 2, 7 ] 1029 | 1030 | let mkCCVar = 1031 | λ(cfg : types.BuildVars) → 1032 | merge 1033 | { Some = 1034 | λ(tgt : types.TargetTriple) → 1035 | [ { var = "CC", value = "${printTargetTriple tgt}-gcc" } ] 1036 | , None = [] : List types.EnvVar 1037 | } 1038 | cfg.targetTriple 1039 | 1040 | let squishVersion = concatMapText Natural Natural/show 1041 | 1042 | let mkCCArg = 1043 | λ(cfg : types.BuildVars) → 1044 | merge 1045 | { Some = 1046 | λ(tgt : types.TargetTriple) → 1047 | [ "CC=${printTargetTriple tgt}-gcc" ] 1048 | , None = [] : List Text 1049 | } 1050 | cfg.targetTriple 1051 | 1052 | let mkFRCArg = 1053 | λ(cfg : types.BuildVars) → 1054 | merge 1055 | { Some = 1056 | λ(tgt : types.TargetTriple) → 1057 | [ "CC=${printTargetTriple tgt}-gcc" ] 1058 | , None = [] : List Text 1059 | } 1060 | cfg.targetTriple 1061 | 1062 | let preloadEnv = 1063 | λ(_ : List Text) → 1064 | λ(cfg : types.BuildVars) → 1065 | Some 1066 | ( defaultPath cfg 1067 | # [ mkLDFlags cfg.linkDirs cfg 1068 | , mkCFlags cfg 1069 | , mkPkgConfigVar cfg.linkDirs 1070 | , libPath cfg 1071 | , mkXdgDataDirs cfg.shareDirs 1072 | , mkLDPreload cfg.preloadLibs 1073 | , mkPerlLib 1074 | { libDirs = cfg.linkDirs, perlVersion = [ 5, 30, 2 ], cfg } 1075 | ] 1076 | ) 1077 | 1078 | let perlConfigure = 1079 | λ(cfg : types.BuildVars) → 1080 | [ call 1081 | { program = "perl" 1082 | , arguments = [ "Makefile.PL", "PREFIX=${cfg.installDir}" ] 1083 | , environment = preloadEnv ([] : List Text) cfg 1084 | , procDir = None Text 1085 | } 1086 | ] 1087 | 1088 | let preloadCfg = 1089 | generalConfigure preloadEnv "configure" ([] : List Text) ([] : List Text) 1090 | 1091 | let printEnvVar = λ(var : types.EnvVar) → "${var.var}=${var.value}" 1092 | 1093 | let mkPyWrapper = 1094 | λ(version : List Natural) → 1095 | λ(binName : Text) → 1096 | λ(cfg : types.BuildVars) → 1097 | let wrapperContents = 1098 | "${printEnvVar 1099 | ( libPath cfg 1100 | )} ${printEnvVar 1101 | ( mkPyPath version cfg.linkDirs 1102 | )}:${cfg.installDir}/lib/python${showVersion 1103 | version}/site-packages ${cfg.installDir}/bin/${binName} \$@" 1104 | 1105 | let wrapped = "wrapper/${binName}" 1106 | 1107 | in [ createDir "wrapper" 1108 | , writeFile { file = wrapped, contents = wrapperContents } 1109 | , mkExe wrapped 1110 | , copyFile wrapped wrapped 1111 | , symlinkBinary wrapped 1112 | ] 1113 | 1114 | let mkPy3Wrapper = mkPyWrapper [ 3, 9 ] 1115 | 1116 | let mkPy2Wrapper = mkPyWrapper [ 2, 7 ] 1117 | 1118 | let installWithPyWrappers = 1119 | λ(version : List Natural) → 1120 | λ(binNames : List Text) → 1121 | λ(cfg : types.BuildVars) → 1122 | pythonInstall version cfg 1123 | # concatMap 1124 | Text 1125 | types.Command 1126 | (λ(bin : Text) → mkPyWrapper version bin cfg) 1127 | binNames 1128 | 1129 | let installWithPy3Wrappers = installWithPyWrappers [ 3, 9 ] 1130 | 1131 | let mkLDPathWrapper = 1132 | λ(cfg : types.BuildVars) → 1133 | λ(binName : Text) → 1134 | let wrapper = 1135 | "${printEnvVar 1136 | ( mkLDPath cfg.linkDirs 1137 | )}:${cfg.installDir}/lib LD_PRELOAD='${( mkLDPreload 1138 | cfg.preloadLibs 1139 | ).value}' ${cfg.installDir}/bin/${binName} \$@" 1140 | 1141 | let wrapped = "wrapper/${binName}" 1142 | 1143 | in [ createDir "wrapper" 1144 | , writeFile { file = wrapped, contents = wrapper } 1145 | , mkExe wrapped 1146 | , copyFile wrapped wrapped 1147 | , symlinkBinary wrapped 1148 | ] 1149 | 1150 | let mkLDPathWrappers = 1151 | λ(cfg : types.BuildVars) → 1152 | λ(bins : List Text) → 1153 | concatMap 1154 | Text 1155 | types.Command 1156 | (λ(bin : Text) → mkLDPathWrapper cfg bin) 1157 | bins 1158 | 1159 | let installWithWrappers = 1160 | λ(bins : List Text) → 1161 | λ(cfg : types.BuildVars) → 1162 | defaultInstall cfg # mkLDPathWrappers cfg bins 1163 | 1164 | let underscoreVersion = concatMapSep "_" Natural Natural/show 1165 | 1166 | let isX64 = 1167 | λ(arch : types.Arch) → 1168 | merge 1169 | { X64 = True 1170 | , AArch = False 1171 | , Arm = False 1172 | , RISCV64 = False 1173 | , PowerPC = False 1174 | , PowerPC64 = False 1175 | , PowerPC64le = False 1176 | , Sparc64 = False 1177 | , S390x = False 1178 | , Alpha = False 1179 | , M68k = False 1180 | , Mips = False 1181 | , MipsEl = False 1182 | , Mips64 = False 1183 | , Mips64El = False 1184 | , X86 = False 1185 | , SH4 = False 1186 | , HPPA = False 1187 | , HPPA64 = False 1188 | , MipsIsa32r6El = False 1189 | , MipsIsa32r6 = False 1190 | , MipsIsa64r6El = False 1191 | , MipsIsa64r6 = False 1192 | } 1193 | arch 1194 | 1195 | let configureWithPatches = 1196 | λ(patches : List Text) → 1197 | λ(cfg : types.BuildVars) → 1198 | map Text types.Command (λ(p : Text) → patch p) patches 1199 | # defaultConfigure cfg 1200 | 1201 | let configureWithPatch = λ(p : Text) → configureWithPatches [ p ] 1202 | 1203 | let installPrefix = 1204 | λ(cfg : types.BuildVars) → 1205 | [ call 1206 | ( defaultCall 1207 | ⫽ { program = "make" 1208 | , arguments = 1209 | [ "prefix=${cfg.installDir}" 1210 | , "PREFIX=${cfg.installDir}" 1211 | , "install" 1212 | ] 1213 | , environment = Some (buildEnv cfg) 1214 | } 1215 | ) 1216 | ] 1217 | 1218 | in { showVersion 1219 | , makeGnuLibrary 1220 | , makeGnuExe 1221 | , defaultPackage 1222 | , unbounded 1223 | , lowerBound 1224 | , upperBound 1225 | , makeExe 1226 | , printArch 1227 | , printManufacturer 1228 | , printOS 1229 | , printTargetTriple 1230 | , call 1231 | , mkExe 1232 | , mkExes 1233 | , createDir 1234 | , mkHost 1235 | , defaultConfigure 1236 | , defaultBuild 1237 | , defaultInstall 1238 | , cmakeConfigure 1239 | , cmakeConfigureGeneral 1240 | , cmakeConfigureWithFlags 1241 | , cmakeBuild 1242 | , cmakeInstall 1243 | , cmakePackage 1244 | , autogenConfigure 1245 | , defaultCall 1246 | , defaultEnv 1247 | , maybeAppend 1248 | , mkCFlags 1249 | , mkLDFlags 1250 | , mkLDFlagsGeneral 1251 | , mkLDPath 1252 | , mkLDRunPath 1253 | , mkStaPath 1254 | , libPath 1255 | , mkPyPath 1256 | , mkPy3Path 1257 | , mkIncludePath 1258 | , isUnix 1259 | , defaultPath 1260 | , simplePackage 1261 | , symlinkBinary 1262 | , symlinkManpage 1263 | , symlink 1264 | , symlinkBinaries 1265 | , symlinkManpages 1266 | , installWithBinaries 1267 | , installWithManpages 1268 | , configureMkExes 1269 | , generalConfigure 1270 | , configureWithFlags 1271 | , configureMkExesExtraFlags 1272 | , writeFile 1273 | , cmakeInstallWithBinaries 1274 | , copyFile 1275 | , mkPathVar 1276 | , mkPkgConfigVar 1277 | , fullVersion 1278 | , mesonConfigure 1279 | , mesonConfigureGeneral 1280 | , mesonEnv 1281 | , mesonConfigureWithFlags 1282 | , ninjaBuild 1283 | , ninjaInstall 1284 | , ninjaInstallWithPkgConfig 1285 | , ninjaPackage 1286 | , doNothing 1287 | , perlConfigure 1288 | , copyFiles 1289 | , mkPerlLib 1290 | , mesonMoves 1291 | , python3Build 1292 | , python3Install 1293 | , python3Package 1294 | , mkLDPreload 1295 | , configureLinkExtraLibs 1296 | , mkXdgDataDirs 1297 | , buildWith 1298 | , installWith 1299 | , mkCCVar 1300 | , squishVersion 1301 | , osCfg 1302 | , archCfg 1303 | , mkCCArg 1304 | , mkFRCArg 1305 | , mesonCfgFile 1306 | , python2Package 1307 | , configEnv 1308 | , configSome 1309 | , preloadEnv 1310 | , preloadCfg 1311 | , printEnvVar 1312 | , mkPyWrapper 1313 | , mkPy3Wrapper 1314 | , mkPy2Wrapper 1315 | , installWithPyWrappers 1316 | , installWithPy3Wrappers 1317 | , cmakeConfigureNinja 1318 | , mkLDPathWrapper 1319 | , mkLDPathWrappers 1320 | , installWithWrappers 1321 | , cmakeEnv 1322 | , cmakeSome 1323 | , underscoreVersion 1324 | , isX64 1325 | , configWithEnv 1326 | , buildEnv 1327 | , patch 1328 | , mkAclocalPath 1329 | , configureWithPatches 1330 | , configureWithPatch 1331 | , installPrefix 1332 | , unixPath 1333 | , generalBuild 1334 | , defaultCpus 1335 | , singleThreaded 1336 | , libSuffix 1337 | } 1338 | --------------------------------------------------------------------------------