Subject: [bug#73668] libglvnd support in mesa

From: aurtzy <[email-masked]>
Date: Sun, 6 Oct 2024 16:31:17 -0400

Hi!

I've been looking further into adding libglvnd support to mesa, following recent
discussions on mesa updates [1].  There is a reportedly working version by The
Man [2] which does so by unionizing libglvnd and mesa files, but with the
suggestion to try a libglvnd-as(-propagated)-input approach first, the rest of
this message will focus on working towards that.  Relevant parties from the
previous discussion have been CCed.

Context as I understand it: Adding libglvnd as an input to mesa causes mesa to
build without some/all lib*.so files that it usually has because libglvnd
becomes the package that will have them.  This means that if a package with mesa
as a dependency employs any code that assumes libraries in mesa
(e.g. =(string-append (assoc-ref inputs "mesa") "/lib/libGL.so")=), the build
fails.  This appears to be the main issue.

I devised a script to find all the packages that probably need fixing.  It is
included at the end of this message.  I cross-checked its coverage with
consult-grep from emacs-consult (search phrase: =mesa lib=), which doesn't seem
to reveal any other packages that would need changes, but I'm not sure if
there's a better way to validate this without going through what seems like a
/lot/ of packages with mesa as a transitive input.

The script outputs the following packages that may need to be changed:

--8<---------------cut here---------------start------------->8---
gnu/packages/virtualization.scm:2133:2 "looking-glass-client"
gnu/packages/video.scm:4030:2 "obs"
gnu/packages/tor-browsers.scm:203:2 "torbrowser"
gnu/packages/qt.scm:450:2 "qtbase"
gnu/packages/python-xyz.scm:25513:4 "python-glcontext"
gnu/packages/python-xyz.scm:25441:2 "python-pyopengl"
gnu/packages/perl.scm:8504:2 "perl-opengl"
gnu/packages/music.scm:1122:2 "extempore"
gnu/packages/librewolf.scm:218:2 "librewolf"
gnu/packages/gnuzilla.scm:709:2 "icecat-minimal"
gnu/packages/gl.scm:746:2 "guile-opengl"
gnu/packages/gl.scm:1207:2 "glmark2"
gnu/packages/chromium.scm:484:2 "ungoogled-chromium"
--8<---------------cut here---------------end--------------->8---

Should we consider adjusting variable names as well?  I have noticed GL
libraries are sometimes assigned to e.g. "mesa-lib", but they will no longer be
part of mesa if libglvnd support is enabled (an alternative name could be
"gl-lib").  While this is more "cosmetic" and applies to a larger number of
packages, I wonder if it might be a point of confusion for readers.  See
libepoxy and its use of "mesa-lib" for an example.

If no one's already started work or wants to take point on this, I should be
able to make some time these next few weeks to write patches :)

The mentioned script:

--8<---------------cut here---------------start------------->8---
#!/usr/bin/env -S guix repl --
!#

(use-modules (gnu)
              (guix)
              (guix diagnostics)
              (guix records)
              (ice-9 match)
              (srfi srfi-1)
              (srfi srfi-26))

(define (sexp-contains sexp predicate)
   "Call (PREDICATE S-EXPRESSION) on every node of SEXP (recursively), and return
the predicate value on the first instance that it is non-false.  If none of the
nodes satisfy the predicate, return false."
   (define (%sexp-contains sexp rest-sexps)
     (match sexp
       ((= predicate (and (not #f) return-value))
        return-value)
       ((child rest-children ...)
        (%sexp-contains child (append rest-children rest-sexps)))
       (else
        (match rest-sexps
          ((next-sexp rest-sexps ...)
           (%sexp-contains next-sexp rest-sexps))
          (else
           #f)))))
   (%sexp-contains sexp '()))

(define (sexp-at-location filename line column)
   "Return the next s-expression after LINE and COLUMN (both one-indexed) in
FILENAME."
   (call-with-input-file filename
     (lambda (port)
       (go-to-location port line column)
       (read port))))

(define (relevant-package? package)
   "Return whether PACKAGE is a potentially relevant package."
   (->bool
    (and (any (match-lambda
                (("mesa" _ ...) #t)
                ((? package? (= package-name "mesa")) #t)
                (else #f))
              (package-transitive-inputs package))
         (and=> (sexp-contains (match (package-location package)
                                 (($ <location> file line column)
                                  (sexp-at-location file line (1+ column))))
                               (lambda (sexp)
                                 (and (list? sexp)
                                      (match (memq #:phases sexp)
                                        ((#:phases phases _ ...) phases)
                                        (else #f)))))
                (lambda (phases-sexp)
                  ;; Use the following conditions to determine if the
                  ;; package does stuff with mesa libraries.
                  (and (sexp-contains phases-sexp
                                      (lambda (sexp)
                                        (and (string? sexp)
                                             (string-contains sexp "lib"))))
                       (or (sexp-contains phases-sexp
                                          (lambda (sexp)
                                            (and (symbol? sexp)
                                                 (eq? sexp 'mesa))))
                           (sexp-contains phases-sexp
                                          (lambda (sexp)
                                            (and (string? sexp)
                                                 (string-contains sexp 
"mesa")))))))))))

(define (main . _)
   "Run this in the top level of the guix repository with \"./pre-inst-env\"."
   (format #t "Relevant packages:\n\n")
   (for-each
    (lambda (package)
      (match (package-location package)
        (($ <location> file line column)
         (format #t "~a:~a:~a ~s\n"
                 file
                 line
                 column
                 (package-name package)))))
    (fold-packages
     (lambda (package result)
       (if (relevant-package? package)
           (cons package result)
           result))
     '())))

(main)
--8<---------------cut here---------------end--------------->8---

[1] https://issues.guix.gnu.org/73071#12

[2] https://issues.guix.gnu.org/73071#13

Cheers,

aurtzy