Repository: conan-io/conan
Pull request #18533 (2025-06-25 13:41:24)

Avoid library renames when Meson + Windows + MSVC static builds
Changelog: Feature: Backporting change from https://github.com/Kitware/CMake/commit/c6efbd78d86798573654d1a791f76de0e71bd93f to CMakeDeps to avoid library renames when using Meson + MSVC + static builds.
Docs: omit
Closes: https://github.com/conan-io/conan/issues/11866

**Rationale**

With this PR, it's possible for a recipe that has:

self.cpp_info.libs = ["foo"]
and a file libfoo.a instead of foo.lib (Windows + shared=False)
To be consumed properly by all of Meson+PkgConfig, CMakeDeps and CMakeConfigDeps .

Meson+PkgConfig already works
CMakeDeps with CMake >= 3.29 already works
CMakeConfigDeps not affected because files are located before generating the CMake files anyway
This allows using CMakeDeps consumers with older versions of CMake (< 3.29) - to align with the improvements in handling this that is already part of newer CMake versions. There's no reason to rename any files - and the msvc linker handles this without any issue.

Coming from https://github.com/conan-io/conan/pull/18533#issuecomment-3013365088 thanks @jcar87  🙏 


Patch:
diff --git a/conan/api/subapi/cache.py b/conan/api/subapi/cache.py
index 621f5aa60..d65bbcd18 100644
--- a/conan/api/subapi/cache.py
+++ b/conan/api/subapi/cache.py
@@ -259,6 +259,14 @@ class CacheAPI:
         download_cache = DownloadCache(download_cache_path)
         return download_cache.get_backup_sources_files(excluded_urls, package_list, only_upload)
 
+    def path_to_ref(self, path):
+        cache = PkgCache(self.conan_api.cache_folder, self.conan_api.config.global_conf)
+        result = cache.path_to_ref(path)
+        if result is None:
+            base, folder = os.path.split(path)
+            result = cache.path_to_ref(base)
+        return result
+
 
 def _resolve_latest_ref(cache, ref):
     if ref.revision is None or ref.revision == "latest":
diff --git a/conan/cli/commands/cache.py b/conan/cli/commands/cache.py
index 52abdb58b..975ff02b3 100644
--- a/conan/cli/commands/cache.py
+++ b/conan/cli/commands/cache.py
@@ -64,6 +64,19 @@ def cache_path(conan_api: ConanAPI, parser, subparser, *args):
     return path
 
 
+@conan_subcommand(formatters={"text": cli_out_write})
+def cache_ref(conan_api: ConanAPI, parser, subparser, *args):
+    """
+    Show the reference for a given Conan cache folder
+    """
+    subparser.add_argument("path", help="Path to a Conan cache folder")
+    args = parser.parse_args(*args)
+    ref = conan_api.cache.path_to_ref(args.path)
+    if ref is None:
+        raise ConanException("Reference for this path not found in cache")
+    return ref.repr_notime()
+
+
 @conan_subcommand()
 def cache_clean(conan_api: ConanAPI, parser, subparser, *args):
     """
diff --git a/conan/internal/cache/cache.py b/conan/internal/cache/cache.py
index fca75a69e..c21d4db41 100644
--- a/conan/internal/cache/cache.py
+++ b/conan/internal/cache/cache.py
@@ -277,3 +277,11 @@ class PkgCache:
 
     def update_package_lru(self, pref):
         self._db.update_package_lru(pref)
+
+    def path_to_ref(self, path):
+        try:
+            path = os.path.relpath(path, self._base_folder)
+            path = path.replace("\\", "/")  # Uniform for Windows and Linux
+        except ValueError:
+            raise ConanException(f"Invalid path: {path}")
+        return self._db.path_to_ref(path)
diff --git a/conan/internal/cache/db/cache_database.py b/conan/internal/cache/db/cache_database.py
index 7baac7d2f..e18468950 100644
--- a/conan/internal/cache/db/cache_database.py
+++ b/conan/internal/cache/db/cache_database.py
@@ -99,3 +99,9 @@ class CacheDatabase:
     def get_package_references(self, ref: RecipeReference, only_latest_prev=True):
         return [d["pref"]
                 for d in self._packages.get_package_references(ref, only_latest_prev)]
+
+    def path_to_ref(self, path):
+        ref = self._recipes.path_to_ref(path)
+        if ref is not None:
+            return ref
+        return self._packages.path_to_ref(path)
diff --git a/conan/internal/cache/db/packages_table.py b/conan/internal/cache/db/packages_table.py
index 4b583e418..5523c65bc 100644
--- a/conan/internal/cache/db/packages_table.py
+++ b/conan/internal/cache/db/packages_table.py
@@ -240,3 +240,16 @@ class PackagesDBTable(BaseDbTable):
             if row:
                 return self._as_dict(self.row_type(*row))
             return None
+
+    def path_to_ref(self, path):
+        query = f'SELECT * FROM {self.table_name} ' \
+                f"WHERE {self.columns.path}='{path}'"
+        with self.db_connection() as conn:
+            r = conn.execute(query)
+            row = r.fetchone()
+            if not row:
+                return None
+            ref = RecipeReference.loads(row[0])
+            ref.revision = row[1]
+            pref = PkgReference(ref, row[2], row[3], row[5])
+            return pref
diff --git a/conan/internal/cache/db/recipes_table.py b/conan/internal/cache/db/recipes_table.py
index 6ceb662c4..c9030c960 100644
--- a/conan/internal/cache/db/recipes_table.py
+++ b/conan/internal/cache/db/recipes_table.py
@@ -127,3 +127,16 @@ class RecipesDBTable(BaseDbTable):
             r = conn.execute(query)
             ret = [self._as_dict(self.row_type(*row))["ref"] for row in r.fetchall()]
         return ret
+
+    def path_to_ref(self, path):
+        query = f'SELECT * FROM {self.table_name} ' \
+                f"WHERE {self.columns.path}='{path}'"
+        with self.db_connection() as conn:
+            r = conn.execute(query)
+            row = r.fetchone()
+            if not row:
+                return None
+            ref = RecipeReference.loads(row[0])
+            ref.revision = row[1]
+            ref.timestamp = row[3]
+            return ref
diff --git a/conan/internal/cache/integrity_check.py b/conan/internal/cache/integrity_check.py
index b1148e612..43b526d11 100644
--- a/conan/internal/cache/integrity_check.py
+++ b/conan/internal/cache/integrity_check.py
@@ -31,11 +31,11 @@ class IntegrityChecker:
 
     def _recipe_corrupted(self, ref: RecipeReference):
         layout = self._cache.recipe_layout(ref)
-        output = ConanOutput()
+        output = ConanOutput(scope=f"{ref.repr_notime()}")
         try:
             read_manifest, expected_manifest = layout.recipe_manifests()
         except FileNotFoundError:
-            output.error(f"{ref.repr_notime()}: Manifest missing", error_type="exception")
+            output.error("Manifest missing", error_type="exception")
             return True
         # Filter exports_sources from read manifest if there are no exports_sources locally
         # This happens when recipe is downloaded without sources (not built from source)
@@ -45,28 +45,28 @@ class IntegrityChecker:
                                        if not k.startswith("export_source")}
 
         if read_manifest != expected_manifest:
-            output.error(f"{ref}: Manifest mismatch", error_type="exception")
-            output.error(f"Folder: {layout.export()}", error_type="exception")
+            output_lines = ["", "Manifest mismatch", f"    Folder: {layout.package()}"]
             diff = read_manifest.difference(expected_manifest)
             for fname, (h1, h2) in diff.items():
-                output.error(f"    '{fname}' (manifest: {h1}, file: {h2})", error_type="exception")
+                output_lines.append(f"        {fname} (manifest: {h1}, file: {h2})")
+            output.error("\n".join(output_lines), error_type="exception")
             return True
-        output.info(f"{ref}: Integrity checked: ok")
+        output.info("Integrity check: ok")
 
     def _package_corrupted(self, ref: PkgReference):
         layout = self._cache.pkg_layout(ref)
-        output = ConanOutput()
+        output = ConanOutput(scope=f"{ref.repr_notime()}")
         try:
             read_manifest, expected_manifest = layout.package_manifests()
         except FileNotFoundError:
-            output.error(f"{ref.repr_notime()}: Manifest missing", error_type="exception")
+            output.error("Manifest missing", error_type="exception")
             return True
 
         if read_manifest != expected_manifest:
-            output.error(f"{ref}: Manifest mismatch", error_type="exception")
-            output.error(f"Folder: {layout.package()}", error_type="exception")
+            output_lines = ["", "Manifest mismatch", f"    Folder: {layout.package()}"]
             diff = read_manifest.difference(expected_manifest)
             for fname, (h1, h2) in diff.items():
-                output.error(f"    '{fname}' (manifest: {h1}, file: {h2})", error_type="exception")
+                output_lines.append(f"        {fname} (manifest: {h1}, file: {h2})")
+            output.error("\n".join(output_lines), error_type="exception")
             return True
-        output.info(f"{ref}: Integrity checked: ok")
+        output.info("Integrity check: ok")
diff --git a/conan/internal/graph/installer.py b/conan/internal/graph/installer.py
index fa09f90ba..a2b6d0773 100644
--- a/conan/internal/graph/installer.py
+++ b/conan/internal/graph/installer.py
@@ -457,6 +457,10 @@ class BinaryInstaller:
                 self._hook_manager.execute("post_package_info", conanfile=conanfile)
 
         conanfile.cpp_info.check_component_requires(conanfile)
+        try:
+            conanfile.conf_info.validate()
+        except ConanException as e:
+            raise ConanException(f"{conanfile}: Error in package_info() method:\n\t{str(e)}")
 
     @staticmethod
     def _call_finalize_method(conanfile, finalize_folder):
diff --git a/conan/internal/model/conf.py b/conan/internal/model/conf.py
index 8b5410bf8..0d7fd97da 100644
--- a/conan/internal/model/conf.py
+++ b/conan/internal/model/conf.py
@@ -150,8 +150,7 @@ USER_CONF_PATTERN = re.compile(r"^(user\..+|user):.*")
 
 def _is_profile_module(module_name):
     # These are the modules that are propagated to profiles and user recipes
-    _profiles_modules_patterns = USER_CONF_PATTERN, TOOLS_CONF_PATTERN
-    return any(pattern.match(module_name) for pattern in _profiles_modules_patterns)
+    return TOOLS_CONF_PATTERN.match(module_name) or USER_CONF_PATTERN.match(module_name)
 
 
 # FIXME: Refactor all the next classes because they are mostly the same as
@@ -542,10 +541,12 @@ class Conf:
 
     @staticmethod
     def _check_conf_name(conf):
-        if USER_CONF_PATTERN.match(conf) is None and conf not in BUILT_IN_CONFS:
-            raise ConanException(f"[conf] Either '{conf}' does not exist in configuration list or "
-                                 f"the conf format introduced is not valid. Run 'conan config list' "
-                                 f"to see all the available confs.")
+        if conf.startswith("user"):
+            if USER_CONF_PATTERN.match(conf) is None:
+                raise ConanException(f"User conf '{conf}' invalid format, not 'user.org.group:conf'")
+        elif conf not in BUILT_IN_CONFS:
+            raise ConanException(f"[conf] '{conf}' does not exist in configuration list. "
+                                 "Run 'conan config list' to see all the available confs.")
 
 
 class ConfDefinition:
diff --git a/conan/internal/model/cpp_info.py b/conan/internal/model/cpp_info.py
index bf60b1b24..3d6fab03f 100644
--- a/conan/internal/model/cpp_info.py
+++ b/conan/internal/model/cpp_info.py
@@ -836,7 +836,7 @@ class CppInfo:
                 if r not in ret:
                     ret.append(r)
         # Then split the names
-        ret = [r.split("::") if "::" in r else (None, r) for r in ret]
+        ret = [r.split("::", 1) if "::" in r else (None, r) for r in ret]
         return ret
 
     def deduce_full_cpp_info(self, conanfile):
diff --git a/conan/tools/build/cppstd.py b/conan/tools/build/cppstd.py
index b7c182276..5832c214f 100644
--- a/conan/tools/build/cppstd.py
+++ b/conan/tools/build/cppstd.py
@@ -266,8 +266,11 @@ def _qcc_supported_cppstd(version):
 
     if version < "5":
         return ["98", "gnu98"]
-    else:
+    elif version < "12":
         return ["98", "gnu98", "11", "gnu11", "14", "gnu14", "17", "gnu17"]
+    else:
+        return ["98", "gnu98", "11", "gnu11", "14", "gnu14", "17", "gnu17", "20", "gnu20"]
+
 
 def _emcc_supported_cppstd(version):
     """
diff --git a/conan/tools/cmake/cmakedeps/templates/macros.py b/conan/tools/cmake/cmakedeps/templates/macros.py
index db804b8de..cccf8083f 100644
--- a/conan/tools/cmake/cmakedeps/templates/macros.py
+++ b/conan/tools/cmake/cmakedeps/templates/macros.py
@@ -41,14 +41,29 @@ class MacrosTemplate(CMakeDepsFileTemplate):
            endif()
        endmacro()
 
-
        function(conan_package_library_targets libraries package_libdir package_bindir library_type
                 is_host_windows deps_target out_libraries_target config_suffix package_name no_soname_mode)
            set(_out_libraries_target "")
 
            foreach(_LIBRARY_NAME ${libraries})
+               if(CMAKE_SYSTEM_NAME MATCHES "Windows" AND NOT DEFINED MINGW AND CMAKE_VERSION VERSION_LESS "3.29")
+                   # Backport logic from https://github.com/Kitware/CMake/commit/c6efbd78d86798573654d1a791f76de0e71bd93f
+                   # which is only needed on versions older than 3.29
+                   # this allows finding static library files created by meson
+                   # We are not affected by PATH-derived folders, because we call find_library with NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH
+                   set(_original_find_library_suffixes "${CMAKE_FIND_LIBRARY_SUFFIXES}")
+                   set(_original_find_library_prefixes "${CMAKE_FIND_LIBRARY_PREFIXES}")
+                   set(CMAKE_FIND_LIBRARY_PREFIXES "" "lib")
+                   set(CMAKE_FIND_LIBRARY_SUFFIXES ".dll.lib" ".lib" ".a")
+               endif()
                find_library(CONAN_FOUND_LIBRARY NAMES ${_LIBRARY_NAME} PATHS ${package_libdir}
-                            NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
+                           NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
+               if(DEFINED _original_find_library_suffixes)
+                   set(CMAKE_FIND_LIBRARY_SUFFIXES "${_original_find_library_suffixes}")
+                   set(CMAKE_FIND_LIBRARY_PREFIXES "${_original_find_library_prefixes}")
+                   unset(_original_find_library_suffixes)
+                   unset(_original_find_library_prefixes)
+               endif()
                if(CONAN_FOUND_LIBRARY)
                    message(VERBOSE "Conan: Library ${_LIBRARY_NAME} found ${CONAN_FOUND_LIBRARY}")
 


Test patch:
diff --git a/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps.py b/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps.py
index f3b953720..081687731 100644
--- a/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps.py
+++ b/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps.py
@@ -1,5 +1,6 @@
 import os
 import platform
+import shutil
 import textwrap
 
 import pytest
@@ -7,7 +8,9 @@ import pytest
 from conan.test.assets.cmake import gen_cmakelists
 from conan.test.assets.genconanfile import GenConanfile
 from conan.test.assets.sources import gen_function_cpp, gen_function_h
+from conan.test.utils.mocks import ConanFileMock
 from conan.test.utils.tools import TestClient, NO_SETTINGS_PACKAGE_ID
+from conan.tools.files import replace_in_file
 
 
 @pytest.fixture
@@ -728,3 +731,79 @@ def test_quiet():
     client.run_command('cmake . -DCMAKE_BUILD_TYPE=Release')
     # Because we used QUIET, not in output
     assert "Target declared 'test::test'" not in client.out
+
+
+@pytest.mark.skipif(platform.system() != "Windows", reason="Only Windows and MSVC")
+@pytest.mark.tool("meson")
+@pytest.mark.tool("ninja")
+@pytest.mark.tool("cmake", "3.23")
+def test_meson_and_cmakedeps_and_static_builds():
+    """
+    Testing when library is built with Meson + MSVC as a static library (lib + name + .a)
+    and consumed using CMakeDeps (and CMakeConfigDeps) or PkgConfigDeps.
+
+    Issues related:
+        - https://github.com/conan-io/conan/issues/11866
+        - https://github.com/mesonbuild/meson/issues/7378
+    """
+    client = TestClient()
+    profile = textwrap.dedent("""
+    [settings]
+    os=Windows
+    arch=x86_64
+    compiler=msvc
+    compiler.version=191
+    compiler.runtime=dynamic
+    build_type=Release
+    """)
+    client.run("new meson_lib -d name=hello -d version=1.0")
+    cmakelists = textwrap.dedent("""
+    cmake_minimum_required(VERSION 3.15)
+    project(PackageTest CXX)
+
+    find_package(hello CONFIG REQUIRED)
+
+    add_executable(example src/example.cpp)
+    target_link_libraries(example hello::hello)
+    """)
+    cmake_conanfile = textwrap.dedent("""
+    import os
+    from conan import ConanFile
+    from conan.tools.cmake import CMake, cmake_layout
+    from conan.tools.build import can_run
+    class pkgTestConan(ConanFile):
+        settings = "os", "compiler", "build_type", "arch"
+        generators = "CMakeDeps", "CMakeToolchain"
+
+        def requirements(self):
+            self.requires(self.tested_reference_str)
+
+        def build(self):
+            cmake = CMake(self)
+            cmake.configure()
+            cmake.build()
+
+        def layout(self):
+            cmake_layout(self)
+
+        def test(self):
+            if can_run(self):
+                cmd = os.path.join(self.cpp.build.bindir, "example")
+                self.run(cmd, env="conanrun")
+        """)
+    client.save({
+        "win": profile,
+        "test_package_cmake/conanfile.py": cmake_conanfile,
+        "test_package_cmake/CMakeLists.txt": cmakelists
+    })
+    shutil.copytree(os.path.join(client.current_folder, "test_package", "src"),
+                    os.path.join(client.current_folder, "test_package_cmake", "src"))
+    client.run("create . -pr:a win")  # meson + pkgconfigdeps (test_package) runs OK
+    client.run("test --profile:all=win test_package_cmake hello/1.0")  # meson + CMakeDeps (test_package_cmake) runs OK
+    # Now, let's use the CMakeConfigDeps to demonstrate that it works with/without changing
+    replace_in_file(ConanFileMock(),
+                    os.path.join(client.current_folder, "test_package_cmake", "conanfile.py"),
+                    '"CMakeDeps"',
+                    '"CMakeConfigDeps"')
+    client.run("test --profile:all=win test_package_cmake hello/1.0 "
+               "-c tools.cmake.cmakedeps:new=will_break_next") # meson + CMakeConfigDeps (test_package_cmake) runs OK
diff --git a/test/integration/command/cache/test_cache_integrity.py b/test/integration/command/cache/test_cache_integrity.py
index cbbf69a61..b40a2f9a6 100644
--- a/test/integration/command/cache/test_cache_integrity.py
+++ b/test/integration/command/cache/test_cache_integrity.py
@@ -30,20 +30,24 @@ def test_cache_integrity(use_pkglist):
     arg = "--list=pkglist.json" if use_pkglist else "*"
 
     t.run(f"cache check-integrity {arg}", assert_error=True)
-    assert "pkg1/1.0: Integrity checked: ok" in t.out
-    assert "pkg1/1.0:da39a3ee5e6b4b0d3255bfef95601890afd80709: Integrity checked: ok" in t.out
-    assert "ERROR: pkg2/2.0:da39a3ee5e6b4b0d3255bfef95601890afd80709: Manifest mismatch" in t.out
-    assert "ERROR: pkg3/3.0:da39a3ee5e6b4b0d3255bfef95601890afd80709: Manifest mismatch" in t.out
-    assert "ERROR: pkg4/4.0:da39a3ee5e6b4b0d3255bfef95601890afd80709: Manifest mismatch" in t.out
+    assert "pkg1/1.0#4d670581ccb765839f2239cc8dff8fbd: Integrity check: ok" in t.out
+    assert "pkg1/1.0#4d670581ccb765839f2239cc8dff8fbd:da39a3ee5e6b4b0d3255bfef95601890afd80709" \
+           "#0ba8627bd47edc3a501e8f0eb9a79e5e: Integrity check: ok" in t.out
+    assert "pkg2/2.0#4d670581ccb765839f2239cc8dff8fbd:da39a3ee5e6b4b0d3255bfef95601890afd80709" \
+           "#0ba8627bd47edc3a501e8f0eb9a79e5e: ERROR: \nManifest mismatch" in t.out
+    assert "pkg3/3.0#4d670581ccb765839f2239cc8dff8fbd:da39a3ee5e6b4b0d3255bfef95601890afd80709" \
+           "#0ba8627bd47edc3a501e8f0eb9a79e5e: ERROR: \nManifest mismatch" in t.out
+    assert "pkg4/4.0#4d670581ccb765839f2239cc8dff8fbd:da39a3ee5e6b4b0d3255bfef95601890afd80709" \
+           "#0ba8627bd47edc3a501e8f0eb9a79e5e: ERROR: \nManifest mismatch" in t.out
 
     t.run("remove pkg2/2.0:da39a3ee5e6b4b0d3255bfef95601890afd80709 -c")
     t.run("remove pkg3/3.0:da39a3ee5e6b4b0d3255bfef95601890afd80709 -c")
     t.run("remove pkg4/4.0:da39a3ee5e6b4b0d3255bfef95601890afd80709 -c")
     t.run("cache check-integrity *")
-    assert "pkg1/1.0: Integrity checked: ok" in t.out
-    assert "pkg2/2.0: Integrity checked: ok" in t.out
-    assert "pkg3/3.0: Integrity checked: ok" in t.out
-    assert "pkg4/4.0: Integrity checked: ok" in t.out
+    assert "pkg1/1.0#4d670581ccb765839f2239cc8dff8fbd: Integrity check: ok" in t.out
+    assert "pkg2/2.0#4d670581ccb765839f2239cc8dff8fbd: Integrity check: ok" in t.out
+    assert "pkg3/3.0#4d670581ccb765839f2239cc8dff8fbd: Integrity check: ok" in t.out
+    assert "pkg4/4.0#4d670581ccb765839f2239cc8dff8fbd: Integrity check: ok" in t.out
 
 
 def test_cache_integrity_missing_recipe_manifest():
@@ -57,15 +61,16 @@ def test_cache_integrity_missing_recipe_manifest():
     t.run("create . --name pkg3 --version=3.0")
 
     t.run("cache check-integrity *", assert_error=True)
-    assert "pkg1/1.0: Integrity checked: ok" in t.out
-    assert "ERROR: pkg2/2.0#4d670581ccb765839f2239cc8dff8fbd: Manifest missing" in t.out
-    assert "pkg3/3.0: Integrity checked: ok" in t.out
+    assert "pkg1/1.0#4d670581ccb765839f2239cc8dff8fbd: Integrity check: ok" in t.out
+    assert "pkg2/2.0#4d670581ccb765839f2239cc8dff8fbd: ERROR: Manifest missing" in t.out
+    assert "pkg3/3.0#4d670581ccb765839f2239cc8dff8fbd: Integrity check: ok" in t.out
     assert "ERROR: There are corrupted artifacts, check the error logs" in t.out
 
     t.run("remove pkg2* -c")
     t.run("cache check-integrity *")
-    assert "pkg1/1.0:da39a3ee5e6b4b0d3255bfef95601890afd80709: Integrity checked: ok" in t.out
-    assert "pkg3/3.0: Integrity checked: ok" in t.out
+    assert "pkg1/1.0#4d670581ccb765839f2239cc8dff8fbd:da39a3ee5e6b4b0d3255bfef95601890afd80709" \
+           "#0ba8627bd47edc3a501e8f0eb9a79e5e: Integrity check: ok" in t.out
+    assert "pkg3/3.0#4d670581ccb765839f2239cc8dff8fbd: Integrity check: ok" in t.out
     assert "Integrity check: ok" in t.out
 
 
@@ -80,17 +85,17 @@ def test_cache_integrity_missing_package_manifest():
     t.run("create . --name pkg3 --version=3.0")
 
     t.run("cache check-integrity *", assert_error=True)
-    assert "pkg1/1.0: Integrity checked: ok" in t.out
-    assert "ERROR: pkg2/2.0#4d670581ccb765839f2239cc8dff8fbd" \
-           ":da39a3ee5e6b4b0d3255bfef95601890afd80709" \
-           "#0ba8627bd47edc3a501e8f0eb9a79e5e: Manifest missing" in t.out
-    assert "pkg3/3.0: Integrity checked: ok" in t.out
+    assert "pkg1/1.0#4d670581ccb765839f2239cc8dff8fbd: Integrity check: ok" in t.out
+    assert "pkg2/2.0#4d670581ccb765839f2239cc8dff8fbd:da39a3ee5e6b4b0d3255bfef95601890afd80709" \
+           "#0ba8627bd47edc3a501e8f0eb9a79e5e: ERROR: Manifest missing" in t.out
+    assert "pkg3/3.0#4d670581ccb765839f2239cc8dff8fbd: Integrity check: ok" in t.out
     assert "ERROR: There are corrupted artifacts, check the error logs" in t.out
 
     t.run("remove pkg2* -c")
     t.run("cache check-integrity *")
-    assert "pkg1/1.0:da39a3ee5e6b4b0d3255bfef95601890afd80709: Integrity checked: ok" in t.out
-    assert "pkg3/3.0: Integrity checked: ok" in t.out
+    assert "pkg1/1.0#4d670581ccb765839f2239cc8dff8fbd:da39a3ee5e6b4b0d3255bfef95601890afd80709" \
+           "#0ba8627bd47edc3a501e8f0eb9a79e5e: Integrity check: ok" in t.out
+    assert "pkg3/3.0#4d670581ccb765839f2239cc8dff8fbd: Integrity check: ok" in t.out
     assert "Integrity check: ok" in t.out
 
 
@@ -104,12 +109,26 @@ def test_cache_integrity_missing_package_conaninfo():
     os.remove(conaninfo)
 
     t.run("cache check-integrity *", assert_error=True)
-    assert "pkg1/1.0: Integrity checked: ok" in t.out
-    assert "ERROR: pkg2/2.0:da39a3ee5e6b4b0d3255bfef95601890afd80709: Manifest mismatch" in t.out
+    assert "pkg1/1.0#4d670581ccb765839f2239cc8dff8fbd: Integrity check: ok" in t.out
+    assert "pkg2/2.0#4d670581ccb765839f2239cc8dff8fbd:da39a3ee5e6b4b0d3255bfef95601890afd80709" \
+           "#0ba8627bd47edc3a501e8f0eb9a79e5e: ERROR: \nManifest mismatch" in t.out
 
     t.run("remove pkg2* -c")
     t.run("cache check-integrity *")
-    assert "pkg1/1.0:da39a3ee5e6b4b0d3255bfef95601890afd80709: Integrity checked: ok" in t.out
+    assert "pkg1/1.0#4d670581ccb765839f2239cc8dff8fbd:da39a3ee5e6b4b0d3255bfef95601890afd80709" \
+           "#0ba8627bd47edc3a501e8f0eb9a79e5e: Integrity check: ok" in t.out
+
+
+def test_cache_integrity_missing_package_file():
+    t = TestClient()
+    t.save({"conanfile.py": GenConanfile().with_package_file("myfile", "mycontents!")})
+    t.run("create . --name pkg --version 1.0")
+    layout = t.created_layout()
+    os.remove(os.path.join(layout.package(), "myfile"))
+
+    t.run("cache check-integrity *", assert_error=True)
+    assert "pkg/1.0#2f2609c8e5c87bf836c3fdaa6096b55d:da39a3ee5e6b4b0d3255bfef95601890afd80709" \
+           "#d950d0cd76f6bba62c8add9c68d1aeb3: ERROR: \nManifest mismatch" in t.out
 
 
 def test_cache_integrity_export_sources():
@@ -119,7 +138,7 @@ def test_cache_integrity_export_sources():
             "src/mysource.cpp": ""})
     t.run("create .")
     t.run("cache check-integrity *")
-    assert "pkg/0.1: Integrity checked: ok" in t.out
+    assert "pkg/0.1#ae07161b81ab07f7f1f746391668df0e: Integrity check: ok" in t.out
 
     # If we download, integrity should be ok
     # (it failed before, because the manifest is not complete)
@@ -127,4 +146,4 @@ def test_cache_integrity_export_sources():
     t.run("remove * -c")
     t.run("install --requires=pkg/0.1")
     t.run("cache check-integrity *")
-    assert "pkg/0.1: Integrity checked: ok" in t.out
+    assert "pkg/0.1#ae07161b81ab07f7f1f746391668df0e: Integrity check: ok" in t.out
diff --git a/test/integration/command/cache/test_cache_path.py b/test/integration/command/cache/test_cache_path.py
index d95c145b4..f7f529496 100644
--- a/test/integration/command/cache/test_cache_path.py
+++ b/test/integration/command/cache/test_cache_path.py
@@ -1,15 +1,17 @@
 import json
 import os
+import platform
 
 import pytest
 
+from conan.api.model import RecipeReference, PkgReference
 from conan.test.assets.genconanfile import GenConanfile
 from conan.test.utils.tools import TestClient
 
 
 @pytest.fixture(scope="module")
 def created_package():
-    t = TestClient()
+    t = TestClient(light=True)
     t.save({"conanfile.py": GenConanfile()})
     t.run("create . --name foo --version 1.0")
     recipe_layout = t.exported_layout()
@@ -115,6 +117,7 @@ def test_cache_path_does_not_exist_folder():
     client.run(f"cache path {pref} --folder build", assert_error=True)
     assert f"ERROR: 'build' folder does not exist for the reference {pref}" in client.out
 
+
 def test_cache_path_output_json():
     client = TestClient()
     conanfile = GenConanfile("mypkg", "0.1")
@@ -124,3 +127,60 @@ def test_cache_path_output_json():
     client.run("cache path mypkg/0.1 --format=json")
     output = json.loads(client.stdout)
     assert output == {"cache_path": os.path.join(layout.base_folder, "e")}
+
+
+class TestCacheRef:
+
+    def test_cache_path(self, created_package):
+        t, recipe_layout, pkg_layout = created_package
+
+        t.run(f'cache ref "{os.path.dirname(recipe_layout.export())}"')
+        assert f"foo/1.0#{recipe_layout.reference.revision}" in t.out
+
+        t.run(f'cache ref "{recipe_layout.export()}"')
+        assert f"foo/1.0#{recipe_layout.reference.revision}" in t.out
+
+        t.run(f'cache ref "{recipe_layout.source()}"')
+        assert f"foo/1.0#{recipe_layout.reference.revision}" in t.out
+
+        t.run(f'cache ref "{os.path.dirname(pkg_layout.package())}"')
+        assert f"foo/1.0#{recipe_layout.reference.revision}" in t.out
+
+        t.run(f'cache ref "{pkg_layout.build()}"')
+        assert f"foo/1.0#{recipe_layout.reference.revision}" in t.out
+
+        t.run(f'cache ref "{pkg_layout.package()}"')
+        assert f"foo/1.0#{recipe_layout.reference.revision}" in t.out
+
+    def test_downloaded_paths(self):
+        t = TestClient(light=True, default_server_user=True)
+        t.save({"conanfile.py": GenConanfile()})
+        t.run("create . --name foo --version 1.0")
+        t.run("upload * -c -r=default")
+        t.run("remove * -c")
+        t.run("install --requires=foo/1.0")
+        ref = RecipeReference.loads("foo/1.0#4d670581ccb765839f2239cc8dff8fbd")
+        pref = PkgReference(ref, "da39a3ee5e6b4b0d3255bfef95601890afd80709")
+        recipe_layout = t.get_latest_ref_layout(ref)
+        pkg_layout = t.get_latest_pkg_layout(pref)
+
+        t.run(f'cache ref "{os.path.dirname(recipe_layout.export())}"')
+        assert f"foo/1.0#{recipe_layout.reference.revision}" in t.out
+
+        t.run(f'cache ref "{recipe_layout.export()}"')
+        assert f"foo/1.0#{recipe_layout.reference.revision}" in t.out
+
+        t.run(f'cache ref "{os.path.dirname(pkg_layout.package())}"')
+        assert f"foo/1.0#{recipe_layout.reference.revision}" in t.out
+
+        t.run(f'cache ref "{pkg_layout.package()}"')
+        assert f"foo/1.0#{recipe_layout.reference.revision}" in t.out
+
+    def test_errors(self):
+        t = TestClient(light=True)
+        t.run('cache ref "/some/non/existing/path"', assert_error=True)
+        assert "ERROR: Reference for this path not found in cache" in t.out
+
+        if platform.system() == "Windows":
+            t.run("cache ref J:/not/path", assert_error=True)
+            assert "ERROR: Invalid path: J:/not/path" in t.out
diff --git a/test/integration/command/upload/upload_test.py b/test/integration/command/upload/upload_test.py
index 45e64ebe3..e8f6adcb0 100644
--- a/test/integration/command/upload/upload_test.py
+++ b/test/integration/command/upload/upload_test.py
@@ -177,8 +177,13 @@ class UploadTest(unittest.TestCase):
         save(os.path.join(package_folder, "added.txt"), "")
         os.remove(os.path.join(package_folder, "include/hello.h"))
         client.run("upload hello0/1.2.1@frodo/stable --check -r default", assert_error=True)
-        self.assertIn("ERROR:     'include/hello.h'", client.out)
-        self.assertIn("ERROR:     'added.txt'", client.out)
+        self.assertIn("hello0/1.2.1@frodo/stable#3afd661184b94bdac7fb2057e7bd9baa"
+                      ":da39a3ee5e6b4b0d3255bfef95601890afd80709"
+                      "#e70e86439dec07a0d5d3414648b0b16c: ERROR", client.out)
+        self.assertIn("include/hello.h (manifest: d41d8cd98f00b204e9800998ecf8427e, file: None)",
+                      client.out)
+        self.assertIn("added.txt (manifest: None, file: d41d8cd98f00b204e9800998ecf8427e)",
+                      client.out)
         self.assertIn("ERROR: There are corrupted artifacts, check the error logs", client.out)
 
     @pytest.mark.artifactory_ready
diff --git a/test/integration/conanfile/test_finalize_method.py b/test/integration/conanfile/test_finalize_method.py
index fe3f0363f..c18d79b34 100644
--- a/test/integration/conanfile/test_finalize_method.py
+++ b/test/integration/conanfile/test_finalize_method.py
@@ -364,5 +364,6 @@ class TestRemoteFlows:
         client.run("create dep")
         dep_layout = client.created_layout()
         client.run("upload * -r=default -c --check")
-        assert f"dep/1.0:{dep_layout.reference.package_id}: Integrity checked: ok" in client.out
+        assert f"dep/1.0#{dep_layout.reference.ref.revision}:{dep_layout.reference.package_id}" \
+               f"#{dep_layout.reference.revision}: Integrity check: ok" in client.out
         assert "There are corrupted artifacts" not in client.out
diff --git a/test/integration/configuration/conf/test_conf.py b/test/integration/configuration/conf/test_conf.py
index 213438661..35b3be231 100644
--- a/test/integration/configuration/conf/test_conf.py
+++ b/test/integration/configuration/conf/test_conf.py
@@ -150,7 +150,7 @@ def test_new_config_file(client):
             """)
     save(client.paths.new_config_path, conf)
     client.run("install .", assert_error=True)
-    assert "[conf] Either 'cache:read_only' does not exist in configuration list" in client.out
+    assert "[conf] 'cache:read_only' does not exist in configuration list" in client.out
 
 
 @patch("conan.__version__", "1.26.0")
@@ -307,10 +307,12 @@ def test_nonexisting_conf():
     c = TestClient()
     c.save({"conanfile.txt": ""})
     c.run("install . -c tools.unknown:conf=value", assert_error=True)
-    assert "ERROR: [conf] Either 'tools.unknown:conf' does not exist in configuration" in c.out
+    assert "ERROR: [conf] 'tools.unknown:conf' does not exist in configuration" in c.out
     c.run("install . -c user.some:var=value")  # This doesn't fail
+    c.run("install . -c user.some.var=value", assert_error=True)
+    assert "ERROR: User conf 'user.some.var' invalid format, not 'user.org.group:conf'" in c.out
     c.run("install . -c tool.build:verbosity=v", assert_error=True)
-    assert "ERROR: [conf] Either 'tool.build:verbosity' does not exist in configuration" in c.out
+    assert "ERROR: [conf] 'tool.build:verbosity' does not exist in configuration" in c.out
 
 
 def test_nonexisting_conf_global_conf():
@@ -318,7 +320,7 @@ def test_nonexisting_conf_global_conf():
     save(c.paths.new_config_path, "tools.unknown:conf=value")
     c.save({"conanfile.txt": ""})
     c.run("install . ", assert_error=True)
-    assert "ERROR: [conf] Either 'tools.unknown:conf' does not exist in configuration" in c.out
+    assert "ERROR: [conf] 'tools.unknown:conf' does not exist in configuration" in c.out
 
 
 def test_global_conf_auto_created():
diff --git a/test/integration/configuration/conf/test_conf_from_br.py b/test/integration/configuration/conf/test_conf_from_br.py
index a0d067526..42394c9ea 100644
--- a/test/integration/configuration/conf/test_conf_from_br.py
+++ b/test/integration/configuration/conf/test_conf_from_br.py
@@ -293,3 +293,35 @@ def test_error_bad_types(conf):
     assert f'self.conf_info.{conf}' in c.out
     assert "Invalid 'conf' type, please use Python types (int, str, ...)" in c.out
 
+
+@pytest.mark.parametrize("conf", ["tools.myorg.myconf", "user.myorg.myconf"])
+def test_error_missing_colon_define(conf):
+    c = TestClient(light=True)
+    conanfile = textwrap.dedent(f"""
+        from conan import ConanFile
+        class Pkg(ConanFile):
+            name = "tool"
+            version = "0.1"
+            def package_info(self):
+                self.conf_info.define("{conf}", 42)
+        """)
+    c.save({"conanfile.py": conanfile})
+    c.run("create .", assert_error=True)
+    assert "ERROR: tool/0.1: Error in package_info() method:" in c.out
+    if conf == "tools.myorg.myconf":
+        assert "[conf] 'tools.myorg.myconf' does not exist in configuration" in c.out
+    else:
+        assert f"User conf '{conf}' invalid format, not 'user.org.group:conf'" in c.out
+
+
+def test_error_missing_colon_consume():
+    c = TestClient(light=True)
+    conanfile = textwrap.dedent(f"""
+        from conan import ConanFile
+        class Pkg(ConanFile):
+            def generate(self):
+                self.conf.get("user.myorg.myconf")
+        """)
+    c.save({"conanfile.py": conanfile})
+    c.run("install .", assert_error=True)
+    assert "User conf 'user.myorg.myconf' invalid format, not 'user.org.group:conf'" in c.out
diff --git a/test/integration/test_components_error.py b/test/integration/test_components_error.py
index bc27f58a5..8d9250089 100644
--- a/test/integration/test_components_error.py
+++ b/test/integration/test_components_error.py
@@ -167,3 +167,26 @@ def test_unused_tool_requirement():
     t.run('create top.py --name=top2 --version=version')
     t.run('create consumer.py --name=wrong --version=version')
     # This runs without crashing, because it is not chcking that top::other doesn't exist
+
+
+def test_component_double_colon_error_message():
+    c = TestClient()
+    t2 = textwrap.dedent("""
+        from conan import ConanFile
+
+        class t2Conan(ConanFile):
+            name = "t2"
+            version = "0.1.0"
+            requires = "t1/0.1.0"
+            def package_info(self):
+                self.cpp_info.requires.append("t1::comp1::other")
+        """)
+
+    c.save({"t1/conanfile.py": GenConanfile("t1", "0.1.0"),
+            "t2/conanfile.py": t2,
+            "t2/test_package/conanfile.py": GenConanfile().with_settings("build_type")
+                                                          .with_generator("CMakeDeps")
+                                                          .with_test("pass")})
+    c.run("create t1")
+    c.run("create t2", assert_error=True)
+    assert "Component 't1::comp1::other' not found in 't1' package requirement" in c.out
diff --git a/test/unittests/model/test_conf.py b/test/unittests/model/test_conf.py
index a06707f6d..dc6364422 100644
--- a/test/unittests/model/test_conf.py
+++ b/test/unittests/model/test_conf.py
@@ -389,8 +389,8 @@ def test_conf_scope_patterns_ok(scope, conf):
 
 @pytest.mark.parametrize("conf", ["user.foo.bar=1"])
 @pytest.mark.parametrize("scope, assert_message", [
-    ("", "Either 'user.foo.bar' does not exist in configuration list"),
-    ("pkg/1.0:", "Either 'pkg/1.0:user.foo.bar' does not exist in configuration list"),
+    ("", "User conf 'user.foo.bar' invalid format, not 'user.org.group:conf'"),
+    ("pkg/1.0:", "'pkg/1.0:user.foo.bar' does not exist in configuration list"),
 ])
 def test_conf_scope_patterns_bad(scope, conf, assert_message):
     final_conf = scope + conf
diff --git a/test/unittests/tools/build/test_cppstd.py b/test/unittests/tools/build/test_cppstd.py
index 1997c72bb..e3c418af9 100644
--- a/test/unittests/tools/build/test_cppstd.py
+++ b/test/unittests/tools/build/test_cppstd.py
@@ -128,6 +128,7 @@ def test_supported_cppstd_mcst(compiler, compiler_version, values):
     ("qcc", "4.4", ['98', 'gnu98']),
     ("qcc", "5.4", ['98', 'gnu98', '11', 'gnu11', "14", "gnu14", "17", "gnu17"]),
     ("qcc", "8.3", ['98', 'gnu98', '11', 'gnu11', "14", "gnu14", "17", "gnu17"]),
+    ("qcc", "12.2", ['98', 'gnu98', '11', 'gnu11', "14", "gnu14", "17", "gnu17", "20", "gnu20"]),
 ])
 def test_supported_cppstd_qcc(compiler, compiler_version, values):
     settings = MockSettings({"compiler": compiler, "compiler.version": compiler_version})