{ lib, stdenv, fetchurl, fetchpatch, buildPackages, texlive, zlib, libiconv, libpng, libX11, freetype, gd, libXaw, icu, ghostscript, libXpm, libXmu, libXext, perl, perlPackages, python3Packages, pkg-config, cmake, ninja, libpaper, graphite2, zziplib, harfbuzz, potrace, gmp, mpfr, mupdf-headless, brotli, cairo, pixman, xorg, clisp, biber, woff2, xxHash, makeWrapper, shortenPerlShebang, useFixedHashes, asymptote, biber-ms, tlpdb, }@args: # Useful resource covering build options: # http://tug.org/texlive/doc/tlbuild.html let withSystemLibs = map (libname: "--with-system-${libname}"); year = toString ((import ./tlpdb.nix)."00texlive.config").year; version = year; # keep names simple for now # detect and stop redundant rebuilds that may occur when building new fixed hashes assertFixedHash = name: src: if !useFixedHashes || src ? outputHash then src else throw "The TeX Live package '${src.pname}' must have a fixed hash before building '${name}'."; # list of packages whose binaries are built in core, core-big # generated manually by inspecting ${core}/bin corePackages = [ "afm2pl" "aleph" "autosp" "axodraw2" "bibtex" "cjkutils" "ctie" "cweb" "detex" "dtl" "dvi2tty" "dvicopy" "dvidvi" "dviljk" "dviout-util" "dvipdfmx" "dvipos" "dvips" "fontware" "gregoriotex" "gsftopk" "hitex" "kpathsea" "lacheck" "lcdftypetools" "m-tx" "makeindex" "mfware" "musixtnt" "omegaware" "patgen" "pdftex" "pdftosrc" "pmx" "ps2eps" "ps2pk" "psutils" "ptex" "seetexk" "synctex" "t1utils" "tex" "tex4ht" "texlive-scripts-extra" "texware" "tie" "tpic2pdftex" "ttfutils" "uptex" "velthuis" "vlna" "web" "xml2pmx" ]; coreBigPackages = [ "metafont" "mflua" "metapost" "luatex" "luahbtex" "upmendex" "xetex" ] ++ lib.optional withLuaJIT "luajittex"; binPackages = lib.getAttrs (corePackages ++ coreBigPackages) tlpdb; common = { src = fetchurl { urls = [ "http://ftp.math.utah.edu/pub/tex/historic/systems/texlive/${year}/texlive-${year}0313-source.tar.xz" "ftp://tug.ctan.org/pub/tex/historic/systems/texlive/${year}/texlive-${year}0313-source.tar.xz" ]; hash = "sha256-OHiqDh7QMBwFOw4u5OmtmZxEE0X0iC55vdHI9M6eebk="; }; prePatch = '' for i in texk/kpathsea/mktex*; do sed -i '/^mydir=/d' "$i" done # ST_NLINK_TRICK causes kpathsea to treat folders with no real subfolders # as leaves, even if they contain symlinks to other folders; must be # disabled to work correctly with the nix store", see section 5.3.6 # “Subdirectory expansion” of the kpathsea manual # http://mirrors.ctan.org/systems/doc/kpathsea/kpathsea.pdf for more # details sed -i '/^#define ST_NLINK_TRICK/d' texk/kpathsea/config.h '' + # when cross compiling, we must use himktables from PATH # (i.e. from buildPackages.texlive.bin.core.dev) lib.optionalString (!stdenv.buildPlatform.canExecute stdenv.hostPlatform) '' sed -i 's|\./himktables|himktables|' texk/web2c/Makefile.in ''; configureFlags = [ "--with-banner-add=/nixos.org" "--disable-missing" # terminate if a requested program or feature must be # disabled, e.g., due to missing libraries "--disable-native-texlive-build" # do not build for the TeX Live binary distribution "--enable-shared" # "--enable-cxx-runtime-hack" # static runtime "--enable-tex-synctex" "--disable-texlive" # do not build the texlive (TeX Live scripts) package "--disable-linked-scripts" # do not install the linked scripts "-C" # use configure cache to speed up ] ++ withSystemLibs [ # see "from TL tree" vs. "Using installed" in configure output "zziplib" "mpfr" "gmp" "pixman" "potrace" "gd" "freetype2" "libpng" "libpaper" "zlib" ] ++ lib.optional ( stdenv.hostPlatform != stdenv.buildPlatform ) "BUILDCC=${buildPackages.stdenv.cc.targetPrefix}cc"; # move binaries to corresponding split outputs, based on content of texlive.tlpdb binToOutput = lib.listToAttrs ( lib.concatMap ( n: map (v: { name = v; value = builtins.replaceStrings [ "-" ] [ "_" ] n; }) binPackages.${n}.binfiles or [ ] ) (builtins.attrNames binPackages) ); moveBins = '' for bin in "$out/bin"/* ; do bin="''${bin##*/}" package="''${binToOutput[$bin]}" if [[ -n "$package" ]] ; then if [[ -z "''${!package}" ]] ; then echo "WARNING: missing output '$package' for binary '$bin', leaving in 'out'" else mkdir -p "''${!package}"/bin mv "$out/bin/$bin" "''${!package}"/bin/ fi else echo "WARNING: no output known for binary '$bin', leaving in 'out'" fi done ''; }; # RISC-V: https://github.com/LuaJIT/LuaJIT/issues/628 withLuaJIT = !(stdenv.hostPlatform.isPower && stdenv.hostPlatform.is64bit) && !stdenv.hostPlatform.isRiscV; in rec { # un-indented texliveYear = year; core = stdenv.mkDerivation rec { pname = "texlive-bin"; inherit version; __structuredAttrs = true; inherit (common) binToOutput src prePatch; patches = [ (fetchpatch { name = "ttfdump-CVE-2024-25262.patch"; url = "https://tug.org/svn/texlive/trunk/Build/source/texk/ttfdump/libttf/hdmx.c?r1=57915&r2=69520&view=patch"; stripLen = 2; hash = "sha256-WH2kioqFAs3jaFmu4DdEUdrTf6eiymtiWTZi3vWwU7k="; }) ]; outputs = [ "out" "dev" "man" "info" ] ++ (builtins.map (builtins.replaceStrings [ "-" ] [ "_" ]) corePackages); nativeBuildInputs = [ pkg-config ] ++ lib.optionals (!stdenv.buildPlatform.canExecute stdenv.hostPlatform) ( with texlive.bin.core; [ # configure: error: tangle was not found but is required when cross-compiling. # dev (himktables) is used when building hitex to generate the additional source file hitables.c web # tangle cweb # ctangle omegaware # otangle tie # tie see "Building TeX Live" 6.4.2 Cross problems dev # himktables ] ); buildInputs = [ # teckit zziplib mpfr gmp pixman gd freetype libpng libpaper zlib perl ]; hardeningDisable = [ "format" ]; preConfigure = '' rm -r libs/{cairo,freetype2,gd,gmp,graphite2,harfbuzz,icu,libpaper,libpng} \ libs/{lua53,luajit,mpfr,pixman,pplib,teckit,zlib,zziplib} \ texk/{bibtex-x,chktex,dvipng,dvisvgm,upmendex,xdvik} \ utils/{asymptote,texdoctk,xindy,xpdfopen} mkdir WorkDir cd WorkDir ''; configureScript = "../configure"; depsBuildBuild = [ buildPackages.stdenv.cc ]; configureFlags = common.configureFlags ++ [ "--without-x" ] # disable xdvik and xpdfopen ++ map (what: "--disable-${what}") [ "chktex" "dvisvgm" "dvipng" # ghostscript dependency "luatex" "luajittex" "luahbtex" "luajithbtex" "mp" "pmp" "upmp" "mf" "mflua" "mfluajit" # cairo would bring in X and more "xetex" "bibtexu" "bibtex8" "bibtex-x" "upmendex" # ICU isn't small ]; enableParallelBuilding = true; doCheck = false; # triptest fails, likely due to missing TEXMF tree preCheck = "patchShebangs ../texk/web2c"; installTargets = [ "install" ]; # TODO: perhaps improve texmf.cnf search locations postInstall = # remove redundant texmf-dist (content provided by TeX Live packages) '' rm -fr "$out"/share/texmf-dist '' # install himktables in separate output for use in cross compilation + '' mkdir -p $dev/bin cp texk/web2c/.libs/himktables $dev/bin/himktables '' + common.moveBins; passthru = { inherit version buildInputs; }; meta = with lib; { description = "Basic binaries for TeX Live"; homepage = "http://www.tug.org/texlive"; license = lib.licenses.gpl2Plus; maintainers = with maintainers; [ veprbl lovek323 raskin jwiegley ]; platforms = platforms.all; }; }; inherit (core-big) metafont mflua metapost luatex luahbtex xetex ; luajittex = core.big.luajittex or null; core-big = stdenv.mkDerivation { pname = "texlive-bin-big"; inherit version; __structuredAttrs = true; inherit (common) binToOutput src prePatch; patches = [ # improves reproducibility of fmt files # see discussion at https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1009196 (fetchpatch { name = "lua_fixed_hash.patch"; url = "https://bugs.debian.org/cgi-bin/bugreport.cgi?att=1;bug=1009196;filename=lua_fixed_hash.patch;msg=45"; sha256 = "sha256-FTu1eRd3AUU7IRs2/7e7uwHuvZsrzTBPypbcEZkU7y4="; }) # update to LuaTeX 1.16.1 to prepare for 1.17.0 below (fetchpatch { name = "luatex-1.16.1.patch"; url = "https://github.com/TeX-Live/texlive-source/commit/ad8702a45e317fa9d396ef4d50467c37964a9543.patch"; hash = "sha256-qfzUfkJUfW285w+fnbpO8JLArM7/uj3yb9PONgZrJLE="; }) # fixes security issues in luatex that allows arbitrary code execution even with shell-escape disabled and network requests, see https://tug.org/~mseven/luatex.html # fixed in LuaTeX 1.17.0, shipped as a rare binary update in TL 2023 (fetchpatch { name = "luatex-1.17.0.patch"; url = "https://github.com/TeX-Live/texlive-source/commit/6ace460233115bd42b36e63c7ddce11cc92a1ebd.patch"; hash = "sha256-2fbIdwnw/XQXci9OqRrb6B5tHiSR0co08NyFgMyXCvc="; }) # Fixes texluajitc crashes on aarch64, backport of the upstream fix # https://github.com/LuaJIT/LuaJIT/commit/e9af1abec542e6f9851ff2368e7f196b6382a44c # to the version vendored by texlive (2.1.0-beta3) (fetchpatch { name = "luajit-fix-aarch64-linux.patch"; url = "https://raw.githubusercontent.com/void-linux/void-packages/master/srcpkgs/LuaJIT/patches/e9af1abec542e6f9851ff2368e7f196b6382a44c.patch"; hash = "sha256-ysSZmfpfCFMukfHmIqwofAZux1e2kEq/37lfqp7HoWo="; stripLen = 1; extraPrefix = "libs/luajit/LuaJIT-src/"; }) ]; hardeningDisable = [ "format" ]; inherit (core) nativeBuildInputs depsBuildBuild; buildInputs = core.buildInputs ++ [ core cairo harfbuzz icu graphite2 libX11 potrace ]; /* deleting the unused packages speeds up configure by a considerable margin and ensures we do not rebuild existing libraries by mistake */ preConfigure = '' rm -r libs/{cairo,freetype2,gd,gmp,graphite2,harfbuzz,icu,libpaper,libpng} \ libs/{mpfr,pixman,xpdf,zlib,zziplib} \ texk/{afm2pl,bibtex-x,chktex,cjkutils,detex,dtl,dvi2tty,dvidvi,dviljk,dviout-util} \ texk/{dvipdfm-x,dvipng,dvipos,dvipsk,dvisvgm,gregorio,gsftopk,kpathsea} \ texk/{lcdf-typetools,makeindexk,makejvf,mendexk,musixtnt,ps2pk,psutils,ptexenc} \ texk/{seetexk,tex4htk,texlive,ttf2pk2,ttfdump,xdvik} \ utils/{asymptote,autosp,axodraw2,devnag,lacheck,m-tx,pmx,ps2eps,t1utils,texdoctk} \ utils/{tpic2pdftex,vlna,xindy,xml2pmx,xpdfopen} mkdir WorkDir cd WorkDir ''; configureFlags = common.configureFlags ++ withSystemLibs [ "kpathsea" "ptexenc" "cairo" "harfbuzz" "icu" "graphite2" ] ++ map (prog: "--disable-${prog}") # don't build things we already have # list from texk/web2c/configure ( [ "tex" "ptex" "eptex" "uptex" "euptex" "aleph" "hitex" "pdftex" "web-progs" "synctex" ] ++ lib.optionals (!withLuaJIT) [ "luajittex" "luajithbtex" "mfluajit" ] ) # disable all packages, re-enable upmendex, web2c packages ++ [ "--disable-all-pkgs" "--enable-upmendex" "--enable-web2c" ] # kpathsea requires specifying the kpathsea location manually ++ [ "--with-kpathsea-includes=${core.dev}/include" ]; configureScript = "../configure"; enableParallelBuilding = true; doCheck = false; # fails outputs = [ "out" "dev" "man" "info" ] ++ (builtins.map (builtins.replaceStrings [ "-" ] [ "_" ]) coreBigPackages) # some outputs of metapost, omegaware are for ptex/uptex ++ [ "ptex" "uptex" ] # unavoidable duplicates from core ++ [ "ctie" "cweb" "omegaware" "texlive_scripts_extra" "tie" "web" ]; postInstall = common.moveBins; }; chktex = stdenv.mkDerivation { pname = "chktex"; inherit (texlive.pkgs.chktex) version; inherit (common) src; nativeBuildInputs = [ pkg-config ]; # perl used in shebang of script bin/deweb buildInputs = [ core # kpathsea perl ]; preConfigure = "cd texk/chktex"; configureFlags = common.configureFlags ++ [ "--with-system-kpathsea" ]; enableParallelBuilding = true; }; # the LuaMetaTeX engine (distributed since TeX Live 2023) must be built separately # the sources used by TL are stored in the source TL repo # for details see https://wiki.contextgarden.net/Building_LuaMetaTeX_for_TeX_Live context = stdenv.mkDerivation rec { pname = "luametatex"; version = "2.10.08"; src = fetchurl { url = "https://tug.org/svn/texlive/trunk/Master/source/luametatex-${version}.tar.xz?revision=67034&view=co"; hash = "sha256-3JeOUQ63jJOZWTxFCoyWjfcrspmdmC/yqgS1JaLfTWk="; }; enableParallelBuilding = true; nativeBuildInputs = [ cmake ninja ]; meta = with lib; { description = "The LUAMETATEX engine is a follow up on LUATEX and is again part of CONTEXT development"; homepage = "https://www.pragma-ade.nl/luametatex-1.htm"; license = licenses.gpl2Plus; maintainers = with lib.maintainers; [ apfelkuchen6 xworld21 ]; }; }; dvisvgm = stdenv.mkDerivation rec { pname = "dvisvgm"; version = "3.2.2"; src = assert lib.assertMsg (version == texlive.pkgs.dvisvgm.version) "dvisvgm: TeX Live version (${texlive.pkgs.dvisvgm.version}) different from source (${version}), please update dvisvgm"; fetchurl { url = "https://github.com/mgieseki/dvisvgm/releases/download/${version}/dvisvgm-${version}.tar.gz"; hash = "sha256-8GKL6lqjMUXXWwpqbdGPrYibdSc4y8AcGUGPNUc6HQA="; }; configureFlags = [ "--disable-manpage" # man pages are provided by the doc container ]; # PDF handling requires mutool (from mupdf) since Ghostscript 10.01 postPatch = '' substituteInPlace src/PDFHandler.cpp \ --replace-fail 'Process("mutool"' "Process(\"$(PATH="$HOST_PATH" command -v mutool)\"" ''; nativeBuildInputs = [ pkg-config ]; buildInputs = [ core brotli ghostscript zlib freetype woff2 potrace xxHash mupdf-headless ]; enableParallelBuilding = true; }; dvipng = stdenv.mkDerivation { pname = "dvipng"; inherit (texlive.pkgs.dvipng) version; inherit (common) src; nativeBuildInputs = [ perl pkg-config makeWrapper ]; buildInputs = [ core # kpathsea zlib libpng freetype gd ghostscript ]; preConfigure = '' cd texk/dvipng patchShebangs doc/texi2pod.pl ''; configureFlags = common.configureFlags ++ [ "--with-system-kpathsea" "--with-gs=yes" "--disable-debug" ]; GS = "${ghostscript}/bin/gs"; enableParallelBuilding = true; }; pygmentex = python3Packages.buildPythonApplication rec { pname = "pygmentex"; inherit (src) version; format = "other"; src = assertFixedHash pname texlive.pkgs.pygmentex.tex; propagatedBuildInputs = with python3Packages; [ pygments chardet ]; dontBuild = true; doCheck = false; installPhase = '' runHook preInstall install -D ./scripts/pygmentex/pygmentex.py "$out"/bin/pygmentex runHook postInstall ''; meta = with lib; { homepage = "https://www.ctan.org/pkg/pygmentex"; description = "Auxiliary tool for typesetting code listings in LaTeX documents using Pygments"; longDescription = '' PygmenTeX is a Python-based LaTeX package that can be used for typesetting code listings in a LaTeX document using Pygments. Pygments is a generic syntax highlighter for general use in all kinds of software such as forum systems, wikis or other applications that need to prettify source code. ''; license = licenses.lppl13c; maintainers = with maintainers; [ romildo ]; }; }; asymptote = args.asymptote.overrideAttrs ( finalAttrs: prevAttrs: { version = texlive.pkgs.asymptote.version; # keep local src and patches even if duplicated in the top level asymptote # so that top level updates do not break texlive src = fetchurl { url = "mirror://sourceforge/asymptote/${finalAttrs.version}/asymptote-${finalAttrs.version}.src.tgz"; hash = "sha256-DecadD+m7pORuH3Sdcs/5M3vUbN6rhSkFoNN0Soq9bs="; }; texContainer = texlive.pkgs.asymptote.tex; texdocContainer = texlive.pkgs.asymptote.texdoc; patches = [ (fetchpatch { # partial fix for macOS XDR/V3D support (LDFLAGS change seems like an unrelated bugfix) name = "restore-LDFLAGS-dont-look-for-tirpc-under-MacOS.patch"; url = "https://github.com/vectorgraphics/asymptote/commit/7e17096b22d18d133d1bc5916b6e32c0cb24ad10.patch"; hash = "sha256-olCFzqfZwWOAjqlB5lDPXYRHU9i3VQNgoR0cO5TmW98="; }) ]; } ); inherit biber; inherit biber-ms; bibtexu = bibtex8; bibtex8 = stdenv.mkDerivation { pname = "bibtex-x"; inherit (texlive.pkgs.bibtexu) version; inherit (common) src; nativeBuildInputs = [ pkg-config ]; buildInputs = [ core # kpathsea icu ]; preConfigure = "cd texk/bibtex-x"; configureFlags = common.configureFlags ++ [ "--with-system-kpathsea" "--with-system-icu" ]; enableParallelBuilding = true; }; xdvi = stdenv.mkDerivation { pname = "xdvi"; inherit (texlive.pkgs.xdvi) version; inherit (common) src; nativeBuildInputs = [ pkg-config ]; buildInputs = [ core # kpathsea freetype ghostscript ] ++ (with xorg; [ libX11 libXaw libXi libXpm libXmu libXaw libXext libXfixes ]); preConfigure = "cd texk/xdvik"; configureFlags = common.configureFlags ++ [ "--with-system-kpathsea" "--with-system-libgs" ]; enableParallelBuilding = true; postInstall = '' substituteInPlace "$out/bin/xdvi" \ --replace-fail "exec xdvi-xaw" "exec '$out/bin/xdvi-xaw'" ''; # TODO: it's suspicious that mktexpk generates fonts into ~/.texlive2014 }; xpdfopen = stdenv.mkDerivation { pname = "xpdfopen"; inherit (texlive.pkgs.xpdfopen) version; inherit (common) src; buildInputs = [ libX11 ]; preConfigure = "cd utils/xpdfopen"; enableParallelBuilding = true; }; } # un-indented // lib.optionalAttrs (!clisp.meta.broken) # broken on aarch64 and darwin (#20062) { xindy = stdenv.mkDerivation { pname = "xindy"; inherit (texlive.pkgs.xindy) version; inherit (common) src; # If unset, xindy will try to mkdir /homeless-shelter HOME = "."; prePatch = "cd utils/xindy"; # hardcode clisp location postPatch = '' substituteInPlace xindy-*/user-commands/xindy.in \ --replace-fail "our \$clisp = ( \$is_windows ? 'clisp.exe' : 'clisp' ) ;" \ "our \$clisp = '$(type -P clisp)';" \ --replace-fail 'die "$cmd: Cannot locate xindy modules directory";' \ '$modules_dir = "${texlive.pkgs.xindy.tex}/xindy/modules"; die "$cmd: Cannot locate xindy modules directory" unless -d $modules_dir;' ''; nativeBuildInputs = [ pkg-config perl ]; buildInputs = [ clisp libiconv perl ]; configureFlags = [ "--with-clisp-runtime=system" "--disable-xindy-docs" "--disable-xindy-rules" ]; preInstall = ''mkdir -p "$out/bin" ''; # fixup various file-location errors of: lib/xindy/{xindy.mem,modules/} postInstall = '' mkdir -p "$out/lib/xindy" mv "$out"/{bin/xindy.mem,lib/xindy/} ''; }; }