{- Dhall prelude imports -} let concatMapSep = https://raw.githubusercontent.com/dhall-lang/dhall-lang/0a7f596d03b3ea760a96a8e03935f4baa64274e1/Prelude/Text/concatMapSep in let concatMapText = https://raw.githubusercontent.com/dhall-lang/dhall-lang/master/Prelude/Text/concatMap in let concatMap = https://raw.githubusercontent.com/dhall-lang/dhall-lang/master/Prelude/List/concatMap in let map = https://raw.githubusercontent.com/dhall-lang/dhall-lang/master/Prelude/List/map in let mapOptional = https://raw.githubusercontent.com/dhall-lang/dhall-lang/master/Prelude/Optional/map in let not = https://raw.githubusercontent.com/dhall-lang/dhall-lang/master/Prelude/Bool/not in {- Imported types -} let types = ../dhall/cpkg-types.dhall in let showVersion = concatMapSep "." Natural Natural/show in let maybeAppend = λ(a : Type) → λ(x : Optional a) → λ(xs : List a) → Optional/fold a x (List a) (λ(x : a) → (xs # [x])) xs in {- Print the architecture for use with GCC -} let printArch = λ(arch : types.Arch) → merge { X64 = λ(_ : {}) → "x86_64" , AArch = λ(_ : {}) → "aarch64" , Arm = λ(_ : {}) → "arm" , RISCV64 = λ(_ : {}) → "riscv64" , PowerPC = λ(_ : {}) → "powerpc" , PowerPC64 = λ(_ : {}) → "powerpc64" , PowerPC64le = λ(_ : {}) → "powerpc64le" , Sparc64 = λ(_ : {}) → "sparc64" , S390x = λ(_ : {}) → "s390x" , Alpha = λ(_ : {}) → "alpha" , M68k = λ(_ : {}) → "m68k" , Mips = λ(_ : {}) → "mips" , MipsEl = λ(_ : {}) → "mipsel" , Mips64 = λ(_ : {}) → "mips64" , Mips64El = λ(_ : {}) → "mips64el" , X86 = λ(_ : {}) → "i686" , SH4 = λ(_ : {}) → "sh4" , HPPA = λ(_ : {}) → "hppa" , HPPA64 = λ(_ : {}) → "hppa64" } arch in let printManufacturer = λ(x : types.Manufacturer) → merge { Unknown = λ(_ : {}) → "unknown" , Apple = λ(_ : {}) → "apple" , IBM = λ(_ : {}) → "ibm" , PC = λ(_ : {}) → "pc" } x in let printOS = λ(os : types.OS) → merge { FreeBSD = λ(_ : {}) → "freebsd" , OpenBSD = λ(_ : {}) → "openbsd" , NetBSD = λ(_ : {}) → "netbsd" , Solaris = λ(_ : {}) → "solaris" , Dragonfly = λ(_ : {}) → "dragonfly" , Linux = λ(_ : {}) → "linux" , Darwin = λ(_ : {}) → "darwin" , Windows = λ(_ : {}) → "w64" , Redox = λ(_ : {}) → "redox" , Haiku = λ(_ : {}) → "haiku" , IOS = λ(_ : {}) → "darwin" , AIX = λ(_ : {}) → "aix" , Hurd = λ(_ : {}) → "hurd" , Android = λ(_ : {}) → "android" , NoOs = λ(_ : {}) → "none" } os in {- Print the ABI for use with GCC -} let printABI = λ(os : types.ABI) → merge { GNU = λ(_ : {}) → "gnu" , GNUabi64 = λ(_ : {}) → "gnuabi64" , GNUeabi = λ(_ : {}) → "gnueabi" , GNUeabihf = λ(_ : {}) → "gnueabihf" , GNUspe = λ(_ : {}) → "gnuspe" , MinGw = λ(_ : {}) → "mingw32" } os in {- Print target triple for use with GCC -} let printTargetTriple = λ(t : types.TargetTriple) → "${printArch t.arch}-${printOS t.os}" ++ Optional/fold types.ABI t.abi Text (λ(abi : types.ABI) → "-${printABI abi}") "" in {- Print --host flag for use with ./configure scripts -} let mkHost = mapOptional types.TargetTriple Text (λ(tgt : types.TargetTriple) → "--host=${printTargetTriple tgt}") in {- Pick executable for 'make'. Use 'gmake' on BSDs, 'make' everywhere else. -} let makeExe = λ(os : types.OS) → let gmake = λ(_ : {}) → "gmake" in let make = λ(_ : {}) → "make" in merge { FreeBSD = gmake , OpenBSD = gmake , NetBSD = gmake , Solaris = gmake , Dragonfly = gmake , Linux = make , Darwin = make , Windows = make , Redox = make , Haiku = make , IOS = make , AIX = make , Hurd = make , Android = make , NoOs = make -- this is bad but it's meaningless in this context } os in let mkExe = λ(x : Text) → types.Command.MakeExecutable { file = x } in let mkExes = map Text types.Command mkExe in let writeFile = types.Command.Write in let defaultEnv = None (List types.EnvVar) in let defaultCall = { arguments = [] : List Text , environment = defaultEnv , procDir = None Text } in let call = types.Command.Call in let symlinkBinary = λ(file : Text) → types.Command.SymlinkBinary { file = file } in let symlink = λ(tgt : Text) → λ(lnk : Text) → types.Command.Symlink { tgt = tgt, linkName = lnk } in let copyFile = λ(src : Text) → λ(dest : Text) → types.Command.CopyFile { src = src, dest = dest } in let symlinkBinaries = map Text types.Command symlinkBinary in {- This is to be used on the build OS -} let isUnix = λ(os : types.OS) → let true = λ(_ : {}) → True in let false = λ(_ : {}) → False in merge { FreeBSD = true , OpenBSD = true , NetBSD = true , Solaris = true , Dragonfly = true , Linux = true , Darwin = true , Windows = false , Redox = false , Haiku = false , IOS = true , AIX = true , Hurd = true , Android = true , NoOs = false -- bad but this should never happen } os in {- Environment variable LDFLAGS for a given configuration -} let mkLDFlagsGeneral = λ(libDirs : List Text) → λ(linkLibs : List Text) → let flag0 = concatMapSep " " Text (λ(dir : Text) → "-L${dir}") libDirs in let flag1 = concatMapText Text (λ(dir : Text) → " -l${dir}") linkLibs let flag2 = concatMapText Text (λ(dir : Text) → " -Wl,-rpath-link,${dir}") libDirs in { var = "LDFLAGS", value = flag0 ++ flag1 ++ flag2 } in let mkLDFlags = λ(libDirs : List Text) → mkLDFlagsGeneral libDirs ([] : List Text) in let mkLDPath = λ(libDirs : List Text) → let flag = concatMapSep ":" Text (λ(dir : Text) → dir) libDirs in { var = "LD_LIBRARY_PATH", value = flag } in let mkLDRunPath = λ(libDirs : List Text) → let flag = concatMapSep ":" Text (λ(dir : Text) → dir) libDirs in { var = "LD_RUN_PATH", value = flag } in let mkStaPath = λ(libDirs : List Text) → let flag = concatMapText Text (λ(dir : Text) → "${dir}:") libDirs in { var = "LIBRARY_PATH", value = flag ++ "/usr/local/lib:/lib:/usr/lib" } in {- Get the host OS from a configuration. If we are not cross-compiling, we can just use the build OS as detected by cpkg -} let osCfg = λ(cfg : types.BuildVars) → Optional/fold types.TargetTriple cfg.targetTriple types.OS (λ(tgt : types.TargetTriple) → tgt.os) cfg.buildOS in {- Get the host architecture for the build, using the method above -} let archCfg = λ(cfg : types.BuildVars) → Optional/fold types.TargetTriple cfg.targetTriple types.Arch (λ(tgt : types.TargetTriple) → tgt.arch) cfg.buildArch in {- Used to set the PERL5LIB variable to the right thing. This is necessary since we install libraries to nonstandard locations. -} let mkPerlLib = λ(x : { libDirs : List Text, perlVersion : List Natural, cfg : types.BuildVars }) → let os = x.cfg.buildOS in let arch = x.cfg.buildArch in let flag = concatMapSep ":" Text (λ(dir : Text) → dir ++ "/site_perl/${showVersion x.perlVersion}/${printArch arch}-${printOS os}/") x.libDirs in let major = Optional/fold Natural (List/head Natural x.perlVersion) Text (Natural/show) "" in { var = "PERL${major}LIB", value = flag } in let mkIncludePath = λ(incls : List Text) → let flag = concatMapSep ":" Text (λ(dir : Text) → dir) incls in { var = "C_INCLUDE_PATH", value = flag } in let mkCFlags = λ(cfg : types.BuildVars) → let flag = concatMapSep " " Text (λ(dir : Text) → "-I${dir}") cfg.includeDirs in let staFlag = if cfg.static then " -static" else "" in { var = "CPPFLAGS", value = flag ++ staFlag } in let mkPkgConfigVar = λ(libDirs : List Text) → let flag = concatMapSep ":" Text (λ(dir : Text) → "${dir}/pkgconfig") libDirs in { var = "PKG_CONFIG_PATH", value = flag } in {- This is used for GLib/GTK/some of that stuff -} let mkXdgDataDirs = λ(shareDirs : List Text) → let flag = concatMapSep ":" Text (λ(dir : Text) → dir) shareDirs in { var = "XDG_DATA_DIRS", value = flag } in let mkPathVar = λ(binDirs : List Text) → concatMapText Text (λ(dir : Text) → "${dir}:") binDirs in let defaultPath = λ(cfg : types.BuildVars) → if isUnix cfg.buildOS then [ { var = "PATH", value = mkPathVar cfg.binDirs ++ "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" } ] : List types.EnvVar else [] : List types.EnvVar -- FIXME: handle non-unix case in {- Set either LD_LIBRARY_PATH or LIBRARY_PATH depending on whether we are doing a static build or not -} let libPath = λ(cfg : types.BuildVars) → if cfg.static then mkStaPath cfg.linkDirs else mkLDPath cfg.linkDirs in {- This is vaguely terrible, but it's needed for GLib for some reason -} let mkLDPreload = λ(libs : List Text) → let flag = concatMapSep " " Text (λ(lib : Text) → lib) libs in { var = "LD_PRELOAD", value = flag } in {- Default environment variables for a given configuration -} let configEnv = λ(linkLibs : List Text) → λ(cfg : types.BuildVars) → defaultPath cfg # [ mkLDFlagsGeneral cfg.linkDirs linkLibs , mkCFlags cfg , mkPkgConfigVar (cfg.shareDirs # cfg.linkDirs) , libPath cfg , mkLDRunPath cfg.linkDirs , mkPerlLib { libDirs = cfg.linkDirs, perlVersion = [5,28,1], cfg = cfg } -- TODO: take this as a parameter ] in let buildEnv = λ(cfg : types.BuildVars) → defaultPath cfg # [ mkPkgConfigVar (cfg.shareDirs # cfg.linkDirs) , mkPerlLib { libDirs = cfg.linkDirs, perlVersion = [5,28,1], cfg = cfg } -- TODO: take this as a parameter , mkLDPath cfg.linkDirs ] in let configSome = λ(linkLibs : List Text) → λ(cfg : types.BuildVars) → Some (configEnv linkLibs cfg) in {- The most general configuration setup. You probably want to use defaultConfigure -} let generalConfigure = λ(envVars : List Text → types.BuildVars → Optional (List types.EnvVar)) → λ(filename : Text) → λ(linkLibs : List Text) → λ(extraFlags : List Text) → λ(cfg : types.BuildVars) → let maybeHost = mkHost cfg.targetTriple in let modifyArgs = maybeAppend Text maybeHost in [ mkExe filename , call (defaultCall ⫽ { program = "./${filename}" , arguments = modifyArgs [ "--prefix=${cfg.installDir}" ] # extraFlags , environment = envVars linkLibs cfg }) ] in let configWithEnv = λ(envVars : List Text → types.BuildVars → Optional (List types.EnvVar)) → generalConfigure envVars "configure" ([] : List Text) ([] : List Text) in let configureWithFlags = generalConfigure configSome "configure" ([] : List Text) in let defaultConfigure = configureWithFlags ([] : List Text) in let configureLinkExtraLibs = λ(linkLibs : List Text) → generalConfigure configSome "configure" linkLibs ([] : List Text) in let mkAclocalPath = λ(shareDirs : List Text) → let flag = concatMapSep ":" Text (λ(dir : Text) → "${dir}/aclocal:${dir}/autoconf/autoconf") shareDirs in { var = "ACLOCAL_PATH", value = flag } in let configureMkExesExtraFlags = λ(x : { bins : List Text, extraFlags : List Text }) → λ(cfg : types.BuildVars) → mkExes x.bins # configureWithFlags x.extraFlags cfg in let configureMkExes = λ(bins : List Text) → configureMkExesExtraFlags { bins = bins, extraFlags = ([] : List Text) } in let buildWith = λ(envs : List types.EnvVar) → λ(cfg : types.BuildVars) → [ call (defaultCall ⫽ { program = makeExe cfg.buildOS , arguments = [ "-j${Natural/show cfg.cpus}" ] , environment = Some envs }) ] in let defaultBuild = λ(cfg : types.BuildVars) → buildWith (buildEnv cfg) cfg in let installWith = λ(envs : List types.EnvVar) → λ(cfg : types.BuildVars) → [ call (defaultCall ⫽ { program = makeExe cfg.buildOS , arguments = [ "install" ] , environment = Some envs }) ] in let defaultInstall = λ(cfg : types.BuildVars) → installWith (buildEnv cfg) cfg in let installWithBinaries = λ(bins : List Text) → λ(installVars : types.BuildVars) → defaultInstall installVars # (if not installVars.isCross then symlinkBinaries bins else [] : List types.Command) in let unbounded = λ(x : Text) → { name = x , bound = types.VersionBound.NoBound {=} } in let lowerBound = λ(pkg : { name : Text, lower : List Natural }) → { name = pkg.name , bound = types.VersionBound.Lower { lower = pkg.lower } } in let upperBound = λ(pkg : { name : Text, upper : List Natural }) → { name = pkg.name , bound = types.VersionBound.Upper { upper = pkg.upper } } in let defaultPackage = { configureCommand = defaultConfigure , buildCommand = defaultBuild , installCommand = defaultInstall , pkgBuildDeps = [] : List types.Dep , pkgDeps = [] : List types.Dep , pkgStream = True } in let simplePackage = λ(pkg : { name : Text, version : List Natural}) → defaultPackage ⫽ { pkgName = pkg.name , pkgVersion = pkg.version , pkgSubdir = "${pkg.name}-${showVersion pkg.version}" } in let makeGnuExe = λ(pkg : { name : Text, version : List Natural}) → simplePackage pkg ⫽ { pkgUrl = "https://ftp.gnu.org/gnu/${pkg.name}/${pkg.name}-${showVersion pkg.version}.tar.xz" , installCommand = installWithBinaries [ "bin/${pkg.name}" ] } in let makeGnuLibrary = λ(pkg : { name : Text, version : List Natural}) → simplePackage pkg ⫽ { pkgUrl = "https://mirrors.ocf.berkeley.edu/gnu/lib${pkg.name}/lib${pkg.name}-${showVersion pkg.version}.tar.xz" , pkgSubdir = "lib${pkg.name}-${showVersion pkg.version}" } in let createDir = λ(x : Text) → types.Command.CreateDirectory { dir = x } in let printCMakeOS = λ(os : types.OS) → merge { FreeBSD = λ(_ : {}) → "BSD" , OpenBSD = λ(_ : {}) → "BSD" , NetBSD = λ(_ : {}) → "BSD" , Solaris = λ(_ : {}) → "Solaris" , Dragonfly = λ(_ : {}) → "BSD" , Linux = λ(_ : {}) → "Linux" , Darwin = λ(_ : {}) → "Darwin" , Windows = λ(_ : {}) → "Windows" , Redox = λ(_ : {}) → "Redox" , Haiku = λ(_ : {}) → "Haiku" , IOS = λ(_ : {}) → "Darwin" , AIX = λ(_ : {}) → "AIX" , Hurd = λ(_ : {}) → "Hurd" , Android = λ(_ : {}) → "Android" , NoOs = λ(_ : {}) → "Generic" } os in let cmakeConfigureGeneral = λ(envVars : types.BuildVars → Optional (List types.EnvVar)) → λ(flags : List Text) → λ(cfg : types.BuildVars) → let host = Optional/fold types.TargetTriple cfg.targetTriple (List Text) (λ(tgt : types.TargetTriple) → ["-DCMAKE_C_COMPILER=${printTargetTriple tgt}-gcc", "-DCMAKE_CXX_COMPILER=${printTargetTriple tgt}-g++"]) (["-DCMAKE_C_COMPILER=cc", "-DCMAKE_CXX_COMPILER=c++"]) in let system = Optional/fold types.TargetTriple cfg.targetTriple (List Text) (λ(tgt : types.TargetTriple) → ["-DCMAKE_SYSTEM_NAME=${printCMakeOS tgt.os}"]) ([] : List Text) in [ createDir "build" , call { program = "cmake" , arguments = [ "../", "-DCMAKE_INSTALL_PREFIX:PATH=${cfg.installDir}", "-DCMAKE_MAKE_PROGRAM=${makeExe cfg.buildOS}" ] # host # system # flags , environment = envVars cfg , procDir = Some "build" } ] in let cmakeEnv = λ(cfg : types.BuildVars) → [ mkPkgConfigVar cfg.shareDirs , { var = "CMAKE_INCLUDE_PATH", value = (mkIncludePath cfg.includeDirs).value } , { var = "CMAKE_LIBRARY_PATH", value = (libPath cfg).value } ] # defaultPath cfg in let cmakeSome = λ(cfg : types.BuildVars) → Some (cmakeEnv cfg) in let cmakeConfigureWithFlags = cmakeConfigureGeneral cmakeSome in let cmakeConfigure = cmakeConfigureWithFlags ([] : List Text) in let cmakeConfigureNinja = λ(cfg : types.BuildVars) → let host = Optional/fold types.TargetTriple cfg.targetTriple (List Text) (λ(tgt : types.TargetTriple) → ["-DCMAKE_C_COMPILER=${printTargetTriple tgt}-gcc", "-DCMAKE_CXX_COMPILER=${printTargetTriple tgt}-g++"]) ([] : List Text) in let system = Optional/fold types.TargetTriple cfg.targetTriple (List Text) (λ(tgt : types.TargetTriple) → ["-DCMAKE_SYSTEM_NAME=${printCMakeOS tgt.os}"]) ([] : List Text) in [ createDir "build" , call { program = "cmake" , arguments = [ "../", "-DCMAKE_INSTALL_PREFIX:PATH=${cfg.installDir}", "-G", "Ninja" ] # host # system , environment = defaultEnv , procDir = Some "build" } ] in let perlConfigure = λ(cfg : types.BuildVars) → [ call { program = "perl" , arguments = [ "Makefile.PL", "PREFIX=${cfg.installDir}" ] , environment = defaultEnv , procDir = None Text } ] in let cmakeBuild = λ(cfg : types.BuildVars) → [ call { program = "cmake" , arguments = [ "--build", ".", "--config", "Release", "--", "-j", Natural/show cfg.cpus ] , environment = defaultEnv , procDir = Some "build" } ] in let cmakeInstall = λ(cfg : types.BuildVars) → [ call { program = "cmake" , arguments = [ "--build", ".", "--target", "install", "--config", "Release" ] , environment = defaultEnv , procDir = Some "build" } ] in let cmakeInstallWithBinaries = λ(bins : List Text) → λ(installVars : types.BuildVars) → cmakeInstall installVars # symlinkBinaries bins in let cmakePackage = defaultPackage ⫽ { configureCommand = cmakeConfigure , buildCommand = cmakeBuild , installCommand = cmakeInstall , pkgBuildDeps = [ unbounded "cmake" ] } in let autogenConfigure = λ(cfg : types.BuildVars) → [ mkExe "autogen.sh" , call (defaultCall ⫽ { program = "./autogen.sh" , environment = Some ([ mkAclocalPath cfg.shareDirs ] # defaultPath cfg) }) ] # defaultConfigure cfg in let fullVersion = λ(x : { version : List Natural, patch : Natural }) → x.version # [x.patch] in let mkPyPath = λ(version : List Natural) → λ(libDirs : List Text) → let flag = concatMapSep ":" Text (λ(dir : Text) → "${dir}/python${showVersion version}/site-packages") libDirs in { var = "PYTHONPATH", value = flag } in let mkPy3Path = mkPyPath [3,7] in {- Write a cross-compilation configuration file for use with meson -} let mesonCfgFile = λ(cfg : types.BuildVars) → let prefix = Optional/fold types.TargetTriple cfg.targetTriple Text (λ(tgt : types.TargetTriple) → "${printTargetTriple tgt}-") "" in "[binaries]\n" ++ "c = '${prefix}gcc'\n" ++ -- FIXME: default to cc/c++ when no cfg.targetTriple is passed "cpp = '${prefix}g++'\n" ++ "ar = '${prefix}ar'\n" ++ "strip = '${prefix}strip'\n" ++ "pkgconfig = 'pkg-config'\n" ++ "[host_machine]\n" ++ "system = '${printOS (osCfg cfg)}'\n" ++ -- TODO: printOSMeson function (w64 -> windows) "cpu_family = '${printArch (archCfg cfg)}'\n" ++ "cpu = '${printArch (archCfg cfg)}'\n" ++ "endian = 'little'" -- FIXME parse endianness in Haskell library? in let mesonEnv = λ(cfg : types.BuildVars) → Some [ mkPkgConfigVar cfg.linkDirs , { var = "PATH", value = mkPathVar cfg.binDirs ++ "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" } , mkPy3Path cfg.linkDirs , libPath cfg , mkLDRunPath cfg.linkDirs , mkLDFlags cfg.linkDirs , mkCFlags cfg ] in let mesonConfigureGeneral = λ(envs : types.BuildVars → Optional (List types.EnvVar)) → λ(flags : List Text) → λ(cfg : types.BuildVars) → let crossArgs = if cfg.isCross then [ "--cross-file", "cross.txt" ] else [] : List Text in [ createDir "build" , writeFile { file = "build/cross.txt", contents = mesonCfgFile cfg } , call { program = "meson" , arguments = [ "--prefix=${cfg.installDir}", ".." ] # crossArgs # flags , environment = envs cfg , procDir = Some "build" } ] in let mesonConfigureWithFlags = mesonConfigureGeneral mesonEnv in let mesonConfigure = mesonConfigureWithFlags ([] : List Text) in let ninjaBuildWith = λ(linkLibs : List Text) → λ(cfg : types.BuildVars) → [ call (defaultCall ⫽ { program = "ninja" , environment = Some [ mkPkgConfigVar cfg.linkDirs , { var = "PATH", value = mkPathVar cfg.binDirs ++ "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" } , mkPy3Path cfg.linkDirs , libPath cfg , mkLDRunPath cfg.linkDirs , mkLDFlagsGeneral cfg.linkDirs linkLibs , mkCFlags cfg , mkPkgConfigVar cfg.linkDirs ] , procDir = Some "build" }) ] in let ninjaBuild = ninjaBuildWith ([] : List Text) in let ninjaInstall = λ(cfg : types.BuildVars) → [ call (defaultCall ⫽ { program = "ninja" , environment = Some [ mkPkgConfigVar cfg.linkDirs , { var = "PATH", value = mkPathVar cfg.binDirs ++ "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" } , mkPy3Path cfg.linkDirs , libPath cfg , mkLDRunPath cfg.linkDirs , mkLDFlags cfg.linkDirs , mkCFlags cfg ] , arguments = [ "install" ] , procDir = Some "build" }) ] in let ninjaPackage = λ(x : { name : Text, version : List Natural }) → simplePackage x ⫽ { configureCommand = mesonConfigure , buildCommand = ninjaBuild , installCommand = ninjaInstall , pkgBuildDeps = [ unbounded "meson" , unbounded "ninja" ] } in let copyFiles = map { src : Text, dest : Text } types.Command types.Command.CopyFile in let ninjaInstallWithPkgConfig = λ(fs : List { src : Text, dest : Text }) → λ(cfg : types.BuildVars) → ninjaInstall cfg # copyFiles fs in let doNothing = λ(_ : types.BuildVars) → [] : List types.Command in let mesonMoves = map Text { src : Text, dest : Text} (λ(pcFile : Text) → { src = "build/meson-private/${pcFile}", dest = "lib/pkgconfig/${pcFile}" }) in let pythonBuild = λ(version : List Natural) → λ(cfg : types.BuildVars) → let major = Optional/fold Natural (List/head Natural version) Text (Natural/show) "" in let versionString = showVersion version in [ createDir "${cfg.installDir}/lib/python${versionString}/site-packages" , call (defaultCall ⫽ { program = "python${major}" , arguments = [ "setup.py", "build" ] , environment = Some ([ { var = "PYTHONPATH", value = "${cfg.installDir}/lib/python${versionString}/site-packages" } , mkPkgConfigVar cfg.linkDirs , libPath cfg ] # defaultPath cfg) }) ] in let pythonInstall = λ(version : List Natural) → λ(cfg : types.BuildVars) → let major = Optional/fold Natural (List/head Natural version) Text (Natural/show) "" in let versionString = showVersion version in [ createDir "${cfg.installDir}/lib/python${versionString}/site-packages" , call (defaultCall ⫽ { program = "python${major}" , arguments = [ "setup.py", "install", "--prefix=${cfg.installDir}", "--optimize=1" ] , environment = Some ([ { var = "PYTHONPATH", value = "${cfg.installDir}/lib/python${versionString}/site-packages" } , mkPkgConfigVar cfg.linkDirs , libPath cfg ] # defaultPath cfg) }) ] in let pythonPackage = λ(pyVersion : List Natural) → λ(x : { name : Text, version : List Natural }) → let major = Optional/fold Natural (List/head Natural pyVersion) Text (Natural/show) "" in simplePackage x ⫽ { configureCommand = doNothing , buildCommand = pythonBuild pyVersion , installCommand = pythonInstall pyVersion , pkgBuildDeps = [ unbounded "python${major}" ] } in let python3Build = pythonBuild [3,7] in let python3Install = pythonInstall [3,7] in let python3Package = pythonPackage [3,7] in let python2Package = pythonPackage [2,7] in let mkCCVar = λ(cfg : types.BuildVars) → Optional/fold types.TargetTriple cfg.targetTriple (List types.EnvVar) (λ(tgt : types.TargetTriple) → [{ var = "CC", value = "${printTargetTriple tgt}-gcc" }]) ([] : List types.EnvVar) in let squishVersion = concatMapText Natural Natural/show in let mkCCArg = λ(cfg : types.BuildVars) → Optional/fold types.TargetTriple cfg.targetTriple (List Text) (λ(tgt : types.TargetTriple) → ["CC=${printTargetTriple tgt}-gcc"]) ([] : List Text) in let preloadEnv = λ(_ : List Text) → λ(cfg : types.BuildVars) → Some (defaultPath cfg # [ mkLDFlags cfg.linkDirs , mkCFlags cfg , mkPkgConfigVar cfg.linkDirs , libPath cfg , mkXdgDataDirs cfg.shareDirs , mkLDPreload cfg.preloadLibs , mkPerlLib { libDirs = cfg.linkDirs, perlVersion = [5,28,1], cfg = cfg } -- TODO: take this as a parameter ]) in let preloadCfg = generalConfigure preloadEnv "configure" ([] : List Text) ([] : List Text) in let printEnvVar = λ(var : types.EnvVar) → "${var.var}=${var.value}" in {- This writes + installs a shell script that allows you to use programs installed via cpkg with the appropriate environment variables set, since of course we install in nonstandard locations -} let mkPyWrapper = λ(version : List Natural) → λ(binName : Text) → λ(cfg : types.BuildVars) → let wrapperContents = "${printEnvVar (libPath cfg)} ${printEnvVar (mkPyPath version cfg.linkDirs)}:${cfg.installDir}/lib/python${showVersion version}/site-packages ${cfg.installDir}/bin/${binName} $@" in let wrapped = "wrapper/${binName}" in [ createDir "wrapper" , writeFile { file = wrapped, contents = wrapperContents } , mkExe wrapped , copyFile wrapped wrapped , symlinkBinary wrapped ] in let mkPy3Wrapper = mkPyWrapper [3,7] in let mkPy2Wrapper = mkPyWrapper [2,7] in let installWithPyWrappers = λ(version : List Natural) → λ(binNames : List Text) → λ(cfg : types.BuildVars) → pythonInstall version cfg # concatMap Text types.Command (λ(bin : Text) → mkPyWrapper version bin cfg) binNames in let installWithPy3Wrappers = installWithPyWrappers [3,7] in {- This is used to make bash scripts that wrap an executable. Since executables are linked against libraries installed in nonstandard places, we wrap them with a shell script that sets LD_LIBRARY_PATH appropriately. For an example use, see the emacs package. -} let mkLDPathWrapper = λ(cfg : types.BuildVars) → λ(binName : Text) → let wrapper = "${printEnvVar (mkLDPath cfg.linkDirs)}:${cfg.installDir}/lib LD_PRELOAD='${(mkLDPreload cfg.preloadLibs).value}' ${cfg.installDir}/bin/${binName} $@" in let wrapped = "wrapper/${binName}" in [ createDir "wrapper" , writeFile { file = wrapped, contents = wrapper } , mkExe wrapped , copyFile wrapped wrapped , symlinkBinary wrapped ] in let installWithWrappers = λ(bins : List Text) → λ(cfg : types.BuildVars) → defaultInstall cfg # concatMap Text types.Command (λ(bin : Text) → mkLDPathWrapper cfg bin) bins -- TODO: add to PATH for e.g. PERL interpreter in let underscoreVersion = concatMapSep "_" Natural Natural/show in let isX64 = let true = λ(_ : {}) → True in let false = λ(_ : {}) → False in λ(arch : types.Arch) → merge { X64 = true , AArch = false , Arm = false , RISCV64 = false , PowerPC = false , PowerPC64 = false , PowerPC64le = false , Sparc64 = false , S390x = false , Alpha = false , M68k = false , Mips = false , MipsEl = false , Mips64 = false , Mips64El = false , X86 = false , SH4 = false , HPPA = false , HPPA64 = false } arch in { showVersion = showVersion , makeGnuLibrary = makeGnuLibrary , makeGnuExe = makeGnuExe , defaultPackage = defaultPackage , unbounded = unbounded , lowerBound = lowerBound , upperBound = upperBound , makeExe = makeExe , printArch = printArch , printManufacturer = printManufacturer , printOS = printOS , printTargetTriple = printTargetTriple , call = call , mkExe = mkExe , mkExes = mkExes , createDir = createDir , mkHost = mkHost , defaultConfigure = defaultConfigure , defaultBuild = defaultBuild , defaultInstall = defaultInstall , cmakeConfigure = cmakeConfigure , cmakeConfigureGeneral = cmakeConfigureGeneral , cmakeConfigureWithFlags = cmakeConfigureWithFlags , cmakeBuild = cmakeBuild , cmakeInstall = cmakeInstall , cmakePackage = cmakePackage , autogenConfigure = autogenConfigure , defaultCall = defaultCall , defaultEnv = defaultEnv , maybeAppend = maybeAppend , mkCFlags = mkCFlags , mkLDFlags = mkLDFlags , mkLDPath = mkLDPath , mkLDRunPath = mkLDRunPath , mkStaPath = mkStaPath , libPath = libPath , mkPyPath = mkPyPath , mkPy3Path = mkPy3Path , mkIncludePath = mkIncludePath , isUnix = isUnix , defaultPath = defaultPath , simplePackage = simplePackage , symlinkBinary = symlinkBinary , symlink = symlink , symlinkBinaries = symlinkBinaries , installWithBinaries = installWithBinaries , configureMkExes = configureMkExes , generalConfigure = generalConfigure , configureWithFlags = configureWithFlags , configureMkExesExtraFlags = configureMkExesExtraFlags , writeFile = writeFile , cmakeInstallWithBinaries = cmakeInstallWithBinaries , copyFile = copyFile , mkPathVar = mkPathVar , mkPkgConfigVar = mkPkgConfigVar , fullVersion = fullVersion , mesonConfigure = mesonConfigure , mesonConfigureGeneral = mesonConfigureGeneral , mesonEnv = mesonEnv , mesonConfigureWithFlags = mesonConfigureWithFlags , ninjaBuild = ninjaBuild , ninjaInstall = ninjaInstall , ninjaInstallWithPkgConfig = ninjaInstallWithPkgConfig , ninjaPackage = ninjaPackage , doNothing = doNothing , perlConfigure = perlConfigure , copyFiles = copyFiles , mkPerlLib = mkPerlLib , mesonMoves = mesonMoves , python3Build = python3Build , python3Install = python3Install , python3Package = python3Package , mkLDPreload = mkLDPreload , configureLinkExtraLibs = configureLinkExtraLibs , mkXdgDataDirs = mkXdgDataDirs , buildWith = buildWith , installWith = installWith , mkCCVar = mkCCVar , squishVersion = squishVersion , osCfg = osCfg , archCfg = archCfg , mkCCArg = mkCCArg , mesonCfgFile = mesonCfgFile , python2Package = python2Package , configEnv = configEnv , configSome = configSome , preloadEnv = preloadEnv , preloadCfg = preloadCfg , printEnvVar = printEnvVar , mkPyWrapper = mkPyWrapper , mkPy3Wrapper = mkPy3Wrapper , mkPy2Wrapper = mkPy2Wrapper , installWithPyWrappers = installWithPyWrappers , installWithPy3Wrappers = installWithPy3Wrappers , cmakeConfigureNinja = cmakeConfigureNinja , mkLDPathWrapper = mkLDPathWrapper , installWithWrappers = installWithWrappers , cmakeEnv = cmakeEnv , cmakeSome = cmakeSome , underscoreVersion = underscoreVersion , isX64 = isX64 , configWithEnv = configWithEnv , buildEnv = buildEnv }