Repository: conan-io/conan
Pull request #18474 (2025-06-16 12:20:13)

avoid leaking core.conf in user profiles
Changelog: Bugfix: Avoid leak of ``global.conf`` and ``-cc`` configuration for ``core.xxx`` items in Conan profiles, the ``core`` conf is exclusively for Conan internals, not for recipes neither for profiles.
Docs: https://github.com/conan-io/docs/pull/XXXX




memsharded: @czoido I guess this could be considered breaking if someone was reading the ``global.conf`` core.conf items in recipes, but this was always unexpected, it is not documented, and users shouldn't rely on that, the ``core.xxx`` was always designed for internal Conan usage

Patch:
diff --git a/conan/api/output.py b/conan/api/output.py
index cf291ec98..535586c00 100644
--- a/conan/api/output.py
+++ b/conan/api/output.py
@@ -175,6 +175,12 @@ class ConanOutput:
 
         return self
 
+    def box(self, msg):
+        color = Color.BRIGHT_GREEN
+        self.writeln("\n**************************************************", fg=color)
+        self.writeln(f'*{msg: ^48}*', fg=color)
+        self.writeln(f"**************************************************\n", fg=color)
+
     def _write_message(self, msg, fg=None, bg=None, newline=True):
         if isinstance(msg, dict):
             # For traces we can receive a dict already, we try to transform then into more natural
diff --git a/conan/api/subapi/command.py b/conan/api/subapi/command.py
index abf5dd9cc..272b5e099 100644
--- a/conan/api/subapi/command.py
+++ b/conan/api/subapi/command.py
@@ -1,4 +1,5 @@
 import os
+import shlex
 
 from conan.api.output import ConanOutput
 from conan.errors import ConanException
@@ -12,7 +13,7 @@ class CommandAPI:
 
     def run(self, cmd):
         if isinstance(cmd, str):
-            cmd = cmd.split()
+            cmd = shlex.split(cmd)
         if isinstance(cmd, list):
             current_cmd = cmd[0]
             args = cmd[1:]
diff --git a/conan/api/subapi/workspace.py b/conan/api/subapi/workspace.py
index 96e00f77e..25e2cae6e 100644
--- a/conan/api/subapi/workspace.py
+++ b/conan/api/subapi/workspace.py
@@ -8,8 +8,10 @@ from conan import ConanFile
 from conan.api.model import RecipeReference
 from conan.api.output import ConanOutput
 from conan.cli import make_abs_path
+from conan.cli.printers.graph import print_graph_basic, print_graph_packages
 from conan.errors import ConanException
 from conan.internal.conan_app import ConanApp
+from conan.internal.graph.install_graph import ProfileArgs
 from conan.internal.model.workspace import Workspace, WORKSPACE_YML, WORKSPACE_PY, WORKSPACE_FOLDER
 from conan.tools.scm import Git
 from conan.internal.graph.graph import RECIPE_EDITABLE, DepsGraph, CONTEXT_HOST, RECIPE_VIRTUAL, Node, \
@@ -74,6 +76,7 @@ class WorkspaceAPI:
     TEST_ENABLED = False
 
     def __init__(self, conan_api):
+        self._enabled = True
         self._conan_api = conan_api
         self._folder = _find_ws_folder()
         if self._folder:
@@ -85,6 +88,9 @@ class WorkspaceAPI:
                 ConanOutput().warning(f"Workspace is a dev-only feature, exclusively for testing")
                 self._ws = _load_workspace(self._folder, conan_api)  # Error if not loading
 
+    def enable(self, value):
+        self._enabled = value
+
     @property
     def name(self):
         self._check_ws()
@@ -94,14 +100,14 @@ class WorkspaceAPI:
         """
         @return: the current workspace folder where the conanws.yml or conanws.py is located
         """
+        self._check_ws()
         return self._folder
 
-    @property
-    def editable_packages(self):
+    def packages(self):
         """
         @return: Returns {RecipeReference: {"path": full abs-path, "output_folder": abs-path}}
         """
-        if not self._folder:
+        if not self._folder or not self._enabled:
             return
         editables = self._ws.packages()
         editables = {RecipeReference.loads(r): v.copy() for r, v in editables.items()}
@@ -115,21 +121,6 @@ class WorkspaceAPI:
                                                                    v["output_folder"]))
         return editables
 
-    def select_editables(self, paths):
-        filtered_refs = [self.editable_from_path(p) for p in paths or []]
-        editables = self.editable_packages
-        requires = [ref for ref in editables]
-        if filtered_refs:
-            ConanOutput().info(f"Filtering and installing only selected editable packages")
-            requires = [ref for ref in requires if ref in filtered_refs]
-            ConanOutput().info(f"Filtered references: {requires}")
-        return requires
-
-    @property
-    def products(self):
-        self._check_ws()
-        return self._ws.products()
-
     def open(self, require, remotes, cwd=None):
         app = ConanApp(self._conan_api)
         ref = RecipeReference.loads(require)
@@ -167,7 +158,7 @@ class WorkspaceAPI:
                                  f"'{WORKSPACE_PY}' or '{WORKSPACE_YML}' file")
 
     def add(self, path, name=None, version=None, user=None, channel=None, cwd=None,
-            output_folder=None, remotes=None, product=False):
+            output_folder=None, remotes=None):
         """
         Add a new editable package to the current workspace (the current workspace must exist)
         @param path: The path to the folder containing the conanfile.py that defines the package
@@ -178,7 +169,6 @@ class WorkspaceAPI:
         @param cwd:
         @param output_folder:
         @param remotes:
-        @param product:
         @return: The reference of the added package
         """
         self._check_ws()
@@ -191,7 +181,7 @@ class WorkspaceAPI:
         ref.validate_ref()
         output_folder = make_abs_path(output_folder) if output_folder else None
         # Check the conanfile is there, and name/version matches
-        self._ws.add(ref, full_path, output_folder, product)
+        self._ws.add(ref, full_path, output_folder)
         return ref
 
     @staticmethod
@@ -230,17 +220,10 @@ class WorkspaceAPI:
         self._check_ws()
         return {"name": self.name,
                 "folder": self._folder,
-                "products": self.products,
                 "packages": self._ws.packages()}
 
-    def editable_from_path(self, path):
-        editables = self._ws.packages()
-        for ref, info in editables.items():
-            if info["path"].replace("\\", "/") == path:
-                return RecipeReference.loads(ref)
-
-    def collapse_editables(self, deps_graph, profile_host, profile_build):
-        ConanOutput().title("Collapsing workspace editables")
+    def super_build_graph(self, deps_graph, profile_host, profile_build):
+        ConanOutput().title("Collapsing workspace packages")
 
         root_class = self._ws.root_conanfile()
         if root_class is not None:
@@ -282,3 +265,56 @@ class WorkspaceAPI:
             result.add_edge(root, t.node, r)
 
         return result
+
+    def export(self, lockfile=None, remotes=None):
+        self._check_ws()
+        exported = []
+        for ref, info in self.packages().items():
+            exported_ref = self._conan_api.export.export(info["path"], ref.name, str(ref.version),
+                                                         ref.user, ref.channel,
+                                                         lockfile=lockfile, remotes=remotes)
+            ref, _ = exported_ref
+            exported.append(ref)
+        return exported
+
+
+    def select_packages(self, packages):
+        self._check_ws()
+        editable = self.packages()
+        packages = packages or []
+        selected_editables = {}
+        for ref, info in editable.items():
+            if packages and not any(ref.matches(p, False) for p in packages):
+                continue
+            selected_editables[ref] = info
+        if not selected_editables:
+            raise ConanException("There are no selected packages defined in the workspace")
+
+        return selected_editables
+
+    def build_order(self, packages, profile_host, profile_build, build_mode, lockfile, remotes,
+                    profile_args, update=False):
+        ConanOutput().title(f"Computing dependency graph for each package")
+        conan_api = self._conan_api
+        from conan.internal.graph.install_graph import InstallGraph
+        install_order = InstallGraph(None)
+
+        for ref, info in packages.items():
+            ConanOutput().title(f"Computing the dependency graph for package: {ref}")
+
+            deps_graph = conan_api.graph.load_graph_requires([ref], None,
+                                                             profile_host, profile_build, lockfile,
+                                                             remotes, update)
+            deps_graph.report_graph_error()
+            print_graph_basic(deps_graph)
+            conan_api.graph.analyze_binaries(deps_graph, build_mode, remotes=remotes, update=update,
+                                             lockfile=lockfile)
+            print_graph_packages(deps_graph)
+
+            ConanOutput().success(f"\nAggregating build-order for package: {ref}")
+            install_graph = InstallGraph(deps_graph, order_by="recipe",
+                                         profile_args=ProfileArgs.from_args(profile_args))
+            install_graph.raise_errors()
+            install_order.merge(install_graph)
+
+        return install_order
diff --git a/conan/cli/commands/workspace.py b/conan/cli/commands/workspace.py
index 9704ad2df..3c88ae39b 100644
--- a/conan/cli/commands/workspace.py
+++ b/conan/cli/commands/workspace.py
@@ -2,6 +2,7 @@ import json
 import os
 
 from conan.api.conan_api import ConanAPI
+from conan.api.model import RecipeReference
 from conan.api.output import ConanOutput, cli_out_write
 from conan.api.subapi.workspace import WorkspaceAPI
 from conan.cli import make_abs_path
@@ -11,6 +12,7 @@ from conan.cli.commands.list import print_serial
 from conan.cli.printers import print_profiles
 from conan.cli.printers.graph import print_graph_packages, print_graph_basic
 from conan.errors import ConanException
+from conan.internal.graph.install_graph import ProfileArgs
 
 
 @conan_subcommand(formatters={"text": cli_out_write})
@@ -20,8 +22,6 @@ def workspace_root(conan_api: ConanAPI, parser, subparser, *args):  # noqa
     """
     parser.parse_args(*args)
     ws = conan_api.workspace
-    if not ws.folder():
-        raise ConanException("No workspace defined, conanws.py file not found")
     return ws.folder()
 
 
@@ -59,7 +59,6 @@ def workspace_add(conan_api: ConanAPI, parser, subparser, *args):
                        help='Look in the specified remote or remotes server')
     group.add_argument("-nr", "--no-remote", action="store_true",
                        help='Do not use remote, resolve exclusively in the cache')
-    subparser.add_argument("--product", action="store_true", help="Add the package as a product")
     args = parser.parse_args(*args)
     if args.path and args.ref:
         raise ConanException("Do not use both 'path' and '--ref' argument")
@@ -71,7 +70,7 @@ def workspace_add(conan_api: ConanAPI, parser, subparser, *args):
         path = conan_api.workspace.open(args.ref, remotes, cwd=cwd)
     ref = conan_api.workspace.add(path,
                                   args.name, args.version, args.user, args.channel,
-                                  cwd, args.output_folder, remotes=remotes, product=args.product)
+                                  cwd, args.output_folder, remotes=remotes)
     ConanOutput().success("Reference '{}' added to workspace".format(ref))
 
 
@@ -109,10 +108,21 @@ def workspace_info(conan_api: ConanAPI, parser, subparser, *args):  # noqa
 @conan_subcommand()
 def workspace_build(conan_api: ConanAPI, parser, subparser, *args):
     """
-    Build the current workspace, starting from the "products"
+    Call "conan build" for packages in the workspace, in the right order
     """
-    subparser.add_argument("path", nargs="?",
-                           help='Path to a package folder in the user workspace')
+    _install_build(conan_api, parser, subparser, True, *args)
+
+
+@conan_subcommand()
+def workspace_install(conan_api: ConanAPI, parser, subparser, *args):
+    """
+    Call "conan install" for packages in the workspace, in the right order
+    """
+    _install_build(conan_api, parser, subparser, False, *args)
+
+
+def _install_build(conan_api: ConanAPI, parser, subparser, build, *args):
+    subparser.add_argument("--pkg", action="append", help='Define specific packages')
     add_common_install_arguments(subparser)
     add_lockfile_args(subparser)
     args = parser.parse_args(*args)
@@ -122,58 +132,61 @@ def workspace_build(conan_api: ConanAPI, parser, subparser, *args):
     # The lockfile by default if not defined will be read from the root workspace folder
     ws_folder = conan_api.workspace.folder()
     lockfile = conan_api.lockfile.get_lockfile(lockfile=args.lockfile, conanfile_path=ws_folder,
-                                               cwd=None,
-                                               partial=args.lockfile_partial, overrides=overrides)
+                                               cwd=None, partial=args.lockfile_partial,
+                                               overrides=overrides)
     profile_host, profile_build = conan_api.profiles.get_profiles_from_args(args)
     print_profiles(profile_host, profile_build)
 
-    build_mode = args.build or []
-    if "editable" not in build_mode:
+    buildmode = args.build
+    if build and (not buildmode or "editable" not in buildmode):
         ConanOutput().info("Adding '--build=editable' as build mode")
-        build_mode.append("editable")
-
-    if args.path:
-        products = [args.path]
-    else:  # all products
-        products = conan_api.workspace.products
-        if not products:
-            raise ConanException("There are no products defined in the workspace, can't build\n"
-                                 "You can use 'conan build <path> --build=editable' to build")
-        ConanOutput().title(f"Building workspace products {products}")
-
-    editables = conan_api.workspace.editable_packages
-    # TODO: This has to be improved to avoid repetition when there are multiple products
-    for product in products:
-        ConanOutput().subtitle(f"Building workspace product: {product}")
-        product_ref = conan_api.workspace.editable_from_path(product)
-        if product_ref is None:
-            raise ConanException(f"Product '{product}' not defined in the workspace as editable")
-        editable = editables[product_ref]
-        editable_path = editable["path"]
-        deps_graph = conan_api.graph.load_graph_consumer(editable_path, None, None, None, None,
-                                                         profile_host, profile_build, lockfile,
-                                                         remotes, args.update)
-        deps_graph.report_graph_error()
-        print_graph_basic(deps_graph)
-        conan_api.graph.analyze_binaries(deps_graph, build_mode, remotes=remotes, update=args.update,
-                                         lockfile=lockfile)
-        print_graph_packages(deps_graph)
-        conan_api.install.install_binaries(deps_graph=deps_graph, remotes=remotes)
-        conan_api.install.install_consumer(deps_graph, None, os.path.dirname(editable_path),
-                                           editable.get("output_folder"))
-        ConanOutput().title(f"Calling build() for the product {product_ref}")
-        conanfile = deps_graph.root.conanfile
-        conan_api.local.build(conanfile)
+        buildmode = buildmode or []
+        buildmode.append("editable")
+
+    all_editables = conan_api.workspace.packages()
+    packages = conan_api.workspace.select_packages(args.pkg)
+    ConanOutput().box("Workspace computing the build order")
+    install_order = conan_api.workspace.build_order(packages, profile_host, profile_build, buildmode,
+                                                    lockfile, remotes, args, update=args.update)
+
+    msg = "build" if build else "install"
+    ConanOutput().box(f"Workspace {msg}ing each package")
+    order = install_order.install_build_order()
+
+    profile_args = ProfileArgs.from_args(args)
+    for level in order["order"]:
+        for elem in level:
+            ref = RecipeReference.loads(elem["ref"])
+            for package_level in elem["packages"]:
+                for package in package_level:
+                    if package["binary"] == "Build":  # Build external to Workspace
+                        cmd = f'install {package["build_args"]} {profile_args}'
+                        ConanOutput().box(f"Workspace building external {ref}")
+                        ConanOutput().info(f"Command: {cmd}\n")
+                        conan_api.command.run(cmd)
+                    elif package["binary"] in ("Editable", "EditableBuild"):
+                        path = all_editables[ref]["path"]
+                        output_folder = all_editables[ref].get("output_folder")
+                        build_arg = "--build-require" if package["context"] == "build" else ""
+                        ref_args = " ".join(f"--{k}={getattr(ref, k)}"
+                                            for k in ("name", "version", "user", "channel")
+                                            if getattr(ref, k, None))
+                        of_arg = f'-of="{output_folder}"' if output_folder else ""
+                        # TODO: Missing --lockfile-overrides arg here
+                        command = "build" if build else "install"
+                        cmd = f'{command} "{path}" {profile_args} {build_arg} {ref_args} {of_arg}'
+                        ConanOutput().box(f"Workspace {command}: {ref}")
+                        ConanOutput().info(f"Command: {cmd}\n")
+                        conan_api.command.run(cmd)
 
 
 @conan_subcommand()
-def workspace_install(conan_api: ConanAPI, parser, subparser, *args):
+def workspace_super_install(conan_api: ConanAPI, parser, subparser, *args):
     """
     Install the workspace as a monolith, installing only external dependencies to the workspace,
     generating a single result (generators, etc) for the whole workspace.
     """
-    subparser.add_argument("path", nargs="*",
-                           help="Install only these editable packages, not all")
+    subparser.add_argument("--pkg", action="append", help='Define specific packages')
     subparser.add_argument("-g", "--generator", action="append", help='Generators to use')
     subparser.add_argument("-of", "--output-folder",
                            help='The root output folder for generated and build files')
@@ -193,11 +206,8 @@ def workspace_install(conan_api: ConanAPI, parser, subparser, *args):
     profile_host, profile_build = conan_api.profiles.get_profiles_from_args(args)
     print_profiles(profile_host, profile_build)
 
-    conan_api.workspace.info()  # FIXME: Just to force error if WS not enabled
     # Build a dependency graph with all editables as requirements
-    requires = conan_api.workspace.select_editables(args.path)
-    if not requires:
-        raise ConanException("This workspace cannot be installed, it doesn't have any editable")
+    requires = conan_api.workspace.select_packages(args.pkg)
     deps_graph = conan_api.graph.load_graph_requires(requires, [],
                                                      profile_host, profile_build, lockfile,
                                                      remotes, args.build, args.update)
@@ -205,7 +215,7 @@ def workspace_install(conan_api: ConanAPI, parser, subparser, *args):
     print_graph_basic(deps_graph)
 
     # Collapsing the graph
-    ws_graph = conan_api.workspace.collapse_editables(deps_graph, profile_host, profile_build)
+    ws_graph = conan_api.workspace.super_build_graph(deps_graph, profile_host, profile_build)
     ConanOutput().subtitle("Collapsed graph")
     print_graph_basic(ws_graph)
 
@@ -219,7 +229,7 @@ def workspace_install(conan_api: ConanAPI, parser, subparser, *args):
 
 
 @conan_subcommand()
-def workspace_clean(conan_api: ConanAPI, parser, subparser, *args):
+def workspace_clean(conan_api: ConanAPI, parser, subparser, *args):  # noqa
     """
     Clean the temporary build folders when possible
     """
@@ -239,6 +249,92 @@ def workspace_init(conan_api: ConanAPI, parser, subparser, *args):
     conan_api.workspace.init(args.path)
 
 
+@conan_subcommand()
+def workspace_create(conan_api: ConanAPI, parser, subparser, *args):
+    """
+    Call "conan create" for packages in the workspace, in the correct order.
+    Packages will be created in the Conan cache, not locally
+    """
+    subparser.add_argument("--pkg", action="append", help='Define specific packages')
+    add_common_install_arguments(subparser)
+    add_lockfile_args(subparser)
+    args = parser.parse_args(*args)
+    # Basic collaborators: remotes, lockfile, profiles
+    remotes = conan_api.remotes.list(args.remote) if not args.no_remote else []
+    overrides = eval(args.lockfile_overrides) if args.lockfile_overrides else None
+    # The lockfile by default if not defined will be read from the root workspace folder
+    ws_folder = conan_api.workspace.folder()
+    lockfile = conan_api.lockfile.get_lockfile(lockfile=args.lockfile, conanfile_path=ws_folder,
+                                               cwd=None,
+                                               partial=args.lockfile_partial, overrides=overrides)
+    profile_host, profile_build = conan_api.profiles.get_profiles_from_args(args)
+    print_profiles(profile_host, profile_build)
+
+    build_mode = args.build if args.build else []
+    ConanOutput().box("Exporting workspace recipes to Conan cache")
+    exported_refs = conan_api.workspace.export()
+    build_mode.extend(f"missing:{r}" for r in exported_refs)
+
+    all_packages = conan_api.workspace.packages()
+    packages = conan_api.workspace.select_packages(args.pkg)
+
+    # If we don't disable the workspace, then, the packages are not created in the Conan cache,
+    # but locally in the user folders, are they are intercepted as editables
+    conan_api.workspace.enable(False)
+
+    install_order = conan_api.workspace.build_order(packages, profile_host, profile_build,
+                                                    build_mode, lockfile, remotes, args,
+                                                    update=args.update)
+
+    ConanOutput().box("Workspace creating each package")
+    order = install_order.install_build_order()
+
+    profile_args = ProfileArgs.from_args(args)
+    for level in order["order"]:
+        for elem in level:
+            ref = RecipeReference.loads(elem["ref"])
+            for package_level in elem["packages"]:
+                for package in package_level:
+                    if package["binary"] not in ("Build", "EditableBuild"):
+                        ConanOutput().info(f"Skip build for {ref} binary: {package['binary']}")
+                        continue
+
+                    if ref not in all_packages:
+                        # Build external to Workspace
+                        cmd = f'install {package["build_args"]} {profile_args}'
+                        ConanOutput().box(f"Workspace building external {ref}")
+                        ConanOutput().info(f"Build command: {cmd}\n")
+                        conan_api.command.run(cmd)
+                    else:  # Package in workspace
+                        path = packages[ref]["path"]
+                        # TODO: Missing --lockfile-overrides arg here
+                        build = "--build-require" if package["context"] == "build" else ""
+                        ref_args = " ".join(f"--{k}={getattr(ref, k)}"
+                                            for k in ("name", "version", "user", "channel")
+                                            if getattr(ref, k, None))
+                        cmd = f'create "{path}" {profile_args} {build} {ref_args}'
+                        ConanOutput().box(f"Workspace create {ref}")
+                        ConanOutput().info(f"Conan create command: {cmd}\n")
+                        conan_api.command.run(cmd)
+
+
+@conan_subcommand()
+def workspace_source(conan_api: ConanAPI, parser, subparser, *args):
+    """
+    Call the source() method of packages in the workspace
+    """
+    subparser.add_argument("--pkg", action="append", help='Define specific packages')
+    args = parser.parse_args(*args)
+
+    remotes = conan_api.remotes.list()  # In case "python_requires" are needed
+    packages = conan_api.workspace.select_packages(args.pkg)
+
+    ConanOutput().box("Workspace getting sources")
+    for pkg, info in packages.items():
+        conan_api.local.source(info["path"], name=pkg.name, version=str(pkg.version),
+                               user=pkg.user, channel=pkg.channel, remotes=remotes)
+
+
 @conan_command(group="Consumer")
 def workspace(conan_api, parser, *args):  # noqa
     """
diff --git a/conan/internal/api/install/generators.py b/conan/internal/api/install/generators.py
index a5866c2e4..e369c4449 100644
--- a/conan/internal/api/install/generators.py
+++ b/conan/internal/api/install/generators.py
@@ -167,7 +167,8 @@ def _receive_generators(conanfile):
             names = [c.__name__ if not isinstance(c, str) else c for c in build_req.generator_info]
             conanfile.output.warning(f"Tool-require {build_req} adding generators: {names}",
                                      warn_tag="experimental")
-            conanfile.generators = build_req.generator_info + conanfile.generators
+            # Generators can be defined as a tuple in recipes, ensure we don't break if so
+            conanfile.generators = build_req.generator_info + list(conanfile.generators)
 
 
 def _generate_aggregated_env(conanfile):
diff --git a/conan/internal/api/new/workspace.py b/conan/internal/api/new/workspace.py
index d89c6acef..95ea84111 100644
--- a/conan/internal/api/new/workspace.py
+++ b/conan/internal/api/new/workspace.py
@@ -11,8 +11,6 @@ packages:
     path: libb
   app1/0.1:
     path: app1
-products:
-- app1
 """
 
 cmake = """\
diff --git a/conan/internal/conan_app.py b/conan/internal/conan_app.py
index 0ca4df974..84ed3c3ae 100644
--- a/conan/internal/conan_app.py
+++ b/conan/internal/conan_app.py
@@ -54,7 +54,7 @@ class ConanBasicApp:
         # Handle remote connections
         self.remote_manager = RemoteManager(self.cache, auth_manager, cache_folder)
         global_editables = conan_api.local.editable_packages
-        ws_editables = conan_api.workspace.editable_packages
+        ws_editables = conan_api.workspace.packages()
         self.editable_packages = global_editables.update_copy(ws_editables)
 
 
diff --git a/conan/internal/graph/install_graph.py b/conan/internal/graph/install_graph.py
index 4062bee83..41879aec8 100644
--- a/conan/internal/graph/install_graph.py
+++ b/conan/internal/graph/install_graph.py
@@ -359,6 +359,9 @@ class ProfileArgs:
                             getattr(args, f"{f}_{context}") or []]
         return ProfileArgs(" ".join(pr_args))
 
+    def __str__(self):
+        return self._args
+
     @staticmethod
     def deserialize(data):
         return ProfileArgs(data.get("args"))
diff --git a/conan/internal/model/conf.py b/conan/internal/model/conf.py
index 8f186e28c..8b5410bf8 100644
--- a/conan/internal/model/conf.py
+++ b/conan/internal/model/conf.py
@@ -384,6 +384,12 @@ class Conf:
         c._values = OrderedDict((k, v.copy()) for k, v in self._values.items())
         return c
 
+    def filter_core(self):
+        c = Conf()
+        c._values = OrderedDict((k, v.copy()) for k, v in self._values.items()
+                                if not CORE_CONF_PATTERN.match(k))
+        return c
+
     def dumps(self):
         """
         Returns a string with the format ``name=conf-value``
@@ -630,7 +636,9 @@ class ConfDefinition:
         :type global_conf: ConfDefinition
         """
         result = ConfDefinition()
-        result._pattern_confs = global_conf._pattern_confs.copy()
+        # Do not add ``core.xxx`` configuration to profiles
+        for k, v in global_conf._pattern_confs.items():
+            result._pattern_confs[k] = v.filter_core()
         result.update_conf_definition(self)
         self._pattern_confs = result._pattern_confs
         return
diff --git a/conan/internal/model/cpp_info.py b/conan/internal/model/cpp_info.py
index ebb4c0f85..bf60b1b24 100644
--- a/conan/internal/model/cpp_info.py
+++ b/conan/internal/model/cpp_info.py
@@ -15,6 +15,7 @@ _DIRS_VAR_NAMES = ["_includedirs", "_srcdirs", "_libdirs", "_resdirs", "_bindirs
 _FIELD_VAR_NAMES = ["_system_libs", "_package_framework", "_frameworks", "_libs", "_defines",
                     "_cflags", "_cxxflags", "_sharedlinkflags", "_exelinkflags", "_sources"]
 _ALL_NAMES = _DIRS_VAR_NAMES + _FIELD_VAR_NAMES
+_SINGLE_VALUE_VARS = "_type", "_exe", "_location", "_link_location", "_languages"
 
 
 class MockInfoProperty:
@@ -461,6 +462,12 @@ class _Component:
                 else:
                     setattr(self, varname, other_values)
 
+        for varname in _SINGLE_VALUE_VARS:  # To allow editable of .exe/.location
+            other_values = getattr(other, varname)
+            if other_values is not None:
+                # Just overwrite the existing value, not possible to append
+                setattr(self, varname, other_values)
+
         if other.requires:
             current_values = self.get_init("requires", [])
             merge_list(other.requires, current_values)
diff --git a/conan/internal/model/workspace.py b/conan/internal/model/workspace.py
index 35ff09777..2fe436564 100644
--- a/conan/internal/model/workspace.py
+++ b/conan/internal/model/workspace.py
@@ -38,15 +38,13 @@ class Workspace:
             raise ConanException("Invalid yml format at {}: {}".format(WORKSPACE_YML, e))
         return data or {}
 
-    def add(self, ref, path, output_folder, product=False):
+    def add(self, ref, path, output_folder):
         assert os.path.isfile(path)
         path = self._conan_rel_path(os.path.dirname(path))
         editable = {"path": path}
         if output_folder:
             editable["output_folder"] = self._conan_rel_path(output_folder)
         self.conan_data.setdefault("packages", {})[str(ref)] = editable
-        if product:
-            self.conan_data.setdefault("products", []).append(path)
         save(os.path.join(self.folder, WORKSPACE_YML), yaml.dump(self.conan_data))
 
     def remove(self, path):
@@ -59,8 +57,6 @@ class Workspace:
         if not found_ref:
             raise ConanException(f"No editable package to remove from this path: {path}")
         self.conan_data["packages"].pop(found_ref)
-        if path in self.conan_data.get("products", []):
-            self.conan_data["products"].remove(path)
         save(os.path.join(self.folder, WORKSPACE_YML), yaml.dump(self.conan_data))
         return found_ref
 
@@ -88,9 +84,6 @@ class Workspace:
     def packages(self):
         return self.conan_data.get("packages", {})
 
-    def products(self):
-        return self.conan_data.get("products", [])
-
     def load_conanfile(self, conanfile_path):
         conanfile_path = os.path.join(self.folder, conanfile_path, "conanfile.py")
         from conan.internal.loader import ConanFileLoader
diff --git a/conan/tools/apple/apple.py b/conan/tools/apple/apple.py
index 8afda1ad2..0e3d7efce 100644
--- a/conan/tools/apple/apple.py
+++ b/conan/tools/apple/apple.py
@@ -334,20 +334,14 @@ def apple_extra_flags(conanfile):
     if not is_apple_os(conanfile):
         return []
     enable_bitcode = conanfile.conf.get("tools.apple:enable_bitcode", check_type=bool)
-    enable_arc = conanfile.conf.get("tools.apple:enable_arc", check_type=bool)
     enable_visibility = conanfile.conf.get("tools.apple:enable_visibility", check_type=bool)
     is_debug = conanfile.settings.get_safe('build_type') == "Debug"
-
     flags = []
     if enable_bitcode:
         if is_debug:
             flags.append("-fembed-bitcode-marker")
         else:
             flags.append("-fembed-bitcode")
-    if enable_arc:
-        flags.append("-fobjc-arc")
-    if enable_arc is False:
-        flags.append("-fno-objc-arc")
     if enable_visibility:
         flags.append("-fvisibility=default")
     if enable_visibility is False:
diff --git a/conan/tools/apple/xcodedeps.py b/conan/tools/apple/xcodedeps.py
index c5efca07c..17dbf31da 100644
--- a/conan/tools/apple/xcodedeps.py
+++ b/conan/tools/apple/xcodedeps.py
@@ -109,7 +109,6 @@ class XcodeDeps(object):
         self._conanfile = conanfile
         self.configuration = conanfile.settings.get_safe("build_type")
         arch = conanfile.settings.get_safe("arch")
-        self.os_version = conanfile.settings.get_safe("os.version")
         self.architecture = _to_apple_arch(arch, default=arch)
         self.os_version = conanfile.settings.get_safe("os.version")
         self.sdk = conanfile.settings.get_safe("os.sdk")
diff --git a/conan/tools/apple/xcodetoolchain.py b/conan/tools/apple/xcodetoolchain.py
index 269f6e08d..194aa3af6 100644
--- a/conan/tools/apple/xcodetoolchain.py
+++ b/conan/tools/apple/xcodetoolchain.py
@@ -13,7 +13,7 @@ class XcodeToolchain(object):
 
     _vars_xconfig = textwrap.dedent("""\
         // Definition of toolchain variables
-        {macosx_deployment_target}
+        {apple_deployment_target}
         {clang_cxx_library}
         {clang_cxx_language_standard}
         """)
@@ -63,9 +63,17 @@ class XcodeToolchain(object):
         return cppstd
 
     @property
-    def _macosx_deployment_target(self):
-        return 'MACOSX_DEPLOYMENT_TARGET{}={}'.format(_xcconfig_conditional(self._conanfile.settings, self.configuration),
-                                                      self.os_version) if self.os_version else ""
+    def _apple_deployment_target(self):
+        deployment_target_key = {
+            "Macos": "MACOSX_DEPLOYMENT_TARGET",
+            "iOS": "IPHONEOS_DEPLOYMENT_TARGET",
+            "tvOS": "TVOS_DEPLOYMENT_TARGET",
+            "watchOS": "WATCHOS_DEPLOYMENT_TARGET",
+            "visionOS": "XROS_DEPLOYMENT_TARGET",
+        }.get(str(self._conanfile.settings.get_safe("os")))
+        return '{}{}={}'.format(deployment_target_key,
+                                _xcconfig_conditional(self._conanfile.settings, self.configuration),
+                                self.os_version) if self.os_version else ""
 
     @property
     def _clang_cxx_library(self):
@@ -83,7 +91,7 @@ class XcodeToolchain(object):
 
     @property
     def _vars_xconfig_content(self):
-        ret = self._vars_xconfig.format(macosx_deployment_target=self._macosx_deployment_target,
+        ret = self._vars_xconfig.format(apple_deployment_target=self._apple_deployment_target,
                                         clang_cxx_library=self._clang_cxx_library,
                                         clang_cxx_language_standard=self._clang_cxx_language_standard)
         return ret
diff --git a/conan/tools/build/flags.py b/conan/tools/build/flags.py
index 441aca0af..49156c5ed 100644
--- a/conan/tools/build/flags.py
+++ b/conan/tools/build/flags.py
@@ -67,11 +67,21 @@ def architecture_flag(conanfile):
                 "e2k-v6": "-march=elbrus-v6",
                 "e2k-v7": "-march=elbrus-v7"}.get(arch, "")
     elif compiler == "emcc":
-        # Emscripten default output is WASM since 1.37.x (long time ago)
         if arch == "wasm64":
             return "-sMEMORY64=1"
+    return ""
+
+
+def architecture_link_flag(conanfile):
+    """
+    returns exclusively linker flags specific to the target architecture and compiler
+    """
+    compiler = conanfile.settings.get_safe("compiler")
+    arch = conanfile.settings.get_safe("arch")
+    if compiler == "emcc":
+        # Emscripten default output is WASM since 1.37.x (long time ago)
         # Deactivate WASM output forcing asm.js output instead
-        elif arch == "asm.js":
+        if arch == "asm.js":
             return "-sWASM=0"
     return ""
 
diff --git a/conan/tools/cmake/toolchain/blocks.py b/conan/tools/cmake/toolchain/blocks.py
index 951aa2662..d2a77fda6 100644
--- a/conan/tools/cmake/toolchain/blocks.py
+++ b/conan/tools/cmake/toolchain/blocks.py
@@ -10,7 +10,7 @@ from conan.tools.apple.apple import get_apple_sdk_fullname, _to_apple_arch
 from conan.tools.android.utils import android_abi
 from conan.tools.apple.apple import is_apple_os, to_apple_arch
 from conan.tools.build import build_jobs
-from conan.tools.build.flags import architecture_flag, libcxx_flags
+from conan.tools.build.flags import architecture_flag, architecture_link_flag, libcxx_flags
 from conan.tools.build.cross_building import cross_building
 from conan.tools.cmake.toolchain import CONAN_TOOLCHAIN_FILENAME
 from conan.tools.cmake.utils import is_multi_configuration
@@ -238,19 +238,26 @@ class SkipRPath(Block):
 class ArchitectureBlock(Block):
     template = textwrap.dedent("""\
         # Define C++ flags, C flags and linker flags from 'settings.arch'
-
+        {% if arch_flag %}
         message(STATUS "Conan toolchain: Defining architecture flag: {{ arch_flag }}")
         string(APPEND CONAN_CXX_FLAGS " {{ arch_flag }}")
         string(APPEND CONAN_C_FLAGS " {{ arch_flag }}")
         string(APPEND CONAN_SHARED_LINKER_FLAGS " {{ arch_flag }}")
         string(APPEND CONAN_EXE_LINKER_FLAGS " {{ arch_flag }}")
+        {% endif %}
+        {% if arch_link_flag %}
+        message(STATUS "Conan toolchain: Defining architecture linker flag: {{ arch_link_flag }}")
+        string(APPEND CONAN_SHARED_LINKER_FLAGS " {{ arch_link_flag }}")
+        string(APPEND CONAN_EXE_LINKER_FLAGS " {{ arch_link_flag }}")
+        {% endif %}
         """)
 
     def context(self):
         arch_flag = architecture_flag(self._conanfile)
-        if not arch_flag:
+        arch_link_flag = architecture_link_flag(self._conanfile)
+        if not arch_flag and not arch_link_flag:
             return
-        return {"arch_flag": arch_flag}
+        return {"arch_flag": arch_flag, "arch_link_flag": arch_link_flag}
 
 
 class LinkerScriptsBlock(Block):
@@ -464,8 +471,11 @@ class AppleSystemBlock(Block):
         if(CMAKE_GENERATOR MATCHES "Xcode")
           message(DEBUG "Not setting any manual command-line buildflags, since Xcode is selected as generator.")
         else()
-            string(APPEND CONAN_C_FLAGS " ${BITCODE} ${VISIBILITY} ${FOBJC_ARC}")
-            string(APPEND CONAN_CXX_FLAGS " ${BITCODE} ${VISIBILITY} ${FOBJC_ARC}")
+            string(APPEND CONAN_C_FLAGS " ${BITCODE} ${VISIBILITY}")
+            string(APPEND CONAN_CXX_FLAGS " ${BITCODE} ${VISIBILITY}")
+            # Objective-C/C++ specific flags
+            string(APPEND CONAN_OBJC_FLAGS " ${BITCODE} ${VISIBILITY} ${FOBJC_ARC}")
+            string(APPEND CONAN_OBJCXX_FLAGS " ${BITCODE} ${VISIBILITY} ${FOBJC_ARC}")
         endif()
         """)
 
@@ -852,6 +862,12 @@ class CMakeFlagsInitBlock(Block):
         if(DEFINED CONAN_EXE_LINKER_FLAGS)
           string(APPEND CMAKE_EXE_LINKER_FLAGS_INIT " ${CONAN_EXE_LINKER_FLAGS}")
         endif()
+        if(DEFINED CONAN_OBJCXX_FLAGS)
+          string(APPEND CMAKE_OBJCXX_FLAGS_INIT " ${CONAN_OBJCXX_FLAGS}")
+        endif()
+        if(DEFINED CONAN_OBJC_FLAGS)
+          string(APPEND CMAKE_OBJC_FLAGS_INIT " ${CONAN_OBJC_FLAGS}")
+        endif()
         """)
 
 
diff --git a/conan/tools/gnu/autotoolstoolchain.py b/conan/tools/gnu/autotoolstoolchain.py
index f2e454474..1b2ecd3c9 100644
--- a/conan/tools/gnu/autotoolstoolchain.py
+++ b/conan/tools/gnu/autotoolstoolchain.py
@@ -6,7 +6,7 @@ from conan.internal.internal_tools import raise_on_universal_arch
 from conan.tools.apple.apple import is_apple_os, resolve_apple_flags, apple_extra_flags
 from conan.tools.build import cmd_args_to_string, save_toolchain_args
 from conan.tools.build.cross_building import cross_building
-from conan.tools.build.flags import architecture_flag, build_type_flags, cppstd_flag, \
+from conan.tools.build.flags import architecture_flag, architecture_link_flag, build_type_flags, cppstd_flag, \
     build_type_link_flags, libcxx_flags, cstd_flag, llvm_clang_front
 from conan.tools.env import Environment, VirtualBuildEnv
 from conan.tools.gnu.get_gnu_triplet import _get_gnu_triplet
@@ -52,6 +52,7 @@ class AutotoolsToolchain:
         self.cppstd = cppstd_flag(self._conanfile)
         self.cstd = cstd_flag(self._conanfile)
         self.arch_flag = architecture_flag(self._conanfile)
+        self.arch_ld_flag = architecture_link_flag(self._conanfile)
         self.libcxx, self.gcc_cxx11_abi = libcxx_flags(self._conanfile)
         self.fpic = self._conanfile.options.get_safe("fPIC")
         self.msvc_runtime_flag = self._get_msvc_runtime_flag()
@@ -223,7 +224,7 @@ class AutotoolsToolchain:
 
     @property
     def ldflags(self):
-        ret = [self.arch_flag, self.sysroot_flag]
+        ret = [self.arch_flag, self.sysroot_flag, self.arch_ld_flag]
         apple_flags = [self.apple_isysroot_flag, self.apple_arch_flag, self.apple_min_version_flag]
         apple_flags += self.apple_extra_flags
         conf_flags = self._conanfile.conf.get("tools.build:sharedlinkflags", default=[],
@@ -243,6 +244,17 @@ class AutotoolsToolchain:
         ret = [self.ndebug, self.gcc_cxx11_abi] + self.extra_defines + conf_flags
         return self._filter_list_empty_fields(ret)
 
+    def _include_obj_arc_flags(self, env):
+        enable_arc = self._conanfile.conf.get("tools.apple:enable_arc", check_type=bool)
+        fobj_arc = ""
+        if enable_arc:
+            fobj_arc = "-fobjc-arc"
+        if enable_arc is False:
+            fobj_arc = "-fno-objc-arc"
+        if fobj_arc:
+            env.append('OBJCFLAGS', [fobj_arc])
+            env.append('OBJCXXFLAGS', [fobj_arc])
+
     def environment(self):
         env = Environment()
         # Setting Android cross-compilation flags (if exist)
@@ -276,6 +288,8 @@ class AutotoolsToolchain:
         env.append("CFLAGS", self.cflags)
         env.append("LDFLAGS", self.ldflags)
         env.prepend_path("PKG_CONFIG_PATH", self._conanfile.generators_folder)
+        # Objective C/C++
+        self._include_obj_arc_flags(env)
         # Issue related: https://github.com/conan-io/conan/issues/15486
         if self._is_cross_building and self._conanfile.conf_build:
             compilers_build_mapping = (
diff --git a/conan/tools/gnu/gnutoolchain.py b/conan/tools/gnu/gnutoolchain.py
index 800cb35b4..3a478d962 100644
--- a/conan/tools/gnu/gnutoolchain.py
+++ b/conan/tools/gnu/gnutoolchain.py
@@ -5,7 +5,7 @@ from conan.internal.internal_tools import raise_on_universal_arch
 from conan.tools.apple.apple import is_apple_os, resolve_apple_flags, apple_extra_flags
 from conan.tools.build import cmd_args_to_string, save_toolchain_args
 from conan.tools.build.cross_building import cross_building
-from conan.tools.build.flags import architecture_flag, build_type_flags, cppstd_flag, \
+from conan.tools.build.flags import architecture_flag, architecture_link_flag, build_type_flags, cppstd_flag, \
     build_type_link_flags, \
     libcxx_flags, llvm_clang_front
 from conan.tools.env import Environment, VirtualBuildEnv
@@ -57,6 +57,7 @@ class GnuToolchain:
 
         self.cppstd = cppstd_flag(self._conanfile)
         self.arch_flag = architecture_flag(self._conanfile)
+        self.arch_ld_flag = architecture_link_flag(self._conanfile)
         self.libcxx, self.gcc_cxx11_abi = libcxx_flags(self._conanfile)
         self.fpic = self._conanfile.options.get_safe("fPIC")
         self.msvc_runtime_flag = self._get_msvc_runtime_flag()
@@ -288,7 +289,7 @@ class GnuToolchain:
 
     @property
     def ldflags(self):
-        ret = [self.arch_flag, self.sysroot_flag]
+        ret = [self.arch_flag, self.sysroot_flag, self.arch_ld_flag]
         apple_flags = [self.apple_isysroot_flag, self.apple_arch_flag, self.apple_min_version_flag]
         apple_flags += self.apple_extra_flags
         conf_flags = self._conanfile.conf.get("tools.build:sharedlinkflags", default=[],
@@ -337,6 +338,17 @@ class GnuToolchain:
                 triplets[f"--{context}"] = info["triplet"]
         return triplets
 
+    def _include_obj_arc_flags(self, env):
+        enable_arc = self._conanfile.conf.get("tools.apple:enable_arc", check_type=bool)
+        fobj_arc = ""
+        if enable_arc:
+            fobj_arc = "-fobjc-arc"
+        if enable_arc is False:
+            fobj_arc = "-fno-objc-arc"
+        if fobj_arc:
+            env.append('OBJCFLAGS', [fobj_arc])
+            env.append('OBJCXXFLAGS', [fobj_arc])
+
     @property
     def _environment(self):
         env = Environment()
@@ -346,6 +358,8 @@ class GnuToolchain:
         env.append("CFLAGS", self.cflags)
         env.append("LDFLAGS", self.ldflags)
         env.prepend_path("PKG_CONFIG_PATH", self._conanfile.generators_folder)
+        # Objective C/C++
+        self._include_obj_arc_flags(env)
         # Let's compose with user extra env variables defined (user ones have precedence)
         return self.extra_env.compose_env(env)
 
diff --git a/conan/tools/gnu/pkgconfigdeps.py b/conan/tools/gnu/pkgconfigdeps.py
index 70d85e5fb..95b2174fd 100644
--- a/conan/tools/gnu/pkgconfigdeps.py
+++ b/conan/tools/gnu/pkgconfigdeps.py
@@ -259,7 +259,8 @@ class _PCFilesDeps:
         # Second, let's load the root package's PC file ONLY
         # if it does not already exist in components one
         # Issue related: https://github.com/conan-io/conan/issues/10341
-        if pkg_name not in pc_files:
+        should_skip_main = self._get_property("pkg_config_name", self._dep) == "none"
+        if pkg_name not in pc_files and not should_skip_main:
             cpp_info = self._dep.cpp_info
             # At first, let's check if we have defined some global requires, e.g., "other::cmp1"
             # Note: If DEP has components, they'll be the requirements == pc_files.keys()
diff --git a/conan/tools/meson/helpers.py b/conan/tools/meson/helpers.py
index fcf49fd40..a6ea07a65 100644
--- a/conan/tools/meson/helpers.py
+++ b/conan/tools/meson/helpers.py
@@ -53,7 +53,7 @@ _meson_cpu_family_map = {
     'x86': ('x86', 'x86', 'little'),
     'x86_64': ('x86_64', 'x86_64', 'little'),
     'riscv32': ('riscv32', 'riscv32', 'little'),
-    'riscv64': ('riscv64', 'riscv32', 'little')
+    'riscv64': ('riscv64', 'riscv64', 'little')
 }
 
 
diff --git a/conan/tools/meson/toolchain.py b/conan/tools/meson/toolchain.py
index 5014c1348..c1f1e79ed 100644
--- a/conan/tools/meson/toolchain.py
+++ b/conan/tools/meson/toolchain.py
@@ -9,7 +9,7 @@ from conan.internal.internal_tools import raise_on_universal_arch
 from conan.tools.apple.apple import is_apple_os, apple_min_version_flag, \
     resolve_apple_flags, apple_extra_flags
 from conan.tools.build.cross_building import cross_building
-from conan.tools.build.flags import libcxx_flags, architecture_flag
+from conan.tools.build.flags import architecture_link_flag, libcxx_flags, architecture_flag
 from conan.tools.env import VirtualBuildEnv
 from conan.tools.meson.helpers import *
 from conan.tools.meson.helpers import get_apple_subsystem
@@ -216,6 +216,8 @@ class MesonToolchain:
         self.extra_defines = []
         #: Architecture flag deduced by Conan and added to ``c_args``, ``cpp_args``, ``c_link_args`` and ``cpp_link_args``
         self.arch_flag = architecture_flag(self._conanfile)  # https://github.com/conan-io/conan/issues/17624
+        #: Architecture link flag deduced by Conan and added to ``c_link_args`` and ``cpp_link_args``
+        self.arch_link_flag = architecture_link_flag(self._conanfile)
         #: Dict-like object that defines Meson ``properties`` with ``key=value`` format
         self.properties = {}
         #: Dict-like object that defines Meson ``project options`` with ``key=value`` format
@@ -403,11 +405,18 @@ class MesonToolchain:
         self.apple_isysroot_flag = isysroot_flag.split() if isysroot_flag else []
         self.apple_min_version_flag = [apple_min_version_flag(self._conanfile)]
         # Objective C/C++ ones
+        flags = []
         self.objc = compilers_by_conf.get("objc", "clang")
         self.objcpp = compilers_by_conf.get("objcpp", "clang++")
-        self.objc_args = self._get_env_list(build_env.get('OBJCFLAGS', []))
+        enable_arc = self._conanfile.conf.get("tools.apple:enable_arc", check_type=bool)
+        fobj_arc = ""
+        if enable_arc:
+            fobj_arc = "-fobjc-arc"
+        if enable_arc is False:
+            fobj_arc = "-fno-objc-arc"
+        self.objc_args = self._get_env_list(build_env.get('OBJCFLAGS', [])) + [fobj_arc]
         self.objc_link_args = self._get_env_list(build_env.get('LDFLAGS', []))
-        self.objcpp_args = self._get_env_list(build_env.get('OBJCXXFLAGS', []))
+        self.objcpp_args = self._get_env_list(build_env.get('OBJCXXFLAGS', [])) + [fobj_arc]
         self.objcpp_link_args = self._get_env_list(build_env.get('LDFLAGS', []))
 
     def _resolve_android_cross_compilation(self):
@@ -452,7 +461,7 @@ class MesonToolchain:
         return {
             "cxxflags": [self.arch_flag] + cxxflags + sys_root + self.extra_cxxflags,
             "cflags": [self.arch_flag] + cflags + sys_root + self.extra_cflags,
-            "ldflags": [self.arch_flag] + ld,
+            "ldflags": [self.arch_flag] + [self.arch_link_flag] + ld,
             "defines": [f"-D{d}" for d in (defines + self.extra_defines)]
         }
 
@@ -474,6 +483,7 @@ class MesonToolchain:
         ret = [x.strip() for x in value.split() if x]
         return ret[0] if len(ret) == 1 else ret
 
+    @property
     def _context(self):
         apple_flags = self.apple_isysroot_flag + self.apple_arch_flag + self.apple_min_version_flag
         extra_flags = self._get_extra_flags()
@@ -483,11 +493,11 @@ class MesonToolchain:
         self.c_link_args.extend(apple_flags + extra_flags["ldflags"])
         self.cpp_link_args.extend(apple_flags + extra_flags["ldflags"])
         # Objective C/C++
-        self.objc_args.extend(self.c_args + extra_flags["defines"])
-        self.objcpp_args.extend(self.cpp_args + extra_flags["defines"])
+        self.objc_args.extend(self.c_args)
+        self.objcpp_args.extend(self.cpp_args)
         # These link_args have already the LDFLAGS env value so let's add only the new possible ones
-        self.objc_link_args.extend(apple_flags + extra_flags["ldflags"])
-        self.objcpp_link_args.extend(apple_flags + extra_flags["ldflags"])
+        self.objc_link_args.extend(self.c_link_args)
+        self.objcpp_link_args.extend(self.cpp_link_args)
 
         if self.libcxx:
             self.cpp_args.append(self.libcxx)
@@ -502,7 +512,6 @@ class MesonToolchain:
                     raise ConanException("MesonToolchain.subproject_options must be a list of dicts")
                 subproject_options[subproject] = [{k: to_meson_value(v) for k, v in keypair.items()}
                                                   for keypair in listkeypair]
-
         return {
             # https://mesonbuild.com/Machine-files.html#properties
             "properties": {k: to_meson_value(v) for k, v in self.properties.items()},
@@ -567,7 +576,7 @@ class MesonToolchain:
 
         :return: ``str`` whole Meson context content.
         """
-        context = self._context()
+        context = self._context
         content = Template(self._meson_file_template, trim_blocks=True, lstrip_blocks=True,
                            undefined=StrictUndefined).render(context)
         return content
diff --git a/conan/tools/scm/git.py b/conan/tools/scm/git.py
index 190711e18..9775a1e6d 100644
--- a/conan/tools/scm/git.py
+++ b/conan/tools/scm/git.py
@@ -120,8 +120,15 @@ class Git:
             self.run(f"fetch {remote} --refetch --dry-run {commit}")
             return True
         except (Exception,):
-            # Don't raise an error because the fetch could fail for many more reasons than the branch.
-            return False
+            # For example, if using an older git<2.36, see
+            # https://github.com/conan-io/conan/issues/18470, then lets try the old approach
+            try:
+                # This will raise if commit not present.
+                self.run("fetch {} --dry-run --depth=1 {}".format(remote, commit))
+                return True
+            except (Exception,):
+                # Don't raise an error because it could fail for many more reasons.
+                return False
 
     def is_dirty(self, repository=False):
         """


Test patch:
diff --git a/conan/test/utils/file_server.py b/conan/test/utils/file_server.py
index f8605c558..53aa12034 100644
--- a/conan/test/utils/file_server.py
+++ b/conan/test/utils/file_server.py
@@ -40,7 +40,7 @@ class TestFileServer:
         def head(folder, file):
             exists = os.path.exists(os.path.join(store, folder, file))
             if exists:
-                return True
+                return bottle.HTTPResponse(status=200)
             return bottle.HTTPError(404, "Not found")
 
         @app.route("/forbidden", method=["GET"])
diff --git a/test/functional/toolchains/cmake/cmakedeps2/test_cmakeconfigdeps_new.py b/test/functional/toolchains/cmake/cmakedeps2/test_cmakeconfigdeps_new.py
index 3bee9360f..3ca484d4f 100644
--- a/test/functional/toolchains/cmake/cmakedeps2/test_cmakeconfigdeps_new.py
+++ b/test/functional/toolchains/cmake/cmakedeps2/test_cmakeconfigdeps_new.py
@@ -15,12 +15,12 @@ new_value = "will_break_next"
 
 @pytest.mark.tool("cmake")
 class TestExes:
-    @pytest.mark.parametrize("tool_requires", [False, True])
-    def test_exe(self, tool_requires):
+    @pytest.mark.parametrize("editable", [False, True])
+    def test_exe(self, editable):
         conanfile = textwrap.dedent(r"""
-            import os
+            import os, platform
             from conan import ConanFile
-            from conan.tools.cmake import CMake
+            from conan.tools.cmake import CMake, cmake_layout
 
             class Test(ConanFile):
                 name = "mytool"
@@ -30,6 +30,13 @@ class TestExes:
                 generators = "CMakeToolchain"
                 exports_sources = "*"
 
+                def layout(self):
+                    cmake_layout(self)
+                    self.cpp.build.exe = "mytool"
+                    name = "mytool.exe" if platform.system() == "Windows" else "mytool"
+                    app_loc = os.path.join("build", str(self.settings.build_type), name)
+                    self.cpp.build.location = app_loc
+
                 def build(self):
                     cmake = CMake(self)
                     cmake.configure()
@@ -57,46 +64,48 @@ class TestExes:
         c.run("new cmake_exe -d name=mytool -d version=0.1")
         c.save({"conanfile.py": conanfile,
                 "src/main.cpp": main})
+        if editable:
+            c.run("editable add .")
         c.run("create .")
 
-        requires = "tool_requires" if tool_requires else "requires"
-        consumer = textwrap.dedent(f"""
-            from conan import ConanFile
-            from conan.tools.cmake import CMakeDeps, CMakeToolchain, CMake, cmake_layout
-            class Consumer(ConanFile):
-                settings = "os", "compiler", "arch", "build_type"
-                {requires} = "mytool/0.1"
-
-                def generate(self):
-                    deps = CMakeDeps(self)
-                    deps.generate()
-                    tc = CMakeToolchain(self)
-                    tc.generate()
-
-                def layout(self):
-                    cmake_layout(self)
-                def build(self):
-                    cmake = CMake(self)
-                    cmake.configure()
-                    cmake.build()
-            """)
-        cmake = textwrap.dedent("""
-            set(CMAKE_C_COMPILER_WORKS 1)
-            set(CMAKE_C_ABI_COMPILED 1)
-            cmake_minimum_required(VERSION 3.15)
-            project(consumer C)
-
-            find_package(mytool)
-            add_custom_command(OUTPUT out.c COMMAND MyTool::myexe)
-            add_library(myLib out.c)
-            """)
-        c.save({"conanfile.py": consumer,
-                "CMakeLists.txt": cmake}, clean_first=True)
-        c.run(f"build . -c tools.cmake.cmakedeps:new={new_value}")
-        assert "find_package(mytool)" in c.out
-        assert "target_link_libraries(..." not in c.out
-        assert "Conan: Target declared imported executable 'MyTool::myexe'" in c.out
-        assert "Mytool generating out.c!!!!!" in c.out
+        for requires in ("tool_requires", "requires"):
+            consumer = textwrap.dedent(f"""
+                from conan import ConanFile
+                from conan.tools.cmake import CMakeDeps, CMakeToolchain, CMake, cmake_layout
+                class Consumer(ConanFile):
+                    settings = "os", "compiler", "arch", "build_type"
+                    {requires} = "mytool/0.1"
+
+                    def generate(self):
+                        deps = CMakeDeps(self)
+                        deps.generate()
+                        tc = CMakeToolchain(self)
+                        tc.generate()
+
+                    def layout(self):
+                        cmake_layout(self)
+                    def build(self):
+                        cmake = CMake(self)
+                        cmake.configure()
+                        cmake.build()
+                """)
+            cmake = textwrap.dedent("""
+                set(CMAKE_C_COMPILER_WORKS 1)
+                set(CMAKE_C_ABI_COMPILED 1)
+                cmake_minimum_required(VERSION 3.15)
+                project(consumer C)
+
+                find_package(mytool)
+                add_custom_command(OUTPUT out.c COMMAND MyTool::myexe)
+                add_library(myLib out.c)
+                """)
+            c.save({f"consumer_{requires}/conanfile.py": consumer,
+                    f"consumer_{requires}/CMakeLists.txt": cmake})
+            c.run(f"build consumer_{requires} -c tools.cmake.cmakedeps:new={new_value}")
+            assert "find_package(mytool)" in c.out
+            assert "target_link_libraries(..." not in c.out
+            assert "Conan: Target declared imported executable 'MyTool::myexe'" in c.out
+            assert "Mytool generating out.c!!!!!" in c.out
 
     def test_exe_components(self):
         conanfile = textwrap.dedent(r"""
diff --git a/test/functional/toolchains/cmake/test_cmake_toolchain_xcode_flags.py b/test/functional/toolchains/cmake/test_cmake_toolchain_xcode_flags.py
index 0cfc20661..16f0881f0 100644
--- a/test/functional/toolchains/cmake/test_cmake_toolchain_xcode_flags.py
+++ b/test/functional/toolchains/cmake/test_cmake_toolchain_xcode_flags.py
@@ -12,6 +12,8 @@ def _add_message_status_flags(client):
     with open(cmakelists_path, "a") as cmakelists_file:
         cmakelists_file.write('message(STATUS "CONAN_C_FLAGS: ${CONAN_C_FLAGS}")\n')
         cmakelists_file.write('message(STATUS "CONAN_CXX_FLAGS: ${CONAN_CXX_FLAGS}")\n')
+        cmakelists_file.write('message(STATUS "CONAN_OBJC_FLAGS: ${CONAN_OBJC_FLAGS}")\n')
+        cmakelists_file.write('message(STATUS "CONAN_OBJCXX_FLAGS: ${CONAN_OBJCXX_FLAGS}")\n')
 
 
 @pytest.mark.skipif(platform.system() != "Darwin", reason="Only OSX")
@@ -52,8 +54,10 @@ def test_cmake_apple_bitcode_arc_and_visibility_flags_enabled(op_system, os_vers
 
     client.run("create . --profile:build=default --profile:host=host -tf=")
     # flags
-    assert "-- CONAN_C_FLAGS:  -fembed-bitcode -fvisibility=default -fobjc-arc" in client.out
-    assert "-- CONAN_CXX_FLAGS:  -fembed-bitcode -fvisibility=default -fobjc-arc" in client.out
+    assert "-- CONAN_C_FLAGS:  -fembed-bitcode -fvisibility=default" in client.out
+    assert "-- CONAN_CXX_FLAGS:  -fembed-bitcode -fvisibility=default" in client.out
+    assert "-- CONAN_OBJC_FLAGS:  -fembed-bitcode -fvisibility=default -fobjc-arc" in client.out
+    assert "-- CONAN_OBJCXX_FLAGS:  -fembed-bitcode -fvisibility=default -fobjc-arc" in client.out
     assert "[100%] Built target hello" in client.out
 
 
@@ -136,8 +140,10 @@ def test_cmake_apple_bitcode_arc_and_visibility_flags_disabled(op_system, os_ver
 
     client.run("create . --profile:build=default --profile:host=host -tf=\"\"")
     # flags
-    assert "-- CONAN_C_FLAGS:   -fvisibility=hidden -fvisibility-inlines-hidden -fno-objc-arc" in client.out
-    assert "-- CONAN_CXX_FLAGS:   -fvisibility=hidden -fvisibility-inlines-hidden -fno-objc-arc" in client.out
+    assert "-- CONAN_C_FLAGS:   -fvisibility=hidden -fvisibility-inlines-hidden" in client.out
+    assert "-- CONAN_CXX_FLAGS:   -fvisibility=hidden -fvisibility-inlines-hidden" in client.out
+    assert "-- CONAN_OBJC_FLAGS:   -fvisibility=hidden -fvisibility-inlines-hidden -fno-objc-arc" in client.out
+    assert "-- CONAN_OBJCXX_FLAGS:   -fvisibility=hidden -fvisibility-inlines-hidden -fno-objc-arc" in client.out
     assert "[100%] Built target hello" in client.out
 
 
diff --git a/test/functional/workspace/test_workspace.py b/test/functional/workspace/test_workspace.py
index 873a13320..a6f80072c 100644
--- a/test/functional/workspace/test_workspace.py
+++ b/test/functional/workspace/test_workspace.py
@@ -1,6 +1,5 @@
 import os
 import platform
-import textwrap
 
 import pytest
 
@@ -20,7 +19,7 @@ def test_build():
     c.save({}, clean_first=True)
     c.run("new workspace -d requires=mymath/0.1")
     c.run("workspace build")
-    assert "Calling build() for the product app1/0.1" in c.out
+    assert "conanfile.py (app1/0.1): Calling build()" in c.out
     assert "conanfile.py (app1/0.1): Running CMake.build()" in c.out
     # it works without failing
 
@@ -35,7 +34,7 @@ def test_metabuild():
 
     c.save({}, clean_first=True)
     c.run("new workspace -d requires=mymath/0.1")
-    c.run("workspace install")
+    c.run("workspace super-install")
     assert os.path.exists(os.path.join(c.current_folder, "CMakeUserPresets.json"))
     build_folder = "build/Release" if platform.system() != "Windows" else "build"
     assert os.path.exists(os.path.join(c.current_folder, build_folder, "generators"))
diff --git a/test/integration/configuration/conf/test_conf.py b/test/integration/configuration/conf/test_conf.py
index 94337f060..213438661 100644
--- a/test/integration/configuration/conf/test_conf.py
+++ b/test/integration/configuration/conf/test_conf.py
@@ -110,6 +110,25 @@ def test_composition_conan_conf(client):
     assert "tools.meson.mesontoolchain:backend$Super" in client.out
 
 
+def test_core_global_conf_not_in_profile(client):
+    client.save_home({"global.conf": "core.upload:retry=1"})
+    profile = textwrap.dedent("""\
+        [conf]
+        tools.build:verbosity=quiet
+        """)
+    client.save({"profile": profile})
+    client.run("install . -pr=profile")
+    assert "tools.build:verbosity$quiet" in client.out
+    # The core conf is not shown
+    assert "core.upload:retry=1" not in client.out
+
+    # also with -cc command line argument
+    client.run("install . -pr=profile -cc core.upload:retry=1")
+    assert "tools.build:verbosity$quiet" in client.out
+    # The core conf is not shown
+    assert "core.upload:retry=1" not in client.out
+
+
 def test_new_config_file(client):
     conf = textwrap.dedent("""\
         tools.build:verbosity=quiet
diff --git a/test/integration/generators/test_generators_from_br.py b/test/integration/generators/test_generators_from_br.py
index c0fa619fd..e7a5dcc2a 100644
--- a/test/integration/generators/test_generators_from_br.py
+++ b/test/integration/generators/test_generators_from_br.py
@@ -1,7 +1,7 @@
 import json
 import textwrap
 
-from conan.test.utils.tools import TestClient
+from conan.test.utils.tools import GenConanfile, TestClient
 
 
 def test_inject_generators_conf():
@@ -24,12 +24,18 @@ def test_inject_generators_conf():
                 self.generator_info = ["CMakeToolchain", MyGenerator]
         """)})
 
+    tc.save({"consumer/conanfile.py": GenConanfile("consumer", "0.1")
+                .with_tool_requires("tool/0.1")
+                .with_class_attribute("generators = 'VirtualBuildEnv', 'VirtualRunEnv'")})
+
     tc.run("create tool")
-    tc.run("install --tool-requires=tool/0.1")
+    tc.run("create consumer")
     assert "WARN: experimental: Tool-require tool/0.1 adding generators: " \
            "['CMakeToolchain', 'MyGenerator']" in tc.out
     assert "Generator 'CMakeToolchain' calling 'generate()'" in tc.out
     assert "Generator 'MyGenerator' calling 'generate()'" in tc.out
+    assert "Generator 'VirtualBuildEnv' calling 'generate()'" in tc.out
+    assert "Generator 'VirtualRunEnv' calling 'generate()'" in tc.out
     assert "CMakeToolchain generated: conan_toolchain.cmake" in tc.out
     assert "MyGenerator generated" in tc.out
 
diff --git a/test/integration/toolchains/apple/test_xcodetoolchain.py b/test/integration/toolchains/apple/test_xcodetoolchain.py
index ffae38c49..8941f162b 100644
--- a/test/integration/toolchains/apple/test_xcodetoolchain.py
+++ b/test/integration/toolchains/apple/test_xcodetoolchain.py
@@ -1,4 +1,6 @@
 import platform
+import re
+import textwrap
 
 import pytest
 
@@ -83,3 +85,45 @@ def test_flags_generated_if_only_defines():
     assert "GCC_PREPROCESSOR_DEFINITIONS = $(inherited) MYDEFINITION" in conan_global_flags
     conan_global_file = client.load("conan_config.xcconfig")
     assert '#include "conan_global_flags.xcconfig"' in conan_global_file
+
+
+@pytest.mark.skipif(platform.system() != "Darwin", reason="Only for MacOS")
+@pytest.mark.parametrize("os_name, sdk, min_version, deployment_target_flag", [
+    ("Macos", None, "11.0", "MACOSX_DEPLOYMENT_TARGET"),
+    ("iOS", "iphoneos", "18.0", "IPHONEOS_DEPLOYMENT_TARGET"),
+    ("tvOS", "appletvos", "18.4", "TVOS_DEPLOYMENT_TARGET"),
+    ("watchOS", "watchos", "9.0", "WATCHOS_DEPLOYMENT_TARGET"),
+    ("visionOS", "xros", "2.0", "XROS_DEPLOYMENT_TARGET"),
+])
+def test_xcodetoolchain_xcconfig_deplyment_target(os_name, sdk, min_version, deployment_target_flag):
+    client = TestClient()
+
+    conanfile = textwrap.dedent(f"""
+        import os
+        from conan import ConanFile
+        from conan.tools.apple import XcodeToolchain
+        from conan.tools.files import save
+        class MyApplicationConan(ConanFile):
+            name = "myapplication"
+            version = "1.0"
+            settings = "os", "compiler", "build_type", "arch"
+            def generate(self):
+                tc = XcodeToolchain(self)
+                tc.generate()
+                # Private access to get the generated xcconfig filename
+                # It changes based on the settings, so this is the less fragile way to get it
+                save(self, os.path.join(self.generators_folder, "name.txt"), tc._vars_xconfig_filename)
+        """)
+
+    client.save({"conanfile.py": conanfile})
+
+    settings = f"-s os={os_name} -s os.version={min_version}"
+    if sdk:
+        settings += f" -s os.sdk={sdk}"
+
+    client.run(f"install . -s build_type=Release {settings} --build=missing")
+
+    xcconfig_name = client.load("name.txt").strip()
+    xcconfig = client.load(xcconfig_name)
+    match = re.search(f"^{deployment_target_flag}.+={min_version}$", xcconfig, re.MULTILINE)
+    assert match is not None
diff --git a/test/integration/toolchains/gnu/test_gnutoolchain.py b/test/integration/toolchains/gnu/test_gnutoolchain.py
index e05754916..6493a3be2 100644
--- a/test/integration/toolchains/gnu/test_gnutoolchain.py
+++ b/test/integration/toolchains/gnu/test_gnutoolchain.py
@@ -476,15 +476,19 @@ def test_conf_extra_apple_flags(toolchain):
     c.run("install . -pr:a host")
     f = "conanautotoolstoolchain.sh" if toolchain == "AutotoolsToolchain" else "conangnutoolchain.sh"
     tc = c.load(f)
-    assert 'export CXXFLAGS="$CXXFLAGS -fembed-bitcode -fobjc-arc -fvisibility=default"' in tc
-    assert 'export CFLAGS="$CFLAGS -fembed-bitcode -fobjc-arc -fvisibility=default"' in tc
-    assert 'export LDFLAGS="$LDFLAGS -fembed-bitcode -fobjc-arc -fvisibility=default"' in tc
+    assert 'export CXXFLAGS="$CXXFLAGS -fembed-bitcode -fvisibility=default"' in tc
+    assert 'export CFLAGS="$CFLAGS -fembed-bitcode -fvisibility=default"' in tc
+    assert 'export LDFLAGS="$LDFLAGS -fembed-bitcode -fvisibility=default"' in tc
+    assert 'export OBJCFLAGS="$OBJCFLAGS -fobjc-arc"' in tc
+    assert 'export OBJCXXFLAGS="$OBJCXXFLAGS -fobjc-arc"' in tc
 
     c.run("install . -pr:a host -s build_type=Debug")
     tc = c.load(f)
-    assert 'export CXXFLAGS="$CXXFLAGS -fembed-bitcode-marker -fobjc-arc -fvisibility=default"' in tc
-    assert 'export CFLAGS="$CFLAGS -fembed-bitcode-marker -fobjc-arc -fvisibility=default"' in tc
-    assert 'export LDFLAGS="$LDFLAGS -fembed-bitcode-marker -fobjc-arc -fvisibility=default"' in tc
+    assert 'export CXXFLAGS="$CXXFLAGS -fembed-bitcode-marker -fvisibility=default"' in tc
+    assert 'export CFLAGS="$CFLAGS -fembed-bitcode-marker -fvisibility=default"' in tc
+    assert 'export LDFLAGS="$LDFLAGS -fembed-bitcode-marker -fvisibility=default"' in tc
+    assert 'export OBJCFLAGS="$OBJCFLAGS -fobjc-arc"' in tc
+    assert 'export OBJCXXFLAGS="$OBJCXXFLAGS -fobjc-arc"' in tc
 
     host = textwrap.dedent("""
         [settings]
@@ -499,9 +503,11 @@ def test_conf_extra_apple_flags(toolchain):
     c.save({"host": host})
     c.run("install . -pr:a host")
     tc = c.load(f)
-    assert 'CXXFLAGS="$CXXFLAGS -fno-objc-arc -fvisibility=hidden -fvisibility-inlines-hidden"' in tc
-    assert 'CFLAGS="$CFLAGS -fno-objc-arc -fvisibility=hidden -fvisibility-inlines-hidden"' in tc
-    assert 'LDFLAGS="$LDFLAGS -fno-objc-arc -fvisibility=hidden -fvisibility-inlines-hidden"' in tc
+    assert 'CXXFLAGS="$CXXFLAGS -fvisibility=hidden -fvisibility-inlines-hidden"' in tc
+    assert 'CFLAGS="$CFLAGS -fvisibility=hidden -fvisibility-inlines-hidden"' in tc
+    assert 'LDFLAGS="$LDFLAGS -fvisibility=hidden -fvisibility-inlines-hidden"' in tc
+    assert 'export OBJCFLAGS="$OBJCFLAGS -fno-objc-arc"' in tc
+    assert 'export OBJCXXFLAGS="$OBJCXXFLAGS -fno-objc-arc"' in tc
 
 
 def test_toolchain_crossbuild_to_android():
diff --git a/test/integration/toolchains/gnu/test_pkgconfigdeps.py b/test/integration/toolchains/gnu/test_pkgconfigdeps.py
index e98c607ac..de7face01 100644
--- a/test/integration/toolchains/gnu/test_pkgconfigdeps.py
+++ b/test/integration/toolchains/gnu/test_pkgconfigdeps.py
@@ -1228,3 +1228,55 @@ def test_pkg_with_duplicated_component_requires():
     pc_content = client.load("mylib-myfirstcomp.pc")
     assert "Requires: mylib-mycomponent" == get_requires_from_content(pc_content)
 
+
+def test_pkg_skip_component():
+    conanfile_a = textwrap.dedent("""
+        from conan import ConanFile
+        class PkgConfigConan(ConanFile):
+            name = "pkg_a"
+            version = "0.1"
+            def package_info(self):
+                self.cpp_info.set_property("pkg_config_name", "none")
+        """)
+    conanfile_b = textwrap.dedent("""
+        from conan import ConanFile
+        class PkgConfigConan(ConanFile):
+            name = "pkg_b"
+            version = "0.1"
+            requires = "pkg_a/0.1"
+            def package_info(self):
+                self.cpp_info.components["cmp1"].set_property("pkg_config_name", "b-cmp1")
+        """)
+
+    conanfile_c = textwrap.dedent("""
+            from conan import ConanFile
+            class PkgConfigConan(ConanFile):
+                name = "pkg_c"
+                version = "0.1"
+                requires = "pkg_b/0.1"
+                def package_info(self):
+                    self.cpp_info.components["cmp2"].set_property("pkg_config_name", "none")
+            """)
+    tc = TestClient(light=True)
+    tc.save({"a/conanfile.py": conanfile_a,
+             "b/conanfile.py": conanfile_b,
+             "c/conanfile.py": conanfile_c})
+    tc.run("create a")
+    tc.run("create b")
+    tc.run("create c")
+
+    tc.run("install --requires=pkg_c/0.1 --generator=PkgConfigDeps -of=out")
+    install_contents = os.listdir(os.path.join(tc.current_folder, "out"))
+    assert "pkg_a.pc" not in install_contents
+    assert "pkg_b.pc" in install_contents
+    pkg_b_content = tc.load(os.path.join("out", "pkg_b.pc"))
+    pkg_b_requires = get_requires_from_content(pkg_b_content)
+    assert "b-cmp1" in pkg_b_requires
+    assert "pkg_a" not in pkg_b_requires
+    assert "none" not in pkg_b_requires
+    assert "b-cmp1.pc" in install_contents
+    b_cmp1_content = tc.load(os.path.join("out", "b-cmp1.pc"))
+    assert "Requires:" not in b_cmp1_content
+    assert "pkg_c.pc" in install_contents
+    # Components can not skip the PC file creation
+    assert "none.pc" in install_contents
diff --git a/test/integration/toolchains/meson/test_mesontoolchain.py b/test/integration/toolchains/meson/test_mesontoolchain.py
index 3b5411212..699da0a5f 100644
--- a/test/integration/toolchains/meson/test_mesontoolchain.py
+++ b/test/integration/toolchains/meson/test_mesontoolchain.py
@@ -748,6 +748,32 @@ def test_cross_x86_64_to_x86():
     assert "cpu = 'x86'" in cross  # This is the host machine
 
 
+def test_cross_x86_64_to_riscv32():
+    """
+    https://github.com/conan-io/conan/issues/18490
+    """
+    c = TestClient()
+    c.save({"conanfile.py": GenConanfile().with_settings("os", "compiler", "arch", "build_type")})
+    c.run("install . -g MesonToolchain -s os=Linux -s arch=riscv32 -s:b arch=x86_64")
+    assert not os.path.exists(os.path.join(c.current_folder, MesonToolchain.native_filename))
+    cross = c.load(MesonToolchain.cross_filename)
+    assert "cpu = 'x86_64'" in cross  # This is the build machine
+    assert "cpu = 'riscv32'" in cross  # This is the host machine
+
+
+def test_cross_x86_64_to_riscv64():
+    """
+    https://github.com/conan-io/conan/issues/18490
+    """
+    c = TestClient()
+    c.save({"conanfile.py": GenConanfile().with_settings("os", "compiler", "arch", "build_type")})
+    c.run("install . -g MesonToolchain -s os=Linux -s arch=riscv64 -s:b arch=x86_64")
+    assert not os.path.exists(os.path.join(c.current_folder, MesonToolchain.native_filename))
+    cross = c.load(MesonToolchain.cross_filename)
+    assert "cpu = 'x86_64'" in cross  # This is the build machine
+    assert "cpu = 'riscv64'" in cross  # This is the host machine
+
+
 def test_conf_extra_apple_flags():
     host = textwrap.dedent("""
     [settings]
@@ -768,13 +794,15 @@ def test_conf_extra_apple_flags():
     f = "conan_meson_native.ini"
     tc = c.load(f)
     for flags in ["c_args", "cpp_args", "c_link_args", "cpp_link_args"]:
-        assert f"{flags} = ['-m64', '-fembed-bitcode', '-fobjc-arc', '-fvisibility=default']" in tc
-
+        assert f"{flags} = ['-m64', '-fembed-bitcode', '-fvisibility=default']" in tc
+    for flags in ["objcpp_args", "objc_args"]:
+        assert f"{flags} = ['-fobjc-arc', '-m64', '-fembed-bitcode', '-fvisibility=default']" in tc
     c.run("install . -pr:a host -s build_type=Debug")
     tc = c.load(f)
     for flags in ["c_args", "cpp_args", "c_link_args", "cpp_link_args"]:
-        assert f"{flags} = ['-m64', '-fembed-bitcode-marker'," \
-               " '-fobjc-arc', '-fvisibility=default']" in tc
+        assert f"{flags} = ['-m64', '-fembed-bitcode-marker', '-fvisibility=default']" in tc
+    for flags in ["objcpp_args", "objc_args"]:
+        assert f"{flags} = ['-fobjc-arc', '-m64', '-fembed-bitcode-marker', '-fvisibility=default']" in tc
 
     host = textwrap.dedent("""
         [settings]
@@ -792,5 +820,6 @@ def test_conf_extra_apple_flags():
     c.run("install . -pr:a host")
     tc = c.load(f)
     for flags in ["c_args", "cpp_args", "c_link_args", "cpp_link_args"]:
-        assert f"{flags} = ['-m64', '-fno-objc-arc', '-fvisibility=hidden', " \
-               "'-fvisibility-inlines-hidden']" in tc
+        assert f"{flags} = ['-m64', '-fvisibility=hidden', '-fvisibility-inlines-hidden']" in tc
+    for flags in ["objcpp_args", "objc_args"]:
+        assert f"{flags} = ['-fno-objc-arc', '-m64', '-fvisibility=hidden', '-fvisibility-inlines-hidden']" in tc
diff --git a/test/integration/workspace/test_workspace.py b/test/integration/workspace/test_workspace.py
index a2b7d870a..3d3b27172 100644
--- a/test/integration/workspace/test_workspace.py
+++ b/test/integration/workspace/test_workspace.py
@@ -21,13 +21,13 @@ class TestWorkspaceRoot:
         c = TestClient(light=True)
         # Just check the root command works
         c.run("workspace root", assert_error=True)
-        assert "ERROR: No workspace defined, conanws.py file not found" in c.out
+        assert "ERROR: Workspace not defined, please create" in c.out
 
         # error, conanws/ folder does not contain conanws.[py | yml]
         c.save({"conanws/test.txt": ""})
         with c.chdir("conanws"):
             c.run("workspace root", assert_error=True)
-            assert "ERROR: No workspace defined, conanws.py file not found" in c.out
+            assert "ERROR: Workspace not defined, please create" in c.out
             c.save({"conanws.yml": ""})
             c.run("workspace root")
             assert c.current_folder in c.stdout
@@ -236,7 +236,7 @@ class TestAddRemove:
         c = TestClient(light=True)
         c.save({"conanws.yml": "",
                 "mydeppkg/conanfile.py": GenConanfile("mydeppkg", "0.1")})
-        c.run("workspace add mydeppkg --product")
+        c.run("workspace add mydeppkg")
         c.run("workspace remove mydeppkg")
         c.run("workspace info")
         assert "mydeppkg" not in c.out
@@ -368,31 +368,6 @@ class TestOpenAdd:
 
 
 class TestWorkspaceBuild:
-    def test_dynamic_products(self):
-        c = TestClient(light=True)
-
-        workspace = textwrap.dedent("""\
-            import os
-            from conan import Workspace
-
-            class MyWorkspace(Workspace):
-                def products(self):
-                    result = []
-                    for f in os.listdir(self.folder):
-                        if os.path.isdir(os.path.join(self.folder, f)):
-                            if f.startswith("product"):
-                                result.append(f)
-                    return result
-            """)
-
-        c.save({"conanws.py": workspace,
-                "lib1/conanfile.py": GenConanfile("lib1", "0.1"),
-                "product_app1/conanfile.py": GenConanfile("app1", "0.1")})
-        c.run("workspace add lib1")
-        c.run("workspace add product_app1")
-        c.run("workspace info --format=json")
-        info = json.loads(c.stdout)
-        assert info["products"] == ["product_app1"]
 
     def test_build(self):
         c = TestClient(light=True)
@@ -402,27 +377,25 @@ class TestWorkspaceBuild:
                 "pkgb/conanfile.py": GenConanfile("pkgb", "0.1").with_build_msg("BUILD PKGB!")
                .with_requires("pkga/0.1")})
         c.run("workspace add pkga")
-        c.run("workspace add pkgb --product")
-        c.run("workspace info --format=json")
-        assert json.loads(c.stdout)["products"] == ["pkgb"]
+        c.run("workspace add pkgb")
         c.run("workspace build")
         c.assert_listed_binary({"pkga/0.1": ("da39a3ee5e6b4b0d3255bfef95601890afd80709",
                                              "EditableBuild")})
-        assert "pkga/0.1: WARN: BUILD PKGA!" in c.out
+        assert "conanfile.py (pkga/0.1): WARN: BUILD PKGA!" in c.out
         assert "conanfile.py (pkgb/0.1): WARN: BUILD PKGB!" in c.out
 
         # It is also possible to build a specific package by path
         # equivalent to ``conan build <path> --build=editable``
         # This can be done even if it is not a product
-        c.run("workspace build pkgc", assert_error=True)
-        assert "ERROR: Product 'pkgc' not defined in the workspace as editable" in c.out
-        c.run("workspace build pkgb")
+        c.run("workspace build --pkg=pkgc/*", assert_error=True)
+        assert "ERROR: There are no selected packages defined in the workspace" in c.out
+        c.run("workspace build --pkg=pkgb/*")
         c.assert_listed_binary({"pkga/0.1": ("da39a3ee5e6b4b0d3255bfef95601890afd80709",
                                              "EditableBuild")})
-        assert "pkga/0.1: WARN: BUILD PKGA!" in c.out
+        assert "conanfile.py (pkga/0.1): WARN: BUILD PKGA!" in c.out
         assert "conanfile.py (pkgb/0.1): WARN: BUILD PKGB!" in c.out
 
-        c.run("workspace build pkga")
+        c.run("workspace build --pkg=pkga/*")
         assert "conanfile.py (pkga/0.1): Calling build()" in c.out
         assert "conanfile.py (pkga/0.1): WARN: BUILD PKGA!" in c.out
 
@@ -430,7 +403,51 @@ class TestWorkspaceBuild:
         c = TestClient(light=True)
         c.save({"conanws.yml": ""})
         c.run("workspace build", assert_error=True)
-        assert "There are no products defined in the workspace, can't build" in c.out
+        assert "ERROR: There are no selected packages defined in the workspace" in c.out
+
+    def test_build_external_missing(self):
+        c = TestClient(light=True)
+        c.save({"conanws.yml": ""})
+
+        c.save({"mymath/conanfile.py": GenConanfile("mymath", "0.1").with_build_msg("MyMATH!!"),
+                "pkga/conanfile.py": GenConanfile("pkga", "0.1").with_build_msg("BUILD PKGA!")
+                                                                .with_requires("mymath/0.1"),
+                "pkgb/conanfile.py": GenConanfile("pkgb", "0.1").with_build_msg("BUILD PKGB!")
+               .with_requires("pkga/0.1")})
+        c.run("export mymath")
+        c.run("workspace add pkga")
+        c.run("workspace add pkgb")
+        c.run("workspace build", assert_error=True)
+        assert "ERROR: Missing prebuilt package for 'mymath/0.1'" in c.out
+        c.run("workspace build --build=missing")
+        assert "Workspace building external mymath/0.1" in c.out
+
+    def test_build_dynamic_name_version(self):
+        conanfile = textwrap.dedent("""\
+            from conan import ConanFile
+            class MyConan(ConanFile):
+                def build(self):
+                    self.output.info(f"Building {self.name} AND {self.version}!!!")
+            """)
+        workspace = textwrap.dedent("""\
+            import os
+            from conan import Workspace
+
+            class MyWorkspace(Workspace):
+                def packages(self):
+                    result = {}
+                    for f in os.listdir(self.folder):
+                        if os.path.isdir(os.path.join(self.folder, f)):
+                            result[f"{f}/0.1"] = {"path": f}
+                    return result
+           """)
+        c = TestClient(light=True)
+        c.save({"conanws.py": workspace,
+                "pkga/conanfile.py": conanfile})
+        c.run("workspace info")
+        assert "pkga/0.1" in c.out
+        c.run("workspace build")
+        assert "conanfile.py (pkga/0.1): Building pkga AND 0.1!!!" in c.out
 
 
 class TestNew:
@@ -469,7 +486,7 @@ class TestMeta:
                clean_first=True)
         c.run("workspace add liba")
         c.run("workspace add libb")
-        c.run("workspace install -g CMakeDeps -g CMakeToolchain -of=build --envs-generation=false")
+        c.run("workspace super-install -g CMakeDeps -g CMakeToolchain -of=build --envs-generation=false")
         assert "Workspace conanws.py not found in the workspace folder, using default" in c.out
         files = os.listdir(os.path.join(c.current_folder, "build"))
         assert "conan_toolchain.cmake" in files
@@ -498,7 +515,7 @@ class TestMeta:
         c.save({"dep/conanfile.py": GenConanfile("dep", "0.1"),
                 "conanws.py": conanfilews})
         c.run("workspace add dep")
-        c.run("workspace install -of=build")
+        c.run("workspace super-install -of=build")
         files = os.listdir(os.path.join(c.current_folder, "build"))
         assert "conandeps.props" in files
 
@@ -518,10 +535,10 @@ class TestMeta:
         c.save({"conanws.yml": "conanfilews: myconanfilews.py",
                 "dep/conanfile.py": GenConanfile("dep", "0.1"),
                 "conanws.py": conanfilews})
-        c.run("workspace install", assert_error=True)
-        assert "ERROR: This workspace cannot be installed, it doesn't have any editable" in c.out
+        c.run("workspace super-install", assert_error=True)
+        assert "ERROR: There are no selected packages defined in the workspace" in c.out
         c.run("workspace add dep")
-        c.run("workspace install", assert_error=True)
+        c.run("workspace super-install", assert_error=True)
         assert "ERROR: Conanfile in conanws.py shouldn't have 'requires'" in c.out
 
     def test_install_partial(self):
@@ -539,8 +556,8 @@ class TestMeta:
         c.run("workspace add liba")
         c.run("workspace add libb")
         c.run("workspace add libc")
-        for arg in ("libb", "libb liba"):
-            c.run(f"workspace install {arg} -g CMakeDeps -of=build")
+        for arg in ("--pkg=libb/*", "--pkg=libb/* --pkg=liba/*"):
+            c.run(f"workspace super-install {arg} -g CMakeDeps -of=build")
             assert "dep1/0.1" in c.out
             assert "dep2/0.1" not in c.out
             assert "libc/0.1" not in c.out
@@ -580,9 +597,9 @@ class TestClean:
         pkgb = GenConanfile("pkgb", "0.1").with_requires("pkga/0.1").with_settings("build_type")
         c.save({"pkga/conanfile.py": pkga ,
                 "pkgb/conanfile.py": pkgb,
-                "pkgc/conanfile.py": GenConanfile("pkgc", "0.1")})
+                "pkgc/conanfile.py": GenConanfile("pkgc", "0.1").with_requires("pkgb/0.1")})
         c.run("workspace add pkga -of=build/pkga")
-        c.run("workspace add pkgb -of=build/pkgb --product")
+        c.run("workspace add pkgb -of=build/pkgb")
         c.run("workspace add pkgc")
         c.run("workspace build")
         assert os.path.exists(os.path.join(c.current_folder, "build", "pkga"))
@@ -622,11 +639,9 @@ def test_relative_paths():
     # cd mywks
     with c.chdir("mywks"):
         c.run("workspace add ../liba")
-        c.run("workspace add ../app1 --product")
+        c.run("workspace add ../app1")
         c.run("workspace info")
         expected = textwrap.dedent("""\
-            products
-              ../app1
             packages
               app1/0.1
                 path: ../app1
@@ -639,11 +654,9 @@ def test_relative_paths():
     # cd otherwks
     with c.chdir("otherwks"):
         c.run("workspace add ../other/libb")
-        c.run("workspace add ../other/app2 --product")
+        c.run("workspace add ../other/app2")
         c.run("workspace info")
         expected = textwrap.dedent("""\
-            products
-              ../other/app2
             packages
               app2/0.1
                 path: ../other/app2
@@ -659,31 +672,265 @@ def test_host_build_require():
     c = TestClient()
     protobuf = textwrap.dedent("""\
         from conan import ConanFile
-        from conan.tools.files import save
+        from conan.tools.files import save, copy
         class Protobuf(ConanFile):
             name = "protobuf"
             version = "0.1"
             settings = "os"
 
             def layout(self):
-                self.folders.build = f"mybuild_folder_{self.settings.os}"
+                self.folders.build = f"mybuild/folder_{self.settings.os}"
+                self.cpp.build.bindirs = ["."]
 
             def build(self):
                 save(self, "myprotobuf.txt", f"MYOS={self.settings.os}!!!")
+
+            def package(self):
+                copy(self, "myprotobuf.txt", src=self.build_folder, dst=self.package_folder)
+
+            def package_info(self):
+                self.cpp_info.bindirs = ["."]
         """)
     app = textwrap.dedent("""\
+        import os
         from conan import ConanFile
+        from conan.tools.files import load
         class Protobuf(ConanFile):
             name = "app"
             version = "0.1"
             requires = "protobuf/0.1"
             tool_requires = "protobuf/0.1"
+
+            def build(self):
+                binhost = self.dependencies.host["protobuf"].cpp_info.bindir
+                binbuild = self.dependencies.build["protobuf"].cpp_info.bindir
+                host = load(self, os.path.join(binhost, "myprotobuf.txt"))
+                build = load(self, os.path.join(binbuild, "myprotobuf.txt"))
+                self.output.info(f"BUILDING WITH BINHOST: {host}")
+                self.output.info(f"BUILDING WITH BINBUILD: {build}")
         """)
     c.save({"protobuf/conanfile.py": protobuf,
             "app/conanfile.py": app})
     c.run("workspace init .")
     c.run("workspace add protobuf")
+    c.run("workspace add app")
     c.run("install app --build=editable -s:b os=Linux -s:h os=Windows")
 
-    assert c.load("protobuf/mybuild_folder_Linux/myprotobuf.txt") == "MYOS=Linux!!!"
-    assert c.load("protobuf/mybuild_folder_Windows/myprotobuf.txt") == "MYOS=Windows!!!"
+    assert c.load("protobuf/mybuild/folder_Linux/myprotobuf.txt") == "MYOS=Linux!!!"
+    assert c.load("protobuf/mybuild/folder_Windows/myprotobuf.txt") == "MYOS=Windows!!!"
+
+    shutil.rmtree(os.path.join(c.current_folder, "protobuf", "mybuild"))
+    assert not os.path.exists(os.path.join(c.current_folder, "protobuf", "mybuild"))
+    c.run("workspace build -s:b os=Linux -s:h os=Windows")
+    assert "conanfile.py (app/0.1): BUILDING WITH BINHOST: MYOS=Windows!!!" in c.out
+    assert "conanfile.py (app/0.1): BUILDING WITH BINBUILD: MYOS=Linux!!!" in c.out
+    assert c.load("protobuf/mybuild/folder_Linux/myprotobuf.txt") == "MYOS=Linux!!!"
+    assert c.load("protobuf/mybuild/folder_Windows/myprotobuf.txt") == "MYOS=Windows!!!"
+
+    shutil.rmtree(os.path.join(c.current_folder, "protobuf", "mybuild"))
+    assert not os.path.exists(os.path.join(c.current_folder, "protobuf", "mybuild"))
+    c.run("workspace create -s:b os=Linux -s:h os=Windows")
+    assert "app/0.1: BUILDING WITH BINHOST: MYOS=Windows!!!" in c.out
+    assert "app/0.1: BUILDING WITH BINBUILD: MYOS=Linux!!!" in c.out
+
+
+class TestCreate:
+    def test_create(self):
+        c = TestClient(light=True, default_server_user=True)
+        c.save({"conanfile.py": GenConanfile("zlib", "0.1").with_build_msg("BUILD ZLIB!")})
+        c.run("export .")
+        c.save({"conanws.yml": ""}, clean_first=True)
+        c.save({"pkga/conanfile.py": GenConanfile("pkga", "0.1").with_requires("zlib/0.1")
+                                                                .with_build_msg("BUILD PKGA!"),
+                "pkga/test_package/conanfile.py": GenConanfile().with_test("pass"),
+                "pkgb/conanfile.py": GenConanfile("pkgb", "0.1").with_build_msg("BUILD PKGB!")
+               .with_requires("pkga/0.1"),
+                "pkgb/test_package/conanfile.py": GenConanfile().with_test("pass"),
+                "pkgc/conanfile.py": GenConanfile("pkgc", "0.1").with_build_msg("BUILD PKGC!")
+               .with_requires("pkgb/0.1"),
+                "pkgc/test_package/conanfile.py": GenConanfile().with_test("pass"),
+                })
+        c.run("workspace add pkga")
+        c.run("workspace add pkgb")
+        c.run("workspace add pkgc")
+        c.run("workspace create --build=zlib/*")
+        assert str(c.out).count("zlib/0.1: WARN: BUILD ZLIB!") == 1
+        assert str(c.out).count("pkga/0.1: WARN: BUILD PKGA!") == 1
+        assert str(c.out).count("pkgb/0.1: WARN: BUILD PKGB!") == 1
+        assert str(c.out).count("pkgc/0.1: WARN: BUILD PKGC!") == 1
+        assert "pkga/0.1 (test package): Running test()" in c.out
+        assert "pkgb/0.1 (test package): Running test()" in c.out
+        assert "pkgc/0.1 (test package): Running test()" in c.out
+
+        # A second conan workspace create will not re-build
+        c.run("workspace create")
+        assert "WARN: BUILD ZLIB!" not in c.out
+        assert "WARN: BUILD PKGA!" not in c.out
+        assert "WARN: BUILD PKGB!" not in c.out
+        assert "WARN: BUILD PKBC!" not in c.out
+        assert "pkga/0.1 (test package): Running test()" not in c.out
+        assert "pkgb/0.1 (test package): Running test()" not in c.out
+        assert "pkgc/0.1 (test package): Running test()" not in c.out
+
+        c.run("upload zlib/* -r=default -c")
+        c.run("remove zlib/* -c")
+        c.run("remove pkgc/* -c")
+        c.run("workspace create")
+        assert "WARN: BUILD ZLIB!" not in c.out
+        assert "pkgc/0.1: WARN: BUILD PKGC!" in c.out
+
+
+    def test_create_dynamic_name(self):
+        workspace = textwrap.dedent("""\
+            import os
+            from conan import Workspace
+
+            class MyWorkspace(Workspace):
+                def packages(self):
+                    result = {}
+                    for f in os.listdir(self.folder):
+                        if os.path.isdir(os.path.join(self.folder, f)):
+                            result[f"{f}/0.1"] = {"path": f}
+                    return result
+           """)
+        c = TestClient(light=True)
+        c.save({"conanws.py": workspace,
+                "pkga/conanfile.py": GenConanfile()})
+        c.run("workspace info")
+        assert "pkga/0.1" in c.out
+        c.run("workspace create")
+        assert "Workspace create pkga/0.1" in c.out
+
+
+    def test_host_build_require(self):
+        c = TestClient()
+        protobuf = textwrap.dedent("""\
+            from conan import ConanFile
+            class Protobuf(ConanFile):
+                name = "protobuf"
+                version = "0.1"
+                settings = "os"
+
+                def build(self):
+                    self.output.info(f"Building for: {self.settings.os}!!!")
+            """)
+        app = textwrap.dedent("""\
+            from conan import ConanFile
+            class Protobuf(ConanFile):
+                name = "app"
+                version = "0.1"
+                requires = "protobuf/0.1"
+                tool_requires = "protobuf/0.1"
+            """)
+        c.save({"protobuf/conanfile.py": protobuf,
+                "app/conanfile.py": app})
+        c.run("workspace init .")
+        c.run("workspace add protobuf")
+        c.run("workspace add app")
+
+        c.run("workspace create -s:b os=Linux -s:h os=Windows")
+
+        assert "protobuf/0.1: Building for: Windows!!!" in c.out
+        assert "protobuf/0.1: Building for: Linux!!!" in c.out
+
+
+class TestSource:
+    def test_source(self):
+        c = TestClient(light=True)
+        c.save({"conanws.yml": ""})
+
+        pkga = textwrap.dedent("""\
+            from conan import ConanFile
+            class TestPackage(ConanFile):
+                name = "pkga"
+                version = "0.1"
+                def source(self):
+                    self.output.info("Executing SOURCE!!!")
+            """)
+        pkgb = textwrap.dedent("""\
+            from conan import ConanFile
+            class TestPackage(ConanFile):
+                name = "pkgb"
+                version = "0.1"
+                requires = "pkga/0.1"
+                def source(self):
+                    self.output.info("Executing SOURCE!!!")
+            """)
+        pkgc = textwrap.dedent("""\
+            from conan import ConanFile
+            class TestPackage(ConanFile):
+                name = "pkgc"
+                version = "0.1"
+                requires = "pkgb/0.1"
+                def source(self):
+                    self.output.info("Executing SOURCE!!!")
+            """)
+        c.save({"pkga/conanfile.py": pkga,
+                "pkgb/conanfile.py": pkgb,
+                "pkgc/conanfile.py": pkgc})
+        c.run("workspace add pkga")
+        c.run("workspace add pkgb")
+        c.run("workspace add pkgc")
+        c.run("workspace source")
+        assert "conanfile.py (pkga/0.1): Executing SOURCE!!!" in c.out
+        assert "conanfile.py (pkgb/0.1): Executing SOURCE!!!" in c.out
+        assert "conanfile.py (pkgc/0.1): Executing SOURCE!!!" in c.out
+
+
+class TestInstall:
+    def test_install(self):
+        c = TestClient()
+        c.save({"conanws.yml": ""})
+
+        pkg = textwrap.dedent("""\
+            from conan import ConanFile
+            class Package(ConanFile):
+                name = "{}"
+                version = "0.1"
+                settings = "os", "build_type"
+                {}
+                generators = "CMakeToolchain"
+            """)
+
+        c.save({"pkga/conanfile.py": pkg.format("pkga", ''),
+                "pkgb/conanfile.py": pkg.format("pkgb", 'requires="pkga/0.1"'),
+                "pkgc/conanfile.py": pkg.format("pkgc", 'requires="pkgb/0.1"')})
+        c.run("workspace add pkga")
+        c.run("workspace add pkgb")
+        c.run("workspace add pkgc")
+        c.run("workspace install")
+        assert "conanfile.py (pkga/0.1): CMakeToolchain generated" in c.out
+        assert "conanfile.py (pkgb/0.1): CMakeToolchain generated" in c.out
+        assert "conanfile.py (pkgc/0.1): CMakeToolchain generated" in c.out
+
+
+def test_keep_core_conf():
+    c = TestClient()
+    myprofile = textwrap.dedent("""\
+        [settings]
+        os=FreeBSD
+        arch=armv7
+        """)
+    conanfile = textwrap.dedent("""\
+        from conan import ConanFile
+
+        class Pkg(ConanFile):
+            name = "pkga"
+            version = "0.1"
+            settings = "os", "arch"
+
+            def generate(self):
+                self.output.info(f"Generating!: {self.settings.os}-{self.settings.arch}!!!!")
+        """)
+    c.save_home({"profiles/myprofile": myprofile})
+    c.run("profile show ")
+    c.save({"conanws.yml": "",
+            "pkga/conanfile.py": conanfile})
+    c.run("workspace add pkga")
+    # The injected -cc is still applied to every "conan install"
+    c.run("workspace install -cc core:default_profile=myprofile")
+    assert "conanfile.py (pkga/0.1): Generating!: FreeBSD-armv7!!!!" in c.out
+    # also the global.conf
+    c.save_home({"global.conf": "core:default_profile=myprofile"})
+    c.run("workspace install")
+    assert "conanfile.py (pkga/0.1): Generating!: FreeBSD-armv7!!!!" in c.out
diff --git a/test/unittests/client/toolchain/autotools/autotools_toolchain_test.py b/test/unittests/client/toolchain/autotools/autotools_toolchain_test.py
index 7576aa6dd..ca6dcde78 100644
--- a/test/unittests/client/toolchain/autotools/autotools_toolchain_test.py
+++ b/test/unittests/client/toolchain/autotools/autotools_toolchain_test.py
@@ -285,6 +285,27 @@ def test_architecture_flag(config):
     assert expected in env["LDFLAGS"]
     assert "-debug" not in env["LDFLAGS"]
 
+@pytest.mark.parametrize("config", [
+    ("gcc", "x86_64", ""),
+    ("emcc", "wasm", ""),
+    ("emcc", "wasm64", ""),
+    ("emcc", "asm.js", "-sWASM=0")])
+def test_architecture_link_flag(config):
+    compiler, arch, expected = config
+    conanfile = ConanFileMock()
+    conanfile.settings = MockSettings(
+        {"build_type": "Release",
+         "os": "Emscripten",
+         "compiler": compiler,
+         "arch": arch})
+    conanfile.settings_build = conanfile.settings
+    be = AutotoolsToolchain(conanfile)
+    assert be.arch_ld_flag == expected
+    env = be.vars()
+    assert "" in env["CXXFLAGS"]
+    assert "" in env["CFLAGS"]
+    assert expected in env["LDFLAGS"]
+
 
 @pytest.mark.parametrize("compiler", ['msvc'])
 def test_build_type_flag(compiler):