Repository: conan-io/conan
Pull request #12598 (2022-11-24 11:20:28)

editables env-vars and confs
Changelog: Feature: Implement ``editable`` env-vars via ``cpp.xxx.buildenv_info`` and ``cpp.xxx.runenv_info`` and conf via ``cpp.xxx.conf_info``
Docs: https://github.com/conan-io/docs/pull/XXXX

Close https://github.com/conan-io/conan/issues/12499


Patch:
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/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/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 49b0e0b33..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
@@ -82,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)
@@ -99,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:
@@ -166,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:
 
@@ -292,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=
@@ -303,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:
@@ -340,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/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/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/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