Repository: conan-io/conan
Pull request #18496 (2025-06-19 10:38:02)

XcodeBuild: pass deployment target from profile
Changelog: Fix: [XcodeBuild] pass deployment target from profile
Changelog: Fix: [XcodeBuild] project path and target name are quoted now
Docs: https://github.com/conan-io/docs/pull/4129

- [ ] Refer to the issue that supports this Pull Request.
- [x] If the issue has missing info, explain the purpose/use case/pain/need that covers this Pull Request.
- [x] I've read the [Contributing guide](https://github.com/conan-io/conan/blob/develop2/.github/CONTRIBUTING.md).
- [x] I've followed the PEP8 style guides for Python code.
- [x] I've opened another PR in the Conan docs repo to the ``develop`` branch, documenting this one.


memsharded: It also seems the PR broke some existing OSX-functional tests, please have a look https://github.com/conan-io/conan/actions/runs/15756189684/job/44412185234?pr=18496 (you an ignore the Windows-unit tests, that seems a temporary glitch).
kambala-decapitator: > Maybe it is better to split this PR, addressing first the bugfix, then the potential improvements in a separate one. Also, some test that covers the changes would be greatly appreciated, please ask us for support or guidance if you need, we might even contribute the tests ourselves.

thanks, I fully agree with splitting. Are you fine with keeping the SYMROOT/OBJROOT change in this PR or it should also go to the other one?
memsharded: > thanks, I fully agree with splitting. Are you fine with keeping the SYMROOT/OBJROOT change in this PR or it should also go to the other one?

You convinced me that if not defining this it might pollute the source directory when ``no_copy_source=True``, then I am willing to consider this a bugfix and move forward.

But please wait a bit for the split, I am going to ask some colleague more knowledgeable than me in Apple for their feedback.
kambala-decapitator: FYI I'm heavily using changes from this PR quite successfully so far, would be great to get a review that I could proceed
memsharded: Also it seems there are a couple of builds broken, I haven't check them yet, but it would be necessary to have them green too.
kambala-decapitator: Removed all the new features from the PR but added 2 small fixes - quoting project path and target name as they can have spaces.

> changing some command layout things with SYMROOT, OBJROOT. These seems should be defined at the project level, or in any case at the toolchain level. Because otherwise, normal flow like conan install + IDE/xcodebuild direct user invocation will do something different

I can't really agree with this.
1. When building from Xcode IDE, those variables are ignored by default and Xcode places all the stuff in `~/Library/Developer/Xcode/DerivedData/<dir>`. They will be used only when project is configured in such a way, but AFAIK it's rarely done nowadays. This is configured in File - Project settings... - Advanced - set to Legacy. This behavior was changed to Legacy like 10 years ago or even more.
<img width="490" height="377" alt="Screenshot 2025-07-17 at 09 35 31" src="https://github.com/user-attachments/assets/503fb4f8-ef00-4113-877f-1ee8a428345c" />

2. Suppose we don't touch those settings. How can a recipe figure out where the build artifacts are? The only reliable way would be to invoke `xcodebuild -showBuildSettings` to see the actual value of all settings and grep `SYMROOT`. Do you really expect every recipe to include such a piece of code (or have a Conan helper function)? To me it looks like an unnecessary complication when you can set a reliable path at build time. And also polluting source directory by default which [we have already discussed](https://github.com/conan-io/conan/pull/18496#issuecomment-2987861008). And one more point here: as soon as I have redirected SYMROOT+OBJROOT, tests started failing because they rely on hardcoded default value, see https://github.com/kambala-decapitator/conan/commit/e53841169470e4c53ef154aea1fbcf05cddc5880

Will open a separate PR with all the new features.
memsharded: > I can't really agree with this.

It would be great to have the feedback of @jcar87 here, I am not a OSX user (it can be discussed in the new PR too)

Patch:
diff --git a/conan/api/conan_api.py b/conan/api/conan_api.py
index 1b2c46ee8..ac809e503 100644
--- a/conan/api/conan_api.py
+++ b/conan/api/conan_api.py
@@ -22,6 +22,8 @@ from conan.api.subapi.remove import RemoveAPI
 from conan.api.subapi.search import SearchAPI
 from conan.api.subapi.upload import UploadAPI
 from conan.errors import ConanException
+from conan.internal.cache.home_paths import HomePaths
+from conan.internal.hook_manager import HookManager
 from conan.internal.paths import get_conan_user_home
 from conan.internal.api.migrations import ClientMigrator
 from conan.internal.model.version_range import validate_conan_version
@@ -48,10 +50,12 @@ class ConanAPI:
         init_colorama(sys.stderr)
         self.cache_folder = cache_folder or get_conan_user_home()
         self.home_folder = self.cache_folder  # Lets call it home, deprecate "cache"
-        self.migrate()
-
         # This API is depended upon by the subsequent ones, it should be initialized first
         self.config = ConfigAPI(self)
+        _check_conan_version(self)
+
+        self._api_helpers = self._ApiHelpers(self)
+        self.migrate()
 
         self.remotes = RemotesAPI(self)
         self.command = CommandAPI(self)
@@ -60,27 +64,27 @@ class ConanAPI:
         # Get latest refs and list refs of recipes and packages
         self.list = ListAPI(self)
         self.profiles = ProfilesAPI(self)
-        self.install = InstallAPI(self)
-        self.graph = GraphAPI(self)
-        self.export = ExportAPI(self)
+        self.install = InstallAPI(self, self._api_helpers)
+        self.graph = GraphAPI(self, self._api_helpers)
+        self.export = ExportAPI(self, self._api_helpers)
         self.remove = RemoveAPI(self)
         self.new = NewAPI(self)
         self.upload = UploadAPI(self)
         self.download = DownloadAPI(self)
         self.cache = CacheAPI(self)
         self.lockfile = LockfileAPI(self)
-        self.local = LocalAPI(self)
+        self.local = LocalAPI(self, self._api_helpers)
         self.audit = AuditAPI(self)
         # Now, lazy loading of editables
         self.workspace = WorkspaceAPI(self)
-        self.report = ReportAPI(self)
-
-        _check_conan_version(self)
+        self.report = ReportAPI(self, self._api_helpers)
 
     def reinit(self):
         """
         Reinitialize the Conan API. This is useful when the configuration changes.
         """
+        # TODO: Think order of reinitialization for helpers
+        self._api_helpers.reinit()
         self.config.reinit()
         self.remotes.reinit()
         self.local.reinit()
@@ -94,6 +98,14 @@ class ConanAPI:
         migrator = ClientMigrator(self.cache_folder, conan_version)
         migrator.migrate()
 
+    class _ApiHelpers:
+        def __init__(self, conan_api):
+            self._conan_api = conan_api
+            self.hook_manager = HookManager(HomePaths(self._conan_api.home_folder).hooks_path)
+
+        def reinit(self):
+            self.hook_manager.reinit()
+
 
 def _check_conan_version(conan_api):
     required_range_new = conan_api.config.global_conf.get("core:required_conan_version")
diff --git a/conan/api/subapi/config.py b/conan/api/subapi/config.py
index 78bd3fec5..86d002cf6 100644
--- a/conan/api/subapi/config.py
+++ b/conan/api/subapi/config.py
@@ -30,7 +30,6 @@ class ConfigAPI:
         self.conan_api = conan_api
         self._new_config = None
         self._cli_core_confs = None
-        self.hook_manager = HookManager(HomePaths(conan_api.home_folder).hooks_path)
 
     def home(self):
         return self.conan_api.cache_folder
@@ -236,4 +235,3 @@ class ConfigAPI:
         if self._new_config is not None:
             self._new_config.clear()
             self._populate_global_conf()
-        self.hook_manager = HookManager(HomePaths(self.conan_api.home_folder).hooks_path)
diff --git a/conan/api/subapi/export.py b/conan/api/subapi/export.py
index 9e43ba57c..5cb188620 100644
--- a/conan/api/subapi/export.py
+++ b/conan/api/subapi/export.py
@@ -10,19 +10,20 @@ from conan.internal.util.files import mkdir
 
 class ExportAPI:
 
-    def __init__(self, conan_api):
+    def __init__(self, conan_api, helpers):
         self.conan_api = conan_api
+        self._helpers = helpers
 
     def export(self, path, name, version, user, channel, lockfile=None, remotes=None):
         ConanOutput().title("Exporting recipe to the cache")
         app = ConanApp(self.conan_api)
-        hook_manager = self.conan_api.config.hook_manager
+        hook_manager = self._helpers.hook_manager
         return cmd_export(app, hook_manager, self.conan_api.config.global_conf, path, name, version,
                           user, channel, graph_lock=lockfile, remotes=remotes)
 
     def export_pkg(self, deps_graph, source_folder, output_folder):
         cache = PkgCache(self.conan_api.cache_folder, self.conan_api.config.global_conf)
-        hook_manager = self.conan_api.config.hook_manager
+        hook_manager = self._helpers.hook_manager
 
         # The graph has to be loaded with build_mode=[ref.name], so that node is not tried
         # to be downloaded from remotes
diff --git a/conan/api/subapi/graph.py b/conan/api/subapi/graph.py
index 041b3a2c3..e62c5bafe 100644
--- a/conan/api/subapi/graph.py
+++ b/conan/api/subapi/graph.py
@@ -13,8 +13,9 @@ from conan.api.model import RecipeReference
 
 class GraphAPI:
 
-    def __init__(self, conan_api):
+    def __init__(self, conan_api, helpers):
         self.conan_api = conan_api
+        self._helpers = helpers
 
     def _load_root_consumer_conanfile(self, path, profile_host, profile_build,
                                       name=None, version=None, user=None, channel=None,
@@ -205,7 +206,8 @@ class GraphAPI:
         """
         ConanOutput().title("Computing necessary packages")
         conan_app = ConanBasicApp(self.conan_api)
-        binaries_analyzer = GraphBinariesAnalyzer(conan_app, self.conan_api.config.global_conf)
+        binaries_analyzer = GraphBinariesAnalyzer(conan_app, self.conan_api.config.global_conf,
+                                                  self._helpers.hook_manager)
         binaries_analyzer.evaluate_graph(graph, build_mode, lockfile, remotes, update,
                                          build_modes_test, tested_graph)
 
diff --git a/conan/api/subapi/install.py b/conan/api/subapi/install.py
index 9f35bf0bc..921bfd362 100644
--- a/conan/api/subapi/install.py
+++ b/conan/api/subapi/install.py
@@ -11,8 +11,9 @@ from conan.errors import ConanInvalidConfiguration
 
 class InstallAPI:
 
-    def __init__(self, conan_api):
+    def __init__(self, conan_api, helpers):
         self.conan_api = conan_api
+        self._helpers = helpers
 
     def install_binaries(self, deps_graph, remotes=None):
         """ Install binaries for dependency graph
@@ -21,7 +22,7 @@ class InstallAPI:
         """
         app = ConanBasicApp(self.conan_api)
         installer = BinaryInstaller(app, self.conan_api.config.global_conf, app.editable_packages,
-                                    self.conan_api.config.hook_manager)
+                                    self._helpers.hook_manager)
         install_graph = InstallGraph(deps_graph)
         install_graph.raise_errors()
         install_order = install_graph.install_order()
@@ -35,7 +36,7 @@ class InstallAPI:
         """
         app = ConanBasicApp(self.conan_api)
         installer = BinaryInstaller(app, self.conan_api.config.global_conf, app.editable_packages,
-                                    self.conan_api.config.hook_manager)
+                                    self._helpers.hook_manager)
         installer.install_system_requires(graph, only_info)
 
     def install_sources(self, graph, remotes):
@@ -46,7 +47,7 @@ class InstallAPI:
         """
         app = ConanBasicApp(self.conan_api)
         installer = BinaryInstaller(app, self.conan_api.config.global_conf, app.editable_packages,
-                                    self.conan_api.config.hook_manager)
+                                    self._helpers.hook_manager)
         installer.install_sources(graph, remotes)
 
     # TODO: Look for a better name
@@ -87,7 +88,7 @@ class InstallAPI:
             if gen not in final_generators:
                 final_generators.append(gen)
         conanfile.generators = final_generators
-        hook_manager = self.conan_api.config.hook_manager
+        hook_manager = self._helpers.hook_manager
         write_generators(conanfile, hook_manager, self.conan_api.home_folder,
                          envs_generation=envs_generation)
 
diff --git a/conan/api/subapi/local.py b/conan/api/subapi/local.py
index 11c6d5c1f..88e6bc607 100644
--- a/conan/api/subapi/local.py
+++ b/conan/api/subapi/local.py
@@ -14,8 +14,9 @@ from conan.internal.util.files import chdir
 
 class LocalAPI:
 
-    def __init__(self, conan_api):
+    def __init__(self, conan_api, helpers):
         self._conan_api = conan_api
+        self._helpers = helpers
         self.editable_packages = EditablePackages(conan_api.home_folder)
 
     @staticmethod
@@ -93,13 +94,13 @@ class LocalAPI:
         conanfile.folders.set_base_build(None)
         conanfile.folders.set_base_package(None)
 
-        hook_manager = self._conan_api.config.hook_manager
+        hook_manager = self._helpers.hook_manager
         run_source_method(conanfile, hook_manager)
 
     def build(self, conanfile):
         """ calls the 'build()' method of the current (user folder) conanfile.py
         """
-        hook_manager = self._conan_api.config.hook_manager
+        hook_manager = self._helpers.hook_manager
         conanfile.folders.set_base_package(conanfile.folders.base_build)
         conanfile.folders.set_base_pkg_metadata(os.path.join(conanfile.build_folder, "metadata"))
         run_build_method(conanfile, hook_manager)
diff --git a/conan/api/subapi/report.py b/conan/api/subapi/report.py
index f1a2a1c8e..c4c04fa43 100644
--- a/conan/api/subapi/report.py
+++ b/conan/api/subapi/report.py
@@ -14,8 +14,9 @@ from conan.internal.util.runners import conan_run
 
 
 class ReportAPI:
-    def __init__(self, conan_api):
+    def __init__(self, conan_api, helpers):
         self.conan_api = conan_api
+        self._helpers = helpers
 
     def diff(self, old_reference, new_reference, remotes, old_path=None, new_path=None, cwd=None):
         """
@@ -36,7 +37,8 @@ class ReportAPI:
                 export_ref, cache_path = _export_recipe_from_path(self.conan_api, path_to_conanfile,
                                                                   reference, remotes, cwd)
             exported_path = self.conan_api.local.get_conanfile_path(cache_path, cwd, py=True)
-            _configure_source(self.conan_api, exported_path, export_ref, remotes)
+            _configure_source(self.conan_api, self._helpers.hook_manager, exported_path, export_ref,
+                              remotes)
             return export_ref, cache_path
 
 
@@ -77,7 +79,7 @@ class ReportAPI:
             "dst_prefix": dst_prefix,
         }
 
-def _configure_source(conan_api, conanfile_path, ref, remotes):
+def _configure_source(conan_api, hook_manager, conanfile_path, ref, remotes):
     app = ConanApp(conan_api)
     conanfile = app.loader.load_consumer(conanfile_path, name=ref.name, version=str(ref.version),
                                          user=ref.user, channel=ref.channel, graph_lock=None,
@@ -97,7 +99,7 @@ def _configure_source(conan_api, conanfile_path, ref, remotes):
     conanfile.folders.set_base_source(source_folder)
     conanfile.folders.set_base_export_sources(export_source_folder)
     conanfile.folders.set_base_recipe_metadata(recipe_layout.metadata())
-    config_source(export_source_folder, conanfile, conan_api.config.hook_manager)
+    config_source(export_source_folder, conanfile, hook_manager)
 
 def _get_ref_from_cache_or_remote(conan_api, reference, enabled_remotes):
     ref = RecipeReference.loads(reference)
diff --git a/conan/cli/commands/new.py b/conan/cli/commands/new.py
index d316bf5a3..e6aab3c35 100644
--- a/conan/cli/commands/new.py
+++ b/conan/cli/commands/new.py
@@ -12,7 +12,7 @@ def new(conan_api, parser, *args):
                         "either a predefined built-in or a user-provided one. "
                         "Available built-in templates: basic, cmake_lib, cmake_exe, header_lib, "
                         "meson_lib, meson_exe, msbuild_lib, msbuild_exe, bazel_lib, bazel_exe, "
-                        "autotools_lib, autotools_exe, local_recipes_index, workspace. "
+                        "autotools_lib, autotools_exe, premake_lib, premake_exe, local_recipes_index, workspace. "
                         "E.g. 'conan new cmake_lib -d name=hello -d version=0.1'. "
                         "You can define your own templates too by inputting an absolute path "
                         "as your template, or a path relative to your conan home folder."
diff --git a/conan/internal/graph/graph_binaries.py b/conan/internal/graph/graph_binaries.py
index 386f69476..128e79646 100644
--- a/conan/internal/graph/graph_binaries.py
+++ b/conan/internal/graph/graph_binaries.py
@@ -19,17 +19,18 @@ from conan.errors import ConanException
 from conan.internal.model.info import RequirementInfo, RequirementsInfo
 from conan.api.model import PkgReference
 from conan.api.model import RecipeReference
+from conan.internal.model.pkg_type import PackageType
 from conan.internal.util.files import load
 
 
 class GraphBinariesAnalyzer:
 
-    def __init__(self, conan_app, global_conf):
+    def __init__(self, conan_app, global_conf, hook_manager):
         self._cache = conan_app.cache
         self._home_folder = conan_app.cache_folder
         self._global_conf = global_conf
         self._remote_manager = conan_app.remote_manager
-        self._hook_manager = conan_app.conan_api.config.hook_manager
+        self._hook_manager = hook_manager
         # These are the nodes with pref (not including PREV) that have been evaluated
         self._evaluated = {}  # {pref: [nodes]}
         compat_folder = HomePaths(conan_app.cache_folder).compatibility_plugin_path
@@ -435,7 +436,10 @@ class GraphBinariesAnalyzer:
             self._evaluate_node(n, mode, remotes, update)
 
         levels = deps_graph.by_levels()
-        config_version = self._config_version()
+        # When creating a "conan config install-pkg" package, it should be independent of conf
+        root_pkg_type = deps_graph.root.edges[0].dst.conanfile.package_type \
+            if deps_graph.root.edges else None
+        config_version = self._config_version() if root_pkg_type is not PackageType.CONF else None
         for level in levels[:-1]:  # all levels but the last one, which is the single consumer
             for node in level:
                 self._evaluate_package_id(node, config_version)
diff --git a/conan/internal/hook_manager.py b/conan/internal/hook_manager.py
index 7ef83bfc8..f790c5d28 100644
--- a/conan/internal/hook_manager.py
+++ b/conan/internal/hook_manager.py
@@ -61,3 +61,7 @@ class HookManager:
                     self.hooks.setdefault(method, []).append((hook_name, hook_method))
         except Exception as e:
             raise ConanException("Error loading hook '%s': %s" % (hook_path, str(e)))
+
+    def reinit(self):
+        self.hooks.clear()
+        self._load_hooks()
diff --git a/conan/internal/model/conan_file.py b/conan/internal/model/conan_file.py
index 5b2c595bf..a68c32775 100644
--- a/conan/internal/model/conan_file.py
+++ b/conan/internal/model/conan_file.py
@@ -75,6 +75,7 @@ class ConanFile:
     runenv_info = None
     conf_info = None
     generator_info = None
+    conan_data = None
 
     def __init__(self, display_name=""):
         self.display_name = display_name
@@ -176,6 +177,8 @@ class ConanFile:
         if self.info is not None:
             result["info"] = self.info.serialize()
         result["vendor"] = self.vendor
+        if self.conan_data:
+            result["conandata"] = self.conan_data
         return result
 
     @property
diff --git a/conan/tools/apple/apple.py b/conan/tools/apple/apple.py
index 0e3d7efce..844084387 100644
--- a/conan/tools/apple/apple.py
+++ b/conan/tools/apple/apple.py
@@ -108,6 +108,16 @@ def resolve_apple_flags(conanfile, is_cross_building=False):
     return min_version_flag, apple_arch_flag, apple_isysroot_flag
 
 
+def xcodebuild_deployment_target_key(os_name):
+    return {
+        "Macos": "MACOSX_DEPLOYMENT_TARGET",
+        "iOS": "IPHONEOS_DEPLOYMENT_TARGET",
+        "tvOS": "TVOS_DEPLOYMENT_TARGET",
+        "watchOS": "WATCHOS_DEPLOYMENT_TARGET",
+        "visionOS": "XROS_DEPLOYMENT_TARGET",
+    }.get(os_name) if os_name else None
+
+
 class XCRun:
     """
     XCRun is a wrapper for the Apple **xcrun** tool used to get information for building.
diff --git a/conan/tools/apple/xcodebuild.py b/conan/tools/apple/xcodebuild.py
index 6aa9420ef..637c4739d 100644
--- a/conan/tools/apple/xcodebuild.py
+++ b/conan/tools/apple/xcodebuild.py
@@ -1,4 +1,4 @@
-from conan.tools.apple import to_apple_arch
+from conan.tools.apple.apple import to_apple_arch, xcodebuild_deployment_target_key
 
 
 class XcodeBuild(object):
@@ -8,6 +8,8 @@ class XcodeBuild(object):
         self._arch = to_apple_arch(self._conanfile)
         self._sdk = conanfile.settings.get_safe("os.sdk") or ""
         self._sdk_version = conanfile.settings.get_safe("os.sdk_version") or ""
+        self._os = conanfile.settings.get_safe("os")
+        self._os_version = conanfile.settings.get_safe("os.version")
 
     @property
     def _verbosity(self):
@@ -36,8 +38,13 @@ class XcodeBuild(object):
                        will build all the targets passing the ``-alltargets`` argument instead.
         :return: the return code for the launched ``xcodebuild`` command.
         """
-        target = "-target {}".format(target) if target else "-alltargets"
-        cmd = "xcodebuild -project {} -configuration {} -arch {} " \
+        target = "-target '{}'".format(target) if target else "-alltargets"
+        cmd = "xcodebuild -project '{}' -configuration {} -arch {} " \
               "{} {} {}".format(xcodeproj, self._build_type, self._arch, self._sdkroot,
                                 self._verbosity, target)
+
+        deployment_target_key = xcodebuild_deployment_target_key(self._os)
+        if deployment_target_key and self._os_version:
+            cmd += f" {deployment_target_key}={self._os_version}"
+
         self._conanfile.run(cmd)
diff --git a/conan/tools/apple/xcodetoolchain.py b/conan/tools/apple/xcodetoolchain.py
index 194aa3af6..b6aca20e3 100644
--- a/conan/tools/apple/xcodetoolchain.py
+++ b/conan/tools/apple/xcodetoolchain.py
@@ -1,7 +1,7 @@
 import textwrap
 
 from conan.internal import check_duplicated_generator
-from conan.tools.apple.apple import to_apple_arch
+from conan.tools.apple.apple import to_apple_arch, xcodebuild_deployment_target_key
 from conan.tools.apple.xcodedeps import GLOBAL_XCCONFIG_FILENAME, GLOBAL_XCCONFIG_TEMPLATE, \
     _add_includes_to_file_or_create, _xcconfig_settings_filename, _xcconfig_conditional
 from conan.internal.util.files import save
@@ -64,16 +64,10 @@ class XcodeToolchain(object):
 
     @property
     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")))
+        deployment_target_key = xcodebuild_deployment_target_key(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 ""
+                                self.os_version) if deployment_target_key and self.os_version else ""
 
     @property
     def _clang_cxx_library(self):
diff --git a/conan/tools/cmake/cmakedeps2/target_configuration.py b/conan/tools/cmake/cmakedeps2/target_configuration.py
index 30b71b0ea..cf11208af 100644
--- a/conan/tools/cmake/cmakedeps2/target_configuration.py
+++ b/conan/tools/cmake/cmakedeps2/target_configuration.py
@@ -122,6 +122,23 @@ class TargetConfigurationTemplate2:
 
         prefixes = self._cmakedeps.get_property("cmake_additional_variables_prefixes",
                                                 self._conanfile, check_type=list) or []
+        seen_aliases = set()
+        root_target_name = self._cmakedeps.get_property("cmake_target_name", self._conanfile)
+        root_target_name = root_target_name or f"{pkg_name}::{pkg_name}"
+        for lib in libs.values():
+            for alias in lib.get("cmake_target_aliases", []):
+                if alias == root_target_name:
+                    raise ConanException(f"Can't define an alias '{alias}' for the "
+                                         f"root target '{root_target_name}' in {self._conanfile}. "
+                                         f"Changing the default target should be done with the "
+                                         f"'cmake_target_name' property.")
+                if alias in seen_aliases:
+                    raise ConanException(f"Alias '{alias}' already defined in {self._conanfile}. ")
+                seen_aliases.add(alias)
+                if alias in libs:
+                    raise ConanException(f"Alias '{alias}' already defined as a target in "
+                                         f"{self._conanfile}. ")
+
         f = self._cmakedeps.get_cmake_filename(self._conanfile)
         prefixes = [f] + prefixes
         include_dirs = definitions = libraries = None
@@ -164,12 +181,16 @@ class TargetConfigurationTemplate2:
                 target = self._get_cmake_lib(component, cpp_info.components, pkg_folder,
                                              pkg_folder_var)
                 if target is not None:
+                    cmake_target_aliases = self._get_aliases(name)
+                    target["cmake_target_aliases"] = cmake_target_aliases
                     libs[target_name] = target
         else:
             target_name = self._cmakedeps.get_property("cmake_target_name", self._conanfile)
             target_name = target_name or f"{pkg_name}::{pkg_name}"
             target = self._get_cmake_lib(cpp_info, None, pkg_folder, pkg_folder_var)
             if target is not None:
+                cmake_target_aliases = self._get_aliases()
+                target["cmake_target_aliases"] = cmake_target_aliases
                 libs[target_name] = target
         return libs
 
@@ -233,11 +254,16 @@ class TargetConfigurationTemplate2:
             target["link_languages"] = link_languages
         return target
 
+    def _get_aliases(self, comp_name=None):
+        aliases = self._cmakedeps.get_property("cmake_target_aliases", self._conanfile,
+                                               comp_name, check_type=list) or []
+        return aliases
+
     def _add_root_lib_target(self, libs, pkg_name, cpp_info):
         """
-        Addd a new pkgname::pkgname INTERFACE target that depends on default_components or
+        Add a new pkgname::pkgname INTERFACE target that depends on default_components or
         on all other library targets (not exes)
-        It will not be added if there exists already a pkgname::pkgname target.
+        It will not be added if there exists already a pkgname::pkgname target (Or an alias exists).
         """
         root_target_name = self._cmakedeps.get_property("cmake_target_name", self._conanfile)
         root_target_name = root_target_name or f"{pkg_name}::{pkg_name}"
@@ -253,8 +279,11 @@ class TargetConfigurationTemplate2:
                     all_requires[comp_name] = True  # It is an interface, full link
             else:
                 all_requires = {k: True for k in libs.keys()}
+            # This target might have an alias, so we need to check it
+            cmake_target_aliases = self._get_aliases()
             libs[root_target_name] = {"type": "INTERFACE",
-                                      "requires": all_requires}
+                                      "requires": all_requires,
+                                      "cmake_target_aliases": cmake_target_aliases}
 
     def _get_exes(self, cpp_info, pkg_name, pkg_folder, pkg_folder_var):
         exes = {}
@@ -333,6 +362,12 @@ class TargetConfigurationTemplate2:
             message(STATUS "Conan: Target declared imported {{lib_info["type"]}} library '{{lib}}'")
             add_library({{lib}} {{lib_info["type"]}} IMPORTED)
         endif()
+        {% for alias in lib_info.get("cmake_target_aliases", []) %}
+        if(NOT TARGET {{alias}})
+            message(STATUS "Conan: Target declared alias '{{alias}}' for '{{lib}}'")
+            add_library({{alias}} ALIAS {{lib}})
+        endif()
+        {% endfor %}
         {% if lib_info.get("includedirs") %}
         set_property(TARGET {{lib}} APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES
                      {{config_wrapper(config, lib_info["includedirs"])}})
diff --git a/conan/tools/premake/premakedeps.py b/conan/tools/premake/premakedeps.py
index 80b291ac2..c98a6377e 100644
--- a/conan/tools/premake/premakedeps.py
+++ b/conan/tools/premake/premakedeps.py
@@ -8,16 +8,27 @@ from conan.tools.premake.constants import CONAN_TO_PREMAKE_ARCH
 
 # Filename format strings
 PREMAKE_VAR_FILE = "conan_{pkgname}_vars_{config}.premake5.lua"
-PREMAKE_CONF_FILE = "conan_{pkgname}{config}.premake5.lua"
 PREMAKE_PKG_FILE = "conan_{pkgname}.premake5.lua"
 PREMAKE_ROOT_FILE = "conandeps.premake5.lua"
 
+PREMAKE_CONFIG_FILE = "conanconfig_{config}.premake5.lua"
+PREMAKE_CONFIG_ROOT_FILE = "conanconfig.premake5.lua"
+
 # File template format strings
+PREMAKE_TEMPLATE_CONFIG = """
+include "conanutils.premake5.lua"
+
+t_conan_deps_order = {{}}
+t_conan_deps_order["{config}"] = {{{order}}}
+
+if conan_deps_order == nil then conan_deps_order = {{}} end
+conan_premake_tmerge(conan_deps_order, t_conan_deps_order)
+"""
 PREMAKE_TEMPLATE_UTILS = """
 function conan_premake_tmerge(dst, src)
     for k, v in pairs(src) do
         if type(v) == "table" then
-            if type(conandeps[k] or 0) == "table" then
+            if type(dst[k] or 0) == "table" then
                 conan_premake_tmerge(dst[k] or {}, src[k] or {})
             else
                 dst[k] = v
@@ -66,8 +77,9 @@ function {function_name}(conf, pkg)
     if conf == nil then
 {filter_call}
     elseif pkg == nil then
-        for k,v in pairs(conandeps[conf]) do
-            {function_name}(conf, k)
+        local order = conan_deps_order[conf]
+        for index, lib in ipairs(order) do
+            {function_name}(conf, lib)
         end
     else
 {lua_content}
@@ -183,10 +195,13 @@ class PremakeDeps:
         # Global utility file
         self._output_lua_file("conanutils.premake5.lua", [PREMAKE_TEMPLATE_UTILS])
 
-        # Extract all dependencies
-        host_req = self._conanfile.dependencies.host
-        test_req = self._conanfile.dependencies.test
-        build_req = self._conanfile.dependencies.build
+        # Extract all dependencies in topological order: some linkers like ld or gold prunes the
+        # functions which are not being used in the lookup table. If the less dependant libraries are
+        # passed first, the linker will not be able to resolve the symbols in the dependent libraries
+        # as they will have been removed
+        host_req = self._conanfile.dependencies.host.topological_sort
+        test_req = self._conanfile.dependencies.test.topological_sort
+        build_req = self._conanfile.dependencies.build.topological_sort
 
         # Merge into one list
         full_req = list(host_req.items()) + list(test_req.items()) + list(build_req.items())
@@ -212,13 +227,13 @@ class PremakeDeps:
             # Create list of all available profiles by searching on disk
             file_pattern = PREMAKE_VAR_FILE.format(pkgname=dep_name, config="*")
             file_regex = PREMAKE_VAR_FILE.format(pkgname=re.escape(dep_name), config="(([^_]*)_(.*))")
-            available_files = glob.glob(file_pattern)
+            available_config_files = glob.glob(file_pattern)
             # Add filename of current generations var file if not already present
-            if var_filename not in available_files:
-                available_files.append(var_filename)
+            if var_filename not in available_config_files:
+                available_config_files.append(var_filename)
             profiles = [
                 (regex_res[0], regex_res.group(1), regex_res.group(2), regex_res.group(3)) for regex_res in [
-                    re.search(file_regex, file_name) for file_name in available_files
+                    re.search(file_regex, file_name) for file_name in available_config_files
                 ]
             ]
             config_sets = [profile[1] for profile in profiles]
@@ -235,6 +250,8 @@ class PremakeDeps:
         self._output_lua_file(PREMAKE_ROOT_FILE, [
             # Includes
             *[f'include "{pkg_file}"' for pkg_file in pkg_files],
+            # Global order for each configuration
+            'include "conanconfig.premake5.lua"',
             # Functions
             PREMAKE_TEMPLATE_ROOT_FUNCTION.format(
                 function_name="conan_setup_build",
@@ -257,4 +274,19 @@ class PremakeDeps:
             PREMAKE_TEMPLATE_ROOT_GLOBAL
         ])
 
+        # Output configuration file for the current build configuration
+        self._output_lua_file(PREMAKE_CONFIG_FILE.format(config=conf_name), [
+            PREMAKE_TEMPLATE_CONFIG.format(
+                config=conf_name, order=", ".join(f'"{name}"' for name in reversed(dep_names))
+            )
+        ])
+
+        # Output root configuration file
+        available_config_files = glob.glob(PREMAKE_CONFIG_FILE.format(config="*"))
+        available_configs = [file_name.split("_", 1)[1].split(".")[0] for file_name in available_config_files]
+        available_configs.append(conf_name)
+        self._output_lua_file(PREMAKE_CONFIG_ROOT_FILE, [
+            *['include "{}"'.format(PREMAKE_CONFIG_FILE.format(config=config)) for config in available_configs],
+        ])
+
         return self.output_files


Test patch:
diff --git a/test/functional/toolchains/apple/test_xcodebuild.py b/test/functional/toolchains/apple/test_xcodebuild.py
index a63e501f0..74c7c0690 100644
--- a/test/functional/toolchains/apple/test_xcodebuild.py
+++ b/test/functional/toolchains/apple/test_xcodebuild.py
@@ -91,11 +91,12 @@ def test_project_xcodebuild(client):
     client.run("install . --build=missing")
     client.run("install . -s build_type=Debug --build=missing")
     client.run_command("xcodegen generate")
-    client.run("create . --build=missing -c tools.build:verbosity=verbose -c tools.compilation:verbosity=verbose")
+    client.run("create . --build=missing -s os.version=15.0 -c tools.build:verbosity=verbose -c tools.compilation:verbosity=verbose")
+    assert "MACOSX_DEPLOYMENT_TARGET=15.0" in client.out
     assert "xcodebuild: error: invalid option" not in client.out
     assert "hello/0.1: Hello World Release!" in client.out
     assert "App Release!" in client.out
-    client.run("create . -s build_type=Debug --build=missing")
+    client.run("create . -s build_type=Debug -s os.version=15.0 --build=missing")
     assert "hello/0.1: Hello World Debug!" in client.out
     assert "App Debug!" in client.out
 
diff --git a/test/functional/toolchains/cmake/cmakedeps2/test_cmakeconfigdeps_aliases.py b/test/functional/toolchains/cmake/cmakedeps2/test_cmakeconfigdeps_aliases.py
new file mode 100644
index 000000000..b09dd2207
--- /dev/null
+++ b/test/functional/toolchains/cmake/cmakedeps2/test_cmakeconfigdeps_aliases.py
@@ -0,0 +1,261 @@
+import textwrap
+import pytest
+
+from conan.test.utils.tools import TestClient
+
+new_value = "will_break_next"
+
+consumer = textwrap.dedent("""
+from conan import ConanFile
+from conan.tools.cmake import CMake
+
+class Consumer(ConanFile):
+    name = "consumer"
+    version = "1.0"
+    settings = "os", "compiler", "build_type", "arch"
+    generators = "CMakeDeps", "CMakeToolchain"
+    exports_sources = ["CMakeLists.txt"]
+    requires = "hello/1.0"
+
+    def build(self):
+        cmake = CMake(self)
+        cmake.configure()
+        cmake.build()
+""")
+
+
+@pytest.mark.tool("cmake", "3.27")
+def test_global_alias():
+    conanfile = textwrap.dedent("""
+    from conan import ConanFile
+
+    class Hello(ConanFile):
+        name = "hello"
+        version = "1.0"
+        settings = "os", "compiler", "build_type", "arch"
+
+        def package_info(self):
+            # the default global target is "hello::hello"
+            self.cpp_info.set_property("cmake_target_aliases", ["hello"])
+    """)
+
+    cmakelists = textwrap.dedent("""
+    cmake_minimum_required(VERSION 3.15)
+    project(test NONE)
+
+    find_package(hello REQUIRED)
+    get_target_property(_aliased_target hello ALIASED_TARGET)
+    message("hello aliased target: ${_aliased_target}")
+    """)
+
+    client = TestClient()
+    client.save({"conanfile.py": conanfile})
+    client.run(f"create . -c tools.cmake.cmakedeps:new={new_value}")
+
+    client.save({"conanfile.py": consumer, "CMakeLists.txt": cmakelists})
+    client.run(f"create . -c tools.cmake.cmakedeps:new={new_value}")
+
+    assert "hello aliased target: hello::hello" in client.out
+
+
+@pytest.mark.tool("cmake", "3.27")
+def test_component_alias():
+    conanfile = textwrap.dedent("""
+    from conan import ConanFile
+
+    class Hello(ConanFile):
+        name = "hello"
+        version = "1.0"
+        settings = "os", "compiler", "build_type", "arch"
+
+        def package_info(self):
+            self.cpp_info.components["buy"].set_property("cmake_target_aliases",
+                ["hola::adios"])
+    """)
+
+    cmakelists = textwrap.dedent("""
+    cmake_minimum_required(VERSION 3.15)
+    project(test NONE)
+
+    find_package(hello REQUIRED)
+    get_target_property(_aliased_target hola::adios ALIASED_TARGET)
+    message("hola::adios aliased target: ${_aliased_target}")
+    """)
+
+    client = TestClient()
+    client.save({"conanfile.py": conanfile})
+    client.run(f"create . -c tools.cmake.cmakedeps:new={new_value}")
+
+    client.save({"conanfile.py": consumer, "CMakeLists.txt": cmakelists})
+    client.run(f"create . -c tools.cmake.cmakedeps:new={new_value}")
+
+    assert "hola::adios aliased target: hello::buy" in client.out
+
+
+@pytest.mark.tool("cmake", "3.27")
+def test_global_and_component_alias():
+    conanfile = textwrap.dedent("""
+    from conan import ConanFile
+
+    class Hello(ConanFile):
+        name = "hello"
+        version = "1.0"
+        settings = "os", "compiler", "build_type", "arch"
+
+        def package_info(self):
+            self.cpp_info.set_property("cmake_target_aliases", ["hola::hola"])
+            self.cpp_info.components["buy"].set_property("cmake_target_aliases",
+                ["hola::adios"])
+    """)
+
+    cmakelists = textwrap.dedent("""
+    cmake_minimum_required(VERSION 3.15)
+    project(test NONE)
+
+    find_package(hello REQUIRED)
+    get_target_property(_aliased_target hola::hola ALIASED_TARGET)
+    message("hola::hola aliased target: ${_aliased_target}")
+    """)
+
+    client = TestClient()
+    client.save({"conanfile.py": conanfile})
+    client.run(f"create . -c tools.cmake.cmakedeps:new={new_value}")
+
+    client.save({"conanfile.py": consumer, "CMakeLists.txt": cmakelists})
+    client.run(f"create . -c tools.cmake.cmakedeps:new={new_value}")
+
+    assert "hola::hola aliased target: hello::hello" in client.out
+
+
+@pytest.mark.tool("cmake", "3.27")
+def test_custom_name():
+    conanfile = textwrap.dedent("""
+    from conan import ConanFile
+
+    class Hello(ConanFile):
+        name = "hello"
+        version = "1.0"
+        settings = "os", "compiler", "build_type", "arch"
+
+        def package_info(self):
+            self.cpp_info.set_property("cmake_target_name", "ola::comprar")
+            self.cpp_info.set_property("cmake_target_aliases", ["hello"])
+    """)
+
+    cmakelists = textwrap.dedent("""
+    cmake_minimum_required(VERSION 3.15)
+    project(test NONE)
+
+    find_package(hello REQUIRED)
+    get_target_property(_aliased_target hello ALIASED_TARGET)
+    message("hello aliased target: ${_aliased_target}")
+    """)
+
+    client = TestClient()
+    client.save({"conanfile.py": conanfile})
+    client.run(f"create . -c tools.cmake.cmakedeps:new={new_value}")
+
+    client.save({"conanfile.py": consumer, "CMakeLists.txt": cmakelists})
+    client.run(f"create . -c tools.cmake.cmakedeps:new={new_value}")
+
+    assert "hello aliased target: ola::comprar" in client.out
+
+
+@pytest.mark.tool("cmake", "3.27")
+def test_collide_component_alias():
+    conanfile = textwrap.dedent("""
+    from conan import ConanFile
+
+    class Hello(ConanFile):
+        name = "hello"
+        version = "1.0"
+        settings = "os", "compiler", "build_type", "arch"
+
+        def package_info(self):
+            self.cpp_info.components["buy"].set_property("cmake_target_aliases", ["hello::buy"])
+    """)
+
+    cmakelists = textwrap.dedent("""
+    cmake_minimum_required(VERSION 3.15)
+    project(test NONE)
+
+    find_package(hello REQUIRED)
+    """)
+
+    client = TestClient()
+    client.save({"conanfile.py": conanfile})
+    client.run(f"create . -c tools.cmake.cmakedeps:new={new_value}")
+
+    client.save({"conanfile.py": consumer, "CMakeLists.txt": cmakelists})
+    client.run(f"create . -c tools.cmake.cmakedeps:new={new_value}", assert_error=True)
+
+    assert "Alias 'hello::buy' already defined as a target in hello/1.0" in client.out
+
+
+@pytest.mark.tool("cmake", "3.27")
+def test_collide_component_alias_to_alias():
+    conanfile = textwrap.dedent("""
+    from conan import ConanFile
+
+    class Hello(ConanFile):
+        name = "hello"
+        version = "1.0"
+        settings = "os", "compiler", "build_type", "arch"
+
+        def package_info(self):
+            self.cpp_info.components["ola"].set_property("cmake_target_aliases", ["hello::foo"])
+            self.cpp_info.components["buy"].set_property("cmake_target_aliases", ["hello::foo"])
+    """)
+
+    cmakelists = textwrap.dedent("""
+    cmake_minimum_required(VERSION 3.15)
+    project(test NONE)
+
+    find_package(hello REQUIRED)
+    """)
+
+    client = TestClient()
+    client.save({"conanfile.py": conanfile})
+    client.run(f"create . -c tools.cmake.cmakedeps:new={new_value}")
+
+    client.save({"conanfile.py": consumer, "CMakeLists.txt": cmakelists})
+    client.run(f"create . -c tools.cmake.cmakedeps:new={new_value}", assert_error=True)
+
+    assert "Alias 'hello::foo' already defined in hello/1.0" in client.out
+
+
+@pytest.mark.tool("cmake", "3.27")
+@pytest.mark.parametrize("root_target", ["hello::custom", None])
+def test_skip_global_if_aliased(root_target):
+    target_line = f'self.cpp_info.set_property("cmake_target_name", "{root_target}")' if root_target else ""
+    target_name = root_target or "hello::hello"
+    conanfile = textwrap.dedent(f"""
+    from conan import ConanFile
+
+    class Hello(ConanFile):
+        name = "hello"
+        version = "1.0"
+        settings = "os", "compiler", "build_type", "arch"
+
+        def package_info(self):
+            {target_line}
+            self.cpp_info.components["foo"].set_property("cmake_target_aliases", ["{target_name}"])
+    """)
+
+    cmakelists = textwrap.dedent("""
+    cmake_minimum_required(VERSION 3.15)
+    project(test NONE)
+
+    find_package(hello REQUIRED)
+    get_target_property(_aliased_target hello::hello ALIASED_TARGET)
+    message("hello::hello aliased target: ${_aliased_target}")
+    """)
+
+    client = TestClient()
+    client.save({"conanfile.py": conanfile})
+    client.run(f"create . -c tools.cmake.cmakedeps:new={new_value}")
+
+    client.save({"conanfile.py": consumer, "CMakeLists.txt": cmakelists})
+    client.run(f"create . -c tools.cmake.cmakedeps:new={new_value}", assert_error=True)
+
+    assert f"Can't define an alias '{target_name}' for the root target '{target_name}' in hello/1.0" in client.out
diff --git a/test/integration/conanfile/conan_data_test.py b/test/integration/conanfile/conan_data_test.py
index e05d4d977..d1abb4ffd 100644
--- a/test/integration/conanfile/conan_data_test.py
+++ b/test/integration/conanfile/conan_data_test.py
@@ -1,3 +1,4 @@
+import json
 import os
 import shutil
 import sys
@@ -193,6 +194,22 @@ class Lib(ConanFile):
         client.run("export-pkg . --name=name --version=version")
         self.assertIn("My URL: this url", client.out)
 
+    def test_conan_data_serialize(self):
+        c = TestClient(light=True)
+        conandata = textwrap.dedent("""
+            src:
+                url: "this url"
+        """)
+        c.save({"conanfile.py": GenConanfile("pkg", "0.1"),
+                "conandata.yml": conandata})
+        c.run("graph info . --format=json")
+        graph = json.loads(c.stdout)
+        assert graph["graph"]["nodes"]["0"]["conandata"]["src"] == {"url": "this url"}
+
+        c.run("inspect . --format=json")
+        result = json.loads(c.stdout)
+        assert result["conandata"]["src"] == {"url": "this url"}
+
 
 class TestConanDataUpdate:
     """
diff --git a/test/integration/configuration/required_version_test.py b/test/integration/configuration/required_version_test.py
index de712afde..fc0092054 100644
--- a/test/integration/configuration/required_version_test.py
+++ b/test/integration/configuration/required_version_test.py
@@ -1,5 +1,4 @@
 import os
-import unittest
 import mock
 
 from conan import __version__
@@ -8,44 +7,49 @@ from conan.test.utils.tools import TestClient
 from conan.internal.util.files import save
 
 
-class RequiredVersionTest(unittest.TestCase):
+class TestRequiredVersion:
 
     @mock.patch("conan.__version__", "1.26.0")
     def test_wrong_version(self):
         required_version = "1.23.0"
-        client = TestClient()
+        client = TestClient(light=True)
         client.save_home({"global.conf": f"core:required_conan_version={required_version}"})
         client.run("help", assert_error=True)
-        self.assertIn("Current Conan version (1.26.0) does not satisfy the defined "
-                      "one ({})".format(required_version), client.out)
+        assert f"Current Conan version (1.26.0) does not satisfy the defined one ({required_version})" in client.out
 
     @mock.patch("conan.__version__", "1.22.0")
     def test_exact_version(self):
         required_version = "1.22.0"
-        client = TestClient()
+        client = TestClient(light=True)
         client.save_home({"global.conf": f"core:required_conan_version={required_version}"})
         client.run("--help")
 
     @mock.patch("conan.__version__", "2.1.0")
     def test_lesser_version(self):
         required_version = "<3.0"
-        client = TestClient()
+        client = TestClient(light=True)
         client.save_home({"global.conf": f"core:required_conan_version={required_version}"})
         client.run("--help")
 
     @mock.patch("conan.__version__", "1.0.0")
     def test_greater_version(self):
         required_version = ">0.1.0"
-        client = TestClient()
+        client = TestClient(light=True)
         client.save_home({"global.conf": f"core:required_conan_version={required_version}"})
         client.run("--help")
 
+    @mock.patch("conan.__version__", "1.0.0")
+    def test_greater_version_cc_override(self):
+        client = TestClient(light=True)
+        client.save_home({"global.conf": f"core:required_conan_version=>0.1.0"})
+        client.run("config home -cc core:required_conan_version=>2.0", assert_error=True)
+        assert f"Current Conan version (1.0.0) does not satisfy the defined one (>2.0)" in client.out
+
     def test_bad_format(self):
         required_version = "1.0.0.0-foobar"
         cache_folder = temp_folder()
         save(os.path.join(cache_folder, "global.conf"),
              f"core:required_conan_version={required_version}")
-        c = TestClient(cache_folder)
+        c = TestClient(cache_folder, light=True)
         c.run("version", assert_error=True)
-        self.assertIn("Current Conan version ({}) does not satisfy the defined one ({})"
-                      .format(__version__, required_version), c.out)
+        assert f"Current Conan version ({__version__}) does not satisfy the defined one ({required_version})" in c.out
diff --git a/test/integration/package_id/test_config_package_id.py b/test/integration/package_id/test_config_package_id.py
index da4b8c64d..cf2383b36 100644
--- a/test/integration/package_id/test_config_package_id.py
+++ b/test/integration/package_id/test_config_package_id.py
@@ -41,6 +41,7 @@ def test_error_config_package_id():
     assert "ERROR: core.package_id:config_mode defined, " \
            "but error while loading 'config_version.json'" in c.out
 
+
 @pytest.mark.parametrize("config_version, mode, result", [
     ("myconfig/1.2.3#rev1:pid1#prev1", "minor_mode", "myconfig/1.2.Z"),
     ("myconfig/1.2.3#rev1:pid1#prev1", "patch_mode", "myconfig/1.2.3"),
@@ -82,3 +83,17 @@ def test_recipe_revision_mode():
     # Now change only the package revision of liba
     clienta.run("create . --name=liba --version=0.1 --user=user --channel=testing")
     clientc.run("install . --user=user --channel=testing")
+
+
+def test_config_package_id_mode():
+    # chicken and egg problem when the configuration package itself is affected by the mode
+    c = TestClient(light=True)
+    config_version = json.dumps({"config_version": ["myconfig/0.1"]})
+    save(c.paths.config_version_path, config_version)
+    c.save_home({"global.conf": "core.package_id:config_mode=minor_mode"})
+
+    c.save({"conanfile.py": GenConanfile("myconfig", "0.1").with_package_type("configuration")})
+    c.run("create . ")
+    c.run("list *:*")
+    # The binary is independent of the configuration version
+    assert "config_version" not in c.out
diff --git a/test/integration/toolchains/cmake/cmakedeps2/test_cmakedeps.py b/test/integration/toolchains/cmake/cmakedeps2/test_cmakedeps.py
index ef72cc991..0f329d469 100644
--- a/test/integration/toolchains/cmake/cmakedeps2/test_cmakedeps.py
+++ b/test/integration/toolchains/cmake/cmakedeps2/test_cmakedeps.py
@@ -482,3 +482,42 @@ def test_requires_to_application_component():
     assert "automake::automake" not in targets
     assert "# Requirement automake::mylibapp => Full link: True" in targets
     assert "$<$<CONFIG:RELEASE>:automake::mylibapp>" in targets
+
+
+def test_alias_cmakedeps_set_property():
+    tc = TestClient()
+    tc.save({"dep/conanfile.py": textwrap.dedent("""
+
+        from conan import ConanFile
+        class Dep(ConanFile):
+            name = "dep"
+            version = "1.0"
+            settings = "os", "compiler", "build_type", "arch"
+            def package_info(self):
+                self.cpp_info.components["mycomp"].set_property("cmake_target_name", "dep::mycomponent")
+        """),
+             "conanfile.py": textwrap.dedent("""
+             from conan import ConanFile
+             from conan.tools.cmake import CMakeDeps, CMake
+             class Pkg(ConanFile):
+                name = "pkg"
+                version = "1.0"
+                settings = "os", "compiler", "build_type", "arch"
+
+                requires = "dep/1.0"
+
+                def generate(self):
+                    deps = CMakeDeps(self)
+                    deps.set_property("dep", "cmake_target_aliases", ["alias", "dep::other_name"])
+                    deps.set_property("dep::mycomp", "cmake_target_aliases", ["component_alias", "dep::my_aliased_component"])
+                    deps.generate()
+             """)})
+    tc.run("create dep")
+    tc.run(f"install . -c tools.cmake.cmakedeps:new={new_value}")
+    targets_data = tc.load('dep-Targets-release.cmake')
+    assert "add_library(dep::dep" in targets_data
+    assert "add_library(alias" in targets_data
+    assert "add_library(dep::other_name" in targets_data
+
+    assert "add_library(component_alias" in targets_data
+    assert "add_library(dep::my_aliased_component" in targets_data
diff --git a/test/integration/toolchains/premake/test_premakedeps.py b/test/integration/toolchains/premake/test_premakedeps.py
index 9e42410b8..e4a8c9b35 100644
--- a/test/integration/toolchains/premake/test_premakedeps.py
+++ b/test/integration/toolchains/premake/test_premakedeps.py
@@ -1,5 +1,6 @@
 import textwrap
 
+from conan.test.assets.genconanfile import GenConanfile
 from conan.test.utils.tools import TestClient
 
 
@@ -63,3 +64,73 @@ def test_premakedeps():
     assert_vars_file(client, 'debug')
     assert_vars_file(client, 'release')
 
+
+def test_premakedeps_link_order():
+    client = TestClient()
+    profile = textwrap.dedent(
+        """
+        [settings]
+        os=Linux
+        arch=x86_64
+        compiler=gcc
+        compiler.version=9
+        compiler.cppstd=17
+        compiler.libcxx=libstdc++
+        build_type=Release
+        """)
+    client.save(
+        {
+            "liba/conanfile.py": GenConanfile("liba")
+            .with_settings("os", "compiler", "build_type", "arch")
+            .with_version("1.0")
+            .with_generator("PremakeDeps")
+            .with_generator("PremakeToolchain")
+            .with_package_info(cpp_info={"libs": ["liba"]}),
+
+            "libb/conanfile.py": GenConanfile("libb")
+            .with_settings("os", "compiler", "build_type", "arch")
+            .with_version("1.0")
+            .with_requires("liba/1.0")
+            .with_generator("PremakeDeps")
+            .with_package_info(
+                cpp_info={
+                    "components": {
+                        "libb1": {"requires": ["liba::liba"]},
+                        "libb2": {"requires": ["libb1"]},
+                    }
+                }
+            ),
+
+            "libc/conanfile.py": GenConanfile("libc")
+            .with_settings("os", "compiler", "build_type", "arch")
+            .with_version("1.0")
+            .with_requires("libb/1.0")
+            .with_generator("PremakeDeps")
+            .with_package_info(cpp_info={"libs": ["libc"]}),
+
+            "consumer/conanfile.py": GenConanfile("consumer")
+            .with_settings("os", "compiler", "build_type", "arch")
+            .with_version("1.0")
+            .with_requires("libc/1.0")
+            .with_generator("PremakeDeps"),
+
+            "profile": profile
+        }
+    )
+    client.run("create liba -pr profile")
+    client.run("create libb -pr profile")
+    client.run("create libc -pr profile")
+    client.run("install consumer -pr profile")
+    contents = client.load("consumer/conanconfig.premake5.lua")
+    assert 'include "conanconfig_release_x86_64.premake5.lua"' in contents
+    contents = client.load("consumer/conanconfig_release_x86_64.premake5.lua")
+    # Check correct order of dependencies: more dependent libs should be linked first
+    assert 't_conan_deps_order["release_x86_64"] = {"libc", "libb", "liba"}' in contents
+
+    # Check previous configurations are preserved when installing new configuration
+    client.run("install consumer -pr profile -s build_type=Debug --build=missing")
+    contents = client.load("consumer/conanconfig.premake5.lua")
+    assert 'include "conanconfig_release_x86_64.premake5.lua"' in contents
+    assert 'include "conanconfig_debug_x86_64.premake5.lua"' in contents
+    contents = client.load("consumer/conanconfig_debug_x86_64.premake5.lua")
+    assert 't_conan_deps_order["debug_x86_64"] = {"libc", "libb", "liba"}' in contents
diff --git a/test/unittests/client/tools/apple/test_xcodebuild.py b/test/unittests/client/tools/apple/test_xcodebuild.py
index 32cf2575b..947a00443 100644
--- a/test/unittests/client/tools/apple/test_xcodebuild.py
+++ b/test/unittests/client/tools/apple/test_xcodebuild.py
@@ -64,3 +64,39 @@ def test_sdk():
     xcodebuild = XcodeBuild(conanfile)
     xcodebuild.build("app.xcodeproj")
     assert "SDKROOT" not in conanfile.command
+
+
+@pytest.mark.parametrize("os_name, os_version, expected_key", [
+    ("Macos", "14.0", "MACOSX_DEPLOYMENT_TARGET"),
+    ("iOS", "15.1", "IPHONEOS_DEPLOYMENT_TARGET"),
+    ("watchOS", "8.0", "WATCHOS_DEPLOYMENT_TARGET"),
+    ("tvOS", "15.0", "TVOS_DEPLOYMENT_TARGET"),
+    ("visionOS", "1.0", "XROS_DEPLOYMENT_TARGET")
+])
+def test_deployment_target_and_quoting(os_name, os_version, expected_key):
+    """
+    Checks that the correct deployment target is passed and that paths are quoted.
+    """
+    conanfile = ConanFileMock()
+    conanfile.settings = MockSettings({"os": os_name, "os.version": os_version})
+    xcodebuild = XcodeBuild(conanfile)
+
+    xcodebuild.build("My Project.xcodeproj", target="My Target")
+
+    expected_arg = f" {expected_key}={os_version}"
+    assert expected_arg in conanfile.command
+
+    assert "-project 'My Project.xcodeproj'" in conanfile.command
+    assert "-target 'My Target'" in conanfile.command
+
+
+def test_no_deployment_target_if_version_is_missing():
+    """
+    Checks that the deployment target argument is not added if os.version is missing.
+    """
+    conanfile = ConanFileMock()
+    conanfile.settings = MockSettings({"os": "Macos"})
+    xcodebuild = XcodeBuild(conanfile)
+    xcodebuild.build("app.xcodeproj")
+
+    assert "MACOSX_DEPLOYMENT_TARGET" not in conanfile.command