From 3f22dabc2a15154bb7fc03d9abf38a40854bf854 Mon Sep 17 00:00:00 2001 From: Nicolas Goaziou Date: Sat, 6 May 2023 07:26:01 +0200 Subject: [PATCH] guix: texlive-build-system: Improvements on non-trivial packages. * guix/build/texlive-build-system.scm (build): Ignore temporary build files when moving runfiles around. Remove ".drv" source files prior to compiling files. Remove need for #:TEX-DIRECTORY keyword. Handle ".ins" and ".dtx" files in different directories. (install): Install docfiles in "doc" output when available. * guix/build-system/texlive.scm (texlive-build): Remove #:TEX-DIRECTORY. * doc/guix.texi (Build Systems): Remove reference to #:TEX-DIRECTORY in TEXLIVE-BUILD-SYSTEM documentation. Also mention it now tries to compile ".dtx" files when there is no ".ins" file. --- doc/guix.texi | 15 ++-- guix/build-system/texlive.scm | 2 - guix/build/texlive-build-system.scm | 115 ++++++++++++++++++++++++---- 3 files changed, 107 insertions(+), 25 deletions(-) diff --git a/doc/guix.texi b/doc/guix.texi index ee03de04dc..a1b624ad6f 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -10001,17 +10001,16 @@ used to build TeX packages in batch mode with a specified engine. The build system sets the @env{TEXINPUTS} variable to find all TeX source files in the inputs. -By default it runs @code{luatex} on all files ending on @code{ins}. A -different engine and format can be specified with the -@code{#:tex-format} argument. Different build targets can be specified -with the @code{#:build-targets} argument, which expects a list of file -names. The build system adds only @code{texlive-bin} and +By default it tries to run @code{luatex} on all @file{.ins} files, and +if it fails to find any, on all @file{.dtx} files. A different engine +and format can be specified with the @code{#:tex-format} argument. +Different build targets can be specified with the @code{#:build-targets} +argument, which expects a list of file names. + +The build system adds only @code{texlive-bin} and @code{texlive-latex-base} (both from @code{(gnu packages tex}) to the inputs. Both can be overridden with the arguments @code{#:texlive-bin} and @code{#:texlive-latex-base}, respectively. - -The @code{#:tex-directory} parameter tells the build system where to -install the built files under the texmf tree. @end defvar @defvar ruby-build-system diff --git a/guix/build-system/texlive.scm b/guix/build-system/texlive.scm index aefd573d11..55e9cfee81 100644 --- a/guix/build-system/texlive.scm +++ b/guix/build-system/texlive.scm @@ -130,7 +130,6 @@ level package ID." #:key source (tests? #f) - tex-directory (build-targets #f) (tex-engine #f) @@ -161,7 +160,6 @@ level package ID." #$(with-build-variables inputs outputs #~(texlive-build #:name #$name #:source #+source - #:tex-directory #$tex-directory #:build-targets #$build-targets #:tex-engine #$(if tex-engine tex-engine diff --git a/guix/build/texlive-build-system.scm b/guix/build/texlive-build-system.scm index 353fb934a6..9bc0ce31c1 100644 --- a/guix/build/texlive-build-system.scm +++ b/guix/build/texlive-build-system.scm @@ -2,6 +2,7 @@ ;;; Copyright © 2017 Ricardo Wurmus ;;; Copyright © 2021 Maxim Cournoyer ;;; Copyright © 2021 Thiago Jung Bauermann +;;; Copyright © 2023 Nicolas Goaziou ;;; ;;; This file is part of GNU Guix. ;;; @@ -22,8 +23,9 @@ #:use-module ((guix build gnu-build-system) #:prefix gnu:) #:use-module (guix build utils) #:use-module (guix build union) - #:use-module (ice-9 match) + #:use-module (ice-9 format) #:use-module (ice-9 ftw) + #:use-module (ice-9 match) #:use-module (srfi srfi-1) #:use-module (srfi srfi-26) #:export (%standard-phases @@ -35,33 +37,116 @@ ;; ;; Code: -(define (compile-with-latex engine format file) +(define (runfiles-root-directories) + "Return list of root directories containing runfiles." + (scandir "." + (negate + (cut member <> '("." ".." "build" "doc" "source"))))) + +(define* (delete-drv-files #:rest _) + "Delete pre-generated \".drv\" files in order to prevent build failures." + (when (file-exists? "source") + (for-each delete-file (find-files "source" "\\.drv$")))) + +(define (compile-with-latex engine format output file) (invoke engine "-interaction=nonstopmode" - "-output-directory=build" + (string-append "-output-directory=" output) (if format (string-append "&" format) "-ini") file)) (define* (build #:key inputs build-targets tex-engine tex-format #:allow-other-keys) - (mkdir "build") - (for-each (cut compile-with-latex tex-engine tex-format <>) - (if build-targets build-targets - (scandir "." (cut string-suffix? ".ins" <>))))) + (let ((targets + (cond + (build-targets + ;; Collect the relative file names of all the specified targets. + (append-map (lambda (target) + (find-files "source" + (lambda (f _) + (string-suffix? (string-append "/" target) + f)))) + build-targets)) + ((directory-exists? "source") + ;; Prioritize ".ins" files over ".dtx" files. There's no + ;; scientific reasoning here; it just seems to work better. + (match (find-files "source" "\\.ins$") + (() (find-files "source" "\\.dtx$")) + (files files))) + (else '())))) + (unless (null? targets) + (let ((output (string-append (getcwd) "/build"))) + (mkdir-p output) + (for-each (lambda (target) + (with-directory-excursion (dirname target) + (compile-with-latex tex-engine + tex-format + output + (basename target)))) + targets)) + ;; Now move generated files from the "build" directory into the rest of + ;; the source tree, effectively replacing downloaded files. -(define* (install #:key outputs tex-directory #:allow-other-keys) - (let* ((out (assoc-ref outputs "out")) - (target (string-append - out "/share/texmf-dist/tex/" tex-directory))) - (mkdir-p target) - (for-each delete-file (find-files "." "\\.(log|aux)$")) - (for-each (cut install-file <> target) - (find-files "build" ".*")))) + ;; Documentation may have been generated, but replace only runfiles, + ;; i.e., files that belong neither to "doc" nor "source" trees. + ;; + ;; In TeX Live, all packages are fully pre-generated. As a consequence, + ;; a generated file from the "build" top directory absent from the rest + ;; of the tree is deemed unnecessary and can safely be ignored. + (let ((runfiles (append-map (cut find-files <>) + (runfiles-root-directories)))) + (for-each (lambda (file) + (match (filter + (cut string-suffix? + (string-drop file (string-length "build")) + <>) + runfiles) + ;; Current file is not a runfile. Ignore it. + (() #f) + ;; One candidate only. Replace it with the one just + ;; generated. + ((destination) + (let ((target (dirname destination))) + (install-file file target) + (format #t "re-generated file ~s in ~s~%" + (basename file) + target))) + ;; Multiple candidates! Not much can be done. + ;; Hopefully, this should never happen. + (_ + (format (current-error-port) + "warning: ambiguous localization of file ~s; \ +ignoring it~%" + (basename file))))) + ;; Preserve the relative file name of the generated file in + ;; order to be more accurate when looking for the + ;; corresponding runfile in the tree. + (find-files "build")))))) + +(define* (install #:key outputs #:allow-other-keys) + (let ((out (assoc-ref outputs "out")) + (doc (assoc-ref outputs "doc"))) + ;; Take care of documentation. + (when (directory-exists? "doc") + (unless doc + (format (current-error-port) + "warning: missing 'doc' output for package documentation~%")) + (let ((doc-dir (string-append (or doc out) "/share/texmf-dist/doc"))) + (mkdir-p doc-dir) + (copy-recursively "doc" doc-dir))) + ;; Handle runfiles. + (let ((texmf (string-append (assoc-ref outputs "out") "/share/texmf-dist"))) + (for-each (lambda (root) + (let ((destination (string-append texmf "/" root))) + (mkdir-p destination) + (copy-recursively root destination))) + (runfiles-root-directories))))) (define %standard-phases (modify-phases gnu:%standard-phases (delete 'bootstrap) (delete 'configure) + (add-before 'build 'delete-drv-files delete-drv-files) (replace 'build build) (delete 'check) (replace 'install install)))