nixpkgs/pkgs/build-support/builder-defs/builder-defs.nix
Wout Mertens 774f74b875 Don't fail if env-vars cannot be written to
env-vars is a debugging aid, see
3e5dbb2433
for a rationale for this change.
2015-11-04 16:32:59 +01:00

608 lines
24 KiB
Nix

args @ {stringsWithDeps, lib, stdenv, writeScript, fetchurl, fetchmtn, fetchgit, ...}: with args; with stringsWithDeps; with lib;
let inherit (builtins) head tail trace; in
(rec
{
inherit writeScript;
src = attrByPath ["src"] "" args;
addSbinPath = attrByPath ["addSbinPath"] false args;
forceShare = if args ? forceShare then args.forceShare else ["man" "doc" "info"];
forceCopy = ["COPYING" "LICENSE" "DISTRIBUTION" "LEGAL"
"README" "AUTHORS" "ChangeLog" "CHANGES" "LICENCE" "COPYRIGHT"] ++
(optional (attrByPath ["forceCopyDoc"] true args) "doc");
hasSuffixHack = a: b: hasSuffix (a+(substring 0 0 b)) ((substring 0 0 a)+b);
archiveType = s:
(if hasSuffixHack ".tar" s then "tar"
else if (hasSuffixHack ".tar.gz" s) || (hasSuffixHack ".tgz" s) then "tgz"
else if (hasSuffixHack ".tar.bz2" s) || (hasSuffixHack ".tbz2" s) ||
(hasSuffixHack ".tbz" s) then "tbz2"
else if hasSuffixHack ".tar.Z" s then "tZ"
else if hasSuffixHack ".tar.lzma" s then "tar.lzma"
else if hasSuffixHack ".tar.xz" s then "tar.xz"
else if hasSuffixHack ".rar" s then "rar"
else if (hasSuffixHack ".zip" s) || (hasSuffixHack ".ZIP" s) then "zip"
else if hasSuffixHack "-cvs-export" s then "cvs-dir"
else if hasSuffixHack "-git-export" s then "git-dir"
else if hasSuffixHack ".nar.bz2" s then "narbz2"
else if hasSuffixHack ".rpm" s then "rpm"
# Mostly for manually specified directories..
else if hasSuffixHack "/" s then "dir"
# Last block - for single files!! It should be always after .tar.*
else if hasSuffixHack ".bz2" s then "plain-bz2"
else if hasSuffixHack ".gz" s then "plain-gz"
# For bootstrap calls
else if (s ==("" + (substring 0 0 s))) then "empty"
else (abort "unknown archive type : ${s}"));
# changing this ? see [1]
defAddToSearchPath = fullDepEntry ("
addToSearchPathWithCustomDelimiter() {
local delimiter=\$1
local varName=\$2
local needDir=\$3
local addDir=\${4:-\$needDir}
local prefix=\$5
if [ -d \$prefix\$needDir ]; then
if [ -z \${!varName} ]; then
eval export \${varName}=\${prefix}\$addDir
else
eval export \${varName}=\${!varName}\${delimiter}\${prefix}\$addDir
fi
fi
}
addToSearchPath()
{
addToSearchPathWithCustomDelimiter \"\${PATH_DELIMITER}\" \"\$@\"
}
") ["defNest"];
# changing this ? see [1]
defNest = noDepEntry ("
nestingLevel=0
startNest() {
nestingLevel=\$((\$nestingLevel + 1))
echo -en \"\\e[\$1p\"
}
stopNest() {
nestingLevel=\$((\$nestingLevel - 1))
echo -en \"\\e[q\"
}
header() {
startNest \"\$2\"
echo \"\$1\"
}
# Make sure that even when we exit abnormally, the original nesting
# level is properly restored.
closeNest() {
while test \$nestingLevel -gt 0; do
stopNest
done
}
trap \"closeNest\" EXIT
");
# changing this ? see [1]
minInit = fullDepEntry ("
${stdenv.preHook}
set -e
NIX_CC=${stdenv.cc}
export SHELL=${stdenv.shell}
PATH_DELIMITER=':'
# Set up the initial path.
PATH=
for i in \$NIX_CC ${toString stdenv.initialPath}; do
PATH=\$PATH\${PATH:+\"\${PATH_DELIMITER}\"}\$i/bin
done
export TZ=UTC
prefix=${if args ? prefix then (toString args.prefix) else "\$out"}
") ["defNest" "defAddToSearchPath"];
# if you change this rewrite using '' instead of "" to get rid of indentation in builder scripts
addInputs = fullDepEntry ("
# Recursively find all build inputs.
findInputs()
{
local pkg=\$1
case \$pkgs in
*\\ \$pkg\\ *)
return 0
;;
esac
pkgs=\"\$pkgs \$pkg \"
echo \$pkg
if test -f \$pkg/nix-support/setup-hook; then
source \$pkg/nix-support/setup-hook
fi
}
pkgs=\"\"
for i in \$NIX_CC ${toString realBuildInputs}; do
findInputs \$i
done
# Set the relevant environment variables to point to the build inputs
# found above.
addToEnv()
{
local pkg=\$1
"+
(if !((args ? ignoreFailedInputs) && (args.ignoreFailedInputs == 1)) then "
if [ -e \$1/nix-support/failed ]; then
echo \"failed input \$1\" >&2
fail
fi
" else "")
+(if addSbinPath then "
if test -d \$1/sbin; then
export _PATH=\$_PATH\${_PATH:+\"\${PATH_DELIMITER}\"}\$1/sbin
fi
" else "")
+"
if test -d \$1/bin; then
export _PATH=\$_PATH\${_PATH:+\"\${PATH_DELIMITER}\"}\$1/bin
fi
for i in \"\${envHooks[@]}\"; do
\$i \$pkg
done
}
for i in \$pkgs; do
addToEnv \$i
done
# Add the output as an rpath.
if test \"\$NIX_NO_SELF_RPATH\" != \"1\"; then
export NIX_LDFLAGS=\"-rpath \$out/lib \$NIX_LDFLAGS\"
fi
PATH=\$_PATH\${_PATH:+\"\${PATH_DELIMITER}\"}\$PATH
") ["minInit"];
# changing this ? see [1]
defEnsureDir = fullDepEntry ("
# Ensure that the given directories exists.
ensureDir() {
local dir
for dir in \"\$@\"; do
if ! test -x \"\$dir\"; then mkdir -p \"\$dir\"; fi
done
}
") ["minInit"];
# changing this ? see [1]
toSrcDir = s : fullDepEntry ((if (archiveType s) == "tar" then "
tar xvf '${s}'
cd \"\$(tar tf '${s}' | head -1 | sed -e 's@/.*@@' )\"
" else if (archiveType s) == "tgz" then "
tar xvzf '${s}'
cd \"\$(tar tzf '${s}' | head -1 | sed -e 's@/.*@@' )\"
" else if (archiveType s) == "tbz2" then "
tar xvjf '${s}'
cd \"\$(tar tjf '${s}' | head -1 | sed -e 's@/.*@@' )\"
" else if (archiveType s) == "tZ" then "
uncompress < '${s}' | tar x
cd \"\$(uncompress < '${s}' | tar t | head -1 | sed -e 's@/.*@@' )\"
" else if (archiveType s) == "tar.lzma" then "
unlzma -d -c <'${s}' | tar xv
cd \"\$(unlzma -d -c <'${s}' | tar t | head -1 | sed -e 's@/.*@@' )\"
" else if (archiveType s) == "tar.xz" then "
xz -d -c <'${s}' | tar xv
cd \"\$(xz -d -c <'${s}' | tar t | head -1 | sed -e 's@/.*@@' )\"
" else if (archiveType s) == "rar" then "
unrar x '${s}'
cd \"$(unrar lb '${s}' | tail -1 | sed -e 's@/.*@@' )\"
" else if (archiveType s) == "zip" then "
unzip '${s}'
cd \"$( unzip -lqq '${s}' | tail -1 |
sed -e 's@^\\(\\s\\+[-0-9:]\\+\\)\\{3,3\\}\\s\\+\\([^/]\\+\\)/.*@\\2@' )\"
" else if (archiveType s) == "cvs-dir" then "
cp -r '${s}' .
cd \$(basename ${s})
chmod u+rwX -R .
" else if (archiveType s) == "git-dir" then "
cp -r '${s}' .
cd \$(basename ${s})
chmod u+rwX -R .
" else if (archiveType s) == "dir" then "
cp -r '${s}' .
cd \$(basename ${s})
chmod u+rwX -R .
" else if (archiveType s) == "narbz2" then "
bzip2 <${s} | nix-store --restore \$PWD/\$(basename ${s} .nar.bz2)
cd \$(basename ${s} .nar.bz2)
" else if (archiveType s) == "rpm" then ''
rpm2cpio ${s} > ${s}.cpio
cpio -iv < ${s}.cpio
test -f *.tar.* && tar -xvf *.tar.*
test -d */ && cd */
'' else if (archiveType s) == "plain-bz2" then "
mkdir \$PWD/\$(basename ${s} .bz2)
NAME=\$(basename ${s} .bz2)
bzip2 -d <${s} > \$PWD/\$(basename ${s} .bz2)/\${NAME#*-}
cd \$(basename ${s} .bz2)
" else if (archiveType s) == "plain-gz" then "
mkdir \$PWD/\$(basename ${s} .gz)
NAME=\$(basename ${s} .gz)
gzip -d <${s} > \$PWD/\$(basename ${s} .gz)/\${NAME#*-}
cd \$(basename ${s} .gz)
" else if (archiveType s) == "empty" then "
echo No source to unpack - doing nothing ..
" else (abort "unknown archive type : ${s}"))+
# goSrcDir is typically something like "cd mysubdir" .. but can be anything else
(if args ? goSrcDir then args.goSrcDir else "")
) ["minInit"];
configureCommand = attrByPath ["configureCommand"] "./configure" args;
# changing this ? see [1]
doConfigure = fullDepEntry ("
${configureCommand} --prefix=\"\$prefix\" ${toString configureFlags}
") ["minInit" "addInputs" "doUnpack"];
# changing this ? see [1]
doIntltool = fullDepEntry ("
mkdir -p config
intltoolize --copy --force
") ["minInit" "addInputs" "doUnpack"];
# changing this ? see [1]
doAutotools = fullDepEntry ("
mkdir -p config
libtoolize --copy --force
aclocal --force
#Some packages do not need this
autoheader || true;
automake --add-missing --copy
autoconf
")["minInit" "addInputs" "doUnpack"];
# changing this ? see [1]
doAutogen = fullDepEntry (''
./autogen.sh
'')["minInit" "addInputs" "doUnpack"];
# changing this ? see [1]
doMake = fullDepEntry ("
make ${toString makeFlags}
") ["minInit" "addInputs" "doUnpack"];
doUnpack = toSrcDir (toString src);
# changing this ? see [1]
installPythonPackage = fullDepEntry ("
python setup.py install --prefix=\"\$prefix\"
") ["minInit" "addInputs" "doUnpack"];
doPythonConfigure = fullDepEntry (''
pythonVersion=$(toPythonPath "$prefix")
pythonVersion=''${pythonVersion#*/lib/python}
pythonVersion=''${pythonVersion%%/site-packages}
${if args ? extraPythonConfigureCommand then
args.extraPythonConfigureCommand
else ""}
python configure.py -b "$prefix/bin" -d "$(toPythonPath "$prefix")" -v "$prefix/share/sip" ${toString configureFlags}
'') ["minInit" "addInputs" "doUnpack"];
# changing this ? see [1]
doMakeInstall = fullDepEntry ("
make ${toString (attrByPath ["makeFlags"] "" args)} "+
"${toString (attrByPath ["installFlags"] "" args)} install") ["doMake"];
# changing this ? see [1]
doForceShare = fullDepEntry ("
mkdir -p \"\$prefix/share\"
for d in ${toString forceShare}; do
if [ -d \"\$prefix/\$d\" -a ! -d \"\$prefix/share/\$d\" ]; then
mv -v \"\$prefix/\$d\" \"\$prefix/share\"
ln -sv share/\$d \"\$prefix\"
fi;
done;
") ["minInit" "defEnsureDir"];
doForceCopy = fullDepEntry (''
name="$(basename $out)"
name="''${name#*-}"
mkdir -p "$prefix/share/$name"
for f in ${toString forceCopy}; do
cp -r "$f" "$prefix/share/$name/$f" || true
done;
'') ["minInit" "defEnsureDir"];
doDump = n: noDepEntry "echo Dump number ${n}; set";
saveEnv = noDepEntry ''export > "$TMP/env-vars" || true'';
doDumpBuildInputs = noDepEntry (''
echo "${toString realBuildInputs}"
'');
patchFlags = if args ? patchFlags then args.patchFlags else "-p1";
patches = attrByPath ["patches"] [] args;
toPatchCommand = s: "cat ${s} | patch ${toString patchFlags}";
doPatch = fullDepEntry (concatStringsSep ";"
(map toPatchCommand patches)
) ["minInit" "doUnpack"];
envAdderInner = s: x: if x==null then s else y:
a: envAdderInner (s+"echo export ${x}='\"'\"\$${x}:${y}\";'\"'\n") a;
envAdder = envAdderInner "";
envAdderList = l: if l==[] then "" else
"echo export ${head l}='\"'\"\\\$${head l}:${head (tail l)}\"'\"';\n" +
envAdderList (tail (tail l));
# changing this ? see [1]
wrapEnv = cmd: env: "
mv \"${cmd}\" \"${cmd}-orig\";
touch \"${cmd}\";
chmod a+rx \"${cmd}\";
(${envAdderList env}
echo '\"'\"${cmd}-orig\"'\"' '\"'\\\$@'\"' \n) > \"${cmd}\"";
doWrap = cmd: fullDepEntry (wrapEnv cmd (attrByPath ["wrappedEnv"] [] args)) ["minInit"];
makeManyWrappers = wildcard : wrapperFlags : fullDepEntry (''
for i in ${wildcard}; do
wrapProgram "$i" ${wrapperFlags}
done
'') ["minInit" "addInputs" "defEnsureDir"];
wrapBinContentsPython = (makeManyWrappers
''$out/bin/*''
pythonWrapperArguments
);
pythonWrapperArguments =
(''--prefix PYTHONPATH : $(toPythonPath $out)'' +
''''${PYTHONPATH:+ --prefix PYTHONPATH : $PYTHONPATH}'');
preservePathWrapperArguments = ''''${PATH:+ --prefix PATH : $PATH }'';
doPropagate = fullDepEntry ("
mkdir -p \$out/nix-support
echo '${toString (attrByPath ["propagatedBuildInputs"] [] args)}' >\$out/nix-support/propagated-build-inputs
") ["minInit" "defEnsureDir"];
cmakeFlags = attrByPath ["cmakeFlags"] [] args;
cmakeRPathFlag = if attrByPath ["cmakeSkipRpath "] true args then " -DCMAKE_SKIP_BUILD_RPATH=ON " else "";
cmakeBuildDir = attrByPath ["cmakeBuildDir"] "build" args;
doCmake = fullDepEntry (''
mkdir ${cmakeBuildDir}
cd ${cmakeBuildDir}
cmake -D CMAKE_INSTALL_PREFIX="$out" ${cmakeRPathFlag}${toString cmakeFlags} ..
'') ["minInit" "addInputs" "doUnpack"];
doScons = fullDepEntry (''
mkdir -p $out
${if (attrByPath ["sconsCleanEnv"] false args)
then ""
else ''
sed -e '1iimport os' -i SConstruct
sed -e 's/env *= *Environment *.*/&; env['"'"'ENV'"'"']=os.environ;/' -i SConstruct
''
}
scons ${toString (attrByPath ["sconsFlags"] [] args)} PREFIX=$out
scons ${toString (attrByPath ["sconsFlags"] [] args)} PREFIX=$out install
'') ["minInit" "doUnpack" "addInputs" "defEnsureDir"];
/*debug = x:(trace x x);
debugX = x:(trace (toXML x) x);*/
makeNest = x: if x == defNest.text then x else "startNest\n" + x + "\nstopNest\n";
textClosure = a: steps: textClosureMap makeNest a (["defNest"] ++ steps);
inherit noDepEntry fullDepEntry packEntry;
defList = attrByPath ["defList"] [] args;
getVal = getValue args defList;
check = checkFlag args;
reqsList = attrByPath ["reqsList"] [] args;
buildInputsNames = filter (x: null != getVal x)
(uniqList {inputList =
(concatLists (map
(x: if x==[] then [] else builtins.tail x)
reqsList));});
configFlags = attrByPath ["configFlags"] [] args;
buildFlags = attrByPath ["buildFlags"] [] args;
nameSuffixes = attrByPath ["nameSuffixes"] [] args;
autoBuildInputs = assert (checkReqs args defList reqsList);
filter (x: x!=null) (map getVal buildInputsNames);
autoConfigureFlags = condConcat "" configFlags check;
autoMakeFlags = condConcat "" buildFlags check;
useConfig = attrByPath ["useConfig"] false args;
realBuildInputs =
lib.closePropagation ((if useConfig then
autoBuildInputs else
attrByPath ["buildInputs"] [] args)++
(attrByPath ["propagatedBuildInputs"] [] args));
configureFlags = if useConfig then autoConfigureFlags else
attrByPath ["configureFlags"] "" args;
makeFlags = if useConfig then autoMakeFlags else attrByPath ["makeFlags"] "" args;
inherit lib;
surroundWithCommands = x : before : after : {deps=x.deps; text = before + "\n" +
x.text + "\n" + after ;};
createDirs = fullDepEntry (concatStringsSep ";"
(map (x: "mkdir -p ${x}") (attrByPath ["neededDirs"] [] args))
) ["minInit" "defEnsureDir"];
copyExtraDoc = fullDepEntry (''
name="$(basename $out)"
name="''${name#*-}"
mkdir -p "$out/share/doc/$name"
'' + (concatStringsSep ";"
(map
(x: ''cp "${x}" "$out/share/doc/$name" || true;'')
(attrByPath ["extraDoc"] [] args)))) ["minInit" "defEnsureDir" "doUnpack"];
realPhaseNames =
(optional ([] != attrByPath ["neededDirs"] [] args) "createDirs")
++
(attrByPath ["phaseNames"] [] args)
++
["doForceShare" "doPropagate" "doForceCopy"]
++
(optional ([] != attrByPath ["extraDoc"] [] args) "copyExtraDoc")
++
(optional (attrByPath ["doCheck"] false args) "doMakeCheck")
++
(optional (attrByPath ["alwaysFail"] false args) "doFail")
;
doFail = noDepEntry "
echo 'Failing to keep builddir (and to invalidate result).'
a() { return 127; } ; a ;
";
doMakeCheck = fullDepEntry (''
make check
'') ["minInit"];
extraDerivationAttrs = lib.attrByPath ["extraDerivationAttrs"] {} args;
# for overrides..
builderDefsArgs = args;
innerBuilderDefsPackage = bd: args: (
let localDefs = bd.passthru.function args; in
stdenv.mkDerivation ((rec {
inherit (localDefs) name;
buildCommand = textClosure localDefs localDefs.realPhaseNames;
meta = localDefs.meta;
passthru = localDefs.passthru // {inherit (localDefs) src; };
}) // (if localDefs ? propagatedBuildInputs then {
inherit (localDefs) propagatedBuildInputs;
} else {}) // extraDerivationAttrs)
);
builderDefsPackage = bd: func:
if builtins.isFunction func then
(foldArgs
(x: y: ((func (bd // x // y)) // y))
(innerBuilderDefsPackage bd)
{})
else
(builderDefsPackage bd (import (toString func)))
;
generateFontsFromSFD = fullDepEntry (''
for i in *.sfd; do
echo $i;
fontforge -c \
'Open($1);
${optionalString (args ? extraFontForgeCommands) args.extraFontForgeCommands
}Reencode("unicode");
${optionalString (attrByPath ["createTTF"] true args) ''Generate($1:r + ".ttf");''}
${optionalString (attrByPath ["createOTF"] true args) ''Generate($1:r + ".otf");''}
Reencode("TeX-Base-Encoding");
${optionalString (attrByPath ["createAFM"] true args) ''Generate($1:r + ".afm");''}
${optionalString (attrByPath ["createPFM"] true args) ''Generate($1:r + ".pfm");''}
${optionalString (attrByPath ["createPFB"] true args) ''Generate($1:r + ".pfb");''}
${optionalString (attrByPath ["createMAP"] true args) ''Generate($1:r + ".map");''}
${optionalString (attrByPath ["createENC"] true args) ''Generate($1:r + ".enc");''}
' $i;
done
'') ["minInit" "addInputs" "doUnpack"];
installFonts =
let retrievedName = (if args ? name then args.name else ""); in
fullDepEntry (''
mkdir -p $out/share/fonts/truetype/public/${retrievedName}
mkdir -p $out/share/fonts/opentype/public/${retrievedName}
mkdir -p $out/share/fonts/type1/public/${retrievedName}
mkdir -p $out/share/texmf/fonts/enc/${retrievedName}
mkdir -p $out/share/texmf/fonts/map/${retrievedName}
find -name '*.ttf' -exec cp {} $out/share/fonts/truetype/public/${retrievedName} \;
find -name '*.otf' -exec cp {} $out/share/fonts/opentype/public/${retrievedName} \;
find -name '*.pfm' -o -name '*.afm' -o -name '*.pfb' -exec cp {} $out/share/fonts/type1/public/${retrievedName} \;
find -name '*.enc' -exec cp {} $out/share/texmf/fonts/enc/${retrievedName} \;
find -name '*.map' -exec cp {} $out/share/texmf/fonts/map/${retrievedName} \;
'') ["minInit" "defEnsureDir"];
simplyShare = shareName: fullDepEntry (''
mkdir -p $out/share
cp -r . $out/share/${shareName}
'') ["doUnpack" "defEnsureDir"];
doPatchShebangs = dir: fullDepEntry (''
patchShebangFun() {
# Rewrite all script interpreter file names (`#! /path') under the
# specified directory tree to paths found in $PATH. E.g.,
# /bin/sh will be rewritten to /nix/store/<hash>-some-bash/bin/sh.
# Interpreters that are already in the store are left untouched.
echo "patching script interpreter paths"
local f
for f in $(find "${dir}" -xtype f -perm -0100); do
local oldPath=$(sed -ne '1 s,^#![ ]*\([^ ]*\).*$,\1,p' "$f")
if test -n "$oldPath" -a "''${oldPath:0:''${#NIX_STORE}}" != "$NIX_STORE"; then
local newPath=$(type -P $(basename $oldPath) || true)
if test -n "$newPath" -a "$newPath" != "$oldPath"; then
echo "$f: interpreter changed from $oldPath to $newPath"
sed -i "1 s,$oldPath,$newPath," "$f"
else
echo "$f: not changing interpreter from $oldPath"
fi
fi
done
}
patchShebangFun;
'') ["minInit"];
createPythonInstallationTarget = fullDepEntry (''
mkdir -p $(toPythonPath $out)
export PYTHONPATH=$PYTHONPATH''${PYTHONPATH:+:}$(toPythonPath $out)
'') ["minInit" "addInputs" "defEnsureDir"];
fetchUrlFromSrcInfo = srcInfo: fetchurl ({
url = srcInfo.url;
sha256 = srcInfo.hash;
} //
(if srcInfo ? downloadName then {name = srcInfo.downloadName;} else {}));
fetchGitFromSrcInfo = srcInfo: fetchgit {
url = srcInfo.url;
rev = srcInfo.rev;
sha256 = srcInfo.hash;
};
}) // args
# [1]: rewrite using '' instead of " so that indentation gets stripped. It's
# only about some spaces but in the end they will sum up