From f5804647d9e705b06e8347653120d19adbcdefc0 Mon Sep 17 00:00:00 2001 From: Vincenzo Mantova <1962985+xworld21@users.noreply.github.com> Date: Sat, 16 May 2026 18:14:04 +0100 Subject: [PATCH 01/20] texlive.withPackages: remove unused arguments --- pkgs/tools/typesetting/tex/texlive/build-tex-env.nix | 3 --- pkgs/tools/typesetting/tex/texlive/combine-wrapper.nix | 1 - 2 files changed, 4 deletions(-) diff --git a/pkgs/tools/typesetting/tex/texlive/build-tex-env.nix b/pkgs/tools/typesetting/tex/texlive/build-tex-env.nix index 7d00099ece85..1e3c1948d6d2 100644 --- a/pkgs/tools/typesetting/tex/texlive/build-tex-env.nix +++ b/pkgs/tools/typesetting/tex/texlive/build-tex-env.nix @@ -1,7 +1,6 @@ { # texlive package set tl, - bin, tlpdbVersion, @@ -12,9 +11,7 @@ makeWrapper, runCommand, writeShellScript, - writeText, toTLPkgSets, - bash, perl, # common runtime dependencies diff --git a/pkgs/tools/typesetting/tex/texlive/combine-wrapper.nix b/pkgs/tools/typesetting/tex/texlive/combine-wrapper.nix index 3176bebc368e..e7bd78ff720a 100644 --- a/pkgs/tools/typesetting/tex/texlive/combine-wrapper.nix +++ b/pkgs/tools/typesetting/tex/texlive/combine-wrapper.nix @@ -2,7 +2,6 @@ { lib, toTLPkgList, - toTLPkgSets, buildTeXEnv, }: args@{ From 62b7051f2849d156cc4f44c3dbc43f9afd9c2ee9 Mon Sep 17 00:00:00 2001 From: Vincenzo Mantova <1962985+xworld21@users.noreply.github.com> Date: Sat, 16 May 2026 18:14:04 +0100 Subject: [PATCH 02/20] texlive.withPackages: use buildenv (finalAttrs: ...) --- pkgs/test/texlive/default.nix | 2 +- .../typesetting/tex/texlive/build-tex-env.nix | 867 +++++++++--------- .../tools/typesetting/tex/texlive/default.nix | 4 +- 3 files changed, 452 insertions(+), 421 deletions(-) diff --git a/pkgs/test/texlive/default.nix b/pkgs/test/texlive/default.nix index e28b33d117ba..36a5dbb9b8a6 100644 --- a/pkgs/test/texlive/default.nix +++ b/pkgs/test/texlive/default.nix @@ -951,7 +951,7 @@ rec { scheme: builtins.foldl' ( acc: pkg: concatLicenses acc (lib.toList (pkg.meta.license or [ ])) - ) [ ] scheme.passthru.requiredTeXPackages; + ) [ ] scheme.passthru.includedTeXPackages; correctLicensesAttrNames = scheme: lib.sort lt (map licenseToAttrName (correctLicenses scheme)); hasLicenseMismatch = diff --git a/pkgs/tools/typesetting/tex/texlive/build-tex-env.nix b/pkgs/tools/typesetting/tex/texlive/build-tex-env.nix index 1e3c1948d6d2..bfc196dd0d8d 100644 --- a/pkgs/tools/typesetting/tex/texlive/build-tex-env.nix +++ b/pkgs/tools/typesetting/tex/texlive/build-tex-env.nix @@ -23,12 +23,9 @@ }: lib.fix ( - self: + buildTeXEnv: { - withDocs ? false, - withSources ? false, requiredTeXPackages ? ps: [ ps.scheme-infraonly ], - ### texlive.combine backward compatibility __extraName ? "combined", __extraVersion ? "", @@ -38,448 +35,484 @@ lib.fix ( __fromCombineWrapper ? false, # build only the formats of a package (for internal use!) __formatsOf ? null, - }@args: + }: + buildEnv ( + finalAttrs: - let - ### texlive.combine backward compatibility - # if necessary, convert old style { pkgs = [ ... ]; } packages to attribute sets - isOldPkgList = p: !p.outputSpecified or false && p ? pkgs && builtins.all (p: p ? tlType) p.pkgs; - ensurePkgSets = - ps: - if !__fromCombineWrapper && builtins.any isOldPkgList ps then - let - oldPkgLists = builtins.partition isOldPkgList ps; - in - oldPkgLists.wrong ++ lib.concatMap toTLPkgSets oldPkgLists.right - else - ps; + let + withDocs = finalAttrs.passthru.withDocs or false; + withSources = finalAttrs.passthru.withSources or false; - pkgList = rec { - # resolve dependencies of the packages that affect the runtime - all = - let - packages = ensurePkgSets (requiredTeXPackages tl); - runtime = builtins.partition ( - p: - p.outputSpecified or false - -> builtins.elem (p.tlOutputName or p.outputName) [ - "out" - "tex" - "tlpkg" - ] - ) packages; - keySet = p: { - key = - p.pname or p.name - + lib.optionalString (p.outputSpecified or false) ("-" + p.tlOutputName or p.outputName or ""); - inherit p; - tlDeps = if p ? tlDeps then ensurePkgSets p.tlDeps else (p.requiredTeXPackages or (_: [ ]) tl); - }; - in - # texlive.combine: the wrapper already resolves all dependencies - if __fromCombineWrapper then - requiredTeXPackages null + # if necessary, convert old style { pkgs = [ ... ]; } packages to attribute sets + isOldPkgList = p: !p.outputSpecified or false && p ? pkgs && builtins.all (p: p ? tlType) p.pkgs; + ensurePkgSets = + ps: + if !finalAttrs.passthru.__fromCombineWrapper && builtins.any isOldPkgList ps then + let + oldPkgLists = builtins.partition isOldPkgList ps; + in + oldPkgLists.wrong ++ lib.concatMap toTLPkgSets oldPkgLists.right else - builtins.catAttrs "p" ( - builtins.genericClosure { - startSet = map keySet runtime.right; - operator = p: map keySet p.tlDeps; - } - ) - ++ runtime.wrong; + ps; - # group the specified outputs - specified = builtins.partition (p: p.outputSpecified or false) all; - specifiedOutputs = lib.groupBy (p: p.tlOutputName or p.outputName) specified.right; - otherOutputNames = builtins.catAttrs "key" ( - builtins.genericClosure { - startSet = map (key: { inherit key; }) ( - lib.concatLists (builtins.catAttrs "outputs" specified.wrong) - ); - operator = _: [ ]; - } - ); - otherOutputs = lib.genAttrs otherOutputNames (n: builtins.catAttrs n specified.wrong); - outputsToInstall = builtins.catAttrs "key" ( - builtins.genericClosure { - startSet = map (key: { inherit key; }) ( - [ "out" ] - ++ lib.optional (otherOutputs ? man) "man" - ++ lib.concatLists (builtins.catAttrs "outputsToInstall" (builtins.catAttrs "meta" specified.wrong)) - ); - operator = _: [ ]; - } - ); + pkgList = rec { + # resolve dependencies of the packages that affect the runtime + all = + let + packages = ensurePkgSets (finalAttrs.passthru.requiredTeXPackages tl); + runtime = builtins.partition ( + p: + p.outputSpecified or false + -> builtins.elem (p.tlOutputName or p.outputName) [ + "out" + "tex" + "tlpkg" + ] + ) packages; + keySet = p: { + key = + p.pname or p.name + + lib.optionalString (p.outputSpecified or false) ("-" + p.tlOutputName or p.outputName or ""); + inherit p; + tlDeps = if p ? tlDeps then ensurePkgSets p.tlDeps else (p.requiredTeXPackages or (_: [ ]) tl); + }; + in + # texlive.combine: the wrapper already resolves all dependencies + if finalAttrs.passthru.__fromCombineWrapper then + finalAttrs.passthru.requiredTeXPackages null + else + builtins.catAttrs "p" ( + builtins.genericClosure { + startSet = map keySet runtime.right; + operator = p: map keySet p.tlDeps; + } + ) + ++ runtime.wrong; - # split binary and tlpkg from tex, texdoc, texsource - bin = - if __fromCombineWrapper then - builtins.filter (p: p.tlType == "bin") all # texlive.combine: legacy filter - else - otherOutputs.out or [ ] ++ specifiedOutputs.out or [ ]; - tlpkg = - if __fromCombineWrapper then - builtins.filter (p: p.tlType == "tlpkg") all # texlive.combine: legacy filter - else - otherOutputs.tlpkg or [ ] ++ specifiedOutputs.tlpkg or [ ]; - - nonbin = - if __fromCombineWrapper then - builtins.filter (p: p.tlType != "bin" && p.tlType != "tlpkg") all # texlive.combine: legacy filter - else - ( - if __combine then # texlive.combine: emulate old input ordering to avoid rebuilds - lib.concatMap ( - p: - lib.optional (p ? tex) p.tex - ++ lib.optional ((withDocs || p ? man) && p ? texdoc) p.texdoc - ++ lib.optional (withSources && p ? texsource) p.texsource - ) specified.wrong - else - otherOutputs.tex or [ ] - ++ lib.optionals withDocs (otherOutputs.texdoc or [ ]) - ++ lib.optionals withSources (otherOutputs.texsource or [ ]) - ) - ++ specifiedOutputs.tex or [ ] - ++ specifiedOutputs.texdoc or [ ] - ++ specifiedOutputs.texsource or [ ]; - - # outputs that do not become part of the environment - nonEnvOutputs = lib.subtractLists [ "out" "tex" "texdoc" "texsource" "tlpkg" ] otherOutputNames; - - # packages that contribute to config files and formats - fontMaps = lib.filter (p: p ? fontMaps && (p.tlOutputName or p.outputName == "tex")) nonbin; - sortedFontMaps = builtins.sort (a: b: a.pname < b.pname) fontMaps; - hyphenPatterns = lib.filter ( - p: p ? hyphenPatterns && (p.tlOutputName or p.outputName == "tex") - ) nonbin; - sortedHyphenPatterns = builtins.sort (a: b: a.pname < b.pname) hyphenPatterns; - formatPkgs = lib.filter ( - p: - p ? formats - && (p.outputSpecified or false -> p.tlOutputName or p.outputName == "tex") - && builtins.any (f: f.enabled or true) p.formats - ) all; - sortedFormatPkgs = - if __formatsOf != null then [ __formatsOf ] else builtins.sort (a: b: a.pname < b.pname) formatPkgs; - formats = map ( - p: - self { - requiredTeXPackages = - ps: - [ - ps.scheme-infraonly - p - ] - ++ hyphenPatterns; - __formatsOf = p; - } - ) sortedFormatPkgs; - }; - - # list generated by inspecting `grep -IR '\([^a-zA-Z]\|^\)gs\( \|$\|"\)' "$TEXMFDIST"/scripts` - # and `grep -IR rungs "$TEXMFDIST"` - # and ignoring luatex, perl, and shell scripts (those must be patched using postFixup) - needsGhostscript = lib.any ( - p: - lib.elem p.pname [ - "context" - "dvipdfmx" - "latex-papersize" - "lyluatex" - ] - ) pkgList.bin; - - pname = - if __combine then - "texlive-${__extraName}" # texlive.combine: old name - else - "texlive"; - version = - if __combine then - "${toString tlpdbVersion.year}${__extraVersion}" # texlive.combine: old version - else - "${toString tlpdbVersion.year}-r${toString tlpdbVersion.revision}-" - + (lib.optionalString tlpdbVersion.frozen "final-") - + (if __formatsOf != null then "${__formatsOf.pname}-fmt" else "env"); - - name = "${pname}-${version}"; - - texmfdist = buildEnv { - name = "${name}-texmfdist"; - - # remove fake derivations (without 'outPath') to avoid undesired build dependencies - paths = builtins.catAttrs "outPath" pkgList.nonbin; - - # mktexlsr - nativeBuildInputs = [ - tl.texlive-scripts # for mktexlsr.pl with --sort support - perl - ]; - - postBuild = # generate ls-R database - '' - perl ${tl.texlive-scripts.tex}/scripts/texlive/mktexlsr.pl --sort "$out" - ''; - }; - - tlpkg = buildEnv { - name = "${name}-tlpkg"; - - # remove fake derivations (without 'outPath') to avoid undesired build dependencies - paths = builtins.catAttrs "outPath" pkgList.tlpkg; - }; - - # the 'non-relocated' packages must live in $TEXMFROOT/texmf-dist - # and sometimes look into $TEXMFROOT/tlpkg (notably fmtutil, updmap look for perl modules in both) - texmfroot = - runCommand "${name}-texmfroot" - { - inherit texmfdist tlpkg; - } - '' - mkdir -p "$out" - ln -s "$texmfdist" "$out"/texmf-dist - ln -s "$tlpkg" "$out"/tlpkg - ''; - - # texlive.combine: expose info and man pages in usual /share/{info,man} location - doc = buildEnv { - name = "${name}-doc"; - - paths = [ (texmfdist.outPath + "/doc") ]; - extraPrefix = "/share"; - - pathsToLink = [ - "/info" - "/man" - ]; - }; - - meta = { - description = - "TeX Live environment" - + lib.optionalString withDocs " with documentation" - + lib.optionalString (withDocs && withSources) " and" - + lib.optionalString withSources " with sources"; - platforms = lib.platforms.all; - longDescription = - "Contains the following packages and their transitive dependencies:\n - " - + lib.concatMapStringsSep "\n - " ( - p: - p.pname + (lib.optionalString (p.outputSpecified or false) " (${p.tlOutputName or p.outputName})") - ) (requiredTeXPackages tl); - }; - - # other outputs - nonEnvOutputs = lib.genAttrs pkgList.nonEnvOutputs ( - outName: - buildEnv { - inherit name; - paths = builtins.catAttrs "outPath" ( - pkgList.otherOutputs.${outName} or [ ] ++ pkgList.specifiedOutputs.${outName} or [ ] + # group the specified outputs + specified = builtins.partition (p: p.outputSpecified or false) all; + specifiedOutputs = lib.groupBy (p: p.tlOutputName or p.outputName) specified.right; + otherOutputNames = builtins.catAttrs "key" ( + builtins.genericClosure { + startSet = map (key: { inherit key; }) ( + lib.concatLists (builtins.catAttrs "outputs" specified.wrong) + ); + operator = _: [ ]; + } ); - derivationArgs = { - outputs = [ outName ]; - nativeBuildInputs = [ - # force the output to be ${outName} or nix-env will not work - (writeShellScript "force-output.sh" '' - export out="''${${outName}-}" - '') - ]; - inherit meta passthru; - }; - } - ); - - passthru = { - # This is set primarily to help find-tarballs.nix to do its job - requiredTeXPackages = builtins.filter lib.isDerivation ( - pkgList.bin - ++ pkgList.nonbin - ++ lib.optionals (!__fromCombineWrapper) ( - lib.concatMap ( - n: (pkgList.otherOutputs.${n} or [ ] ++ pkgList.specifiedOutputs.${n} or [ ]) - ) pkgList.nonEnvOutputs - ) - ); - # useful for inclusion in the `fonts.packages` nixos option or for use in devshells - fonts = "${texmfroot}/texmf-dist/fonts"; - # support variants attrs, (prev: attrs) - __overrideTeXConfig = - newArgs: - let - appliedArgs = if builtins.isFunction newArgs then newArgs args else newArgs; - in - self (args // { __fromCombineWrapper = false; } // appliedArgs); - withPackages = - reqs: - self ( - args - // { - requiredTeXPackages = ps: reqs ps ++ requiredTeXPackages ps; - __fromCombineWrapper = false; + otherOutputs = lib.genAttrs otherOutputNames (n: builtins.catAttrs n specified.wrong); + outputsToInstall = builtins.catAttrs "key" ( + builtins.genericClosure { + startSet = map (key: { inherit key; }) ( + [ "out" ] + ++ lib.optional (otherOutputs ? man) "man" + ++ lib.concatLists (builtins.catAttrs "outputsToInstall" (builtins.catAttrs "meta" specified.wrong)) + ); + operator = _: [ ]; } ); - }; - # TeXLive::TLOBJ::fmtutil_cnf_lines - fmtutilLine = - { - name, - engine, - enabled ? true, - patterns ? [ "-" ], - options ? "", - ... - }: - lib.optionalString (!enabled) "#! " - + "${name} ${engine} ${lib.concatStringsSep "," patterns} ${options}"; - fmtutilLines = - { pname, formats, ... }: - [ - "#" - "# from ${pname}:" - ] - ++ map fmtutilLine formats; + # split binary and tlpkg from tex, texdoc, texsource + bin = + if finalAttrs.passthru.__fromCombineWrapper then + builtins.filter (p: p.tlType == "bin") all # texlive.combine: legacy filter + else + otherOutputs.out or [ ] ++ specifiedOutputs.out or [ ]; + tlpkg = + if finalAttrs.passthru.__fromCombineWrapper then + builtins.filter (p: p.tlType == "tlpkg") all # texlive.combine: legacy filter + else + otherOutputs.tlpkg or [ ] ++ specifiedOutputs.tlpkg or [ ]; - # TeXLive::TLOBJ::language_dat_lines - langDatLine = - { - name, - file, - synonyms ? [ ], - ... - }: - [ "${name} ${file}" ] ++ map (s: "=" + s) synonyms; - langDatLines = - { pname, hyphenPatterns, ... }: - [ "% from ${pname}:" ] ++ builtins.concatMap langDatLine hyphenPatterns; + nonbin = + if finalAttrs.passthru.__fromCombineWrapper then + builtins.filter (p: p.tlType != "bin" && p.tlType != "tlpkg") all # texlive.combine: legacy filter + else + ( + if finalAttrs.__combine then # texlive.combine: emulate old input ordering to avoid rebuilds + lib.concatMap ( + p: + lib.optional (p ? tex) p.tex + ++ lib.optional ((withDocs || p ? man) && p ? texdoc) p.texdoc + ++ lib.optional (withSources && p ? texsource) p.texsource + ) specified.wrong + else + otherOutputs.tex or [ ] + ++ lib.optionals withDocs (otherOutputs.texdoc or [ ]) + ++ lib.optionals withSources (otherOutputs.texsource or [ ]) + ) + ++ specifiedOutputs.tex or [ ] + ++ specifiedOutputs.texdoc or [ ] + ++ specifiedOutputs.texsource or [ ]; - # TeXLive::TLOBJ::language_def_lines - # see TeXLive::TLUtils::parse_AddHyphen_line for default values - langDefLine = - { - name, - file, - lefthyphenmin ? "", - righthyphenmin ? "", - synonyms ? [ ], - ... - }: - map ( - n: - "\\addlanguage{${n}}{${file}}{}{${if lefthyphenmin == "" then "2" else lefthyphenmin}}{${ - if righthyphenmin == "" then "3" else righthyphenmin - }}" - ) ([ name ] ++ synonyms); - langDefLines = - { pname, hyphenPatterns, ... }: - [ "% from ${pname}:" ] ++ builtins.concatMap langDefLine hyphenPatterns; + # outputs that do not become part of the environment + nonEnvOutputs = lib.subtractLists [ "out" "tex" "texdoc" "texsource" "tlpkg" ] otherOutputNames; - # TeXLive::TLOBJ::language_lua_lines - # see TeXLive::TLUtils::parse_AddHyphen_line for default values - langLuaLine = - { - name, - file, - lefthyphenmin ? "", - righthyphenmin ? "", - synonyms ? [ ], - ... - }@args: - '' - ''\t['${name}'] = { - ''\t''\tloader = '${file}', - ''\t''\tlefthyphenmin = ${if lefthyphenmin == "" then "2" else lefthyphenmin}, - ''\t''\trighthyphenmin = ${if righthyphenmin == "" then "3" else righthyphenmin}, - ''\t''\tsynonyms = { ${lib.concatStringsSep ", " (map (s: "'${s}'") synonyms)} }, - '' - + lib.optionalString (args ? file_patterns) "\t\tpatterns = '${args.file_patterns}',\n" - + lib.optionalString (args ? file_exceptions) "\t\thyphenation = '${args.file_exceptions}',\n" - + lib.optionalString (args ? luaspecial) "\t\tspecial = '${args.luaspecial}',\n" - + "\t},"; - langLuaLines = - { pname, hyphenPatterns, ... }: [ "-- from ${pname}:" ] ++ map langLuaLine hyphenPatterns; + # packages that contribute to config files and formats + fontMaps = lib.filter (p: p ? fontMaps && (p.tlOutputName or p.outputName == "tex")) nonbin; + sortedFontMaps = builtins.sort (a: b: a.pname < b.pname) fontMaps; + hyphenPatterns = lib.filter ( + p: p ? hyphenPatterns && (p.tlOutputName or p.outputName == "tex") + ) nonbin; + sortedHyphenPatterns = builtins.sort (a: b: a.pname < b.pname) hyphenPatterns; + formatPkgs = lib.filter ( + p: + p ? formats + && (p.outputSpecified or false -> p.tlOutputName or p.outputName == "tex") + && builtins.any (f: f.enabled or true) p.formats + ) all; + sortedFormatPkgs = + if __formatsOf != null then [ __formatsOf ] else builtins.sort (a: b: a.pname < b.pname) formatPkgs; + formats = map ( + p: + buildTeXEnv { + requiredTeXPackages = + ps: + [ + ps.scheme-infraonly + p + ] + ++ hyphenPatterns; + __formatsOf = p; + } + ) sortedFormatPkgs; + }; - assembleConfigLines = f: packages: builtins.concatStringsSep "\n" (builtins.concatMap f packages); + # list generated by inspecting `grep -IR '\([^a-zA-Z]\|^\)gs\( \|$\|"\)' "$TEXMFDIST"/scripts` + # and `grep -IR rungs "$TEXMFDIST"` + # and ignoring luatex, perl, and shell scripts (those must be patched using postFixup) + needsGhostscript = lib.any ( + p: + lib.elem p.pname [ + "context" + "dvipdfmx" + "latex-papersize" + "lyluatex" + ] + ) pkgList.bin; - updmapLines = { pname, fontMaps, ... }: [ "# from ${pname}:" ] ++ fontMaps; + pname = + if finalAttrs.__combine then + "texlive-${finalAttrs.passthru.__extraName}" # texlive.combine: old name + else + "texlive"; + version = + if finalAttrs.__combine then + "${toString tlpdbVersion.year}${finalAttrs.passthru.__extraVersion}" # texlive.combine: old version + else + "${toString tlpdbVersion.year}-r${toString tlpdbVersion.revision}-" + + (lib.optionalString tlpdbVersion.frozen "final-") + + (if __formatsOf != null then "${__formatsOf.pname}-fmt" else "env"); - in - buildEnv { + name = "${pname}-${version}"; - inherit name; + texmfdist = buildEnv { + name = "${name}-texmfdist"; - # remove fake derivations (without 'outPath') to avoid undesired build dependencies - paths = - builtins.catAttrs "outPath" pkgList.bin - ++ lib.optionals (!__combine && __formatsOf == null) pkgList.formats - ++ lib.optional __combine doc; - pathsToLink = [ - "/" - "/share/texmf-var/scripts" - "/share/texmf-var/tex/generic/config" - "/share/texmf-var/web2c" - "/share/texmf-config" - "/bin" # ensure these are writeable directories - ]; + # remove fake derivations (without 'outPath') to avoid undesired build dependencies + paths = builtins.catAttrs "outPath" pkgList.nonbin; - postBuild = '' - . "${./build-tex-env.sh}" - ''; + # mktexlsr + nativeBuildInputs = [ + tl.texlive-scripts # for mktexlsr.pl with --sort support + perl + ]; - derivationArgs = { - # use attrNames, attrValues to ensure the two lists are sorted in the same way - outputs = [ - "out" - ] - ++ lib.optionals (!__combine && __formatsOf == null) (builtins.attrNames nonEnvOutputs); - otherOutputs = lib.optionals (!__combine && __formatsOf == null) ( - builtins.attrValues nonEnvOutputs + postBuild = # generate ls-R database + '' + perl ${tl.texlive-scripts.tex}/scripts/texlive/mktexlsr.pl --sort "$out" + ''; + }; + + tlpkg = buildEnv { + name = "${name}-tlpkg"; + + # remove fake derivations (without 'outPath') to avoid undesired build dependencies + paths = builtins.catAttrs "outPath" pkgList.tlpkg; + }; + + # the 'non-relocated' packages must live in $TEXMFROOT/texmf-dist + # and sometimes look into $TEXMFROOT/tlpkg (notably fmtutil, updmap look for perl modules in both) + texmfroot = + runCommand "${name}-texmfroot" + { + inherit texmfdist tlpkg; + } + '' + mkdir -p "$out" + ln -s "$texmfdist" "$out"/texmf-dist + ln -s "$tlpkg" "$out"/tlpkg + ''; + + # texlive.combine: expose info and man pages in usual /share/{info,man} location + doc = buildEnv { + name = "${name}-doc"; + + paths = [ (texmfdist.outPath + "/doc") ]; + extraPrefix = "/share"; + + pathsToLink = [ + "/info" + "/man" + ]; + }; + + meta = { + description = + "TeX Live environment" + + lib.optionalString withDocs " with documentation" + + lib.optionalString (withDocs && withSources) " and" + + lib.optionalString withSources " with sources"; + platforms = lib.platforms.all; + longDescription = + "Contains the following packages and their transitive dependencies:\n - " + + lib.concatMapStringsSep "\n - " ( + p: + p.pname + (lib.optionalString (p.outputSpecified or false) " (${p.tlOutputName or p.outputName})") + ) (finalAttrs.passthru.requiredTeXPackages tl); + }; + + # other outputs + nonEnvOutputs = lib.genAttrs pkgList.nonEnvOutputs ( + outName: + buildEnv { + inherit name; + paths = builtins.catAttrs "outPath" ( + pkgList.otherOutputs.${outName} or [ ] ++ pkgList.specifiedOutputs.${outName} or [ ] + ); + derivationArgs = { + outputs = [ outName ]; + nativeBuildInputs = [ + # force the output to be ${outName} or nix-env will not work + (writeShellScript "force-output.sh" '' + export out="''${${outName}-}" + '') + ]; + inherit meta passthru; + }; + } ); - nativeBuildInputs = [ - makeWrapper - libfaketime - tl."texlive.infra" # mktexlsr - tl.texlive-scripts # fmtutil, updmap - tl.texlive-scripts-extra # texlinks - perl + passthru = { + inherit + requiredTeXPackages + __fromCombineWrapper + __extraName + __extraVersion + ; + # This is set primarily to help find-tarballs.nix to do its job + includedTeXPackages = builtins.filter lib.isDerivation ( + pkgList.bin + ++ pkgList.nonbin + ++ lib.optionals (!finalAttrs.passthru.__fromCombineWrapper) ( + lib.concatMap ( + n: (pkgList.otherOutputs.${n} or [ ] ++ pkgList.specifiedOutputs.${n} or [ ]) + ) pkgList.nonEnvOutputs + ) + ); + # useful for inclusion in the `fonts.packages` nixos option or for use in devshells + fonts = "${texmfroot}/texmf-dist/fonts"; + __overrideTeXConfig = lib.warn "__overrideTeXConfig is deprecated, please switch to overrideAttrs" ( + newArgs: + let + # arguments of buildTeXEnv before deprecation of __overrideTeXConfig + prevArgs = { + withDocs = finalAttrs.passthru.withDocs or false; + withSources = finalAttrs.passthru.withSources or false; + inherit (finalAttrs) + __combine + ; + inherit (finalAttrs.passthru) + requiredTeXPackages + __extraName + __extraVersion + __fromCombineWrapper + ; + }; + appliedArgs = prevArgs // (if builtins.isFunction newArgs then newArgs prevArgs else newArgs); + in + finalAttrs.finalPackage.overrideAttrs (prevAttrs: { + passthru = prevAttrs.passthru // { + inherit (appliedArgs) + withDocs + withSources + requiredTeXPackages + __extraName + __extraVersion + ; + __fromCombineWrapper = false; + }; + inherit (appliedArgs) __combine; + }) + ); + withPackages = + reqs: + finalAttrs.finalPackage.overrideAttrs (prevAttrs: { + passthru = prevAttrs.passthru // { + requiredTeXPackages = ps: reqs ps ++ prevAttrs.passthru.requiredTeXPackages ps; + __fromCombineWrapper = false; + }; + }); + }; + + # TeXLive::TLOBJ::fmtutil_cnf_lines + fmtutilLine = + { + name, + engine, + enabled ? true, + patterns ? [ "-" ], + options ? "", + ... + }: + lib.optionalString (!enabled) "#! " + + "${name} ${engine} ${lib.concatStringsSep "," patterns} ${options}"; + fmtutilLines = + { pname, formats, ... }: + [ + "#" + "# from ${pname}:" + ] + ++ map fmtutilLine formats; + + # TeXLive::TLOBJ::language_dat_lines + langDatLine = + { + name, + file, + synonyms ? [ ], + ... + }: + [ "${name} ${file}" ] ++ map (s: "=" + s) synonyms; + langDatLines = + { pname, hyphenPatterns, ... }: + [ "% from ${pname}:" ] ++ builtins.concatMap langDatLine hyphenPatterns; + + # TeXLive::TLOBJ::language_def_lines + # see TeXLive::TLUtils::parse_AddHyphen_line for default values + langDefLine = + { + name, + file, + lefthyphenmin ? "", + righthyphenmin ? "", + synonyms ? [ ], + ... + }: + map ( + n: + "\\addlanguage{${n}}{${file}}{}{${if lefthyphenmin == "" then "2" else lefthyphenmin}}{${ + if righthyphenmin == "" then "3" else righthyphenmin + }}" + ) ([ name ] ++ synonyms); + langDefLines = + { pname, hyphenPatterns, ... }: + [ "% from ${pname}:" ] ++ builtins.concatMap langDefLine hyphenPatterns; + + # TeXLive::TLOBJ::language_lua_lines + # see TeXLive::TLUtils::parse_AddHyphen_line for default values + langLuaLine = + { + name, + file, + lefthyphenmin ? "", + righthyphenmin ? "", + synonyms ? [ ], + ... + }@args: + '' + ''\t['${name}'] = { + ''\t''\tloader = '${file}', + ''\t''\tlefthyphenmin = ${if lefthyphenmin == "" then "2" else lefthyphenmin}, + ''\t''\trighthyphenmin = ${if righthyphenmin == "" then "3" else righthyphenmin}, + ''\t''\tsynonyms = { ${lib.concatStringsSep ", " (map (s: "'${s}'") synonyms)} }, + '' + + lib.optionalString (args ? file_patterns) "\t\tpatterns = '${args.file_patterns}',\n" + + lib.optionalString (args ? file_exceptions) "\t\thyphenation = '${args.file_exceptions}',\n" + + lib.optionalString (args ? luaspecial) "\t\tspecial = '${args.luaspecial}',\n" + + "\t},"; + langLuaLines = + { pname, hyphenPatterns, ... }: [ "-- from ${pname}:" ] ++ map langLuaLine hyphenPatterns; + + assembleConfigLines = f: packages: builtins.concatStringsSep "\n" (builtins.concatMap f packages); + + updmapLines = { pname, fontMaps, ... }: [ "# from ${pname}:" ] ++ fontMaps; + + in + { + + inherit name; + + # remove fake derivations (without 'outPath') to avoid undesired build dependencies + paths = + builtins.catAttrs "outPath" pkgList.bin + ++ lib.optionals (!finalAttrs.__combine && __formatsOf == null) pkgList.formats + ++ lib.optional finalAttrs.__combine doc; + pathsToLink = [ + "/" + "/share/texmf-var/scripts" + "/share/texmf-var/tex/generic/config" + "/share/texmf-var/web2c" + "/share/texmf-config" + "/bin" # ensure these are writeable directories ]; - buildInputs = [ - coreutils - gawk - gnugrep - gnused - ] - ++ lib.optional needsGhostscript ghostscript; + postBuild = '' + . "${./build-tex-env.sh}" + ''; - inherit passthru __combine; - __formatsOf = __formatsOf.pname or null; + derivationArgs = { + # use attrNames, attrValues to ensure the two lists are sorted in the same way + outputs = [ + "out" + ] + ++ lib.optionals (!finalAttrs.__combine && __formatsOf == null) (builtins.attrNames nonEnvOutputs); + otherOutputs = lib.optionals (!finalAttrs.__combine && __formatsOf == null) ( + builtins.attrValues nonEnvOutputs + ); - inherit texmfdist texmfroot; + nativeBuildInputs = [ + makeWrapper + libfaketime + tl."texlive.infra" # mktexlsr + tl.texlive-scripts # fmtutil, updmap + tl.texlive-scripts-extra # texlinks + perl + ]; - fontconfigFile = makeFontsConf { fontDirectories = [ "${texmfroot}/texmf-dist/fonts" ]; }; + buildInputs = [ + coreutils + gawk + gnugrep + gnused + ] + ++ lib.optional needsGhostscript ghostscript; - fmtutilCnf = assembleConfigLines fmtutilLines pkgList.sortedFormatPkgs; - updmapCfg = assembleConfigLines updmapLines pkgList.sortedFontMaps; + inherit passthru __combine; + __formatsOf = __formatsOf.pname or null; - languageDat = assembleConfigLines langDatLines pkgList.sortedHyphenPatterns; - languageDef = assembleConfigLines langDefLines pkgList.sortedHyphenPatterns; - languageLua = assembleConfigLines langLuaLines pkgList.sortedHyphenPatterns; + inherit texmfdist texmfroot; - postactionScripts = builtins.catAttrs "postactionScript" pkgList.tlpkg; + fontconfigFile = makeFontsConf { fontDirectories = [ "${texmfroot}/texmf-dist/fonts" ]; }; - allowSubstitutes = true; - preferLocalBuild = false; + fmtutilCnf = assembleConfigLines fmtutilLines pkgList.sortedFormatPkgs; + updmapCfg = assembleConfigLines updmapLines pkgList.sortedFontMaps; - meta = - meta - // lib.optionalAttrs (!__combine && __formatsOf == null) { - inherit (pkgList) outputsToInstall; - }; - }; - } + languageDat = assembleConfigLines langDatLines pkgList.sortedHyphenPatterns; + languageDef = assembleConfigLines langDefLines pkgList.sortedHyphenPatterns; + languageLua = assembleConfigLines langLuaLines pkgList.sortedHyphenPatterns; + + postactionScripts = builtins.catAttrs "postactionScript" pkgList.tlpkg; + + allowSubstitutes = true; + preferLocalBuild = false; + + meta = + meta + // lib.optionalAttrs (!finalAttrs.__combine && __formatsOf == null) { + inherit (pkgList) outputsToInstall; + }; + }; + } + ) ) diff --git a/pkgs/tools/typesetting/tex/texlive/default.nix b/pkgs/tools/typesetting/tex/texlive/default.nix index a5d81fbbaa7c..9e1cd3913fa3 100644 --- a/pkgs/tools/typesetting/tex/texlive/default.nix +++ b/pkgs/tools/typesetting/tex/texlive/default.nix @@ -233,7 +233,7 @@ let # function for creating a working environment buildTeXEnv = import ./build-tex-env.nix { - inherit bin tl; + inherit tl; inherit tlpdbVersion; ghostscript = ghostscript_headless; inherit @@ -244,9 +244,7 @@ let makeWrapper runCommand writeShellScript - writeText toTLPkgSets - bash perl coreutils gawk From 41d265c82a41c0582b27bb746d1fd9205dc6a750 Mon Sep 17 00:00:00 2001 From: Vincenzo Mantova <1962985+xworld21@users.noreply.github.com> Date: Sat, 16 May 2026 18:14:05 +0100 Subject: [PATCH 03/20] texlive.withPackages: move withDocs, withSources from passthru to derivation arguments --- doc/languages-frameworks/texlive.section.md | 8 ++-- .../typesetting/tex/texlive/build-tex-env.nix | 39 ++++++++++--------- 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/doc/languages-frameworks/texlive.section.md b/doc/languages-frameworks/texlive.section.md index b3305e259044..9822cfca0347 100644 --- a/doc/languages-frameworks/texlive.section.md +++ b/doc/languages-frameworks/texlive.section.md @@ -42,13 +42,11 @@ Release 23.11 ships with a new interface that will eventually replace `texlive.c ``` Note that the packages in `texlive.pkgs` are only provided for search purposes and must not be used directly. -- **Experimental and subject to change without notice:** to add the documentation for all packages in the environment, use +- To add the documentation for all packages in the environment, use ```nix - texliveSmall.__overrideTeXConfig { withDocs = true; } + texliveSmall.overrideAttrs { withDocs = true; } ``` - This can be applied before or after calling `withPackages`. - - The function currently supports the parameters `withDocs`, `withSources`, and `requireTeXPackages`. + This can be applied before or after calling `withPackages`. The parameter `withSources` adds all source containers. ## User's guide {#sec-language-texlive-user-guide} diff --git a/pkgs/tools/typesetting/tex/texlive/build-tex-env.nix b/pkgs/tools/typesetting/tex/texlive/build-tex-env.nix index bfc196dd0d8d..35fcf111a44a 100644 --- a/pkgs/tools/typesetting/tex/texlive/build-tex-env.nix +++ b/pkgs/tools/typesetting/tex/texlive/build-tex-env.nix @@ -40,8 +40,8 @@ lib.fix ( finalAttrs: let - withDocs = finalAttrs.passthru.withDocs or false; - withSources = finalAttrs.passthru.withSources or false; + withDocs = finalAttrs.withDocs or false; + withSources = finalAttrs.withSources or false; # if necessary, convert old style { pkgs = [ ... ]; } packages to attribute sets isOldPkgList = p: !p.outputSpecified or false && p ? pkgs && builtins.all (p: p ? tlType) p.pkgs; @@ -317,8 +317,6 @@ lib.fix ( let # arguments of buildTeXEnv before deprecation of __overrideTeXConfig prevArgs = { - withDocs = finalAttrs.passthru.withDocs or false; - withSources = finalAttrs.passthru.withSources or false; inherit (finalAttrs) __combine ; @@ -328,22 +326,27 @@ lib.fix ( __extraVersion __fromCombineWrapper ; - }; + } + // lib.optionalAttrs (finalAttrs ? withDocs) { inherit (finalAttrs) withDocs; } + // lib.optionalAttrs (finalAttrs ? withSources) { inherit (finalAttrs) withSources; }; appliedArgs = prevArgs // (if builtins.isFunction newArgs then newArgs prevArgs else newArgs); in - finalAttrs.finalPackage.overrideAttrs (prevAttrs: { - passthru = prevAttrs.passthru // { - inherit (appliedArgs) - withDocs - withSources - requiredTeXPackages - __extraName - __extraVersion - ; - __fromCombineWrapper = false; - }; - inherit (appliedArgs) __combine; - }) + finalAttrs.finalPackage.overrideAttrs ( + prevAttrs: + { + passthru = prevAttrs.passthru // { + inherit (appliedArgs) + requiredTeXPackages + __extraName + __extraVersion + ; + __fromCombineWrapper = false; + }; + inherit (appliedArgs) __combine; + } + // lib.optionalAttrs (appliedArgs ? withDocs) { inherit (appliedArgs) withDocs; } + // lib.optionalAttrs (appliedArgs ? withSources) { inherit (appliedArgs) withSources; } + ) ); withPackages = reqs: From 38a19e2d2f6fc4e4c688485e404b64dd01c5b0bf Mon Sep 17 00:00:00 2001 From: Vincenzo Mantova <1962985+xworld21@users.noreply.github.com> Date: Sat, 16 May 2026 18:14:05 +0100 Subject: [PATCH 04/20] texliveFullWithDocs: init at 2025-r78234-final --- pkgs/top-level/all-packages.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index fd02ed8d386e..67b4fb2fcee5 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -1741,6 +1741,7 @@ with pkgs; texliveSmall texliveTeTeX ; + texliveFullWithDocs = texliveFull.overrideAttrs { withDocs = true; }; texlivePackages = recurseIntoAttrs (lib.mapAttrs (_: v: v.build) texlive.pkgs); futhark = haskell.lib.compose.justStaticExecutables haskellPackages.futhark; From 96c9b622de66e64771a019373d6afffa8b6a9a85 Mon Sep 17 00:00:00 2001 From: Vincenzo Mantova <1962985+xworld21@users.noreply.github.com> Date: Sat, 16 May 2026 18:14:05 +0100 Subject: [PATCH 05/20] tests.texlive.texdoc: use withDocs to add the doc containers --- pkgs/test/texlive/default.nix | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pkgs/test/texlive/default.nix b/pkgs/test/texlive/default.nix index 36a5dbb9b8a6..052bfa5e6636 100644 --- a/pkgs/test/texlive/default.nix +++ b/pkgs/test/texlive/default.nix @@ -239,11 +239,7 @@ rec { runCommand "texlive-test-texdoc" { nativeBuildInputs = [ - (texlive.withPackages (ps: [ - ps.luatex - ps.texdoc - ps.texdoc.texdoc - ])) + ((texlive.withPackages (ps: [ ps.texdoc ])).overrideAttrs { withDocs = true; }) ]; } '' From d40578e2b169e5396f7a2d8dfd8c458f90382c5e Mon Sep 17 00:00:00 2001 From: Vincenzo Mantova <1962985+xworld21@users.noreply.github.com> Date: Sat, 16 May 2026 18:14:05 +0100 Subject: [PATCH 06/20] texlive.withPackages: enable strictDeps --- pkgs/tools/typesetting/tex/texlive/build-tex-env.nix | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkgs/tools/typesetting/tex/texlive/build-tex-env.nix b/pkgs/tools/typesetting/tex/texlive/build-tex-env.nix index 35fcf111a44a..d6cd085286dd 100644 --- a/pkgs/tools/typesetting/tex/texlive/build-tex-env.nix +++ b/pkgs/tools/typesetting/tex/texlive/build-tex-env.nix @@ -474,6 +474,8 @@ lib.fix ( builtins.attrValues nonEnvOutputs ); + strictDeps = true; + nativeBuildInputs = [ makeWrapper libfaketime From 27da8a373793dc584b31038fb28c488abb9e152b Mon Sep 17 00:00:00 2001 From: Vincenzo Mantova <1962985+xworld21@users.noreply.github.com> Date: Sat, 16 May 2026 18:14:06 +0100 Subject: [PATCH 07/20] texlive.withPackages: add withDocs, withSources to default attributes --- .../typesetting/tex/texlive/build-tex-env.nix | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/pkgs/tools/typesetting/tex/texlive/build-tex-env.nix b/pkgs/tools/typesetting/tex/texlive/build-tex-env.nix index d6cd085286dd..7c5e870dfdcd 100644 --- a/pkgs/tools/typesetting/tex/texlive/build-tex-env.nix +++ b/pkgs/tools/typesetting/tex/texlive/build-tex-env.nix @@ -40,9 +40,6 @@ lib.fix ( finalAttrs: let - withDocs = finalAttrs.withDocs or false; - withSources = finalAttrs.withSources or false; - # if necessary, convert old style { pkgs = [ ... ]; } packages to attribute sets isOldPkgList = p: !p.outputSpecified or false && p ? pkgs && builtins.all (p: p ? tlType) p.pkgs; ensurePkgSets = @@ -133,13 +130,13 @@ lib.fix ( lib.concatMap ( p: lib.optional (p ? tex) p.tex - ++ lib.optional ((withDocs || p ? man) && p ? texdoc) p.texdoc - ++ lib.optional (withSources && p ? texsource) p.texsource + ++ lib.optional ((finalAttrs.withDocs || p ? man) && p ? texdoc) p.texdoc + ++ lib.optional (finalAttrs.withSources && p ? texsource) p.texsource ) specified.wrong else otherOutputs.tex or [ ] - ++ lib.optionals withDocs (otherOutputs.texdoc or [ ]) - ++ lib.optionals withSources (otherOutputs.texsource or [ ]) + ++ lib.optionals finalAttrs.withDocs (otherOutputs.texdoc or [ ]) + ++ lib.optionals finalAttrs.withSources (otherOutputs.texsource or [ ]) ) ++ specifiedOutputs.tex or [ ] ++ specifiedOutputs.texdoc or [ ] @@ -260,9 +257,9 @@ lib.fix ( meta = { description = "TeX Live environment" - + lib.optionalString withDocs " with documentation" - + lib.optionalString (withDocs && withSources) " and" - + lib.optionalString withSources " with sources"; + + lib.optionalString finalAttrs.withDocs " with documentation" + + lib.optionalString (finalAttrs.withDocs && finalAttrs.withSources) " and" + + lib.optionalString finalAttrs.withSources " with sources"; platforms = lib.platforms.all; longDescription = "Contains the following packages and their transitive dependencies:\n - " @@ -509,6 +506,10 @@ lib.fix ( postactionScripts = builtins.catAttrs "postactionScript" pkgList.tlpkg; + # whethe to include doc, source containers + withDocs = false; + withSources = false; + allowSubstitutes = true; preferLocalBuild = false; From c8b6540469215daba507457cbdf48f114b8ceb26 Mon Sep 17 00:00:00 2001 From: Vincenzo Mantova <1962985+xworld21@users.noreply.github.com> Date: Sat, 16 May 2026 18:14:06 +0100 Subject: [PATCH 08/20] texlive.withPackages: replace force-output.sh with preHook --- .../tools/typesetting/tex/texlive/build-tex-env.nix | 13 ++++++------- pkgs/tools/typesetting/tex/texlive/default.nix | 1 - 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/pkgs/tools/typesetting/tex/texlive/build-tex-env.nix b/pkgs/tools/typesetting/tex/texlive/build-tex-env.nix index 7c5e870dfdcd..17d31e0303e7 100644 --- a/pkgs/tools/typesetting/tex/texlive/build-tex-env.nix +++ b/pkgs/tools/typesetting/tex/texlive/build-tex-env.nix @@ -10,7 +10,6 @@ makeFontsConf, makeWrapper, runCommand, - writeShellScript, toTLPkgSets, perl, @@ -279,12 +278,12 @@ lib.fix ( ); derivationArgs = { outputs = [ outName ]; - nativeBuildInputs = [ - # force the output to be ${outName} or nix-env will not work - (writeShellScript "force-output.sh" '' - export out="''${${outName}-}" - '') - ]; + + # force the output to be ${outName} or nix-env will not work + preHook = '' + export out="''${${outName}}" + ''; + inherit meta passthru; }; } diff --git a/pkgs/tools/typesetting/tex/texlive/default.nix b/pkgs/tools/typesetting/tex/texlive/default.nix index 9e1cd3913fa3..5f486f608e2a 100644 --- a/pkgs/tools/typesetting/tex/texlive/default.nix +++ b/pkgs/tools/typesetting/tex/texlive/default.nix @@ -243,7 +243,6 @@ let makeFontsConf makeWrapper runCommand - writeShellScript toTLPkgSets perl coreutils From 3a6bafbdf59140a330bc0836bcaafaae0afe3272 Mon Sep 17 00:00:00 2001 From: Vincenzo Mantova <1962985+xworld21@users.noreply.github.com> Date: Sat, 23 May 2026 13:17:17 +0100 Subject: [PATCH 09/20] texlive.withPackages: allow tlDeps to be a function, drop unused requiredTeXPackages --- doc/languages-frameworks/texlive.section.md | 13 +++++----- .../typesetting/tex/texlive/build-tex-env.nix | 6 ++++- .../tex/texlive/combine-wrapper.nix | 7 ++++- .../tools/typesetting/tex/texlive/default.nix | 26 ++++++++++++++----- 4 files changed, 37 insertions(+), 15 deletions(-) diff --git a/doc/languages-frameworks/texlive.section.md b/doc/languages-frameworks/texlive.section.md index 9822cfca0347..4a378fee2d9b 100644 --- a/doc/languages-frameworks/texlive.section.md +++ b/doc/languages-frameworks/texlive.section.md @@ -110,7 +110,7 @@ Release 23.11 ships with a new interface that will eventually replace `texlive.c ## Custom packages {#sec-language-texlive-custom-packages} -You may find that you need to use an external TeX package. A derivation for such package has to provide the contents of the "texmf" directory in its `"tex"` output, according to the [TeX Directory Structure](https://tug.ctan.org/tds/tds.html). Dependencies on other TeX packages can be listed in the attribute `tlDeps`. +You may find that you need to use an external TeX package. A derivation for such package has to provide the contents of the "texmf" directory in its `"tex"` output, according to the [TeX Directory Structure](https://tug.ctan.org/tds/tds.html). Dependencies on other TeX packages can be listed in the attribute `passthru.tlDeps`, which is a function taking a package set and returning a list of packages. The functions `texlive.combine` and `texlive.withPackages` recognise the following outputs: @@ -136,7 +136,7 @@ let "tex" "texdoc" ]; - passthru.tlDeps = with texlive; [ latex ]; + passthru.tlDeps = ps: [ ps.latex ]; srcs = [ (fetchurl { @@ -167,13 +167,14 @@ let latexmk ] )) - # multiple-outputs.sh fails if $out is not defined - (writeShellScript "force-tex-output.sh" '' - out="''${tex-}" - '') writableTmpDirAsHomeHook # Need a writable $HOME for latexmk ]; + # multiple-outputs.sh fails if $out is not defined + preHook = '' + out="''${tex-}" + ''; + dontConfigure = true; buildPhase = '' diff --git a/pkgs/tools/typesetting/tex/texlive/build-tex-env.nix b/pkgs/tools/typesetting/tex/texlive/build-tex-env.nix index 17d31e0303e7..01ae7e52c427 100644 --- a/pkgs/tools/typesetting/tex/texlive/build-tex-env.nix +++ b/pkgs/tools/typesetting/tex/texlive/build-tex-env.nix @@ -70,7 +70,11 @@ lib.fix ( p.pname or p.name + lib.optionalString (p.outputSpecified or false) ("-" + p.tlOutputName or p.outputName or ""); inherit p; - tlDeps = if p ? tlDeps then ensurePkgSets p.tlDeps else (p.requiredTeXPackages or (_: [ ]) tl); + tlDeps = + if p ? tlDeps then + (if builtins.isFunction p.tlDeps then p.tlDeps tl else ensurePkgSets p.tlDeps) + else + [ ]; }; in # texlive.combine: the wrapper already resolves all dependencies diff --git a/pkgs/tools/typesetting/tex/texlive/combine-wrapper.nix b/pkgs/tools/typesetting/tex/texlive/combine-wrapper.nix index e7bd78ff720a..e0ed2bc8f1fa 100644 --- a/pkgs/tools/typesetting/tex/texlive/combine-wrapper.nix +++ b/pkgs/tools/typesetting/tex/texlive/combine-wrapper.nix @@ -2,6 +2,7 @@ { lib, toTLPkgList, + tl, buildTeXEnv, }: args@{ @@ -45,7 +46,11 @@ let in builtins.genericClosure { startSet = pkgListToSets pkgList; - operator = { pkg, ... }: pkgListToSets (pkg.tlDeps or [ ]); + operator = + { pkg, ... }: + pkgListToSets ( + if pkg ? tlDeps then if builtins.isFunction pkg.tlDeps then pkg.tlDeps tl else pkg.tlDeps else [ ] + ); } ); combined = combinePkgs (lib.attrValues pkgSet); diff --git a/pkgs/tools/typesetting/tex/texlive/default.nix b/pkgs/tools/typesetting/tex/texlive/default.nix index 5f486f608e2a..c819f4b32112 100644 --- a/pkgs/tools/typesetting/tex/texlive/default.nix +++ b/pkgs/tools/typesetting/tex/texlive/default.nix @@ -257,19 +257,31 @@ let # respecting specified outputs toTLPkgList = drv: + let + drvWithoutDeps = removeAttrs drv [ "tlDeps" ]; + drvWithDeps = + if (drv ? tlDeps) then + drv // { tlDeps = if builtins.isFunction drv.tlDeps then drv.tlDeps tl else drv.tlDeps; } + else + drv; + in if drv.outputSpecified or false then let tlType = drv.tlType or tlOutToType.${drv.tlOutputName or drv.outputName} or null; in - lib.optional (tlType != null) (drv // { inherit tlType; }) + lib.optional (tlType != null) (drvWithDeps // { inherit tlType; }) else - [ (drv.tex // { tlType = "run"; }) ] + lib.optional (drv ? tex) (drvWithDeps.tex // { tlType = "run"; }) ++ lib.optional (drv ? texdoc) ( - drv.texdoc // { tlType = "doc"; } // lib.optionalAttrs (drv ? man) { hasManpages = true; } + drvWithoutDeps.texdoc + // { + tlType = "doc"; + } + // lib.optionalAttrs (drv ? man) { hasManpages = true; } ) - ++ lib.optional (drv ? texsource) (drv.texsource // { tlType = "source"; }) - ++ lib.optional (drv ? tlpkg) (drv.tlpkg // { tlType = "tlpkg"; }) - ++ lib.optional (drv ? out) (drv.out // { tlType = "bin"; }); + ++ lib.optional (drv ? texsource) (drvWithoutDeps.texsource // { tlType = "source"; }) + ++ lib.optional (drv ? tlpkg) (drvWithDeps.tlpkg // { tlType = "tlpkg"; }) + ++ lib.optional (drv ? out) (drvWithDeps.out // { tlType = "bin"; }); tlOutToType = { out = "bin"; tex = "run"; @@ -312,8 +324,8 @@ let inherit buildTeXEnv lib + tl toTLPkgList - toTLPkgSets ; }; From dbeafe9461768153f82cff35564d104f74718511 Mon Sep 17 00:00:00 2001 From: Vincenzo Mantova <1962985+xworld21@users.noreply.github.com> Date: Sat, 23 May 2026 13:17:18 +0100 Subject: [PATCH 10/20] auctex: remove legacy tlType, pkgs attributes --- pkgs/by-name/au/auctex/package.nix | 79 ++++++++++++++---------------- 1 file changed, 36 insertions(+), 43 deletions(-) diff --git a/pkgs/by-name/au/auctex/package.nix b/pkgs/by-name/au/auctex/package.nix index 594d504db3d3..ac750c614f08 100644 --- a/pkgs/by-name/au/auctex/package.nix +++ b/pkgs/by-name/au/auctex/package.nix @@ -7,50 +7,43 @@ ghostscript, }: -let - auctex = stdenv.mkDerivation rec { - # Make this a valid tex(live-new) package; - # the pkgs attribute is provided with a hack below. - pname = "auctex"; - version = "13.2"; - tlType = "run"; +stdenv.mkDerivation rec { + pname = "auctex"; + version = "13.2"; - outputs = [ - "out" - "tex" - ]; + outputs = [ + "out" + "tex" + ]; - src = fetchurl { - url = "mirror://gnu/auctex/auctex-${version}.tar.gz"; - hash = "sha256-Hn5AKrz4RmlOuncZklvwlcI+8zpeZgIgHHS2ymCUQDU="; - }; - - buildInputs = [ - emacs - ghostscript - (texliveBasic.withPackages (ps: [ - ps.etoolbox - ps.hypdoc - ])) - ]; - - preConfigure = '' - mkdir -p "$tex" - export HOME=$(mktemp -d) - ''; - - configureFlags = [ - "--with-lispdir=\${out}/share/emacs/site-lisp" - "--with-texmf-dir=\${tex}" - ]; - - meta = { - homepage = "https://www.gnu.org/software/auctex"; - description = "Extensible package for writing and formatting TeX files in GNU Emacs and XEmacs"; - license = lib.licenses.gpl3Plus; - platforms = lib.platforms.unix; - }; + src = fetchurl { + url = "mirror://gnu/auctex/auctex-${version}.tar.gz"; + hash = "sha256-Hn5AKrz4RmlOuncZklvwlcI+8zpeZgIgHHS2ymCUQDU="; }; -in -auctex // { pkgs = [ auctex.tex ]; } + buildInputs = [ + emacs + ghostscript + (texliveBasic.withPackages (ps: [ + ps.etoolbox + ps.hypdoc + ])) + ]; + + preConfigure = '' + mkdir -p "$tex" + export HOME=$(mktemp -d) + ''; + + configureFlags = [ + "--with-lispdir=\${out}/share/emacs/site-lisp" + "--with-texmf-dir=\${tex}" + ]; + + meta = { + homepage = "https://www.gnu.org/software/auctex"; + description = "Extensible package for writing and formatting TeX files in GNU Emacs and XEmacs"; + license = lib.licenses.gpl3Plus; + platforms = lib.platforms.unix; + }; +} From aaf6a1e1f4911bb3be2d469538411774f356b7ca Mon Sep 17 00:00:00 2001 From: Vincenzo Mantova <1962985+xworld21@users.noreply.github.com> Date: Sat, 23 May 2026 13:17:18 +0100 Subject: [PATCH 11/20] auto-multiple-choice: remove legacy tlType, pkgs attributes --- pkgs/by-name/au/auto-multiple-choice/package.nix | 5 ----- 1 file changed, 5 deletions(-) diff --git a/pkgs/by-name/au/auto-multiple-choice/package.nix b/pkgs/by-name/au/auto-multiple-choice/package.nix index 9c754efdfb61..1dd15b5b40c1 100644 --- a/pkgs/by-name/au/auto-multiple-choice/package.nix +++ b/pkgs/by-name/au/auto-multiple-choice/package.nix @@ -145,11 +145,6 @@ stdenv.mkDerivation (finalAttrs: { perlWithPackages ]; - passthru = { - tlType = "run"; - pkgs = [ finalAttrs.finalPackage ]; - }; - meta = { description = "Create and manage multiple choice questionnaires with automated marking"; mainProgram = "auto-multiple-choice"; From 27f106cf12ff7e5af90bb279ee2e3af5b08942bf Mon Sep 17 00:00:00 2001 From: Vincenzo Mantova <1962985+xworld21@users.noreply.github.com> Date: Sat, 23 May 2026 13:17:19 +0100 Subject: [PATCH 12/20] eukleides: remove legacy tlType, pkgs attributes --- pkgs/by-name/eu/eukleides/package.nix | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/pkgs/by-name/eu/eukleides/package.nix b/pkgs/by-name/eu/eukleides/package.nix index 9d43405c6a4b..f8ef0b20da27 100644 --- a/pkgs/by-name/eu/eukleides/package.nix +++ b/pkgs/by-name/eu/eukleides/package.nix @@ -91,17 +91,13 @@ stdenv.mkDerivation (finalAttrs: { "tex" ]; - passthru = { - tlType = "run"; - # packages needed by euktoeps, euktopdf and eukleides.sty - tlDeps = with texlive; [ - collection-pstricks - epstopdf - iftex - moreverb - ]; - pkgs = [ finalAttrs.finalPackage.tex ]; - }; + # packages needed by euktoeps, euktopdf and eukleides.sty + passthru.tlDeps = with texlive; [ + collection-pstricks + epstopdf + iftex + moreverb + ]; doInstallCheck = true; nativeInstallCheckInputs = [ versionCheckHook ]; From 7751dd9cbef559c85e4e684c7999a19cf81631a0 Mon Sep 17 00:00:00 2001 From: Vincenzo Mantova <1962985+xworld21@users.noreply.github.com> Date: Sat, 23 May 2026 13:17:20 +0100 Subject: [PATCH 13/20] eukleides: make tlDeps a function --- pkgs/by-name/eu/eukleides/package.nix | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/pkgs/by-name/eu/eukleides/package.nix b/pkgs/by-name/eu/eukleides/package.nix index f8ef0b20da27..91b9f6f4c7f5 100644 --- a/pkgs/by-name/eu/eukleides/package.nix +++ b/pkgs/by-name/eu/eukleides/package.nix @@ -9,7 +9,6 @@ getopt, readline, texinfo, - texlive, versionCheckHook, }: @@ -92,11 +91,11 @@ stdenv.mkDerivation (finalAttrs: { ]; # packages needed by euktoeps, euktopdf and eukleides.sty - passthru.tlDeps = with texlive; [ - collection-pstricks - epstopdf - iftex - moreverb + passthru.tlDeps = ps: [ + ps.collection-pstricks + ps.epstopdf + ps.iftex + ps.moreverb ]; doInstallCheck = true; From deedb05a2367a474dae53f4a6321e5f86976c5bf Mon Sep 17 00:00:00 2001 From: Vincenzo Mantova <1962985+xworld21@users.noreply.github.com> Date: Sat, 23 May 2026 13:17:20 +0100 Subject: [PATCH 14/20] junicode: make tlDeps a function --- pkgs/by-name/ju/junicode/package.nix | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pkgs/by-name/ju/junicode/package.nix b/pkgs/by-name/ju/junicode/package.nix index fbf232c6c2f7..a3fbd2989009 100644 --- a/pkgs/by-name/ju/junicode/package.nix +++ b/pkgs/by-name/ju/junicode/package.nix @@ -2,7 +2,6 @@ lib, stdenvNoCC, fetchzip, - texlive, callPackage, }: @@ -47,9 +46,9 @@ stdenvNoCC.mkDerivation rec { ''; passthru = { - tlDeps = with texlive; [ - xkeyval - fontspec + tlDeps = ps: [ + ps.xkeyval + ps.fontspec ]; tests = callPackage ./tests.nix { }; From 089f87d34b8a8c17a5c0a475f6f12ad63e61ccb9 Mon Sep 17 00:00:00 2001 From: Vincenzo Mantova <1962985+xworld21@users.noreply.github.com> Date: Sat, 23 May 2026 13:17:20 +0100 Subject: [PATCH 15/20] mftrace: make tlDeps a function --- pkgs/by-name/mf/mftrace/package.nix | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/pkgs/by-name/mf/mftrace/package.nix b/pkgs/by-name/mf/mftrace/package.nix index 98aafdba2ee4..9405cab06b32 100644 --- a/pkgs/by-name/mf/mftrace/package.nix +++ b/pkgs/by-name/mf/mftrace/package.nix @@ -7,7 +7,6 @@ python3, fontforge, potrace, - texlive, fetchpatch2, }: @@ -59,12 +58,11 @@ stdenv.mkDerivation (finalAttrs: { wrapProgram $out/bin/mftrace --prefix PATH : ${lib.makeBinPath finalAttrs.buildInputs} ''; - # experimental texlive.combine support - # (note that only the bin/ folder will be combined into texlive) - passthru.tlDeps = with texlive; [ - kpathsea - t1utils - metafont + # for use with texlive.withPackages + passthru.tlDeps = ps: [ + ps.kpathsea + ps.t1utils + ps.metafont ]; meta = { From 539315b6fc2061a812d30054cf782b081f57ec92 Mon Sep 17 00:00:00 2001 From: Vincenzo Mantova <1962985+xworld21@users.noreply.github.com> Date: Sat, 23 May 2026 13:17:20 +0100 Subject: [PATCH 16/20] noweb: remove legacy tlType, pkgs attributes --- pkgs/by-name/no/noweb/package.nix | 5 ----- 1 file changed, 5 deletions(-) diff --git a/pkgs/by-name/no/noweb/package.nix b/pkgs/by-name/no/noweb/package.nix index 1c9f1bb2795e..4d59bb8e3e5a 100644 --- a/pkgs/by-name/no/noweb/package.nix +++ b/pkgs/by-name/no/noweb/package.nix @@ -88,11 +88,6 @@ stdenv.mkDerivation (finalAttrs: { "tex" ]; - passthru = { - tlType = "run"; - pkgs = [ finalAttrs.finalPackage.tex ]; - }; - meta = { description = "Simple, extensible literate-programming tool"; homepage = "https://www.cs.tufts.edu/~nr/noweb"; From 9dd731c4bffef9683e342e1a0a5d923102676033 Mon Sep 17 00:00:00 2001 From: Vincenzo Mantova <1962985+xworld21@users.noreply.github.com> Date: Sat, 23 May 2026 13:17:21 +0100 Subject: [PATCH 17/20] perlPackages.LaTeXML: remove legacy tlType, pkgs attributes --- pkgs/top-level/perl-packages.nix | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pkgs/top-level/perl-packages.nix b/pkgs/top-level/perl-packages.nix index a2a671c0d19b..21ebfbbf50a5 100644 --- a/pkgs/top-level/perl-packages.nix +++ b/pkgs/top-level/perl-packages.nix @@ -18573,10 +18573,6 @@ with self; } done ''; - passthru = { - tlType = "run"; - pkgs = [ LaTeXML.tex ]; - }; meta = { description = "Transforms TeX and LaTeX into XML/HTML/MathML"; homepage = "https://dlmf.nist.gov/LaTeXML/"; From f53f80a757787b436b855a5d1e14f73c1b5f5ae9 Mon Sep 17 00:00:00 2001 From: Vincenzo Mantova <1962985+xworld21@users.noreply.github.com> Date: Sat, 23 May 2026 13:17:21 +0100 Subject: [PATCH 18/20] R: remove legacy tlType, pkgs attributes --- pkgs/applications/science/math/R/default.nix | 3 --- 1 file changed, 3 deletions(-) diff --git a/pkgs/applications/science/math/R/default.nix b/pkgs/applications/science/math/R/default.nix index 3df0435e5926..4aaa715f2f02 100644 --- a/pkgs/applications/science/math/R/default.nix +++ b/pkgs/applications/science/math/R/default.nix @@ -198,9 +198,6 @@ stdenv.mkDerivation (finalAttrs: { passthru.tests.pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage; - # make tex output available to texlive.combine - passthru.pkgs = [ finalAttrs.finalPackage.tex ]; - passthru.tlType = "run"; # dependencies (based on \RequirePackage in jss.cls, Rd.sty, Sweave.sty) passthru.tlDeps = with texlive; [ amsfonts From af229eadca4890c9a4570ce5bbd837e1a7a2c512 Mon Sep 17 00:00:00 2001 From: Vincenzo Mantova <1962985+xworld21@users.noreply.github.com> Date: Sat, 23 May 2026 13:17:22 +0100 Subject: [PATCH 19/20] R: make tlDeps a function --- pkgs/applications/science/math/R/default.nix | 27 ++++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/pkgs/applications/science/math/R/default.nix b/pkgs/applications/science/math/R/default.nix index 4aaa715f2f02..840f6bbd79af 100644 --- a/pkgs/applications/science/math/R/default.nix +++ b/pkgs/applications/science/math/R/default.nix @@ -16,7 +16,6 @@ perl, readline, tcl, - texlive, texliveSmall, tk, xz, @@ -199,19 +198,19 @@ stdenv.mkDerivation (finalAttrs: { passthru.tests.pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage; # dependencies (based on \RequirePackage in jss.cls, Rd.sty, Sweave.sty) - passthru.tlDeps = with texlive; [ - amsfonts - amsmath - fancyvrb - graphics - hyperref - iftex - jknapltx - latex - lm - tools - upquote - url + passthru.tlDeps = ps: [ + ps.amsfonts + ps.amsmath + ps.fancyvrb + ps.graphics + ps.hyperref + ps.iftex + ps.jknapltx + ps.latex + ps.lm + ps.tools + ps.upquote + ps.url ]; meta = { From 022d9ebeeb627bb2c250ab92fb3a4c45db173bde Mon Sep 17 00:00:00 2001 From: Vincenzo Mantova <1962985+xworld21@users.noreply.github.com> Date: Sat, 23 May 2026 13:42:25 +0100 Subject: [PATCH 20/20] doc: remove texlive.combine from the TeX Live documentation --- doc/languages-frameworks/texlive.section.md | 59 +++------------------ doc/redirects.json | 6 +-- 2 files changed, 8 insertions(+), 57 deletions(-) diff --git a/doc/languages-frameworks/texlive.section.md b/doc/languages-frameworks/texlive.section.md index 4a378fee2d9b..f380cc4c5a92 100644 --- a/doc/languages-frameworks/texlive.section.md +++ b/doc/languages-frameworks/texlive.section.md @@ -2,9 +2,7 @@ There is a TeX Live packaging that lives entirely under attribute `texlive`. -## User's guide (experimental new interface) {#sec-language-texlive-user-guide-experimental} - -Release 23.11 ships with a new interface that will eventually replace `texlive.combine`. +## User's guide {#sec-language-texlive-user-guide} - For basic usage, use some of the prebuilt environments available at the top level, such as `texliveBasic`, `texliveSmall`. For the full list of prebuilt environments, inspect `texlive.schemes`. @@ -24,7 +22,7 @@ Release 23.11 ships with a new interface that will eventually replace `texlive.c - `texlive.withPackages` uses the same logic as `buildEnv`. Only parts of a package are installed in an environment: its 'runtime' files (`tex` output), binaries (`out` output), and support files (`tlpkg` output). Moreover, man and info pages are assembled into separate `man` and `info` outputs. To add only the TeX files of a package, or its documentation (`texdoc` output), just specify the outputs: ```nix - texlive.withPackages ( + texliveBasic.withPackages ( ps: with ps; [ texdoc # recommended package to navigate the documentation perlPackages.LaTeXML.tex # tex files of LaTeXML, omit binaries @@ -34,62 +32,19 @@ Release 23.11 ships with a new interface that will eventually replace `texlive.c ) ``` -- All packages distributed by TeX Live, which contains most of CTAN, are available and can be found under `texlive.pkgs`: - ```ShellSession - $ nix repl - nix-repl> :l - nix-repl> texlive.pkgs.[TAB] - ``` - Note that the packages in `texlive.pkgs` are only provided for search purposes and must not be used directly. - - To add the documentation for all packages in the environment, use ```nix texliveSmall.overrideAttrs { withDocs = true; } ``` This can be applied before or after calling `withPackages`. The parameter `withSources` adds all source containers. -## User's guide {#sec-language-texlive-user-guide} - -- For basic usage just pull `texlive.combined.scheme-basic` for an environment with basic LaTeX support. - -- It typically won't work to use separately installed packages together. Instead, you can build a custom set of packages like this. Most CTAN packages should be available: - - ```nix - texlive.combine { - inherit (texlive) - scheme-small - collection-langkorean - algorithms - cm-super - ; - } - ``` - -- There are all the schemes, collections and a few thousand packages, as defined upstream (perhaps with tiny differences). - -- By default you only get executables and files needed during runtime, and a little documentation for the core packages. To change that, you need to add `pkgFilter` function to `combine`. - - ```nix - texlive.combine { - # inherit (texlive) whatever-you-want; - pkgFilter = - pkg: pkg.tlType == "run" || pkg.tlType == "bin" || pkg.hasManpages || pkg.pname == "cm-super"; - # elem tlType [ "run" "bin" "doc" "source" ] - # there are also other attributes: version, name - } - ``` - -- You can list packages e.g. by `nix repl`. - +- All packages distributed by TeX Live, which contains most of CTAN, are available and can be found under `texlive.pkgs`: ```ShellSession $ nix repl nix-repl> :l - nix-repl> texlive.collection-[TAB] + nix-repl> texlive.pkgs.[TAB] ``` - -- Note that the wrapper assumes that the result has a chance to be useful. For example, the core executables should be present, as well as some core data files. The supported way of ensuring this is by including some scheme, for example, `scheme-basic`, into the combination. - -- TeX Live packages are also available under `texlive.pkgs` as derivations with outputs `out`, `tex`, `texdoc`, `texsource`, `tlpkg`, `man`, `info`. They cannot be installed outside of `texlive.combine` but are available for other uses. To repackage a font, for instance, use + These are derivations with outputs `out`, `tex`, `texdoc`, `texsource`, `tlpkg`, `man`, `info`. They cannot be installed outside of `texlive.withPackages` but are available for other uses. To repackage a font, for instance, use ```nix stdenvNoCC.mkDerivation (finalAttrs: { @@ -112,7 +67,7 @@ Release 23.11 ships with a new interface that will eventually replace `texlive.c You may find that you need to use an external TeX package. A derivation for such package has to provide the contents of the "texmf" directory in its `"tex"` output, according to the [TeX Directory Structure](https://tug.ctan.org/tds/tds.html). Dependencies on other TeX packages can be listed in the attribute `passthru.tlDeps`, which is a function taking a package set and returning a list of packages. -The functions `texlive.combine` and `texlive.withPackages` recognise the following outputs: +The function `texlive.withPackages` recognise the following outputs: - `"out"`: contents are linked in the TeX Live environment, and binaries in the `$out/bin` folder are wrapped; - `"tex"`: linked in `$TEXMFDIST`; files should follow the TDS (for instance `$tex/tex/latex/foiltex/foiltex.cls`); @@ -120,8 +75,6 @@ The functions `texlive.combine` and `texlive.withPackages` recognise the followi - `"tlpkg"`: linked in `$TEXMFROOT/tlpkg`; - `"man"`, `"info"`, ...: the other outputs are combined into separate outputs. -When using `pkgFilter`, `texlive.combine` will assign `tlType` respectively `"bin"`, `"run"`, `"doc"`, `"source"`, `"tlpkg"` to the above outputs. - Here is a (very verbose) example. See also the packages `auctex`, `eukleides`, `mftrace` for more examples. ```nix diff --git a/doc/redirects.json b/doc/redirects.json index 646b12a5a077..d06728e02abd 100644 --- a/doc/redirects.json +++ b/doc/redirects.json @@ -4428,11 +4428,9 @@ "sec-language-texlive": [ "index.html#sec-language-texlive" ], - "sec-language-texlive-user-guide-experimental": [ - "index.html#sec-language-texlive-user-guide-experimental" - ], "sec-language-texlive-user-guide": [ - "index.html#sec-language-texlive-user-guide" + "index.html#sec-language-texlive-user-guide", + "index.html#sec-language-texlive-user-guide-experimental" ], "sec-language-texlive-custom-packages": [ "index.html#sec-language-texlive-custom-packages"