diff --git a/recipes/xkbcommon/all/conanfile.py b/recipes/xkbcommon/all/conanfile.py
index 19621077451e77..88077ccdd7ca0f 100644
--- a/recipes/xkbcommon/all/conanfile.py
+++ b/recipes/xkbcommon/all/conanfile.py
@@ -1,7 +1,11 @@
+import os
+
 from conan import ConanFile
-from conan.tools import scm, files
+from conan.tools.files import copy, get, replace_in_file, rmdir
+from conan.tools.layout import basic_layout
+from conan.tools.meson import Meson, MesonToolchain
+from conan.tools.scm import Version
 from conan.errors import ConanInvalidConfiguration
-from conans import Meson, tools
 
 required_conan_version = ">=1.50.0"
 
@@ -30,20 +34,11 @@ class XkbcommonConan(ConanFile):
         "xkbregistry": True,
     }
 
-    generators = "pkg_config"
-    _meson = None
-
-    @property
-    def _source_subfolder(self):
-        return "source_subfolder"
-
-    @property
-    def _build_subfolder(self):
-        return "build_subfolder"
+    generators = "PkgConfigDeps", "VirtualBuildEnv", "VirtualRunEnv"
 
     @property
     def _has_xkbregistry_option(self):
-        return scm.Version(self.version) >= "1.0.0"
+        return Version(self.version) >= "1.0.0"
 
     def config_options(self):
         if not self._has_xkbregistry_option:
@@ -70,80 +65,97 @@ def validate(self):
             raise ConanInvalidConfiguration("This library is only compatible with Linux or FreeBSD")
 
     def build_requirements(self):
-        self.build_requires("meson/0.63.1")
-        self.build_requires("bison/3.7.6")
-        if hasattr(self, "settings_build") and self.options.get_safe("wayland"):
-            self.build_requires("wayland/1.21.0")
+        self.tool_requires("meson/0.63.0")
+        self.tool_requires("bison/3.7.6")
+        self.tool_requires("pkgconf/1.7.4")
+        if self.options.get_safe("with_wayland"):
+            self.tool_requires("wayland/1.21.0")
+
+    def layout(self):
+        basic_layout(self, src_folder="src")
 
     def source(self):
-        files.get(self, **self.conan_data["sources"][self.version], strip_root=True, destination=self._source_subfolder)
+        get(self, **self.conan_data["sources"][self.version], strip_root=True)
 
-        # Conan doesn't provide a `wayland-scanner.pc` file for the package in the _build_ context
-        files.replace_in_file(self, f"{self._source_subfolder}/meson.build",
-                              "wayland_scanner_dep = dependency('wayland-scanner', required: false, native: true)",
-                              "# wayland_scanner_dep = dependency('wayland-scanner', required: false, native: true)")
-
-        files.replace_in_file(self, f"{self._source_subfolder}/meson.build",
-                              "if not wayland_client_dep.found() or not wayland_protocols_dep.found() or not wayland_scanner_dep.found()",
-                              "if not wayland_client_dep.found() or not wayland_protocols_dep.found()")
-
-        files.replace_in_file(self, f"{self._source_subfolder}/meson.build",
-                              "wayland_scanner = find_program(wayland_scanner_dep.get_pkgconfig_variable('wayland_scanner'))",
-                              "wayland_scanner = find_program('wayland-scanner')")
-
-    def _configure_meson(self):
-        if self._meson:
-            return self._meson
-        defs={
-            "enable-wayland": self.options.get_safe("with_wayland", False),
-            "enable-docs": False,
-            "enable-x11": self.options.with_x11,
-            "libdir": f"{self.package_folder}/lib",
-            "default_library": ("shared" if self.options.shared else "static")}
-        if self._has_xkbregistry_option:
-            defs["enable-xkbregistry"] = self.options.xkbregistry
+    def generate(self):
+        tc = MesonToolchain(self)
+
+        tc.project_options["libexecdir"] = "bin"
+        tc.project_options["libdir"] = "lib"
+        tc.project_options["datadir"] = "res"
+        tc.project_options["mandir"] = "res/man"
 
-        self._meson = Meson(self)
-        self._meson.configure(
-            defs=defs,
-            source_folder=self._source_subfolder,
-            build_folder=self._build_subfolder,
-            pkg_config_paths=self.build_folder)
-        return self._meson
+        tc.project_options["enable-docs"] = False
+        tc.project_options["enable-wayland"] = self.options.get_safe("with_wayland", False)
+        tc.project_options["enable-x11"] = self.options.with_x11
+
+        if self._has_xkbregistry_option:
+            tc.project_options["enable-xkbregistry"] = self.options.xkbregistry
+        tc.generate()
 
     def build(self):
-        with tools.run_environment(self):
-            meson = self._configure_meson()
-            meson.build()
+        # Conan doesn't provide a `wayland-scanner.pc` file for the package in the _build_ context
+        meson_build_file = os.path.join(self.source_folder, "meson.build")
+        replace_in_file(self, meson_build_file,
+                        "wayland_scanner_dep = dependency('wayland-scanner', required: false, native: true)",
+                        "# wayland_scanner_dep = dependency('wayland-scanner', required: false, native: true)")
+
+        replace_in_file(self, meson_build_file,
+                        "if not wayland_client_dep.found() or not wayland_protocols_dep.found() or not wayland_scanner_dep.found()",
+                        "if not wayland_client_dep.found() or not wayland_protocols_dep.found()")
+
+        replace_in_file(self, meson_build_file,
+                        "wayland_scanner = find_program(wayland_scanner_dep.get_pkgconfig_variable('wayland_scanner'))",
+                        "wayland_scanner = find_program('wayland-scanner')")
+
+        meson = Meson(self)
+        meson.configure()
+        meson.build()
 
     def package(self):
-        self.copy(pattern="LICENSE", dst="licenses", src=self._source_subfolder)
-        meson = self._configure_meson()
+        copy(self, "LICENSE", self.source_folder, "licenses")
+        meson = Meson(self)
         meson.install()
-        files.rmdir(self, f"{self.package_folder}/lib/pkgconfig")
-        files.rmdir(self, f"{self.package_folder}/share")
+        rmdir(self, os.path.join(self.package_folder, "lib", "pkgconfig"))
 
     def package_info(self):
         self.cpp_info.components["libxkbcommon"].set_property("pkg_config_name", "xkbcommon")
         self.cpp_info.components["libxkbcommon"].libs = ["xkbcommon"]
         self.cpp_info.components["libxkbcommon"].requires = ["xorg::xkeyboard-config"]
+        self.cpp_info.components["libxkbcommon"].resdirs = ["res"]
+
+        # todo Remove in Conan version 1.50.0 where these are set by default for the PkgConfigDeps generator.
+        self.cpp_info.components["libxkbcommon"].includedirs = ["include"]
+        self.cpp_info.components["libxkbcommon"].libdirs = ["lib"]
+
         if self.options.with_x11:
             self.cpp_info.components["libxkbcommon-x11"].set_property("pkg_config_name", "xkbcommon-x11")
             self.cpp_info.components["libxkbcommon-x11"].libs = ["xkbcommon-x11"]
             self.cpp_info.components["libxkbcommon-x11"].requires = ["libxkbcommon", "xorg::xcb", "xorg::xcb-xkb"]
+
+            # todo Remove in Conan version 1.50.0 where these are set by default for the PkgConfigDeps generator.
+            self.cpp_info.components["libxkbcommon-x11"].includedirs = ["include"]
+            self.cpp_info.components["libxkbcommon-x11"].libdirs = ["lib"]
         if self.options.get_safe("xkbregistry"):
             self.cpp_info.components["libxkbregistry"].set_property("pkg_config_name", "xkbregistry")
             self.cpp_info.components["libxkbregistry"].libs = ["xkbregistry"]
             self.cpp_info.components["libxkbregistry"].requires = ["libxml2::libxml2"]
+
+            # todo Remove in Conan version 1.50.0 where these are set by default for the PkgConfigDeps generator.
+            self.cpp_info.components["libxkbregistry"].includedirs = ["include"]
+            self.cpp_info.components["libxkbregistry"].libdirs = ["lib"]
         if self.options.get_safe("with_wayland", False):
             # FIXME: This generates just executable, but I need to use the requirements to pass Conan checks
             self.cpp_info.components["xkbcli-interactive-wayland"].libs = []
+            self.cpp_info.components["xkbcli-interactive-wayland"].includedirs = []
             self.cpp_info.components["xkbcli-interactive-wayland"].requires = ["wayland::wayland", "wayland-protocols::wayland-protocols"]
 
-        if scm.Version(self.version) >= "1.0.0":
-            bin_path = f"{self.package_folder}/bin"
-            self.output.info(f"Appending PATH environment variable: {bin_path}")
-            self.env_info.PATH.append(bin_path)
+        if Version(self.version) >= "1.0.0":
+            bindir = os.path.join(self.package_folder, "bin")
+            self.buildenv_info.prepend_path("PATH", bindir)
+            self.runenv_info.prepend_path("PATH", bindir)
+            self.output.info(f"Appending PATH environment variable: {bindir}")
+            self.env_info.PATH.append(bindir)
 
         # unofficial, but required to avoid side effects (libxkbcommon component
         # "steals" the default global pkg_config name)
diff --git a/recipes/xkbcommon/all/test_package/CMakeLists.txt b/recipes/xkbcommon/all/test_package/CMakeLists.txt
index 196188113685c8..0b0b6cb9fe82d0 100644
--- a/recipes/xkbcommon/all/test_package/CMakeLists.txt
+++ b/recipes/xkbcommon/all/test_package/CMakeLists.txt
@@ -1,8 +1,7 @@
-cmake_minimum_required(VERSION 3.1)
-project(test_package)
+cmake_minimum_required(VERSION 3.15)
+project(test_package LANGUAGES CXX)
 
-include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
-conan_basic_setup()
+find_package(xkbcommon REQUIRED COMPONENTS libxkbcommon)
 
-add_executable(${PROJECT_NAME} test_package.cpp)
-target_link_libraries(${PROJECT_NAME} ${CONAN_LIBS})
+add_executable(test_package test_package.cpp)
+target_link_libraries(test_package PRIVATE xkbcommon::libxkbcommon)
diff --git a/recipes/xkbcommon/all/test_package/conanfile.py b/recipes/xkbcommon/all/test_package/conanfile.py
index 5c09494bc67c01..eecad0444878e9 100644
--- a/recipes/xkbcommon/all/test_package/conanfile.py
+++ b/recipes/xkbcommon/all/test_package/conanfile.py
@@ -1,10 +1,20 @@
-from conans import ConanFile, CMake, tools
 import os
 
+from conan import ConanFile
+from conan.tools.build import can_run
+from conan.tools.cmake import CMake
+from conan.tools.layout import cmake_layout
+
 
 class TestPackageConan(ConanFile):
     settings = "os", "arch", "compiler", "build_type"
-    generators = "cmake"
+    generators = "CMakeToolchain", "CMakeDeps", "VirtualBuildEnv", "VirtualRunEnv"
+
+    def requirements(self):
+        self.requires(self.tested_reference_str)
+
+    def layout(self):
+        cmake_layout(self)
 
     def build(self):
         cmake = CMake(self)
@@ -12,6 +22,6 @@ def build(self):
         cmake.build()
 
     def test(self):
-        if not tools.cross_building(self):
-            bin_path = os.path.join("bin", "test_package")
-            self.run(bin_path, run_environment=True)
+        if can_run(self):
+            cmd = os.path.join(self.cpp.build.bindirs[0], "test_package")
+            self.run(cmd, env="conanrun")
diff --git a/recipes/xkbcommon/all/test_v1_package/CMakeLists.txt b/recipes/xkbcommon/all/test_v1_package/CMakeLists.txt
new file mode 100644
index 00000000000000..16dc0ecfa5a2ea
--- /dev/null
+++ b/recipes/xkbcommon/all/test_v1_package/CMakeLists.txt
@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION 3.1)
+project(test_package)
+
+include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
+conan_basic_setup()
+
+add_executable(${PROJECT_NAME} test_package.cpp)
+target_link_libraries(${PROJECT_NAME} ${CONAN_LIBS})
\ No newline at end of file
diff --git a/recipes/xkbcommon/all/test_v1_package/conanfile.py b/recipes/xkbcommon/all/test_v1_package/conanfile.py
new file mode 100644
index 00000000000000..e532c741b9e198
--- /dev/null
+++ b/recipes/xkbcommon/all/test_v1_package/conanfile.py
@@ -0,0 +1,19 @@
+import os
+
+from conans import ConanFile, CMake
+from conan.tools.build import cross_building
+
+
+class TestPackageConan(ConanFile):
+    settings = "os", "arch", "compiler", "build_type"
+    generators = "cmake"
+
+    def build(self):
+        cmake = CMake(self)
+        cmake.configure()
+        cmake.build()
+
+    def test(self):
+        if not cross_building(self):
+            bin_path = os.path.join("bin", "test_package")
+            self.run(bin_path, run_environment=True)
\ No newline at end of file