Repository: conan-io/conan
Pull request #16231 (2024-05-09 12:29:23)

Add property to change the CMake variable names generated with CMakeDeps
Changelog: Feature: Add new variable to CMakeDeps generator to allow changing the name used in CMake variables
Docs: https://github.com/conan-io/docs/pull/3721

Created new property for CMakeDeps generator: `cmake_legacy_variable_prefix` that can be set in `package_info()` of the conanfile.
It allows changing the prefix used when creating CMake variables instead of the package name that was currently being used.

Closes: https://github.com/conan-io/conan/issues/14788

- [x] 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.

valgur: Just wanted to say thanks for adding this feature. The simple difference in capitalization of variable prefixes has been by far the most common reason for having to apply patches to public CMake projects on CCI. Also the most common reason for having to include custom CMake modules in the recipe. Two birds with one stone. Thanks!

Patch:
diff --git a/conan/tools/cmake/cmakedeps/templates/__init__.py b/conan/tools/cmake/cmakedeps/templates/__init__.py
index 64e90955b..f1cd8ba1b 100644
--- a/conan/tools/cmake/cmakedeps/templates/__init__.py
+++ b/conan/tools/cmake/cmakedeps/templates/__init__.py
@@ -24,6 +24,12 @@ class CMakeDepsFileTemplate(object):
     def file_name(self):
         return self.cmakedeps.get_cmake_package_name(self.conanfile, module_mode=self.generating_module) + self.suffix
 
+    @property
+    def additional_variables_prefixes(self):
+        prefix_list = (
+            self.cmakedeps.get_property("cmake_additional_variables_prefixes", self.conanfile) or [])
+        return list(set([self.file_name] + prefix_list))
+
     @property
     def suffix(self):
         if not self.require.build:
diff --git a/conan/tools/cmake/cmakedeps/templates/config.py b/conan/tools/cmake/cmakedeps/templates/config.py
index ea0184457..a4df8a399 100644
--- a/conan/tools/cmake/cmakedeps/templates/config.py
+++ b/conan/tools/cmake/cmakedeps/templates/config.py
@@ -28,7 +28,8 @@ class ConfigTemplate(CMakeDepsFileTemplate):
         targets_include += "{}Targets.cmake".format(self.file_name)
         return {"is_module": self.generating_module,
                 "version": self.conanfile.ref.version,
-                "file_name": self.file_name,
+                "file_name":  self.file_name,
+                "additional_variables_prefixes": self.additional_variables_prefixes,
                 "pkg_name": self.pkg_name,
                 "config_suffix": self.config_suffix,
                 "check_components_exist": self.cmakedeps.check_components_exist,
@@ -67,11 +68,14 @@ class ConfigTemplate(CMakeDepsFileTemplate):
             endif()
         endforeach()
 
-        set({{ file_name }}_VERSION_STRING "{{ version }}")
-        set({{ file_name }}_INCLUDE_DIRS {{ pkg_var(pkg_name, 'INCLUDE_DIRS', config_suffix) }} )
-        set({{ file_name }}_INCLUDE_DIR {{ pkg_var(pkg_name, 'INCLUDE_DIRS', config_suffix) }} )
-        set({{ file_name }}_LIBRARIES {{ pkg_var(pkg_name, 'LIBRARIES', config_suffix) }} )
-        set({{ file_name }}_DEFINITIONS {{ pkg_var(pkg_name, 'DEFINITIONS', config_suffix) }} )
+        {% for prefix in additional_variables_prefixes %}
+        set({{ prefix }}_VERSION_STRING "{{ version }}")
+        set({{ prefix }}_INCLUDE_DIRS {{ pkg_var(pkg_name, 'INCLUDE_DIRS', config_suffix) }} )
+        set({{ prefix }}_INCLUDE_DIR {{ pkg_var(pkg_name, 'INCLUDE_DIRS', config_suffix) }} )
+        set({{ prefix }}_LIBRARIES {{ pkg_var(pkg_name, 'LIBRARIES', config_suffix) }} )
+        set({{ prefix }}_DEFINITIONS {{ pkg_var(pkg_name, 'DEFINITIONS', config_suffix) }} )
+
+        {% endfor %}
 
         # Only the first installed configuration is included to avoid the collision
         foreach(_BUILD_MODULE {{ pkg_var(pkg_name, 'BUILD_MODULES_PATHS', config_suffix) }} )


Test patch:
diff --git a/conans/test/integration/toolchains/cmake/cmakedeps/test_cmakedeps.py b/conans/test/integration/toolchains/cmake/cmakedeps/test_cmakedeps.py
index f8a7eddf5..53dee8032 100644
--- a/conans/test/integration/toolchains/cmake/cmakedeps/test_cmakedeps.py
+++ b/conans/test/integration/toolchains/cmake/cmakedeps/test_cmakedeps.py
@@ -707,3 +707,38 @@ def test_cmakedeps_set_property_overrides():
     assert 'set(dep_NO_SONAME_MODE_RELEASE TRUE)' in dep
     other = c.load("app/other-release-data.cmake")
     assert 'set(other_other_mycomp1_NO_SONAME_MODE_RELEASE TRUE)' in other
+
+def test_cmakedeps_set_legacy_variable_name():
+    client = TestClient()
+    base_conanfile = str(GenConanfile("dep", "1.0"))
+    conanfile = base_conanfile + """
+    def package_info(self):
+        self.cpp_info.set_property("cmake_file_name", "CMakeFileName")
+    """
+    client.save({"dep/conanfile.py": conanfile})
+    client.run("create dep")
+    client.run("install --requires=dep/1.0 -g CMakeDeps")
+
+    # Check that all the CMake variables are generated with the file_name
+    dep_config = client.load("CMakeFileNameConfig.cmake")
+    cmake_variables = ["VERSION_STRING", "INCLUDE_DIRS", "INCLUDE_DIR", "LIBRARIES", "DEFINITIONS"]
+    for variable in cmake_variables:
+        assert f"CMakeFileName_{variable}" in dep_config
+
+    conanfile = base_conanfile + """
+    def package_info(self):
+        self.cpp_info.set_property("cmake_file_name", "NewCMakeFileName")
+        self.cpp_info.set_property("cmake_additional_variables_prefixes", ["PREFIX", "prefix", "PREFIX"])
+    """
+    client.save({"dep/conanfile.py": conanfile})
+    client.run("create dep")
+    client.run("install --requires=dep/1.0 -g CMakeDeps")
+
+    # Check that all the CMake variables are generated with the file_name and both prefixes
+    dep_config = client.load("NewCMakeFileNameConfig.cmake")
+    for variable in cmake_variables:
+        assert f"NewCMakeFileName_{variable}" in dep_config
+        assert f"PREFIX_{variable}" in dep_config
+        assert f"prefix_{variable}" in dep_config
+    # Check that variables are not duplicated
+    assert dep_config.count("PREFIX_VERSION") == 1