Repository: conan-io/conan
Pull request #12609 (2022-11-25 13:14:16)

Set some CMakeDeps properties from consumer
Changelog: Feature: Set some CMakeDeps properties from consumer
Docs: TODO

Gives you the possibility to overwrite some properties set in dependencies in CMakeDeps: `cmake_file_name`, `cmake_target_name`, `cmake_find_mode`, `cmake_module_file_name` and `cmake_module_target_name`

The interface is:

```
def generate(self):
    deps = CMakeDeps(self)
    deps.set_property("<dep>", "cmake_find_mode", "module")
    deps.set_property("<dep>::<component>",  "cmake_target_name", "mycompname")
    deps.generate()
```
for the cases with `build_context_activated`:

```
def generate(self):
    ...
    deps = CMakeDeps(self)
    deps.set_property("<dep>", "cmake_find_mode", "module", build_context=True)
    deps.set_property("<dep>::<component>",  "cmake_target_name", "mycompname", build_context=True)
    deps.generate()
    ...
```

You can also invalidate from consumer the properties set upstream assigning a `None`:

```
def generate(self):
    ...
    deps.set_property("<dep>", "cmake_module_target_name",  None)
```

Closes: https://github.com/conan-io/conan/issues/12534
Close https://github.com/conan-io/conan/issues/7118



SpaceIm: Looks very promising for conan-center as well, to avoid breakage in recipes when their dependencies break these properties (for example when suddenly a new version of a library implements a CMake config file, we have to update these names in this recipe, but it can break downstream recipes which were relying on default values `<recipeName>-config.cmake` & target `<recipeName>::<recipeName>`).

Patch:
diff --git a/conan/tools/cmake/cmakedeps/cmakedeps.py b/conan/tools/cmake/cmakedeps/cmakedeps.py
index 0306575cb..75751841c 100644
--- a/conan/tools/cmake/cmakedeps/cmakedeps.py
+++ b/conan/tools/cmake/cmakedeps/cmakedeps.py
@@ -32,6 +32,7 @@ class CMakeDeps(object):
 
         # Enable/Disable checking if a component target exists or not
         self.check_components_exist = False
+        self._properties = {}
 
     def generate(self):
         # FIXME: Remove this in 2.0
@@ -76,7 +77,7 @@ class CMakeDeps(object):
             if dep.is_build_context and dep.ref.name not in self.build_context_activated:
                 continue
 
-            cmake_find_mode = dep.cpp_info.get_property("cmake_find_mode")
+            cmake_find_mode = self.get_property("cmake_find_mode", dep)
             cmake_find_mode = cmake_find_mode or FIND_MODE_CONFIG
             cmake_find_mode = cmake_find_mode.lower()
             # Skip from the requirement
@@ -112,3 +113,41 @@ class CMakeDeps(object):
         # file is common for the different configurations.
         if not os.path.exists(config.filename):
             ret[config.filename] = config.render()
+
+    def set_property(self, dep, prop, value, build_context=False):
+        build_suffix = "&build" if build_context else ""
+        self._properties.setdefault(f"{dep}{build_suffix}", {}).update({prop: value})
+
+    def get_property(self, prop, dep, comp_name=None):
+        dep_name = dep.ref.name
+        build_suffix = "&build" if str(
+            dep_name) in self.build_context_activated and dep.context == "build" else ""
+        dep_comp = f"{str(dep_name)}::{comp_name}" if comp_name else f"{str(dep_name)}"
+        try:
+            return self._properties[f"{dep_comp}{build_suffix}"][prop]
+        except KeyError:
+            return dep.cpp_info.get_property(prop) if not comp_name else dep.cpp_info.components[
+                comp_name].get_property(prop)
+
+    def get_cmake_package_name(self, dep, module_mode=None):
+        """Get the name of the file for the find_package(XXX)"""
+        # This is used by CMakeDeps to determine:
+        # - The filename to generate (XXX-config.cmake or FindXXX.cmake)
+        # - The name of the defined XXX_DIR variables
+        # - The name of transitive dependencies for calls to find_dependency
+        if module_mode and self.get_find_mode(dep) in [FIND_MODE_MODULE, FIND_MODE_BOTH]:
+            ret = self.get_property("cmake_module_file_name", dep)
+            if ret:
+                return ret
+        ret = self.get_property("cmake_file_name", dep)
+        return ret or dep.ref.name
+
+    def get_find_mode(self, dep):
+        """
+        :param dep: requirement
+        :return: "none" or "config" or "module" or "both" or "config" when not set
+        """
+        tmp = self.get_property("cmake_find_mode", dep)
+        if tmp is None:
+            return "config"
+        return tmp.lower()
diff --git a/conan/tools/cmake/cmakedeps/templates/__init__.py b/conan/tools/cmake/cmakedeps/templates/__init__.py
index 05415e983..7e11bd861 100644
--- a/conan/tools/cmake/cmakedeps/templates/__init__.py
+++ b/conan/tools/cmake/cmakedeps/templates/__init__.py
@@ -1,7 +1,6 @@
 import jinja2
 from jinja2 import Template
 
-from conan.tools.cmake.utils import get_cmake_package_name
 from conans.errors import ConanException
 
 
@@ -23,7 +22,7 @@ class CMakeDepsFileTemplate(object):
 
     @property
     def file_name(self):
-        return get_cmake_package_name(self.conanfile, module_mode=self.generating_module) + self.suffix
+        return self.cmakedeps.get_cmake_package_name(self.conanfile, module_mode=self.generating_module) + self.suffix
 
     @property
     def suffix(self):
@@ -85,10 +84,10 @@ class CMakeDepsFileTemplate(object):
 
     def get_root_target_name(self, req, suffix=""):
         if self.generating_module:
-            ret = req.cpp_info.get_property("cmake_module_target_name")
+            ret = self.cmakedeps.get_property("cmake_module_target_name", req)
             if ret:
                 return ret
-        ret = req.cpp_info.get_property("cmake_target_name")
+        ret = self.cmakedeps.get_property("cmake_target_name", req)
         return ret or self._get_target_default_name(req, suffix=suffix)
 
     def get_component_alias(self, req, comp_name):
@@ -99,10 +98,11 @@ class CMakeDepsFileTemplate(object):
             raise ConanException("Component '{name}::{cname}' not found in '{name}' "
                                  "package requirement".format(name=req.ref.name, cname=comp_name))
         if self.generating_module:
-            ret = req.cpp_info.components[comp_name].get_property("cmake_module_target_name")
+            ret = self.cmakedeps.get_property("cmake_module_target_name", req, comp_name=comp_name)
             if ret:
                 return ret
-        ret = req.cpp_info.components[comp_name].get_property("cmake_target_name")
+        ret = self.cmakedeps.get_property("cmake_target_name", req, comp_name=comp_name)
+
         # If we don't specify the `cmake_target_name` property for the component it will
         # fallback to the pkg_name::comp_name, it wont use the root cpp_info cmake_target_name
         # property because that is also an absolute name (Greetings::Greetings), it is not a namespace
diff --git a/conan/tools/cmake/cmakedeps/templates/target_data.py b/conan/tools/cmake/cmakedeps/templates/target_data.py
index f22858592..61d249de3 100644
--- a/conan/tools/cmake/cmakedeps/templates/target_data.py
+++ b/conan/tools/cmake/cmakedeps/templates/target_data.py
@@ -4,7 +4,7 @@ import textwrap
 from conan.tools.cmake.cmakedeps import FIND_MODE_NONE, FIND_MODE_CONFIG, FIND_MODE_MODULE, \
     FIND_MODE_BOTH
 from conan.tools.cmake.cmakedeps.templates import CMakeDepsFileTemplate
-from conan.tools.cmake.utils import get_cmake_package_name, get_find_mode
+
 """
 
 foo-release-x86_64-data.cmake
@@ -189,9 +189,9 @@ class ConfigDataTemplate(CMakeDepsFileTemplate):
             for dep_name, _ in self.conanfile.cpp_info.required_components:
                 if dep_name and dep_name not in ret:  # External dep
                     req = direct_host[dep_name]
-                    ret.append(get_cmake_package_name(req))
+                    ret.append(self.cmakedeps.get_cmake_package_name(req))
         elif direct_host:
-            ret = [get_cmake_package_name(r, self.generating_module) for r in direct_host.values()]
+            ret = [self.cmakedeps.get_cmake_package_name(r, self.generating_module) for r in direct_host.values()]
 
         return ret
 
@@ -201,8 +201,8 @@ class ConfigDataTemplate(CMakeDepsFileTemplate):
             return ret
         deps = self.conanfile.dependencies.filter({"build": False, "visible": True, "direct": True})
         for dep in deps.values():
-            dep_file_name = get_cmake_package_name(dep, self.generating_module)
-            find_mode = get_find_mode(dep)
+            dep_file_name = self.cmakedeps.get_cmake_package_name(dep, self.generating_module)
+            find_mode = self.cmakedeps.get_find_mode(dep)
             default_value = "NO_MODULE" if not self.generating_module else "MODULE"
             values = {
                 FIND_MODE_NONE: "",
diff --git a/conan/tools/cmake/utils.py b/conan/tools/cmake/utils.py
index cceea99bf..0a99e28b9 100644
--- a/conan/tools/cmake/utils.py
+++ b/conan/tools/cmake/utils.py
@@ -6,27 +6,3 @@ def is_multi_configuration(generator):
         return False
     return "Visual" in generator or "Xcode" in generator or "Multi-Config" in generator
 
-
-def get_cmake_package_name(conanfile, module_mode=None):
-    """Get the name of the file for the find_package(XXX)"""
-    # This is used by CMakeToolchain/CMakeDeps to determine:
-    # - The filename to generate (XXX-config.cmake or FindXXX.cmake)
-    # - The name of the defined XXX_DIR variables
-    # - The name of transitive dependencies for calls to find_dependency
-    if module_mode and get_find_mode(conanfile) in [FIND_MODE_MODULE, FIND_MODE_BOTH]:
-        ret = conanfile.cpp_info.get_property("cmake_module_file_name")
-        if ret:
-            return ret
-    ret = conanfile.cpp_info.get_property("cmake_file_name")
-    return ret or conanfile.ref.name
-
-
-def get_find_mode(conanfile):
-    """
-    :param conanfile: conanfile of the requirement
-    :return: "none" or "config" or "module" or "both" or "config" when not set
-    """
-    tmp = conanfile.cpp_info.get_property("cmake_find_mode")
-    if tmp is None:
-        return "config"
-    return tmp.lower()
diff --git a/conan/tools/env/environment.py b/conan/tools/env/environment.py
index a4b96ea9f..e4ffed329 100644
--- a/conan/tools/env/environment.py
+++ b/conan/tools/env/environment.py
@@ -154,6 +154,12 @@ class _EnvValue:
         previous_value = os.getenv(self._name)
         return self.get_str(previous_value, subsystem, pathsep)
 
+    def set_relative_base_folder(self, folder):
+        if not self._path:
+            return
+        self._values = [os.path.join(folder, v) if v != _EnvVarPlaceHolder else v
+                        for v in self._values]
+
 
 class Environment:
     def __init__(self):
@@ -233,6 +239,10 @@ class Environment:
     def vars(self, conanfile, scope="build"):
         return EnvVars(conanfile, self._values, scope)
 
+    def set_relative_base_folder(self, folder):
+        for v in self._values.values():
+            v.set_relative_base_folder(folder)
+
 
 class EnvVars:
     def __init__(self, conanfile, values, scope):
diff --git a/conan/tools/gnu/autotoolstoolchain.py b/conan/tools/gnu/autotoolstoolchain.py
index df84c6c2d..58115a607 100644
--- a/conan/tools/gnu/autotoolstoolchain.py
+++ b/conan/tools/gnu/autotoolstoolchain.py
@@ -13,9 +13,10 @@ from conans.tools import args_to_string
 
 
 class AutotoolsToolchain:
-    def __init__(self, conanfile, namespace=None):
+    def __init__(self, conanfile, namespace=None, prefix="/"):
         self._conanfile = conanfile
         self._namespace = namespace
+        self._prefix = prefix
 
         self.configure_args = self._default_configure_shared_flags() + self._default_configure_install_flags()
         self.autoreconf_args = self._default_autoreconf_flags()
@@ -168,7 +169,7 @@ class AutotoolsToolchain:
             return "--{}=${{prefix}}/{}".format(argument_name, elements[0]) if elements else ""
 
         # If someone want arguments but not the defaults can pass them in args manually
-        configure_install_flags.extend(["--prefix=/",
+        configure_install_flags.extend([f"--prefix={self._prefix}",
                                        _get_argument("bindir", "bindirs"),
                                        _get_argument("sbindir", "bindirs"),
                                        _get_argument("libdir", "libdirs"),
diff --git a/conan/tools/gnu/gnudeps_flags.py b/conan/tools/gnu/gnudeps_flags.py
index 052711afd..983a45606 100644
--- a/conan/tools/gnu/gnudeps_flags.py
+++ b/conan/tools/gnu/gnudeps_flags.py
@@ -52,7 +52,7 @@ class GnuDepsFlags(object):
         if str(compiler) not in self._GCC_LIKE:
             return []
         if is_path:
-            return ["-F %s" % self._adjust_path(framework_path) for framework_path in frameworks]
+            return ["-F\"%s\"" % self._adjust_path(framework_path) for framework_path in frameworks]
         else:
             return ["-framework %s" % framework for framework in frameworks]
 
diff --git a/conan/tools/meson/meson.py b/conan/tools/meson/meson.py
index 82ed7e745..e16326afa 100644
--- a/conan/tools/meson/meson.py
+++ b/conan/tools/meson/meson.py
@@ -17,17 +17,23 @@ class Meson(object):
         cross = os.path.join(generators_folder, MesonToolchain.cross_filename)
         native = os.path.join(generators_folder, MesonToolchain.native_filename)
         deps_flags = os.path.join(generators_folder, MesonDeps.filename)  # extra machine files layer
-        has_deps_flags = os.path.exists(deps_flags)
-
+        meson_filenames = []
         if os.path.exists(cross):
-            cmd += ' --cross-file "{}"'.format(cross)
-            if has_deps_flags:
-                cmd += ' --cross-file "{}"'.format(deps_flags)
+            cmd_param = " --cross-file"
+            meson_filenames.append(cross)
         else:
-            cmd += ' --native-file "{}"'.format(native)
-            if has_deps_flags:
-                cmd += ' --native-file "{}"'.format(deps_flags)
+            cmd_param = " --native-file"
+            meson_filenames.append(native)
+
+        if os.path.exists(deps_flags):
+            meson_filenames.append(deps_flags)
+
+        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 += ' "{}" "{}"'.format(build_folder, source_folder)
         if self._conanfile.package_folder:
             cmd += ' -Dprefix="{}"'.format(self._conanfile.package_folder)
diff --git a/conan/tools/meson/toolchain.py b/conan/tools/meson/toolchain.py
index e5ca38954..ca4d7fe7b 100644
--- a/conan/tools/meson/toolchain.py
+++ b/conan/tools/meson/toolchain.py
@@ -111,6 +111,8 @@ class MesonToolchain(object):
         self._default_library = ("shared" if shared else "static") if shared is not None else None
 
         compiler = self._conanfile.settings.get_safe("compiler")
+        if compiler is None:
+            raise ConanException("MesonToolchain needs 'settings.compiler', but it is not defined")
         cppstd = self._conanfile.settings.get_safe("compiler.cppstd")
         self._cpp_std = to_cppstd_flag(compiler, cppstd)
 
diff --git a/conans/client/build/compiler_flags.py b/conans/client/build/compiler_flags.py
index fe60015f9..c04be2799 100644
--- a/conans/client/build/compiler_flags.py
+++ b/conans/client/build/compiler_flags.py
@@ -280,4 +280,4 @@ def format_framework_paths(framework_paths, settings):
     compiler_base = settings.get_safe("compiler.base")
     if (str(compiler) not in GCC_LIKE) and (str(compiler_base) not in GCC_LIKE):
         return []
-    return ["-F %s" % adjust_path(framework_path, settings) for framework_path in framework_paths]
+    return ["-F\"%s\"" % adjust_path(framework_path, settings) for framework_path in framework_paths]
diff --git a/conans/client/generators/markdown.py b/conans/client/generators/markdown.py
index 1776b11d0..f855662be 100644
--- a/conans/client/generators/markdown.py
+++ b/conans/client/generators/markdown.py
@@ -6,9 +6,7 @@ from jinja2 import DictLoader
 from jinja2 import Environment
 
 from conan.tools.cmake.cmakedeps.cmakedeps import CMakeDeps
-from conan.tools.cmake.cmakedeps.templates import (
-    CMakeDepsFileTemplate,
-    get_cmake_package_name as cmake_get_file_name)
+from conan.tools.cmake.cmakedeps.templates import CMakeDepsFileTemplate
 from conan.tools.gnu.pkgconfigdeps import (
     _get_component_name as pkgconfig_get_component_name,
     _get_name_with_namespace as pkgconfig_get_name_with_namespace,
@@ -444,7 +442,7 @@ class MarkdownGenerator(Generator):
             cmake_variables = {
                 'global_target_name': requirement.cpp_info.get_property('cmake_target_name') or "{0}::{0}".format(requirement.ref.name),
                 'component_alias': cmake_component_alias,
-                'file_name': cmake_get_file_name(requirement)
+                'file_name': cmake_deps.get_cmake_package_name(requirement)
             }
 
             pkgconfig_component_alias = {
diff --git a/conans/client/graph/graph.py b/conans/client/graph/graph.py
index 0b40149f8..35a2aea01 100644
--- a/conans/client/graph/graph.py
+++ b/conans/client/graph/graph.py
@@ -238,7 +238,7 @@ class Edge(object):
         return self.require.build_require
 
     def __eq__(self, other):
-        return self.src == self.src and self.dst == other.dst
+        return self.src == other.src and self.dst == other.dst
 
     def __ne__(self, other):
         return not self.__eq__(other)
diff --git a/conans/client/installer.py b/conans/client/installer.py
index 8b2627829..87d47a616 100644
--- a/conans/client/installer.py
+++ b/conans/client/installer.py
@@ -711,6 +711,12 @@ class BinaryInstaller(object):
                         # Paste the editable cpp_info but prioritizing it, only if a
                         # variable is not declared at build/source, the package will keep the value
                         fill_old_cppinfo(full_editable_cppinfo, conanfile.cpp_info)
+                        conanfile.buildenv_info.compose_env(conanfile.cpp.source.buildenv_info)
+                        conanfile.buildenv_info.compose_env(conanfile.cpp.build.buildenv_info)
+                        conanfile.runenv_info.compose_env(conanfile.cpp.source.runenv_info)
+                        conanfile.runenv_info.compose_env(conanfile.cpp.build.runenv_info)
+                        conanfile.conf_info.compose_conf(conanfile.cpp.source.conf_info)
+                        conanfile.conf_info.compose_conf(conanfile.cpp.build.conf_info)
 
                     if conanfile._conan_dep_cpp_info is None:
                         try:
diff --git a/conans/model/conf.py b/conans/model/conf.py
index e19f04017..ba3094804 100644
--- a/conans/model/conf.py
+++ b/conans/model/conf.py
@@ -1,4 +1,5 @@
 import fnmatch
+import os
 from collections import OrderedDict
 
 import six
@@ -60,6 +61,7 @@ BUILT_IN_CONFS = {
     "tools.gnu:pkg_config": "Define the 'pkg_config' executable name or full path",
     "tools.env.virtualenv:powershell": "Opt-in to generate Powershell '.ps1' scripts instead of '.bat'",
     "tools.meson.mesontoolchain:backend": "Set the Meson backend. Possible values: 'ninja', 'vs', 'vs2010', 'vs2015', 'vs2017', 'vs2019', 'xcode'",
+    "tools.meson.mesontoolchain:extra_machine_files": "List of paths for any additional native/cross file references to be appended to the existing Conan ones",
     "tools.files.download:download_cache": "Location for the download cache",
     "tools.build.cross_building:can_run": "Set the return value for the 'conan.tools.build.can_run()' tool",
 }
@@ -81,10 +83,11 @@ class _ConfVarPlaceHolder:
 
 class _ConfValue(object):
 
-    def __init__(self, name, value):
+    def __init__(self, name, value, path=False):
         self._name = name
         self._value = value
         self._value_type = type(value)
+        self._path = path
 
     def __repr__(self):
         return repr(self._value)
@@ -98,7 +101,7 @@ class _ConfValue(object):
         return self._value
 
     def copy(self):
-        return _ConfValue(self._name, self._value)
+        return _ConfValue(self._name, self._value, self._path)
 
     def dumps(self):
         if self._value is None:
@@ -165,6 +168,17 @@ class _ConfValue(object):
                                  "and {} ones.".format(v_type.__name__, o_type.__name__))
         # TODO: In case of any other object types?
 
+    def set_relative_base_folder(self, folder):
+        if not self._path:
+            return
+        if isinstance(self._value, list):
+            self._value = [os.path.join(folder, v) if v != _ConfVarPlaceHolder else v
+                           for v in self._value]
+        if isinstance(self._value, dict):
+            self._value = {k: os.path.join(folder, v) for k, v in self._value.items()}
+        elif isinstance(self._value, str):
+            self._value = os.path.join(folder, self._value)
+
 
 class Conf:
 
@@ -291,6 +305,10 @@ class Conf:
         self._validate_lower_case(name)
         self._values[name] = _ConfValue(name, value)
 
+    def define_path(self, name, value):
+        self._validate_lower_case(name)
+        self._values[name] = _ConfValue(name, value, path=True)
+
     def unset(self, name):
         """
         clears the variable, equivalent to a unset or set XXX=
@@ -302,16 +320,31 @@ class Conf:
         conf_value = _ConfValue(name, {})
         self._values.setdefault(name, conf_value).update(value)
 
+    def update_path(self, name, value):
+        self._validate_lower_case(name)
+        conf_value = _ConfValue(name, {}, path=True)
+        self._values.setdefault(name, conf_value).update(value)
+
     def append(self, name, value):
         self._validate_lower_case(name)
         conf_value = _ConfValue(name, [_ConfVarPlaceHolder])
         self._values.setdefault(name, conf_value).append(value)
 
+    def append_path(self, name, value):
+        self._validate_lower_case(name)
+        conf_value = _ConfValue(name, [_ConfVarPlaceHolder], path=True)
+        self._values.setdefault(name, conf_value).append(value)
+
     def prepend(self, name, value):
         self._validate_lower_case(name)
         conf_value = _ConfValue(name, [_ConfVarPlaceHolder])
         self._values.setdefault(name, conf_value).prepend(value)
 
+    def prepend_path(self, name, value):
+        self._validate_lower_case(name)
+        conf_value = _ConfValue(name, [_ConfVarPlaceHolder], path=True)
+        self._values.setdefault(name, conf_value).prepend(value)
+
     def remove(self, name, value):
         conf_value = self._values.get(name)
         if conf_value:
@@ -339,6 +372,10 @@ class Conf:
                 result._values[k] = v
         return result
 
+    def set_relative_base_folder(self, folder):
+        for v in self._values.values():
+            v.set_relative_base_folder(folder)
+
 
 class ConfDefinition:
 
diff --git a/conans/model/layout.py b/conans/model/layout.py
index d3c4828cb..d8c17202f 100644
--- a/conans/model/layout.py
+++ b/conans/model/layout.py
@@ -1,14 +1,30 @@
 import os
 
+from conans.model.conf import Conf
 from conans.model.new_build_info import NewCppInfo
 
 
+class _SubInfo(NewCppInfo):
+    def __init__(self, with_defaults=False):
+        super().__init__(with_defaults)
+        from conan.tools.env import Environment
+        self.buildenv_info = Environment()
+        self.runenv_info = Environment()
+        self.conf_info = Conf()
+
+    def set_relative_base_folder(self, folder):
+        super().set_relative_base_folder(folder)
+        self.buildenv_info.set_relative_base_folder(folder)
+        self.runenv_info.set_relative_base_folder(folder)
+        self.conf_info.set_relative_base_folder(folder)
+
+
 class Infos(object):
 
     def __init__(self):
-        self.source = NewCppInfo()
-        self.build = NewCppInfo()
-        self.package = NewCppInfo(with_defaults=True)
+        self.source = _SubInfo()
+        self.build = _SubInfo()
+        self.package = _SubInfo(with_defaults=True)
 
 
 class Folders(object):


Test patch:
diff --git a/conans/test/functional/toolchains/gnu/test_pkgconfigdeps_autotools.py b/conans/test/functional/toolchains/gnu/test_pkgconfigdeps_autotools.py
new file mode 100644
index 000000000..d1d903020
--- /dev/null
+++ b/conans/test/functional/toolchains/gnu/test_pkgconfigdeps_autotools.py
@@ -0,0 +1,103 @@
+import platform
+import textwrap
+
+import pytest
+
+from conans.test.utils.tools import TestClient
+
+
+@pytest.mark.tool_pkg_config
+@pytest.mark.tool_autotools
+@pytest.mark.skipif(platform.system() == "Windows", reason="Needs pkg-config")
+def test_pkg_configdeps_definitions_escape():
+    client = TestClient(path_with_spaces=False)
+    # client.run("new autotools_lib -d name=pkg -d version=1.0")
+    conanfile_pkg = textwrap.dedent("""
+    from conan import ConanFile
+    from conan.tools.gnu import Autotools
+    from conan.tools.layout import basic_layout
+    from conan.tools.apple import fix_apple_shared_install_name
+
+
+    class PkgConan(ConanFile):
+        name = "pkg"
+        version = "1.0"
+        settings = "os", "compiler", "build_type", "arch"
+        exports_sources = "configure.ac", "Makefile.am", "src/*"
+        generators = "AutotoolsToolchain"
+
+        def layout(self):
+            basic_layout(self)
+
+        def build(self):
+            autotools = Autotools(self)
+            autotools.autoreconf()
+            autotools.configure()
+            autotools.make()
+
+        def package(self):
+            autotools = Autotools(self)
+            autotools.install()
+            fix_apple_shared_install_name(self)
+
+        def package_info(self):
+            self.cpp_info.libs = ["pkg"]
+            self.cpp_info.frameworkdirs = ["/my/framework/file1", "/my/framework/file2"]
+    """)
+    conanfile_test = textwrap.dedent("""
+    import os
+    from conan import ConanFile
+    from conan.tools.gnu import Autotools
+    from conan.tools.layout import basic_layout
+    from conan.tools.build import cross_building
+    class PkgTestConan(ConanFile):
+        settings = "os", "compiler", "build_type", "arch"
+        generators = "PkgConfigDeps", "AutotoolsToolchain", "VirtualBuildEnv", "VirtualRunEnv"
+        apply_env = False
+        test_type = "explicit"
+
+        def requirements(self):
+            self.requires(self.tested_reference_str)
+
+        def build(self):
+            autotools = Autotools(self)
+            autotools.autoreconf()
+            autotools.configure()
+            autotools.make()
+
+        def layout(self):
+            basic_layout(self)
+
+        def test(self):
+            if not cross_building(self):
+                cmd = os.path.join(self.cpp.build.bindirs[0], "main")
+                self.run(cmd, env="conanrun")
+    """)
+    configure_test = textwrap.dedent("""
+    AC_INIT([main], [1.0], [])
+    AM_INIT_AUTOMAKE([-Wall -Werror foreign])
+    AC_PROG_CXX
+    PKG_PROG_PKG_CONFIG
+    PKG_CHECK_MODULES([pkg], [pkg >= 1.0])
+    AC_CONFIG_FILES([Makefile])
+    AC_OUTPUT
+    """)
+    makefile_test = textwrap.dedent("""
+    bin_PROGRAMS = main
+    main_SOURCES = main.cpp
+    AM_CXXFLAGS = $(pkg_CFLAGS)
+    main_LDADD = $(pkg_LIBS)
+    """)
+    client.run("new pkg/1.0 -m autotools_lib")
+    client.save({"conanfile.py": conanfile_pkg,
+                 "test_package/conanfile.py": conanfile_test,
+                 "test_package/configure.ac": configure_test,
+                 "test_package/Makefile.am": makefile_test,
+                 })
+    client.run("create .")
+    if platform.system() == "Darwin":
+        # Checking that frameworkdirs appear all together instead of "-F /whatever/f1"
+        assert '-F/my/framework/file1' in client.out
+        assert '-F/my/framework/file2' in client.out
+        assert "warning: directory not found for option '-F/my/framework/file1'" in client.out
+        assert "warning: directory not found for option '-F/my/framework/file2'" in client.out
diff --git a/conans/test/functional/toolchains/meson/_base.py b/conans/test/functional/toolchains/meson/_base.py
index 41c2d6858..818ac542b 100644
--- a/conans/test/functional/toolchains/meson/_base.py
+++ b/conans/test/functional/toolchains/meson/_base.py
@@ -1,5 +1,4 @@
 import platform
-import sys
 import unittest
 
 import pytest
@@ -8,7 +7,6 @@ from conans.test.utils.tools import TestClient
 
 
 @pytest.mark.tool_meson
-@pytest.mark.skipif(sys.version_info.major == 2, reason="Meson not supported in Py2")
 @pytest.mark.skipif(platform.system() not in ("Darwin", "Windows", "Linux"),
                     reason="Not tested for not mainstream boring operating systems")
 class TestMesonBase(unittest.TestCase):
diff --git a/conans/test/functional/toolchains/meson/test_meson.py b/conans/test/functional/toolchains/meson/test_meson.py
index 6ee637ad7..e754c052f 100644
--- a/conans/test/functional/toolchains/meson/test_meson.py
+++ b/conans/test/functional/toolchains/meson/test_meson.py
@@ -1,10 +1,14 @@
 import os
 import platform
+import sys
 import textwrap
 
+import pytest
+
 from conans.model.ref import ConanFileReference
 from conans.test.assets.sources import gen_function_cpp, gen_function_h
 from conans.test.functional.toolchains.meson._base import TestMesonBase
+from conans.test.utils.tools import TestClient
 
 
 class MesonToolchainTest(TestMesonBase):
@@ -167,3 +171,57 @@ class MesonToolchainTest(TestMesonBase):
         # res/tutorial -> tutorial is being added automatically by Meson
         assert os.path.exists(os.path.join(package_folder, "res", "tutorial", "file1.txt"))
         assert os.path.exists(os.path.join(package_folder, "res", "tutorial", "file2.txt"))
+
+
+@pytest.mark.tool_meson
+@pytest.mark.skipif(sys.version_info.minor < 8, reason="Latest Meson versions needs Python >= 3.8")
+def test_meson_and_additional_machine_files_composition():
+    """
+    Testing when users wants to append their own meson machine files and override/complement some
+    sections from Conan file ones.
+
+    See more information in Meson web page: https://mesonbuild.com/Machine-files.html
+
+    In this test, we're overriding only the Meson section ``[binaries]`` for instance.
+    """
+    profile = textwrap.dedent("""
+        [settings]
+        os=Windows
+        arch=x86_64
+        compiler=gcc
+        compiler.version=9
+        compiler.cppstd=17
+        compiler.libcxx=libstdc++11
+        build_type=Release
+
+        [conf]
+        tools.meson.mesontoolchain:extra_machine_files=["myfilename.ini"]
+   """)
+    myfilename = textwrap.dedent("""
+    [project options]
+    my_option = 'fake-option'
+    """)
+    conanfile = textwrap.dedent("""
+    from conan import ConanFile
+    from conan.tools.meson import Meson
+    class Pkg(ConanFile):
+        settings = "os", "compiler", "build_type", "arch"
+        generators = "MesonToolchain"
+        def build(self):
+            meson = Meson(self)
+            meson.configure()
+            meson.build()
+    """)
+    client = TestClient()
+    client.save({"conanfile.py": conanfile,
+                 "build/myfilename.ini": myfilename,
+                 "meson.build": "project('tutorial', 'cpp')",  # dummy one
+                 "profile": profile})
+
+    client.run("install . -pr=profile -if build")
+    client.run("build . -bf build", assert_error=True)
+    # Checking the order of the appended user file (the order matters)
+    conan_meson_native = os.path.join(client.current_folder, "build", "conan_meson_native.ini")
+    assert f'meson setup --native-file "{conan_meson_native}" --native-file "myfilename.ini"' in client.out
+    # Meson fails because of an unknown option
+    assert 'ERROR: Unknown options: "my_option"' in client.out
diff --git a/conans/test/integration/editable/test_editable_envvars.py b/conans/test/integration/editable/test_editable_envvars.py
new file mode 100644
index 000000000..81fe645a2
--- /dev/null
+++ b/conans/test/integration/editable/test_editable_envvars.py
@@ -0,0 +1,74 @@
+import os
+import textwrap
+
+from conans.test.assets.genconanfile import GenConanfile
+from conans.test.utils.tools import TestClient
+
+
+def test_editable_envvars():
+    c = TestClient()
+    dep = textwrap.dedent("""
+        from conan import ConanFile
+        class Dep(ConanFile):
+            def layout(self):
+                self.folders.source = "mysource"
+                self.folders.build = "mybuild"
+                self.cpp.source.runenv_info.append_path("MYRUNPATH", "mylocalsrc")
+                self.cpp.build.buildenv_info.define_path("MYBUILDPATH", "mylocalbuild")
+        """)
+
+    c.save({"dep/conanfile.py": dep,
+            "pkg/conanfile.py": GenConanfile().with_settings("os")
+                                              .with_requires("dep/1.0")
+                                              .with_generator("VirtualBuildEnv")
+                                              .with_generator("VirtualRunEnv")})
+    c.run("editable add dep dep/1.0")
+    c.run("install pkg -s os=Linux -s:b os=Linux")
+    build_path = os.path.join(c.current_folder, "dep", "mybuild", "mylocalbuild")
+    buildenv = c.load("conanbuildenv.sh")
+    assert f'export MYBUILDPATH="{build_path}"' in buildenv
+    runenv = c.load("conanrunenv.sh")
+    run_path = os.path.join(c.current_folder, "dep", "mysource", "mylocalsrc")
+    assert f'export MYRUNPATH="$MYRUNPATH:{run_path}"' in runenv
+
+
+def test_editable_conf():
+    c = TestClient()
+    # TODO: Define if we want conf.xxxx_path(), instead of (..., path=True) methods
+    dep = textwrap.dedent("""
+        from conan import ConanFile
+        class Dep(ConanFile):
+            def layout(self):
+                self.folders.source = "mysource"
+                self.folders.build = "mybuild"
+                self.cpp.source.conf_info.append_path("myconf", "mylocalsrc")
+                self.cpp.build.conf_info.append_path("myconf", "mylocalbuild")
+                self.cpp.build.conf_info.update_path("mydictconf", {"a": "mypatha", "b": "mypathb"})
+                self.cpp.build.conf_info.define_path("mydictconf2", {"c": "mypathc"})
+        """)
+
+    pkg = textwrap.dedent("""
+        from conan import ConanFile
+        class Pkg(ConanFile):
+            requires = "dep/1.0"
+            def generate(self):
+                conf = self.dependencies["dep"].conf_info.get("myconf")
+                self.output.info(f"CONF: {conf}")
+                dictconf = self.dependencies["dep"].conf_info.get("mydictconf", check_type=dict)
+                self.output.info(f"CONFDICT: {dictconf}")
+                dictconf2 = self.dependencies["dep"].conf_info.get("mydictconf2", check_type=dict)
+                self.output.info(f"CONFDICT: {dictconf2}")
+        """)
+    c.save({"dep/conanfile.py": dep,
+            "pkg/conanfile.py": pkg})
+    c.run("editable add dep dep/1.0")
+    c.run("install pkg -s os=Linux -s:b os=Linux")
+    out = str(c.out).replace("\\\\", "\\")
+    conf_source = os.path.join(c.current_folder, "dep", "mybuild", "mylocalbuild")
+    conf_build = os.path.join(c.current_folder, "dep", "mysource", "mylocalsrc")
+    confdict1 = os.path.join(c.current_folder, "dep", "mybuild", "mypatha")
+    confdict2 = os.path.join(c.current_folder, "dep", "mybuild", "mypathc")
+    assert conf_source in out
+    assert conf_build in out
+    assert confdict1 in out
+    assert confdict2 in out
diff --git a/conans/test/integration/toolchains/cmake/cmakedeps/test_cmakedeps.py b/conans/test/integration/toolchains/cmake/cmakedeps/test_cmakedeps.py
index 5e147de51..15d07a2e9 100644
--- a/conans/test/integration/toolchains/cmake/cmakedeps/test_cmakedeps.py
+++ b/conans/test/integration/toolchains/cmake/cmakedeps/test_cmakedeps.py
@@ -187,3 +187,202 @@ def test_cmakedeps_cppinfo_complex_strings():
     assert r"spaces=me you" in deps
     assert r"foobar=bazbuz" in deps
     assert r"answer=42" in deps
+
+
+def test_dependency_props_from_consumer():
+    client = TestClient(path_with_spaces=False)
+    bar = textwrap.dedent(r'''
+        from conan import ConanFile
+        class FooConan(ConanFile):
+            settings = "os", "compiler", "build_type", "arch"
+            def package_info(self):
+                self.cpp_info.set_property("cmake_find_mode", "both")
+                self.cpp_info.components["component1"].requires = []
+        ''')
+
+    foo = textwrap.dedent(r'''
+        from conan import ConanFile
+        from conan.tools.cmake import CMakeDeps, cmake_layout
+        class FooConan(ConanFile):
+            settings = "os", "compiler", "build_type", "arch"
+            requires = "bar/1.0"
+            def layout(self):
+                cmake_layout(self)
+            def generate(self):
+                deps = CMakeDeps(self)
+                {set_find_mode}
+                deps.set_property("bar", "cmake_file_name", "custom_bar_file_name")
+                deps.set_property("bar", "cmake_module_file_name", "custom_bar_module_file_name")
+                deps.set_property("bar", "cmake_target_name", "custom_bar_target_name")
+                deps.set_property("bar", "cmake_module_target_name", "custom_bar_module_target_name")
+                deps.set_property("bar::component1", "cmake_target_name", "custom_bar_component_target_name")
+                deps.generate()
+        ''')
+
+    set_find_mode = """
+        deps.set_property("bar", "cmake_find_mode", {find_mode})
+    """
+
+    client.save({"foo.py": foo.format(set_find_mode=""), "bar.py": bar}, clean_first=True)
+
+    module_file = os.path.join(client.current_folder, "build", "generators", "module-custom_bar_module_file_nameTargets.cmake")
+    components_module = os.path.join(client.current_folder, "build", "generators", "custom_bar_file_name-Target-release.cmake")
+    config_file = os.path.join(client.current_folder, "build", "generators", "custom_bar_file_nameTargets.cmake")
+
+    # uses cmake_find_mode set in bar: both
+    client.run("create bar.py bar/1.0@")
+    client.run("install foo.py foo/1.0@")
+    assert os.path.exists(module_file)
+    assert os.path.exists(config_file)
+    module_content = client.load(module_file)
+    assert "add_library(custom_bar_module_target_name INTERFACE IMPORTED)" in module_content
+    config_content = client.load(config_file)
+    assert "add_library(custom_bar_target_name INTERFACE IMPORTED)" in config_content
+    components_module_content = client.load(components_module)
+    assert "add_library(bar_custom_bar_component_target_name_DEPS_TARGET INTERFACE IMPORTED)" in components_module_content
+
+    client.save({"foo.py": foo.format(set_find_mode=set_find_mode.format(find_mode="'none'")),
+                 "bar.py": bar}, clean_first=True)
+    client.run("create bar.py bar/1.0@")
+    client.run("install foo.py foo/1.0@")
+    assert not os.path.exists(module_file)
+    assert not os.path.exists(config_file)
+
+    client.save({"foo.py": foo.format(set_find_mode=set_find_mode.format(find_mode="'module'")),
+                 "bar.py": bar}, clean_first=True)
+    client.run("create bar.py bar/1.0@")
+    client.run("install foo.py foo/1.0@")
+    assert os.path.exists(module_file)
+    assert not os.path.exists(config_file)
+
+    client.save({"foo.py": foo.format(set_find_mode=set_find_mode.format(find_mode="'config'")),
+                 "bar.py": bar}, clean_first=True)
+    client.run("create bar.py bar/1.0@")
+    client.run("install foo.py foo/1.0@")
+    assert not os.path.exists(module_file)
+    assert os.path.exists(config_file)
+
+
+def test_props_from_consumer_build_context_activated():
+    client = TestClient(path_with_spaces=False)
+    bar = textwrap.dedent(r'''
+        from conan import ConanFile
+        class FooConan(ConanFile):
+            settings = "os", "compiler", "build_type", "arch"
+            def package_info(self):
+                self.cpp_info.set_property("cmake_find_mode", "both")
+                self.cpp_info.components["component1"].requires = []
+        ''')
+
+    foo = textwrap.dedent(r'''
+        from conan import ConanFile
+        from conan.tools.cmake import CMakeDeps, cmake_layout
+        class FooConan(ConanFile):
+            settings = "os", "compiler", "build_type", "arch"
+            requires = "bar/1.0"
+            tool_requires = "bar/1.0"
+            def layout(self):
+                cmake_layout(self)
+            def generate(self):
+                deps = CMakeDeps(self)
+                deps.build_context_activated = ["bar"]
+                deps.build_context_suffix = {{"bar": "_BUILD"}}
+                {set_find_mode}
+
+                deps.set_property("bar", "cmake_file_name", "custom_bar_file_name")
+                deps.set_property("bar", "cmake_module_file_name", "custom_bar_module_file_name")
+                deps.set_property("bar", "cmake_target_name", "custom_bar_target_name")
+                deps.set_property("bar", "cmake_module_target_name", "custom_bar_module_target_name")
+                deps.set_property("bar::component1", "cmake_target_name", "custom_bar_component_target_name")
+
+                deps.set_property("bar", "cmake_file_name", "custom_bar_build_file_name", build_context=True)
+                deps.set_property("bar", "cmake_module_file_name", "custom_bar_build_module_file_name", build_context=True)
+                deps.set_property("bar", "cmake_target_name", "custom_bar_build_target_name", build_context=True)
+                deps.set_property("bar", "cmake_module_target_name", "custom_bar_build_module_target_name", build_context=True)
+                deps.set_property("bar::component1", "cmake_target_name", "custom_bar_build_component_target_name", build_context=True)
+
+                deps.generate()
+        ''')
+
+    set_find_mode = """
+        deps.set_property("bar", "cmake_find_mode", {find_mode})
+        deps.set_property("bar", "cmake_find_mode", {find_mode}, build_context=True)
+    """
+
+    client.save({"foo.py": foo.format(set_find_mode=""), "bar.py": bar}, clean_first=True)
+
+    module_file = os.path.join(client.current_folder, "build", "generators",
+                               "module-custom_bar_module_file_nameTargets.cmake")
+    components_module = os.path.join(client.current_folder, "build", "generators",
+                                     "custom_bar_file_name-Target-release.cmake")
+    config_file = os.path.join(client.current_folder, "build", "generators",
+                               "custom_bar_file_nameTargets.cmake")
+
+    module_file_build = os.path.join(client.current_folder, "build", "generators",
+                                     "module-custom_bar_build_module_file_name_BUILDTargets.cmake")
+    components_module_build = os.path.join(client.current_folder, "build", "generators",
+                                           "custom_bar_build_file_name_BUILD-Target-release.cmake")
+    config_file_build = os.path.join(client.current_folder, "build", "generators",
+                                     "custom_bar_build_file_name_BUILDTargets.cmake")
+
+    # uses cmake_find_mode set in bar: both
+    client.run("create bar.py bar/1.0@ -pr:h=default -pr:b=default")
+    client.run("install foo.py foo/1.0@ -pr:h=default -pr:b=default")
+    assert os.path.exists(module_file)
+    assert os.path.exists(config_file)
+    assert os.path.exists(module_file_build)
+    assert os.path.exists(config_file_build)
+
+    module_content = client.load(module_file)
+    assert "add_library(custom_bar_module_target_name INTERFACE IMPORTED)" in module_content
+    config_content = client.load(config_file)
+    assert "add_library(custom_bar_target_name INTERFACE IMPORTED)" in config_content
+
+    module_content_build = client.load(module_file_build)
+    assert "add_library(custom_bar_build_module_target_name INTERFACE IMPORTED)" in module_content_build
+    config_content_build = client.load(config_file_build)
+    assert "add_library(custom_bar_build_target_name INTERFACE IMPORTED)" in config_content_build
+
+    components_module_content = client.load(components_module)
+    assert "add_library(bar_custom_bar_component_target_name_DEPS_TARGET INTERFACE IMPORTED)" in components_module_content
+
+    components_module_content_build = client.load(components_module_build)
+    assert "add_library(bar_BUILD_custom_bar_build_component_target_name_DEPS_TARGET INTERFACE IMPORTED)" in components_module_content_build
+
+    client.save(
+        {"foo.py": foo.format(set_find_mode=set_find_mode.format(find_mode="'none'")), "bar.py": bar},
+        clean_first=True)
+    client.run("create bar.py bar/1.0@ -pr:h=default -pr:b=default")
+    client.run("install foo.py foo/1.0@ -pr:h=default -pr:b=default")
+    assert not os.path.exists(module_file)
+    assert not os.path.exists(config_file)
+    assert not os.path.exists(module_file_build)
+    assert not os.path.exists(config_file_build)
+
+    client.save({"foo.py": foo.format(set_find_mode=set_find_mode.format(find_mode="'module'")),
+                 "bar.py": bar}, clean_first=True)
+    client.run("create bar.py bar/1.0@ -pr:h=default -pr:b=default")
+    client.run("install foo.py foo/1.0@ -pr:h=default -pr:b=default")
+    assert os.path.exists(module_file)
+    assert not os.path.exists(config_file)
+    assert os.path.exists(module_file_build)
+    assert not os.path.exists(config_file_build)
+
+    client.save({"foo.py": foo.format(set_find_mode=set_find_mode.format(find_mode="'config'")),
+                 "bar.py": bar}, clean_first=True)
+    client.run("create bar.py bar/1.0@ -pr:h=default -pr:b=default")
+    client.run("install foo.py foo/1.0@ -pr:h=default -pr:b=default")
+    assert not os.path.exists(module_file)
+    assert os.path.exists(config_file)
+    assert not os.path.exists(module_file_build)
+    assert os.path.exists(config_file_build)
+
+    # invalidate upstream property setting a None, will use config that's the default
+    client.save({"foo.py": foo.format(set_find_mode=set_find_mode.format(find_mode="None")),
+                 "bar.py": bar}, clean_first=True)
+    client.run("create bar.py bar/1.0@ -pr:h=default -pr:b=default")
+    client.run("install foo.py foo/1.0@ -pr:h=default -pr:b=default")
+    assert not os.path.exists(module_file)
+    assert os.path.exists(config_file)
+    assert not os.path.exists(module_file_build)
+    assert os.path.exists(config_file_build)
diff --git a/conans/test/integration/toolchains/gnu/test_autotoolstoolchain.py b/conans/test/integration/toolchains/gnu/test_autotoolstoolchain.py
index 1b9b3269a..9c91d3c8e 100644
--- a/conans/test/integration/toolchains/gnu/test_autotoolstoolchain.py
+++ b/conans/test/integration/toolchains/gnu/test_autotoolstoolchain.py
@@ -1,3 +1,4 @@
+import os
 import platform
 import textwrap
 
@@ -67,3 +68,28 @@ def test_not_none_values():
     client.save({"conanfile.py": conanfile})
     client.run("install .")
 
+
+def test_set_prefix():
+
+    conanfile = textwrap.dedent("""
+        from conan import ConanFile
+        from conan.tools.gnu import AutotoolsToolchain
+        from conan.tools.layout import basic_layout
+
+
+        class Foo(ConanFile):
+            name = "foo"
+            version = "1.0"
+            def layout(self):
+                basic_layout(self)
+            def generate(self):
+                at_toolchain = AutotoolsToolchain(self, prefix="/somefolder")
+                at_toolchain.generate()
+    """)
+
+    client = TestClient()
+    client.save({"conanfile.py": conanfile})
+    client.run("install .")
+    conanbuild = client.load(os.path.join(client.current_folder, "build", "conan", "conanbuild.conf"))
+    assert "--prefix=/somefolder" in conanbuild
+    assert conanbuild.count("--prefix") == 1
diff --git a/conans/test/integration/toolchains/meson/test_mesontoolchain.py b/conans/test/integration/toolchains/meson/test_mesontoolchain.py
index c5b273ada..7a1932fb9 100644
--- a/conans/test/integration/toolchains/meson/test_mesontoolchain.py
+++ b/conans/test/integration/toolchains/meson/test_mesontoolchain.py
@@ -1,13 +1,9 @@
-import sys
 import textwrap
 
-import pytest
-
 from conan.tools.meson import MesonToolchain
 from conans.test.utils.tools import TestClient
 
 
-@pytest.mark.skipif(sys.version_info.major == 2, reason="Meson not supported in Py2")
 def test_apple_meson_keep_user_custom_flags():
     default = textwrap.dedent("""
     [settings]
@@ -62,7 +58,6 @@ def test_apple_meson_keep_user_custom_flags():
     assert "cpp_link_args = ['-isysroot', '/other/sdk/path', '-arch', 'myarch', '-otherminversion=10.7', '-stdlib=libc++']" in content
 
 
-@pytest.mark.skipif(sys.version_info.major == 2, reason="Meson not supported in Py2")
 def test_extra_flags_via_conf():
     profile = textwrap.dedent("""
         [settings]
@@ -97,7 +92,6 @@ def test_extra_flags_via_conf():
     assert "cpp_link_args = ['-flag0', '-other=val', '-flag5', '-flag6']" in content
 
 
-@pytest.mark.skipif(sys.version_info.major == 2, reason="Meson not supported in Py2")
 def test_correct_quotes():
     profile = textwrap.dedent("""
        [settings]
diff --git a/conans/test/unittests/client/build/autotools_environment_test.py b/conans/test/unittests/client/build/autotools_environment_test.py
index 666fff793..32d83c0bf 100644
--- a/conans/test/unittests/client/build/autotools_environment_test.py
+++ b/conans/test/unittests/client/build/autotools_environment_test.py
@@ -236,7 +236,7 @@ class AutoToolsConfigureTest(unittest.TestCase):
                                 '-D_GLIBCXX_USE_CXX11_ABI=0',
                     'CXXFLAGS': 'a_c_flag -m32 -O3 -s --sysroot=/path/to/folder a_cxx_flag',
                     'LDFLAGS': 'shared_link_flag exe_link_flag -framework oneframework -framework twoframework '
-                               '-F one/framework/path -m32 --sysroot=/path/to/folder -Lone/lib/path',
+                               '-F\"one/framework/path\" -m32 --sysroot=/path/to/folder -Lone/lib/path',
                     'LIBS': '-lonelib -ltwolib -lonesystemlib -ltwosystemlib'}
 
         self.assertEqual(be.vars, expected)
@@ -254,7 +254,7 @@ class AutoToolsConfigureTest(unittest.TestCase):
                                 ' -D_GLIBCXX_USE_CXX11_ABI=0',
                     'CXXFLAGS': 'a_c_flag -m64 -g --sysroot=/path/to/folder a_cxx_flag',
                     'LDFLAGS': 'shared_link_flag exe_link_flag -framework oneframework -framework twoframework '
-                               '-F one/framework/path -m64 --sysroot=/path/to/folder -Lone/lib/path',
+                               '-F\"one/framework/path\" -m64 --sysroot=/path/to/folder -Lone/lib/path',
                     'LIBS': '-lonelib -ltwolib -lonesystemlib -ltwosystemlib'}
         be = AutoToolsBuildEnvironment(conanfile)
         self.assertEqual(be.vars, expected)
@@ -272,7 +272,7 @@ class AutoToolsConfigureTest(unittest.TestCase):
                                 ' -DNDEBUG -D_GLIBCXX_USE_CXX11_ABI=0',
                     'CXXFLAGS': 'a_c_flag -m64 -O3 --sysroot=/path/to/folder a_cxx_flag -stdlib=libstdc++',
                     'LDFLAGS': 'shared_link_flag exe_link_flag -framework oneframework -framework twoframework '
-                               '-F one/framework/path -m64 --sysroot=/path/to/folder -Lone/lib/path',
+                               '-F\"one/framework/path\" -m64 --sysroot=/path/to/folder -Lone/lib/path',
                     'LIBS': '-lonelib -ltwolib -lonesystemlib -ltwosystemlib'}
         be = AutoToolsBuildEnvironment(conanfile)
         self.assertEqual(be.vars, expected)
@@ -289,7 +289,7 @@ class AutoToolsConfigureTest(unittest.TestCase):
                     'CPPFLAGS': '-Ipath/includes -Iother/include/path -Donedefinition -Dtwodefinition -DNDEBUG',
                     'CXXFLAGS': 'a_c_flag -m64 -O3 --sysroot=/path/to/folder a_cxx_flag -stdlib=libc++',
                     'LDFLAGS': 'shared_link_flag exe_link_flag -framework oneframework -framework twoframework '
-                               '-F one/framework/path -m64 --sysroot=/path/to/folder -Lone/lib/path',
+                               '-F\"one/framework/path\" -m64 --sysroot=/path/to/folder -Lone/lib/path',
                     'LIBS': '-lonelib -ltwolib -lonesystemlib -ltwosystemlib'}
         be = AutoToolsBuildEnvironment(conanfile)
         self.assertEqual(be.vars, expected)
@@ -307,7 +307,7 @@ class AutoToolsConfigureTest(unittest.TestCase):
                                 '-D_GLIBCXX_USE_CXX11_ABI=1',
                     'CXXFLAGS': 'a_c_flag -m64 -O3 -s --sysroot=/path/to/folder a_cxx_flag',
                     'LDFLAGS': 'shared_link_flag exe_link_flag -framework oneframework -framework twoframework '
-                               '-F one/framework/path -m64 --sysroot=/path/to/folder -Lone/lib/path',
+                               '-F\"one/framework/path\" -m64 --sysroot=/path/to/folder -Lone/lib/path',
                     'LIBS': '-lonelib -ltwolib -lonesystemlib -ltwosystemlib'}
         be = AutoToolsBuildEnvironment(conanfile)
         self.assertEqual(be.vars, expected)
@@ -387,7 +387,7 @@ class AutoToolsConfigureTest(unittest.TestCase):
                                 '-D_GLIBCXX_USE_CXX11_ABI=1',
                     'CXXFLAGS': 'a_c_flag -m64 -O3 -s --sysroot=/path/to/folder a_cxx_flag',
                     'LDFLAGS': 'shared_link_flag exe_link_flag -framework oneframework -framework twoframework '
-                               '-F one/framework/path -m64 --sysroot=/path/to/folder '
+                               '-F\"one/framework/path\" -m64 --sysroot=/path/to/folder '
                                '-Wl,-rpath,"one/lib/path" -Lone/lib/path',
                     'LIBS': '-lonelib -ltwolib -lonesystemlib -ltwosystemlib'}
         be = AutoToolsBuildEnvironment(conanfile, include_rpath_flags=True)
@@ -414,7 +414,7 @@ class AutoToolsConfigureTest(unittest.TestCase):
                         'CXXFLAGS': 'a_c_flag -m64 -g --sysroot=/path/to/folder a_cxx_flag -additionalcxxflag',
                         'LIBS': '-lonelib -ltwolib -lonesystemlib -ltwosystemlib -additionallibs',
                         'LDFLAGS': 'shared_link_flag exe_link_flag -framework oneframework '
-                                   '-framework twoframework -F one/framework/path -m64 '
+                                   '-framework twoframework -F\"one/framework/path\" -m64 '
                                    '--sysroot=/path/to/folder -Lone/lib/path -additionalldflag',
                         'CFLAGS': 'a_c_flag -m64 -g --sysroot=/path/to/folder -additionalcflag'}
             self.assertEqual(be.vars, expected)
diff --git a/conans/test/unittests/client/generators/compiler_args_test.py b/conans/test/unittests/client/generators/compiler_args_test.py
index d510c0126..db7b93e47 100644
--- a/conans/test/unittests/client/generators/compiler_args_test.py
+++ b/conans/test/unittests/client/generators/compiler_args_test.py
@@ -78,7 +78,7 @@ class CompilerArgsTest(unittest.TestCase):
                          ' cxx_flag1 c_flag1 -m32 -O3 -s -DNDEBUG'
                          ' -Wl,-rpath,"/root/lib" -Wl,-rpath,"/root/path/to/lib1"'
                          ' -L/root/lib -L/root/path/to/lib1 -lmylib'
-                         ' -F /root/Frameworks -std=gnu++17', gcc.content)
+                         ' -F"/root/Frameworks" -std=gnu++17', gcc.content)
 
         settings.arch = "x86_64"
         settings.build_type = "Debug"
@@ -89,7 +89,7 @@ class CompilerArgsTest(unittest.TestCase):
                          ' cxx_flag1 c_flag1 -m64 -g'
                          ' -Wl,-rpath,"/root/lib" -Wl,-rpath,"/root/path/to/lib1"'
                          ' -L/root/lib -L/root/path/to/lib1 -lmylib'
-                         ' -D_GLIBCXX_USE_CXX11_ABI=1 -F /root/Frameworks -std=gnu++17',
+                         ' -D_GLIBCXX_USE_CXX11_ABI=1 -F"/root/Frameworks" -std=gnu++17',
                          gcc.content)
 
         settings.compiler.libcxx = "libstdc++"
@@ -98,7 +98,7 @@ class CompilerArgsTest(unittest.TestCase):
                          ' cxx_flag1 c_flag1 -m64 -g'
                          ' -Wl,-rpath,"/root/lib" -Wl,-rpath,"/root/path/to/lib1"'
                          ' -L/root/lib -L/root/path/to/lib1 -lmylib'
-                         ' -D_GLIBCXX_USE_CXX11_ABI=0 -F /root/Frameworks -std=gnu++17',
+                         ' -D_GLIBCXX_USE_CXX11_ABI=0 -F"/root/Frameworks" -std=gnu++17',
                          gcc.content)
 
         settings.os = "Windows"
@@ -112,7 +112,7 @@ class CompilerArgsTest(unittest.TestCase):
                          ' cxx_flag1 c_flag1 -m32 -O3 -s -DNDEBUG'
                          ' -Wl,-rpath,"/root/lib" -Wl,-rpath,"/root/path/to/lib1"'
                          ' -L/root/lib -L/root/path/to/lib1 -lmylib'
-                         ' -D_GLIBCXX_USE_CXX11_ABI=0 -F /root/Frameworks -std=gnu++17',
+                         ' -D_GLIBCXX_USE_CXX11_ABI=0 -F"/root/Frameworks" -std=gnu++17',
                          gcc.content)
 
     def test_compiler_args(self):
@@ -142,7 +142,7 @@ class CompilerArgsTest(unittest.TestCase):
                          ' cxx_flag1 c_flag1 -m32 -O3 -DNDEBUG'
                          ' -Wl,-rpath,"/root/lib" -Wl,-rpath,"/root/path/to/lib1"'
                          ' -L/root/lib -L/root/path/to/lib1 -lmylib'
-                         ' -F /root/Frameworks', gen.content)
+                         ' -F"/root/Frameworks"', gen.content)
 
         settings = Settings.loads(get_default_settings_yml())
         settings.os = "Linux"
@@ -158,7 +158,7 @@ class CompilerArgsTest(unittest.TestCase):
                          ' cxx_flag1 c_flag1 -m32 -O3 -DNDEBUG'
                          ' -Wl,-rpath,"/root/lib" -Wl,-rpath,"/root/path/to/lib1"'
                          ' -L/root/lib -L/root/path/to/lib1 -lmylib'
-                         ' -F /root/Frameworks', args.content)
+                         ' -F"/root/Frameworks"', args.content)
 
     def test_apple_frameworks(self):
         settings = Settings.loads(get_default_settings_yml())
@@ -175,8 +175,8 @@ class CompilerArgsTest(unittest.TestCase):
                          ' -Wl,-rpath,"/root/lib" -Wl,-rpath,"/root/path/to/lib1"'
                          ' -L/root/lib -L/root/path/to/lib1 -lmylib'
                          ' -framework AVFoundation -framework VideoToolbox'
-                         ' -F /root/Frameworks -F /root/path/to/Frameworks1'
-                         ' -F /root/path/to/Frameworks2', args.content)
+                         ' -F"/root/Frameworks" -F"/root/path/to/Frameworks1"'
+                         ' -F"/root/path/to/Frameworks2"', args.content)
 
     def test_system_libs(self):
         settings = Settings.loads(get_default_settings_yml())
@@ -192,4 +192,4 @@ class CompilerArgsTest(unittest.TestCase):
                          ' cxx_flag1 c_flag1 -m64 -O3 -s -DNDEBUG'
                          ' -Wl,-rpath,"/root/lib" -Wl,-rpath,"/root/path/to/lib1"'
                          ' -L/root/lib -L/root/path/to/lib1 -lmylib -lsystem_lib1'
-                         ' -F /root/Frameworks', args.content)
+                         ' -F"/root/Frameworks"', args.content)
diff --git a/conans/test/unittests/client/generators/pkg_config_test.py b/conans/test/unittests/client/generators/pkg_config_test.py
index d8b028eca..665574755 100644
--- a/conans/test/unittests/client/generators/pkg_config_test.py
+++ b/conans/test/unittests/client/generators/pkg_config_test.py
@@ -214,6 +214,6 @@ includedir=${prefix}/include
 Name: MyPkg
 Description: My cool description
 Version: 1.3
-Libs: -L"${libdir}" -Wl,-rpath,"${libdir}" -framework AudioUnit -framework AudioToolbox -F /dummy_root_folder1/Frameworks
+Libs: -L"${libdir}" -Wl,-rpath,"${libdir}" -framework AudioUnit -framework AudioToolbox -F"/dummy_root_folder1/Frameworks"
 Cflags: -I"${includedir}"
 """)
diff --git a/conans/test/unittests/tools/gnu/gnudepsflags_test.py b/conans/test/unittests/tools/gnu/gnudepsflags_test.py
index 35836a946..1584af11c 100644
--- a/conans/test/unittests/tools/gnu/gnudepsflags_test.py
+++ b/conans/test/unittests/tools/gnu/gnudepsflags_test.py
@@ -28,6 +28,6 @@ def test_framework_flags_only_for_apple_os(os_):
     expected_framework_path = []
     if is_apple_os(conanfile):
         expected_framework = ["-framework Foundation"]
-        expected_framework_path = ["-F Framework"]
+        expected_framework_path = ["-F\"Framework\""]
     assert gnudepsflags.frameworks == expected_framework
     assert gnudepsflags.framework_paths == expected_framework_path