|
1 | 1 | // Generate the protocol sources for libwayland-client. |
2 | 2 | // |
3 | | -// wayland's libraries are mostly GENERATED: protocol/wayland.xml describes |
4 | | -// every interface, and wayland-scanner emits the marshalling code and the |
5 | | -// headers from it. Upstream does this with meson custom_targets; here it is |
6 | | -// three mcpp::action edges, which means the work is DECLARED rather than done |
7 | | -// — it re-runs exactly when wayland.xml changes, and a failure is attributed |
8 | | -// to the edge instead of to "build.mcpp exited 1". |
| 3 | +// wayland's libraries are mostly GENERATED: upstream/protocol/wayland.xml |
| 4 | +// describes every interface, and wayland-scanner emits the marshalling code and |
| 5 | +// the headers from it — most of what this package compiles. |
9 | 6 | // |
10 | | -// The scanner is the one this build produced (compat.wayland-scanner, asked |
11 | | -// for with `tools = ["wayland-scanner"]`), never a host one. That matters |
12 | | -// more than it looks: a system wayland-scanner 1.22 rejects 1.23's |
13 | | -// wayland.xml outright — it does not know the `deprecated-since` attribute — |
14 | | -// so a build that reached for the host would fail or, worse, silently emit |
15 | | -// code for a different protocol revision than the headers describe. |
| 7 | +// The scanner is the one this build produced (freedesktop.wayland-scanner, asked |
| 8 | +// for with `tools = ["wayland-scanner"]`), never a host one. A system |
| 9 | +// wayland-scanner 1.22 rejects 1.26's wayland.xml outright — it does not know the |
| 10 | +// `deprecated-since` attribute — so a build that reached for whatever is on |
| 11 | +// PATH would fail, or worse emit code for a different protocol revision than the |
| 12 | +// headers describe. |
| 13 | +// |
| 14 | +// WHY THIS RUNS THE SCANNER INSTEAD OF DECLARING mcpp::action EDGES |
| 15 | +// |
| 16 | +// Declaring them is the nicer shape and was tried first. It does not work for a |
| 17 | +// DEPENDENCY's own sources: an action's outputs become ninja nodes, but the |
| 18 | +// package's compile edges get no order-only dependency on them, so |
| 19 | +// `wayland-server.o` races the generator and usually loses — |
| 20 | +// |
| 21 | +// wayland-server.c:334: error: 'WL_DISPLAY_ERROR' undeclared |
| 22 | +// |
| 23 | +// with the header appearing in the output directory moments later. build.mcpp |
| 24 | +// itself runs at CONFIGURE time, before ninja is written, so doing the work here |
| 25 | +// is ordered by construction. `rerun_if_changed` keeps it incremental. |
16 | 26 | #include <cstdio> |
| 27 | +#include <cstdlib> |
17 | 28 | #include <string> |
18 | 29 |
|
19 | 30 | import mcpp; |
20 | 31 |
|
21 | | -int main() { |
| 32 | +namespace { |
| 33 | + |
| 34 | +// One scanner invocation. Returns false and explains itself rather than |
| 35 | +// letting a silent partial generation surface later as a missing symbol. |
| 36 | +bool generate(const std::string &scanner, const std::string &mode, |
| 37 | + const std::string &core, const std::string &xml, |
| 38 | + const std::string &out) |
| 39 | +{ |
| 40 | + std::string cmd = "'" + scanner + "' -s " + mode; |
| 41 | + if (!core.empty()) { |
| 42 | + cmd += " " + core; |
| 43 | + } |
| 44 | + cmd += " '" + xml + "' '" + out + "'"; |
| 45 | + |
| 46 | + if (std::system(cmd.c_str()) != 0) { |
| 47 | + std::fprintf(stderr, "wayland-scanner failed: %s\n", cmd.c_str()); |
| 48 | + return false; |
| 49 | + } |
| 50 | + return true; |
| 51 | +} |
| 52 | + |
| 53 | +} // namespace |
| 54 | + |
| 55 | +int main() |
| 56 | +{ |
22 | 57 | const std::string root = mcpp::manifest_dir(); |
23 | 58 | const std::string out = mcpp::out_dir(); |
24 | 59 |
|
25 | 60 | const char *scanner = mcpp::dep_bin("wayland-scanner", "wayland-scanner"); |
26 | 61 | if (scanner == nullptr || *scanner == '\0') { |
27 | | - std::fputs("no wayland-scanner: declare compat.wayland-scanner = " |
28 | | - "{ version = \"1.23.1\", tools = [\"wayland-scanner\"] }\n", |
| 62 | + std::fputs("no wayland-scanner: declare freedesktop.wayland-scanner = " |
| 63 | + "{ version = \"1.26.0\", tools = [\"wayland-scanner\"] }\n", |
29 | 64 | stderr); |
30 | 65 | return 1; |
31 | 66 | } |
32 | 67 |
|
33 | | - const std::string xml = root + "/../../protocol/wayland.xml"; |
| 68 | + const std::string xml = root + "/../../upstream/protocol/wayland.xml"; |
| 69 | + mcpp::rerun_if_changed(xml.c_str()); |
34 | 70 |
|
35 | | - struct Gen { const char *id; const char *mode; const char *core; const char *output; }; |
| 71 | + struct Gen { const char *mode; const char *core; const char *output; }; |
36 | 72 | const Gen work[] = { |
37 | | - // The marshalling code: wl_interface tables and the proxy/resource |
38 | | - // stubs. Both libraries carry it — upstream does the same, and |
| 73 | + // The marshalling code: the wl_interface tables and the proxy/resource |
| 74 | + // stubs. BOTH libraries carry it — upstream does the same, and |
39 | 75 | // `wl_display_interface` is exported from libwayland-client.so.0 and |
40 | 76 | // libwayland-server.so.0 alike. |
41 | | - { "wayland:protocol-code", "public-code", nullptr, "wayland-protocol.c" }, |
42 | | - { "wayland:client-header", "client-header", nullptr, "wayland-client-protocol.h" }, |
| 77 | + { "public-code", nullptr, "wayland-protocol.c" }, |
| 78 | + { "client-header", nullptr, "wayland-client-protocol.h" }, |
43 | 79 | // The -c variant: the same header without the convenience wrappers. |
44 | | - // Not installed by upstream, but the .c above includes it. |
45 | | - { "wayland:client-core", "client-header", "-c", "wayland-client-protocol-core.h" }, |
| 80 | + // Upstream does not install it, but the generated .c includes it. |
| 81 | + { "client-header", "-c", "wayland-client-protocol-core.h" }, |
46 | 82 | }; |
47 | 83 |
|
48 | 84 | for (const Gen &g : work) { |
49 | | - const std::string output = out + "/" + g.output; |
50 | | - mcpp::action a; |
51 | | - a.id = g.id; |
52 | | - a.role = "source"; |
53 | | - const std::string desc = std::string("wayland-scanner -> ") + g.output; |
54 | | - a.description = desc.c_str(); |
55 | | - a.arg(scanner).arg("-s").arg(g.mode); |
56 | | - if (g.core != nullptr) { |
57 | | - a.arg(g.core); |
| 85 | + if (!generate(scanner, g.mode, g.core == nullptr ? "" : g.core, |
| 86 | + xml, out + "/" + g.output)) { |
| 87 | + return 1; |
58 | 88 | } |
59 | | - a.arg(xml.c_str()) |
60 | | - .arg(output.c_str()) |
61 | | - .input(xml.c_str()) |
62 | | - .output(output.c_str()) |
63 | | - .submit(); |
64 | 89 | } |
65 | 90 |
|
| 91 | + // The generated .c is a translation unit of this package; the headers are |
| 92 | + // reached through the include directory. |
| 93 | + mcpp::source((out + "/wayland-protocol.c").c_str()); |
66 | 94 | mcpp::include_dir(out.c_str()); |
67 | 95 | } |
0 commit comments