AtlatestRepositorycore-channel

core-channel / tree / src / core / packageswayland.sgl

1;;; The Wayland display protocol: the client library, the code generator, and
2;;; the protocol definitions.
3;;;
4;;; WHAT DOES AND DOES NOT HAVE TO MATCH THE USER'S COMPOSITOR, because it is
5;;; the first question anyone asks about a store-built Wayland client and the
6;;; answer is not obvious:
7;;;
8;;; Wayland is a WIRE PROTOCOL over a Unix socket, not a shared-library ABI.
9;;; A client links libwayland-client, a compositor links libwayland-server,
10;;; and the two never link against each other or share an address space. So
11;;; a statically linked musl client built from this channel talks to a
12;;; glibc compositor from any distribution, at any library version, without
13;;; difficulty. What must line up is the PROTOCOL VERSIONS a client binds
14;;; against those the compositor advertises -- and `wayland-protocols` below
15;;; is a BUILD-TIME source of XML for code generation, not something the
16;;; compositor needs to have.
17;;;
18;;; The same reasoning covers libxkbcommon: a Wayland compositor sends its
19;;; keymap to clients as TEXT over a file descriptor, and each client compiles
20;;; it with its own copy of the library. That is why nothing here needs
21;;; `xkeyboard-config` -- a Wayland client never reads the keymap database.
22(define-library (core packages wayland)
23 (import (sigil core)
24 (core build-environments)
25 (core packages ffi)
26 (core packages xml)
27 (core packages build-tools)
28 (core packages python)
29 (sigil env package)
30 (sigil build external))
31 (export wayland wayland-protocols)
32 (begin
33 ;; THE CHANNEL'S FIRST MESON PACKAGE.
34 ;;
35 ;; There is no `meson` phase kind and none is needed: `run` executes an
36 ;; authored argv under `set -eu`, so the three steps are three phases.
37 ;; Separate phases rather than one script because a failure then names
38 ;; which step failed without anyone reading a log.
39 ;;
40 ;; `--buildtype=plain` is the load-bearing flag. Meson's other build
41 ;; types inject their own optimisation and debug flags, which would sit
42 ;; alongside the builder's `@compiler.flags` response file with no defined
43 ;; precedence. `plain` tells meson to add nothing and use CFLAGS,
44 ;; CPPFLAGS and LDFLAGS from the environment -- which is exactly the
45 ;; channel's model, and is what every distribution uses for the same
46 ;; reason.
47 ;;
48 ;; DESTDIR is passed to `meson install` through the environment rather
49 ;; than as `--destdir`, so the same idiom works on any meson old enough to
50 ;; predate that flag. `$d` is derived from the phase's cwd rather than
51 ;; hardcoded: a run phase cannot interpolate the staged install root, but
52 ;; it always runs in `<build-root>/source` and the staged root is always
53 ;; `<build-root>/install-root`.
54 (define wayland
55 (package
56 name: "wayland"
57 version: "1.24.0"
58 source: (external-source
59 location: "https://gitlab.freedesktop.org/wayland/wayland/-/releases/1.24.0/downloads/wayland-1.24.0.tar.xz"
60 sha256: "82892487a01ad67b334eca83b54317a7c86a03a89cfadacfef5211f11a5d0536")
61 buildenv: core-buildenv
62 ;; libffi is a genuine runtime dependency: libwayland dispatches every
63 ;; protocol message through `ffi_call`, in the client as well as the
64 ;; server. expat is needed by wayland-scanner, which parses protocol
65 ;; XML -- and although the scanner is a build-time tool for consumers,
66 ;; it is a linked artifact OF THIS package, so expat is a dependency
67 ;; and not a build input.
68 dependencies: (list libffi expat)
69 build-inputs: (list meson samurai python)
70 phases: (list
71 (external-phase
72 kind: 'run
73 args: (list "sh" "-c"
74 (string-append
75 "set -eu\n"
76 "meson setup build"
77 " --prefix=${out}"
78 " --buildtype=plain"
79 " --default-library=static"
80 ;; `-Dprefer_static=true` HERE TOO, although
81 ;; nothing needs it TODAY. wayland builds
82 ;; `wayland-scanner`, an executable that links
83 ;; expat, and it links only because `expat.pc`
84 ;; happens to carry no `Requires.private:` -- so
85 ;; the default, non-static pkg-config query is
86 ;; sufficient by coincidence rather than by
87 ;; construction. The moment expat grows one, or
88 ;; the scanner gains a dependency that has one,
89 ;; this package reproduces the `undefined symbol`
90 ;; link failure that fontconfig's
91 ;; `Requires.private: expat` produced in foot.
92 " -Dprefer_static=true"
93 ;; documentation wants doxygen, xmlto and
94 ;; xsltproc; dtd_validation wants libxml2. Both
95 ;; are probes on what happens to be visible, and
96 ;; neither produces anything foot consumes.
97 " -Ddocumentation=false"
98 " -Dtests=false"
99 " -Ddtd_validation=false\n"
100 "echo WAYLAND-CONFIGURED\n")))
101 (external-phase
102 kind: 'run
103 args: (list "sh" "-c"
104 (string-append
105 "set -eu\n"
106 "meson compile -C build\n"
107 "echo WAYLAND-COMPILED\n")))
108 (external-phase
109 kind: 'run
110 args: (list "sh" "-c"
111 (string-append
112 "set -eu\n"
113 "d=\"$(dirname \"$PWD\")/install-root\"\n"
114 "DESTDIR=\"$d\" meson install -C build --no-rebuild\n"
115 ;; Assert the three things consumers resolve by
116 ;; name. foot asks for wayland-client and
117 ;; wayland-cursor through pkg-config and then
118 ;; reads `wayland_scanner` out of the
119 ;; wayland-scanner `.pc` to find the generator.
120 "test -f \"$d${out}/lib/pkgconfig/wayland-client.pc\"\n"
121 "test -f \"$d${out}/lib/pkgconfig/wayland-cursor.pc\"\n"
122 "test -f \"$d${out}/lib/pkgconfig/wayland-scanner.pc\"\n"
123 "test -x \"$d${out}/bin/wayland-scanner\"\n"
124 "echo WAYLAND-INSTALLED\n"))))))
126 ;; wayland-protocols is DATA -- XML files and one `.pc` -- so it is
127 ;; installed by hand for the same reason tllist is: running meson to copy
128 ;; a directory tree would add three build inputs to a package that
129 ;; compiles nothing.
130 ;;
131 ;; TWO THINGS HERE ARE NOT COSMETIC.
132 ;;
133 ;; 1. THE `.pc` GOES IN `lib/pkgconfig`, WHERE UPSTREAM PUTS IT IN
134 ;; `share/pkgconfig`. `dependency-pkgconfig` in (sigil build external)
135 ;; composes PKG_CONFIG_PATH as exactly `<dep>/lib/pkgconfig` for each
136 ;; dependency and nothing else. An arch-independent `.pc` in
137 ;; `share/pkgconfig` -- which is the correct place for one, and where
138 ;; upstream's meson puts it -- WOULD BE INVISIBLE TO EVERY CONSUMER IN
139 ;; THIS CHANNEL. A package cannot fix that by declaring a search path
140 ;; either: `PKG_CONFIG_PATH` is builder-owned, and a `search-paths:`
141 ;; export naming a builder variable is refused outright.
142 ;;
143 ;; 2. `pkgdatadir` MUST BE DEFINED IN THE `.pc`, because foot does not
144 ;; merely link against this -- it reads the variable back out
145 ;; (`wayland_protocols.get_variable('pkgdatadir')`, meson.build:169) and
146 ;; then joins protocol paths onto it. Upstream's template writes it as
147 ;; `${pc_sysrootdir}${datarootdir}/@PACKAGE@`; that spelling cannot be
148 ;; used here because sigil interpolates `${...}` in a phase argument
149 ;; before any consumer sees it. An absolute path is equivalent for
150 ;; every use in this channel.
151 (define wayland-protocols
152 (package
153 name: "wayland-protocols"
154 version: "1.45"
155 source: (external-source
156 location: "https://gitlab.freedesktop.org/wayland/wayland-protocols/-/releases/1.45/downloads/wayland-protocols-1.45.tar.xz"
157 sha256: "4d2b2a9e3e099d017dc8107bf1c334d27bb87d9e4aff19a0c8d856d17cd41ef0")
158 buildenv: core-buildenv
159 phases: (list
160 (external-phase
161 kind: 'run
162 args: (list "sh" "-c"
163 (string-append
164 "set -eu\n"
165 "d=\"$(dirname \"$PWD\")/install-root\"\n"
166 "p=\"$d${out}/share/wayland-protocols\"\n"
167 "mkdir -p \"$p\" \"$d${out}/lib/pkgconfig\"\n"
168 "cp -a stable unstable staging \"$p/\"\n"
169 "cat > \"$d${out}/lib/pkgconfig/wayland-protocols.pc\" <<'PC'\n"
170 "prefix=${out}\n"
171 "datarootdir=${out}/share\n"
172 "pkgdatadir=${out}/share/wayland-protocols\n"
173 "\n"
174 "Name: Wayland Protocols\n"
175 "Description: Wayland protocol files\n"
176 "Version: 1.45\n"
177 "PC\n"
178 ;; foot names these three files explicitly, so
179 ;; assert them rather than the directory: a
180 ;; reorganised tarball would otherwise fail three
181 ;; packages later inside wayland-scanner.
182 "test -f \"$p/stable/xdg-shell/xdg-shell.xml\"\n"
183 "test -f \"$p/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml\"\n"
184 "test -f \"$p/unstable/xdg-output/xdg-output-unstable-v1.xml\"\n"
185 ;; And prove the variable foot reads back is
186 ;; actually readable, by the tool that will read
187 ;; it.
188 ;; A BARE `pkg-config --variable=` CALL IS NOT A
189 ;; GATE. pkg-config exits 0 and prints an empty
190 ;; line when the requested variable is UNDEFINED,
191 ;; so deleting the `pkgdatadir=` line from the
192 ;; heredoc above would leave this green -- and
193 ;; foot's `get_variable('pkgdatadir')` would then
194 ;; fail three packages later, inside
195 ;; wayland-scanner, which is exactly the distance
196 ;; these assertions exist to close. Require the
197 ;; value to be non-empty AND to name a real
198 ;; directory.
199 "v=$(PKG_CONFIG_PATH=\"$d${out}/lib/pkgconfig\" pkg-config --variable=pkgdatadir wayland-protocols)\n"
200 "echo \"WAYLAND-PROTOCOLS-PKGDATADIR=[$v]\"\n"
201 "test -n \"$v\"\n"
202 ;; AND THE VALUE MUST NAME A REAL DIRECTORY --
203 ;; but the STAGED one. `$v` is an absolute
204 ;; `/sigil/store/<item>/...` path, which is where
205 ;; the directory will live once this output is in
206 ;; the store and bound into a consumer's sandbox.
207 ;; It does not exist yet DURING this build; the
208 ;; files are under `$d` until the realizer moves
209 ;; them. So the staged equivalent is `$d$v`.
210 ;;
211 ;; The first version of this check tested `$v`
212 ;; directly and failed the build immediately --
213 ;; which is the right direction for a new gate to
214 ;; be wrong in, and worth leaving a note about:
215 ;; a path emitted by pkg-config is a CONSUMER-time
216 ;; path, and a build-time assertion about it has
217 ;; to add the staging offset.
218 "test -d \"$d$v\"\n"
219 "echo WAYLAND-PROTOCOLS-INSTALLED\n"))))))))