From 5a4177523e382cc13057d65905266ad261c4bba2 Mon Sep 17 00:00:00 2001 From: Mark Bolhuis Date: Thu, 10 Feb 2022 21:01:58 +0000 Subject: [PATCH] modules/wayland: Add unstable_wayland module --- CODEOWNERS | 1 + ci/ciimage/arch/install.sh | 2 +- ci/ciimage/fedora/install.sh | 2 +- docs/markdown/Wayland-module.md | 64 ++++++++++ docs/markdown/_Sidebar.md | 1 + docs/markdown/snippets/wayland-module.md | 4 + docs/sitemap.txt | 1 + docs/theme/extra/templates/navbar_links.html | 1 + mesonbuild/modules/__init__.py | 6 +- mesonbuild/modules/unstable_wayland.py | 120 +++++++++++++++++++ run_project_tests.py | 10 +- test cases/wayland/1 client/main.c | 9 ++ test cases/wayland/1 client/meson.build | 16 +++ test cases/wayland/2 server/main.c | 9 ++ test cases/wayland/2 server/meson.build | 16 +++ test cases/wayland/3 local/main.c | 9 ++ test cases/wayland/3 local/meson.build | 11 ++ test cases/wayland/3 local/test.xml | 6 + 18 files changed, 283 insertions(+), 5 deletions(-) create mode 100644 docs/markdown/Wayland-module.md create mode 100644 docs/markdown/snippets/wayland-module.md create mode 100644 mesonbuild/modules/unstable_wayland.py create mode 100644 test cases/wayland/1 client/main.c create mode 100644 test cases/wayland/1 client/meson.build create mode 100644 test cases/wayland/2 server/main.c create mode 100644 test cases/wayland/2 server/meson.build create mode 100644 test cases/wayland/3 local/main.c create mode 100644 test cases/wayland/3 local/meson.build create mode 100644 test cases/wayland/3 local/test.xml diff --git a/CODEOWNERS b/CODEOWNERS index e6be76c8d..b531c2658 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -3,6 +3,7 @@ /mesonbuild/modules/cmake.py @mensinda /mesonbuild/modules/unstable_external_project.py @xclaesse /mesonbuild/modules/unstable_rust.py @dcbaker +/mesonbuild/modules/unstable_wayland.py @markbolhuis /mesonbuild/ast/ @mensinda /mesonbuild/cmake/ @mensinda /mesonbuild/compilers/ @dcbaker diff --git a/ci/ciimage/arch/install.sh b/ci/ciimage/arch/install.sh index 72816ab95..96286358c 100755 --- a/ci/ciimage/arch/install.sh +++ b/ci/ciimage/arch/install.sh @@ -14,7 +14,7 @@ pkgs=( itstool gtk3 java-environment=8 gtk-doc llvm clang sdl2 graphviz doxygen vulkan-validation-layers openssh mercurial gtk-sharp-2 qt5-tools libwmf valgrind cmake netcdf-fortran openmpi nasm gnustep-base gettext - python-lxml hotdoc rust-bindgen qt6-base qt6-tools + python-lxml hotdoc rust-bindgen qt6-base qt6-tools wayland wayland-protocols # cuda ) diff --git a/ci/ciimage/fedora/install.sh b/ci/ciimage/fedora/install.sh index df1d853cd..2f1ae7dfd 100755 --- a/ci/ciimage/fedora/install.sh +++ b/ci/ciimage/fedora/install.sh @@ -15,7 +15,7 @@ pkgs=( doxygen vulkan-devel vulkan-validation-layers-devel openssh mercurial gtk-sharp2-devel libpcap-devel gpgme-devel qt5-qtbase-devel qt5-qttools-devel qt5-linguist qt5-qtbase-private-devel libwmf-devel valgrind cmake openmpi-devel nasm gnustep-base-devel gettext-devel ncurses-devel - libxml2-devel libxslt-devel libyaml-devel glib2-devel json-glib-devel libgcrypt-devel + libxml2-devel libxslt-devel libyaml-devel glib2-devel json-glib-devel libgcrypt-devel wayland-devel wayland-protocols-devel ) # Sys update diff --git a/docs/markdown/Wayland-module.md b/docs/markdown/Wayland-module.md new file mode 100644 index 000000000..d30627c2b --- /dev/null +++ b/docs/markdown/Wayland-module.md @@ -0,0 +1,64 @@ +# Unstable Wayland Module + +This module is available since version 0.62.0. + +This module provides helper functions to find wayland protocol +xmls and to generate .c and .h files using wayland-scanner + +**Note**: this module is unstable. It is only provided as a technology +preview. Its API may change in arbitrary ways between releases or it +might be removed from Meson altogether. + +## Quick Usage + +```meson +project('hello-wayland', 'c') + +wl_dep = dependency('wayland-client') +wl_mod = import('unstable-wayland') + +xml = wl_mod.find_protocol('xdg-shell') +xdg_shell = wl_mod.scan_xml(xml) + +executable('hw', 'main.c', xdg_shell, dependencies : wl_dep) +``` + +## Methods + +### find_protocol + +```meson +xml = wl_mod.find_protocol( + 'xdg-decoration', + state : 'unstable', + version : 1, +) +``` +This function requires one positional argument: the protocol base name. +- `state` Optional arg that specifies the current state of the protocol. +Either stable, staging, or unstable. +The default is stable. +- `version` The backwards incompatible version number. +Required for staging or unstable. An error is raised for stable. + +### scan_xml +```meson +generated = wl_mod.scan_xml( + 'my-protocol.xml', + side : 'client', + scope : 'private', +) +``` +This function accepts one or more arguments of either string or file type. + +- `side` Optional arg that specifies if client or server side code is generated. +The default is client side. +- `scope` Optional arg that specifies the scope of the generated code. +Either public or private. +The default is private. + + +## Links +- [Official Wayland Documentation](https://wayland.freedesktop.org/docs/html/) +- [Wayland GitLab](https://gitlab.freedesktop.org/wayland) +- [Wayland Book](https://wayland-book.com/) diff --git a/docs/markdown/_Sidebar.md b/docs/markdown/_Sidebar.md index 0ca1762b5..ce73d5aad 100644 --- a/docs/markdown/_Sidebar.md +++ b/docs/markdown/_Sidebar.md @@ -13,3 +13,4 @@ * [i18n](i18n-module.md) * [pkgconfig](Pkgconfig-module.md) * [rust](Rust-module.md) +* [wayland](Wayland-module.md) diff --git a/docs/markdown/snippets/wayland-module.md b/docs/markdown/snippets/wayland-module.md new file mode 100644 index 000000000..cd5e5dce7 --- /dev/null +++ b/docs/markdown/snippets/wayland-module.md @@ -0,0 +1,4 @@ +## New unstable wayland module + +This module can search for protocol xml files from the wayland-protocols +package, and generate .c and .h files using wayland-scanner. diff --git a/docs/sitemap.txt b/docs/sitemap.txt index 82e0a7b44..11b64e0c7 100644 --- a/docs/sitemap.txt +++ b/docs/sitemap.txt @@ -58,6 +58,7 @@ index.md SourceSet-module.md Windows-module.md i18n-module.md + Wayland-module.md Java.md Vala.md D.md diff --git a/docs/theme/extra/templates/navbar_links.html b/docs/theme/extra/templates/navbar_links.html index c518de5a1..65a21a260 100644 --- a/docs/theme/extra/templates/navbar_links.html +++ b/docs/theme/extra/templates/navbar_links.html @@ -26,6 +26,7 @@ ("Rust-module.html","Rust"), \ ("Simd-module.html","Simd"), \ ("SourceSet-module.html","SourceSet"), \ + ("Wayland-module.html","Wayland"), \ ("Windows-module.html","Windows")]:
  • @tup[1] diff --git a/mesonbuild/modules/__init__.py b/mesonbuild/modules/__init__.py index 72bcd001d..85bec0b03 100644 --- a/mesonbuild/modules/__init__.py +++ b/mesonbuild/modules/__init__.py @@ -80,8 +80,10 @@ class ModuleState: def find_program(self, prog: T.Union[str, T.List[str]], required: bool = True, version_func: T.Optional[T.Callable[['ExternalProgram'], str]] = None, - wanted: T.Optional[str] = None, silent: bool = False) -> 'ExternalProgram': - return self._interpreter.find_program_impl(prog, required=required, version_func=version_func, wanted=wanted, silent=silent) + wanted: T.Optional[str] = None, silent: bool = False, + for_machine: MachineChoice = MachineChoice.HOST) -> 'ExternalProgram': + return self._interpreter.find_program_impl(prog, required=required, version_func=version_func, + wanted=wanted, silent=silent, for_machine=for_machine) def test(self, args: T.Tuple[str, T.Union[build.Executable, build.Jar, 'ExternalProgram', mesonlib.File]], workdir: T.Optional[str] = None, diff --git a/mesonbuild/modules/unstable_wayland.py b/mesonbuild/modules/unstable_wayland.py new file mode 100644 index 000000000..85da2b790 --- /dev/null +++ b/mesonbuild/modules/unstable_wayland.py @@ -0,0 +1,120 @@ +# Copyright 2022 Mark Bolhuis + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +from . import ExtensionModule, ModuleReturnValue +from ..build import CustomTarget +from ..interpreter.type_checking import NoneType, in_set_validator +from ..interpreterbase import FeatureNew, typed_pos_args, typed_kwargs, KwargInfo +from ..mesonlib import File, MesonException, MachineChoice + + +class WaylandModule(ExtensionModule): + + @FeatureNew('wayland module', '0.62.0') + def __init__(self, interpreter): + super().__init__(interpreter) + + self.protocols_dep = None + self.pkgdatadir = None + self.scanner_bin = None + + self.methods.update({ + 'scan_xml': self.scan_xml, + 'find_protocol': self.find_protocol, + }) + + @typed_pos_args('wayland.scan_xml', varargs=(str, File), min_varargs=1) + @typed_kwargs( + 'wayland.scan_xml', + KwargInfo('side', str, default='client', validator=in_set_validator({'client', 'server'})), + KwargInfo('scope', str, default='private', validator=in_set_validator({'private', 'public'})), + ) + def scan_xml(self, state, args, kwargs): + if self.scanner_bin is None: + self.scanner_bin = state.find_program('wayland-scanner', for_machine=MachineChoice.BUILD) + + scope = kwargs['scope'] + side = kwargs['side'] + + xml_files = self.interpreter.source_strings_to_files(args[0]) + targets = [] + for xml_file in xml_files: + name = os.path.splitext(os.path.basename(xml_file.fname))[0] + + code = CustomTarget( + f'{name}-protocol', + state.subdir, + state.subproject, + [self.scanner_bin, f'{scope}-code', '@INPUT@', '@OUTPUT@'], + [xml_file], + [f'{name}-protocol.c'], + backend=state.backend, + ) + targets.append(code) + + header = CustomTarget( + f'{name}-{side}-protocol', + state.subdir, + state.subproject, + [self.scanner_bin, f'{side}-header', '@INPUT@', '@OUTPUT@'], + [xml_file], + [f'{name}-{side}-protocol.h'], + backend=state.backend, + ) + targets.append(header) + + return ModuleReturnValue(targets, targets) + + @typed_pos_args('wayland.find_protocol', str) + @typed_kwargs( + 'wayland.find_protocol', + KwargInfo('state', str, default='stable', validator=in_set_validator({'stable', 'staging', 'unstable'})), + KwargInfo('version', (int, NoneType)), + ) + def find_protocol(self, state, args, kwargs): + base_name = args[0] + xml_state = kwargs['state'] + version = kwargs['version'] + + if xml_state != 'stable' and version is None: + raise MesonException(f'{xml_state} protocols require a version number.') + + if xml_state == 'stable' and version is not None: + raise MesonException('stable protocols do not require a version number.') + + if self.protocols_dep is None: + self.protocols_dep = self.interpreter.func_dependency(state.current_node, ['wayland-protocols'], {}) + + if self.pkgdatadir is None: + self.pkgdatadir = self.protocols_dep.get_variable(pkgconfig='pkgdatadir', internal='pkgdatadir') + + if xml_state == 'stable': + xml_name = f'{base_name}.xml' + elif xml_state == 'staging': + xml_name = f'{base_name}-v{version}.xml' + else: + xml_name = f'{base_name}-unstable-v{version}.xml' + + path = os.path.join(self.pkgdatadir, xml_state, base_name, xml_name) + + if not os.path.exists(path): + raise MesonException(f'The file {path} does not exist.') + + return File.from_absolute_file(path) + + +def initialize(interpreter): + return WaylandModule(interpreter) diff --git a/run_project_tests.py b/run_project_tests.py index 926f4ef38..ea8f9016c 100755 --- a/run_project_tests.py +++ b/run_project_tests.py @@ -84,7 +84,7 @@ if T.TYPE_CHECKING: ALL_TESTS = ['cmake', 'common', 'native', 'warning-meson', 'failing-meson', 'failing-build', 'failing-test', 'keyval', 'platform-osx', 'platform-windows', 'platform-linux', 'java', 'C#', 'vala', 'cython', 'rust', 'd', 'objective c', 'objective c++', - 'fortran', 'swift', 'cuda', 'python3', 'python', 'fpga', 'frameworks', 'nasm', 'wasm', + 'fortran', 'swift', 'cuda', 'python3', 'python', 'fpga', 'frameworks', 'nasm', 'wasm', 'wayland' ] @@ -1033,6 +1033,13 @@ def should_skip_rust(backend: Backend) -> bool: return True return False +def should_skip_wayland() -> bool: + if mesonlib.is_windows() or mesonlib.is_osx(): + return True + if not shutil.which('wayland-scanner'): + return True + return False + def detect_tests_to_run(only: T.Dict[str, T.List[str]], use_tmp: bool) -> T.List[T.Tuple[str, T.List[TestDef], bool]]: """ Parameters @@ -1089,6 +1096,7 @@ def detect_tests_to_run(only: T.Dict[str, T.List[str]], use_tmp: bool) -> T.List TestCategory('frameworks', 'frameworks'), TestCategory('nasm', 'nasm'), TestCategory('wasm', 'wasm', shutil.which('emcc') is None or backend is not Backend.ninja), + TestCategory('wayland', 'wayland', should_skip_wayland()), ] categories = [t.category for t in all_tests] diff --git a/test cases/wayland/1 client/main.c b/test cases/wayland/1 client/main.c new file mode 100644 index 000000000..6aca80d98 --- /dev/null +++ b/test cases/wayland/1 client/main.c @@ -0,0 +1,9 @@ +#include "xdg-shell-client-protocol.h" + +int main() { +#ifdef XDG_SHELL_CLIENT_PROTOCOL_H + return 0; +#else + return 1; +#endif +} diff --git a/test cases/wayland/1 client/meson.build b/test cases/wayland/1 client/meson.build new file mode 100644 index 000000000..7ca868b87 --- /dev/null +++ b/test cases/wayland/1 client/meson.build @@ -0,0 +1,16 @@ +project('wayland-test-client', 'c') + +wl_protocols_dep = dependency('wayland-protocols', required : false) +if not wl_protocols_dep.found() + error('MESON_SKIP_TEST: wayland-protocols not installed') +endif + +wl_dep = dependency('wayland-client') +wl_mod = import('unstable-wayland') + +xdg_shell_xml = wl_mod.find_protocol('xdg-shell') +xdg_shell = wl_mod.scan_xml(xdg_shell_xml) + +exe = executable('client', 'main.c', xdg_shell, dependencies : wl_dep) + +test('client', exe) diff --git a/test cases/wayland/2 server/main.c b/test cases/wayland/2 server/main.c new file mode 100644 index 000000000..3307499fa --- /dev/null +++ b/test cases/wayland/2 server/main.c @@ -0,0 +1,9 @@ +#include "xdg-shell-server-protocol.h" + +int main() { +#ifdef XDG_SHELL_SERVER_PROTOCOL_H + return 0; +#else + return 1; +#endif +} diff --git a/test cases/wayland/2 server/meson.build b/test cases/wayland/2 server/meson.build new file mode 100644 index 000000000..c93ff119c --- /dev/null +++ b/test cases/wayland/2 server/meson.build @@ -0,0 +1,16 @@ +project('wayland-test-server', 'c') + +wl_protocols_dep = dependency('wayland-protocols', required : false) +if not wl_protocols_dep.found() + error('MESON_SKIP_TEST: wayland-protocols not installed') +endif + +wl_dep = dependency('wayland-server') +wl_mod = import('unstable-wayland') + +xdg_shell_xml = wl_mod.find_protocol('xdg-shell') +xdg_shell = wl_mod.scan_xml(xdg_shell_xml, side : 'server') + +exe = executable('server', 'main.c', xdg_shell, dependencies : wl_dep) + +test('client', exe) diff --git a/test cases/wayland/3 local/main.c b/test cases/wayland/3 local/main.c new file mode 100644 index 000000000..97bfa56c3 --- /dev/null +++ b/test cases/wayland/3 local/main.c @@ -0,0 +1,9 @@ +#include "test-client-protocol.h" + +int main() { +#ifdef TEST_CLIENT_PROTOCOL_H + return 0; +#else + return 1; +#endif +} diff --git a/test cases/wayland/3 local/meson.build b/test cases/wayland/3 local/meson.build new file mode 100644 index 000000000..7a470d603 --- /dev/null +++ b/test cases/wayland/3 local/meson.build @@ -0,0 +1,11 @@ +project('wayland-test-local', 'c') + +wl_dep = dependency('wayland-client') +wl_mod = import('unstable-wayland') + +xmls = files('test.xml') +gen = wl_mod.scan_xml(xmls) + +exe = executable('local', 'main.c', gen, dependencies : wl_dep) + +test('local', exe) diff --git a/test cases/wayland/3 local/test.xml b/test cases/wayland/3 local/test.xml new file mode 100644 index 000000000..f3c6db1b8 --- /dev/null +++ b/test cases/wayland/3 local/test.xml @@ -0,0 +1,6 @@ + + + + + +