Repository: conan-io/conan
Pull request #15919 (2024-03-22 10:05:57)

[MesonToolchain] Added `native` mechanism when cross-building
Changelog: Feature: MesonToolchain can generate a native file if native=True (only makes sense when cross-building).
Changelog: Feature: Meson helper injects native and cross files if both exist.
Docs: https://github.com/conan-io/docs/pull/XXXX
Closes: https://github.com/conan-io/conan/issues/15878



Patch:
diff --git a/conan/tools/cmake/cmake.py b/conan/tools/cmake/cmake.py
index 02a80b39c..6af622fc4 100644
--- a/conan/tools/cmake/cmake.py
+++ b/conan/tools/cmake/cmake.py
@@ -85,10 +85,9 @@ class CMake(object):
         cmakelist_folder = self._conanfile.source_folder
         if build_script_folder:
             cmakelist_folder = os.path.join(self._conanfile.source_folder, build_script_folder)
+        cmakelist_folder = cmakelist_folder.replace("\\", "/")
 
         build_folder = self._conanfile.build_folder
-        generator_folder = self._conanfile.generators_folder
-
         mkdir(self._conanfile, build_folder)
 
         arg_list = [self._cmake_program]
diff --git a/conan/tools/meson/meson.py b/conan/tools/meson/meson.py
index 13541bc43..3003f9319 100644
--- a/conan/tools/meson/meson.py
+++ b/conan/tools/meson/meson.py
@@ -29,24 +29,22 @@ class Meson(object):
                                            " Removing in Conan 2.x.", warn_tag="deprecated")
         source_folder = self._conanfile.source_folder
         build_folder = self._conanfile.build_folder
-        cmd = "meson setup"
         generators_folder = self._conanfile.generators_folder
         cross = os.path.join(generators_folder, MesonToolchain.cross_filename)
         native = os.path.join(generators_folder, MesonToolchain.native_filename)
-        meson_filenames = []
-        if os.path.exists(cross):
-            cmd_param = " --cross-file"
-            meson_filenames.append(cross)
-        else:
-            cmd_param = " --native-file"
-            meson_filenames.append(native)
-
+        is_cross_build = os.path.exists(cross)
         machine_files = self._conanfile.conf.get("tools.meson.mesontoolchain:extra_machine_files",
                                                  default=[], check_type=list)
-        if machine_files:
-            meson_filenames.extend(machine_files)
-
-        cmd += "".join([f'{cmd_param} "{meson_option}"' for meson_option in meson_filenames])
+        cmd = "meson setup "
+        if is_cross_build:
+            machine_files.insert(0, cross)
+            cmd += "".join([f'--cross-file "{file}"' for file in machine_files])
+        if os.path.exists(native):
+            if not is_cross_build:  # machine files are only appended to the cross or the native one
+                machine_files.insert(0, native)
+                cmd += "".join([f'--native-file "{file}"' for file in machine_files])
+            else:  # extra native file for cross-building scenarios
+                cmd += f' --native-file "{native}"'
         cmd += ' "{}" "{}"'.format(build_folder, source_folder)
         # Issue related: https://github.com/mesonbuild/meson/issues/12880
         cmd += ' --prefix=/'  # this must be an absolute path, otherwise, meson complains
diff --git a/conan/tools/meson/toolchain.py b/conan/tools/meson/toolchain.py
index 80f133387..586e9afbc 100644
--- a/conan/tools/meson/toolchain.py
+++ b/conan/tools/meson/toolchain.py
@@ -1,7 +1,7 @@
 import os
 import textwrap
 
-from jinja2 import Template
+from jinja2 import Template, StrictUndefined
 
 from conan.errors import ConanException
 from conan.internal import check_duplicated_generator
@@ -20,11 +20,10 @@ class MesonToolchain(object):
     """
     MesonToolchain generator
     """
-
     native_filename = "conan_meson_native.ini"
     cross_filename = "conan_meson_cross.ini"
 
-    _meson_file_template = textwrap.dedent("""
+    _meson_file_template = textwrap.dedent("""\
     [properties]
     {% for it, value in properties.items() -%}
     {{it}} = {{value}}
@@ -49,33 +48,76 @@ class MesonToolchain(object):
     {% endfor %}
 
     [binaries]
-    {% if c %}c = {{c}}{% endif %}
-    {% if cpp %}cpp = {{cpp}}{% endif %}
-    {% if ld %}ld = {{ld}}{% endif %}
+    {% if c %}
+    c = {{c}}
+    {% endif %}
+    {% if cpp %}
+    cpp = {{cpp}}
+    {% endif %}
+    {% if ld %}
+    ld = {{ld}}
+    {% endif %}
     {% if is_apple_system %}
-    {% if objc %}objc = '{{objc}}'{% endif %}
-    {% if objcpp %}objcpp = '{{objcpp}}'{% endif %}
+    {% if objc %}
+    objc = '{{objc}}'
+    {% endif %}
+    {% if objcpp %}
+    objcpp = '{{objcpp}}'
+    {% endif %}
+    {% endif %}
+    {% if c_ld %}
+    c_ld = '{{c_ld}}'
+    {% endif %}
+    {% if cpp_ld %}
+    cpp_ld = '{{cpp_ld}}'
+    {% endif %}
+    {% if ar %}
+    ar = '{{ar}}'
+    {% endif %}
+    {% if strip %}
+    strip = '{{strip}}'
+    {% endif %}
+    {% if as %}
+    as = '{{as}}'
+    {% endif %}
+    {% if windres %}
+    windres = '{{windres}}'
+    {% endif %}
+    {% if pkgconfig %}
+    pkgconfig = '{{pkgconfig}}'
+    {% endif %}
+    {% if pkgconfig %}
+    pkg-config = '{{pkgconfig}}'
     {% endif %}
-    {% if c_ld %}c_ld = '{{c_ld}}'{% endif %}
-    {% if cpp_ld %}cpp_ld = '{{cpp_ld}}'{% endif %}
-    {% if ar %}ar = '{{ar}}'{% endif %}
-    {% if strip %}strip = '{{strip}}'{% endif %}
-    {% if as %}as = '{{as}}'{% endif %}
-    {% if windres %}windres = '{{windres}}'{% endif %}
-    {% if pkgconfig %}pkgconfig = '{{pkgconfig}}'{% endif %}
-    {% if pkgconfig %}pkg-config = '{{pkgconfig}}'{% endif %}
 
     [built-in options]
-    {% if buildtype %}buildtype = '{{buildtype}}'{% endif %}
-    {% if debug %}debug = {{debug}}{% endif %}
-    {% if default_library %}default_library = '{{default_library}}'{% endif %}
-    {% if b_vscrt %}b_vscrt = '{{b_vscrt}}' {% endif %}
-    {% if b_ndebug %}b_ndebug = {{b_ndebug}}{% endif %}
-    {% if b_staticpic %}b_staticpic = {{b_staticpic}}{% endif %}
-    {% if cpp_std %}cpp_std = '{{cpp_std}}' {% endif %}
-    {% if backend %}backend = '{{backend}}' {% endif %}
-    {% if pkg_config_path %}pkg_config_path = '{{pkg_config_path}}'{% endif %}
-    {% if build_pkg_config_path %}build.pkg_config_path = '{{build_pkg_config_path}}'{% endif %}
+    {% if buildtype %}
+    buildtype = '{{buildtype}}'
+    {% endif %}
+    {% if default_library %}
+    default_library = '{{default_library}}'
+    {% endif %}
+    {% if b_vscrt %}
+    b_vscrt = '{{b_vscrt}}'
+    {% endif %}
+    {% if b_ndebug %}
+    b_ndebug = {{b_ndebug}}
+    {% endif %}
+    {% if b_staticpic %}
+    b_staticpic = {{b_staticpic}}
+    {% endif %}
+    {% if cpp_std %}
+    cpp_std = '{{cpp_std}}'
+    {% endif %}
+    {% if backend %}
+    backend = '{{backend}}'
+    {% endif %}
+    {% if pkg_config_path %}
+    pkg_config_path = '{{pkg_config_path}}'
+    {% endif %}
+    {% if build_pkg_config_path %}
+    build.pkg_config_path = '{{build_pkg_config_path}}'
+    {% endif %}
     # C/C++ arguments
     c_args = {{c_args}} + preprocessor_definitions
     c_link_args = {{c_link_args}}
@@ -98,16 +140,20 @@ class MesonToolchain(object):
     {% endfor %}
     """)
 
-    def __init__(self, conanfile, backend=None):
+    def __init__(self, conanfile, backend=None, native=False):
         """
         :param conanfile: ``< ConanFile object >`` The current recipe object. Always use ``self``.
         :param backend: ``str`` ``backend`` Meson variable value. By default, ``ninja``.
         """
         raise_on_universal_arch(conanfile)
         self._conanfile = conanfile
-        self._os = self._conanfile.settings.get_safe("os")
+        self._native = native
         self._is_apple_system = is_apple_os(self._conanfile)
-
+        is_cross_building = cross_building(conanfile, skip_x64_x86=True)
+        if not is_cross_building and native:
+            raise ConanException("You can only pass native=True if you're cross-building, "
+                                 "otherwise, it could cause unexpected results.")
+        self._conanfile_conf = self._conanfile.conf_build if native else self._conanfile.conf
         # Values are kept as Python built-ins so users can modify them more easily, and they are
         # only converted to Meson file syntax for rendering
         # priority: first user conf, then recipe, last one is default "ninja"
@@ -163,12 +209,11 @@ class MesonToolchain(object):
         # Issue: https://github.com/conan-io/conan/issues/14935
         self.build_pkg_config_path = None
         self.libcxx, self.gcc_cxx11_abi = libcxx_flags(self._conanfile)
-
         #: Dict-like object with the build, host, and target as the Meson machine context
         self.cross_build = {}
         default_comp = ""
         default_comp_cpp = ""
-        if cross_building(conanfile, skip_x64_x86=True):
+        if native is False and is_cross_building:
             os_host = conanfile.settings.get_safe("os")
             arch_host = conanfile.settings.get_safe("arch")
             os_build = conanfile.settings_build.get_safe('os')
@@ -197,10 +242,11 @@ class MesonToolchain(object):
             default_comp_cpp = "cl"
 
         # Read configuration for compilers
-        compilers_by_conf = self._conanfile.conf.get("tools.build:compiler_executables", default={},
+        compilers_by_conf = self._conanfile_conf.get("tools.build:compiler_executables", default={},
                                                      check_type=dict)
         # Read the VirtualBuildEnv to update the variables
-        build_env = VirtualBuildEnv(self._conanfile, auto_generate=True).vars()
+        build_env = self._conanfile.buildenv_build.vars(self._conanfile) if native else (
+            VirtualBuildEnv(self._conanfile, auto_generate=True).vars())
         #: Sets the Meson ``c`` variable, defaulting to the ``CC`` build environment value.
         #: If provided as a blank-separated string, it will be transformed into a list.
         #: Otherwise, it remains a single string.
@@ -232,7 +278,7 @@ class MesonToolchain(object):
         self.windres = build_env.get("WINDRES")
         #: Defines the Meson ``pkgconfig`` variable. Defaulted to ``PKG_CONFIG``
         #: build environment value
-        self.pkgconfig = (self._conanfile.conf.get("tools.gnu:pkg_config", check_type=str) or
+        self.pkgconfig = (self._conanfile_conf.get("tools.gnu:pkg_config", check_type=str) or
                           build_env.get("PKG_CONFIG"))
         #: Defines the Meson ``c_args`` variable. Defaulted to ``CFLAGS`` build environment value
         self.c_args = self._get_env_list(build_env.get("CFLAGS", []))
@@ -266,7 +312,8 @@ class MesonToolchain(object):
         self.objcpp_link_args = []
 
         self._resolve_apple_flags_and_variables(build_env, compilers_by_conf)
-        self._resolve_android_cross_compilation()
+        if native is False:
+            self._resolve_android_cross_compilation()
 
     def _get_default_dirs(self):
         """
@@ -309,7 +356,7 @@ class MesonToolchain(object):
             return
         # Calculating the main Apple flags
         min_flag, arch_flag, isysroot_flag = (
-            resolve_apple_flags(self._conanfile, is_cross_building=bool(self.cross_build)))
+            resolve_apple_flags(self._conanfile, is_cross_building=self.cross_build))
         self.apple_arch_flag = arch_flag.split() if arch_flag else []
         self.apple_isysroot_flag = isysroot_flag.split() if isysroot_flag else []
         self.apple_min_version_flag = [apple_min_version_flag(self._conanfile)]
@@ -325,7 +372,7 @@ class MesonToolchain(object):
         if not self.cross_build or not self.cross_build["host"]["system"] == "android":
             return
 
-        ndk_path = self._conanfile.conf.get("tools.android:ndk_path")
+        ndk_path = self._conanfile_conf.get("tools.android:ndk_path")
         if not ndk_path:
             raise ConanException("You must provide a NDK path. Use 'tools.android:ndk_path' "
                                  "configuration field.")
@@ -346,11 +393,11 @@ class MesonToolchain(object):
 
     def _get_extra_flags(self):
         # Now, it's time to get all the flags defined by the user
-        cxxflags = self._conanfile.conf.get("tools.build:cxxflags", default=[], check_type=list)
-        cflags = self._conanfile.conf.get("tools.build:cflags", default=[], check_type=list)
-        sharedlinkflags = self._conanfile.conf.get("tools.build:sharedlinkflags", default=[], check_type=list)
-        exelinkflags = self._conanfile.conf.get("tools.build:exelinkflags", default=[], check_type=list)
-        linker_scripts = self._conanfile.conf.get("tools.build:linker_scripts", default=[], check_type=list)
+        cxxflags = self._conanfile_conf.get("tools.build:cxxflags", default=[], check_type=list)
+        cflags = self._conanfile_conf.get("tools.build:cflags", default=[], check_type=list)
+        sharedlinkflags = self._conanfile_conf.get("tools.build:sharedlinkflags", default=[], check_type=list)
+        exelinkflags = self._conanfile_conf.get("tools.build:exelinkflags", default=[], check_type=list)
+        linker_scripts = self._conanfile_conf.get("tools.build:linker_scripts", default=[], check_type=list)
         linker_script_flags = ['-T"' + linker_script + '"' for linker_script in linker_scripts]
         defines = [f"-D{d}" for d in self._conanfile.conf.get("tools.build:defines", default=[], check_type=list)]
         return {
@@ -450,6 +497,15 @@ class MesonToolchain(object):
             "is_apple_system": self._is_apple_system
         }
 
+    @property
+    def _filename(self):
+        if self.cross_build and self._native:
+            return self.native_filename
+        elif self.cross_build:
+            return self.cross_filename
+        else:
+            return self.native_filename
+
     @property
     def _content(self):
         """
@@ -458,7 +514,8 @@ class MesonToolchain(object):
         :return: ``str`` whole Meson context content.
         """
         context = self._context()
-        content = Template(self._meson_file_template).render(context)
+        content = Template(self._meson_file_template, trim_blocks=True, lstrip_blocks=True,
+                           undefined=StrictUndefined).render(context)
         return content
 
     def generate(self):
@@ -468,7 +525,6 @@ class MesonToolchain(object):
         If Windows OS, it will be created a ``conanvcvars.bat`` as well.
         """
         check_duplicated_generator(self, self._conanfile)
-        filename = self.native_filename if not self.cross_build else self.cross_filename
-        save(filename, self._content)
+        save(self._filename, self._content)
         # FIXME: Should we check the OS and compiler to call VCVars?
         VCVars(self._conanfile).generate()
diff --git a/conans/client/graph/profile_node_definer.py b/conans/client/graph/profile_node_definer.py
index 548c4596e..2b905ef0c 100644
--- a/conans/client/graph/profile_node_definer.py
+++ b/conans/client/graph/profile_node_definer.py
@@ -26,8 +26,13 @@ def initialize_conanfile_profile(conanfile, profile_build, profile_host, base_co
     settings_build = _per_package_settings(conanfile, profile_build, ref)
     if is_build_require or base_context == CONTEXT_BUILD:
         _initialize_conanfile(conanfile, profile_build, settings_build.copy(), ref)
+        conanfile.buildenv_build = None
+        conanfile.conf_build = None
     else:
         _initialize_conanfile(conanfile, profile_host, settings_host, ref)
+        # Host profile with some build profile information
+        conanfile.buildenv_build = profile_build.buildenv.get_profile_env(ref, conanfile._conan_is_consumer)
+        conanfile.conf_build = profile_build.conf.get_conanfile_conf(ref, conanfile._conan_is_consumer)
     conanfile.settings_build = settings_build
     conanfile.settings_target = None
 
diff --git a/conans/model/conan_file.py b/conans/model/conan_file.py
index 554d0938a..03118d236 100644
--- a/conans/model/conan_file.py
+++ b/conans/model/conan_file.py
@@ -9,7 +9,6 @@ from conans.model.conf import Conf
 from conans.model.dependencies import ConanFileDependencies
 from conans.model.layout import Folders, Infos, Layouts
 from conans.model.options import Options
-
 from conans.model.requires import Requirements
 from conans.model.settings import Settings
 
diff --git a/pyinstaller.py b/pyinstaller.py
index 013406198..da754f7ea 100644
--- a/pyinstaller.py
+++ b/pyinstaller.py
@@ -19,20 +19,12 @@ import argparse
 import os
 import platform
 import shutil
-import subprocess
 import sys
 
 from conans import __version__
 from conans.util.files import save
 
 
-def _install_pyinstaller(pyinstaller_path):
-    subprocess.call(f"{sys.executable} -m pip install pyinstaller", shell=True)
-    # try to install pyinstaller if not installed
-    if not os.path.exists(pyinstaller_path):
-        os.mkdir(pyinstaller_path)
-
-
 def _run_bin(pyinstaller_path):
     # run the binary to test if working
     conan_bin = os.path.join(pyinstaller_path, 'dist', 'conan', 'conan')
@@ -93,9 +85,16 @@ VSVersionInfo(
 
 
 def pyinstall(source_folder, onefile=False):
-    pyinstaller_path = os.path.join(os.getcwd(), 'pyinstaller')
-    _install_pyinstaller(pyinstaller_path)
+    try:
+        import PyInstaller.__main__  # noqa  Pyinstaller is not in the default requirements.txt
+    except ImportError:
+        print(f"ERROR: PyInstaller not found. Please install it with "
+              f"'python -m pip install pyinstaller'")
+        sys.exit(-1)
 
+    pyinstaller_path = os.path.join(os.getcwd(), 'pyinstaller')
+    if not os.path.exists(pyinstaller_path):
+        os.mkdir(pyinstaller_path)
     try:
         shutil.rmtree(os.path.join(pyinstaller_path))
     except Exception as e:
@@ -133,14 +132,14 @@ def pyinstall(source_folder, onefile=False):
     else:
         distpath = os.path.join(pyinstaller_path, "dist")
 
-    command_args = [conan_path, "--noconfirm", f"--paths={source_folder}",  "--console", f"--distpath={distpath}"]
+    command_args = [conan_path, "--noconfirm", f"--paths={source_folder}",
+                    "--console", f"--distpath={distpath}"]
     command_args.extend(hidden.split(" "))
     if win_ver:
         command_args.extend(win_ver)
     if onefile:
         command_args.append("--onefile")
 
-    import PyInstaller.__main__
     PyInstaller.__main__.run(command_args)
 
     _run_bin(pyinstaller_path)


Test patch:
diff --git a/conans/test/functional/toolchains/meson/test_meson_native_attribute.py b/conans/test/functional/toolchains/meson/test_meson_native_attribute.py
new file mode 100644
index 000000000..a35c12861
--- /dev/null
+++ b/conans/test/functional/toolchains/meson/test_meson_native_attribute.py
@@ -0,0 +1,98 @@
+import os
+import platform
+import textwrap
+
+import pytest
+
+from conan.tools.apple.apple import _to_apple_arch, XCRun
+from conans.test.assets.sources import gen_function_cpp, gen_function_h
+from conans.test.utils.mocks import ConanFileMock
+from conans.test.utils.tools import TestClient
+from conans.util.runners import conan_run
+
+
+@pytest.mark.tool("meson")
+@pytest.mark.skipif(platform.system() != "Darwin", reason="requires OSX")
+def test_apple_meson_toolchain_cross_compiling():
+    arch_host = 'armv8' if platform.machine() == "x86_64" else "x86_64"
+    arch_build = 'armv8' if platform.machine() != "x86_64" else "x86_64"
+    profile = textwrap.dedent(f"""
+    [settings]
+    os = Macos
+    arch = {arch_host}
+    compiler = apple-clang
+    compiler.version = 13.0
+    compiler.libcxx = libc++
+    """)
+    profile_build = textwrap.dedent(f"""
+    [settings]
+    os = Macos
+    arch = {arch_build}
+    compiler = apple-clang
+    compiler.version = 13.0
+    compiler.libcxx = libc++
+    """)
+    conanfile_py = textwrap.dedent("""
+    from conan import ConanFile
+    from conan.tools.meson import Meson, MesonToolchain
+    from conan.tools.build import cross_building
+
+    class App(ConanFile):
+        settings = "os", "arch", "compiler", "build_type"
+        options = {"shared": [True, False], "fPIC": [True, False]}
+        default_options = {"shared": False, "fPIC": True}
+
+        def layout(self):
+            self.folders.build = "build"
+
+        def config_options(self):
+            if self.settings.os == "Windows":
+                self.options.rm_safe("fPIC")
+
+        def configure(self):
+            if self.options.shared:
+                self.options.rm_safe("fPIC")
+
+        def generate(self):
+            tc = MesonToolchain(self)
+            tc.generate()
+            # Forcing to create the native context too
+            if cross_building(self):
+                tc = MesonToolchain(self, native=True)
+                tc.generate()
+
+        def build(self):
+            meson = Meson(self)
+            meson.configure()
+            meson.build()
+    """)
+    meson_build = textwrap.dedent("""
+    project('tutorial', 'cpp')
+    hello = library('hello', 'hello.cpp')
+    # Even cross-building the library, we want to create an executable using only the native context
+    executable('mygen', 'mygen.cpp', native: true)
+    """)
+    my_gen_cpp = gen_function_cpp(name="main")
+    hello_h = gen_function_h(name="hello")
+    hello_cpp = gen_function_cpp(name="hello")
+    client = TestClient()
+    client.save({"conanfile.py": conanfile_py,
+                 "meson.build": meson_build,
+                 "hello.h": hello_h,
+                 "hello.cpp": hello_cpp,
+                 "mygen.cpp": my_gen_cpp,
+                 "profile_host": profile,
+                 "profile_build": profile_build})
+    client.run("build . --profile:build=profile_build --profile:host=profile_host")
+    libhello = os.path.join(client.current_folder, "build", "libhello.a")
+    assert os.path.isfile(libhello) is True
+    # Now, ensuring that we can run the mygen executable
+    mygen = os.path.join(client.current_folder, "build", "mygen")
+    client.run_command(f"'{mygen}'")
+    assert "Release!" in client.out
+    # Extra check for lib arch
+    conanfile = ConanFileMock({}, runner=conan_run)
+    xcrun = XCRun(conanfile)
+    lipo = xcrun.find('lipo')
+    client.run_command('"%s" -info "%s"' % (lipo, libhello))
+    assert "architecture: %s" % _to_apple_arch(arch_host) in client.out
diff --git a/conans/test/integration/toolchains/gnu/test_pkgconfigdeps.py b/conans/test/integration/toolchains/gnu/test_pkgconfigdeps.py
index 31d10d756..eacad9411 100644
--- a/conans/test/integration/toolchains/gnu/test_pkgconfigdeps.py
+++ b/conans/test/integration/toolchains/gnu/test_pkgconfigdeps.py
@@ -227,6 +227,55 @@ def test_custom_content_and_version_components():
     assert "componentdir=${prefix}/mydir" in pc_content
     assert "Version: 19.8.199" in pc_content
 
+    # Now with lockfile
+    # https://github.com/conan-io/conan/issues/16197
+    lockfile = textwrap.dedent("""
+        {
+            "version": "0.5",
+            "requires": [
+                "pkg/0.1#9a5fed2bf506fd28817ddfbc92b07fc1"
+            ]
+        }
+        """)
+    client.save({"conan.lock": lockfile})
+    client.run("install --requires=pkg/0.1 -g PkgConfigDeps --lockfile=conan.lock")
+    pc_content = client.load("pkg-mycomponent.pc")
+    assert "componentdir=${prefix}/mydir" in pc_content
+    assert "Version: 19.8.199" in pc_content
+
+
+def test_custom_version():
+    # https://github.com/conan-io/conan/issues/16197
+    conanfile = textwrap.dedent("""
+        from conan import ConanFile
+
+        class PkgConfigConan(ConanFile):
+            def package_info(self):
+                self.cpp_info.set_property("system_package_version", "19.8.199")
+        """)
+    client = TestClient()
+    client.save({"conanfile.py": conanfile})
+    client.run("create . --name=pkg --version=0.1")
+    client.run("install --requires=pkg/0.1 -g PkgConfigDeps")
+
+    pc_content = client.load("pkg.pc")
+    assert "Version: 19.8.199" in pc_content
+
+    # Now with lockfile
+    # https://github.com/conan-io/conan/issues/16197
+    lockfile = textwrap.dedent("""
+        {
+            "version": "0.5",
+            "requires": [
+                "pkg/0.1#0fe93a852dd6a177bca87cb2d4491a18"
+            ]
+        }
+        """)
+    client.save({"conan.lock": lockfile})
+    client.run("install --requires=pkg/0.1 -g PkgConfigDeps --lockfile=conan.lock")
+    pc_content = client.load("pkg.pc")
+    assert "Version: 19.8.199" in pc_content
+
 
 def test_pkg_with_public_deps_and_component_requires():
     """
diff --git a/conans/test/integration/toolchains/meson/test_mesontoolchain.py b/conans/test/integration/toolchains/meson/test_mesontoolchain.py
index 740cb931d..21bd02c59 100644
--- a/conans/test/integration/toolchains/meson/test_mesontoolchain.py
+++ b/conans/test/integration/toolchains/meson/test_mesontoolchain.py
@@ -4,6 +4,7 @@ import textwrap
 
 import pytest
 
+from conan.tools.files import load
 from conan.tools.meson import MesonToolchain
 from conans.test.utils.tools import TestClient
 
@@ -418,3 +419,101 @@ def test_subproject_options():
     assert "option2 = 'disabled'" in content
     assert "option3 = 'enabled'" in content
     assert "option4 = 'disabled'" in content
+
+
+def test_native_attribute():
+    """
+    Tests that native file only has the build context (not as a build require) content.
+    """
+    host = textwrap.dedent("""
+    [settings]
+    arch=armv8
+    build_type=Release
+    compiler=gcc
+    compiler.cppstd=gnu17
+    compiler.libcxx=libstdc++11
+    compiler.version=11
+    os=Linux
+
+    [buildenv]
+    STRIP=False
+    PKG_CONFIG=/usr/bin/pkg-config
+
+    [conf]
+    tools.build:compiler_executables={"c": "gcc", "cpp": "g++"}
+    """)
+    build = textwrap.dedent("""
+    [settings]
+    os=Linux
+    arch=x86_64
+    compiler=clang
+    compiler.version=12
+    compiler.libcxx=libc++
+    compiler.cppstd=11
+
+    [buildenv]
+    STRIP=True
+    PKG_CONFIG=/usr/lib/meson/pkgconfig
+
+    [conf]
+    tools.build:compiler_executables={"c": "clang", "cpp": "clang++"}
+    """)
+    client = TestClient()
+    conanfile = textwrap.dedent("""
+    from conan import ConanFile
+    from conan.tools.meson import MesonToolchain
+    class Pkg(ConanFile):
+        settings = "os", "compiler", "arch", "build_type"
+        def generate(self):
+            tc = MesonToolchain(self)
+            tc.generate()
+            # We're cross-building, no need to check it
+            tc = MesonToolchain(self, native=True)
+            tc.generate()
+    """)
+    client.save({"host": host,
+                 "build": build,
+                 "conanfile.py": conanfile})
+    client.run("install . -pr:h host -pr:b build")
+    native_content = load(None, os.path.join(client.current_folder, MesonToolchain.native_filename))
+    cross_content = load(None, os.path.join(client.current_folder, MesonToolchain.cross_filename))
+    expected_native = textwrap.dedent("""
+    [binaries]
+    c = 'clang'
+    cpp = 'clang++'
+    strip = 'True'
+    pkgconfig = '/usr/lib/meson/pkgconfig'
+    pkg-config = '/usr/lib/meson/pkgconfig'
+    """)
+    expected_cross = textwrap.dedent("""
+    [binaries]
+    c = 'gcc'
+    cpp = 'g++'
+    strip = 'False'
+    pkgconfig = '/usr/bin/pkg-config'
+    pkg-config = '/usr/bin/pkg-config'
+    """)
+    assert expected_native in native_content
+    assert "[host_machine]" not in native_content
+    assert "[build_machine]" not in native_content
+    assert expected_cross in cross_content
+    assert "[build_machine]" in cross_content
+    assert "[host_machine]" in cross_content
+
+
+def test_native_attribute_error():
+    client = TestClient()
+    conanfile = textwrap.dedent("""
+    from conan import ConanFile
+    from conan.tools.meson import MesonToolchain
+    class Pkg(ConanFile):
+        settings = "os", "compiler", "arch", "build_type"
+        def generate(self):
+            tc = MesonToolchain(self)
+            tc.generate()
+            tc = MesonToolchain(self, native=True)
+            tc.generate()
+    """)
+    client.save({"conanfile.py": conanfile})
+    client.run("install .", assert_error=True)
+    assert "You can only pass native=True if you're cross-building" in client.out
diff --git a/conans/test/unittests/tools/cmake/test_cmake_presets_definitions.py b/conans/test/unittests/tools/cmake/test_cmake_presets_definitions.py
index ff1cdaa6b..8e06972d4 100644
--- a/conans/test/unittests/tools/cmake/test_cmake_presets_definitions.py
+++ b/conans/test/unittests/tools/cmake/test_cmake_presets_definitions.py
@@ -45,6 +45,7 @@ def test_cmake_make_program(conanfile):
         assert '-DCMAKE_MAKE_PROGRAM="C:/mymake.exe"' in command
 
     conanfile.run = run
+    conanfile.folders.set_base_source(temp_folder())
     conanfile.conf.define("tools.gnu:make_program", "C:\\mymake.exe")
 
     with mock.patch("platform.system", mock.MagicMock(return_value='Windows')):