Repository: conan-io/conan

Issue:
[feature] cmake_find_package support Standard Variable Names
<!-- What is your suggestion? Please be as specific as possible! -->

`cmake_find_package` generator should set standard variable names as per https://cmake.org/cmake/help/v3.20/manual/cmake-developer.7.html#standard-variable-names:

- [ ] I've read the [CONTRIBUTING guide](https://github.com/conan-io/conan/blob/develop/.github/CONTRIBUTING.md).



Discussion:
Hi @SSE4 

yes, this makes sense, but as we are moving to ``CMakeDeps`` generator as the main one, does it make sense to invest this effort? If we are doing it, I would be extra careful not to break anything, not changing existing vars, only adding new ones.

Resolving patch:
diff --git a/conan/tools/cmake/cmakedeps.py b/conan/tools/cmake/cmakedeps.py
--- a/conan/tools/cmake/cmakedeps.py
+++ b/conan/tools/cmake/cmakedeps.py
@@ -83,10 +83,8 @@
    """)
 
 
-target_template = """
+variables_template = """
 set({name}_INCLUDE_DIRS{build_type_suffix} {deps.include_paths})
-set({name}_INCLUDE_DIR{build_type_suffix} {deps.include_path})
-set({name}_INCLUDES{build_type_suffix} {deps.include_paths})
 set({name}_RES_DIRS{build_type_suffix} {deps.res_paths})
 set({name}_DEFINITIONS{build_type_suffix} {deps.defines})
 set({name}_LINKER_FLAGS{build_type_suffix}_LIST
@@ -98,44 +96,31 @@
 set({name}_COMPILE_OPTIONS{build_type_suffix}_LIST "{deps.cxxflags_list}" "{deps.cflags_list}")
 set({name}_COMPILE_OPTIONS_C{build_type_suffix} "{deps.cflags_list}")
 set({name}_COMPILE_OPTIONS_CXX{build_type_suffix} "{deps.cxxflags_list}")
-set({name}_LIBRARIES_TARGETS{build_type_suffix} "") # Will be filled later, if CMake 3
-set({name}_LIBRARIES{build_type_suffix} "") # Will be filled later
-set({name}_LIBS{build_type_suffix} "") # Same as {name}_LIBRARIES
+set({name}_LIB_DIRS{build_type_suffix} {deps.lib_paths})
+set({name}_LIBS{build_type_suffix} {deps.libs})
 set({name}_SYSTEM_LIBS{build_type_suffix} {deps.system_libs})
 set({name}_FRAMEWORK_DIRS{build_type_suffix} {deps.framework_paths})
 set({name}_FRAMEWORKS{build_type_suffix} {deps.frameworks})
-set({name}_FRAMEWORKS_FOUND{build_type_suffix} "") # Will be filled later
 set({name}_BUILD_MODULES_PATHS{build_type_suffix} {deps.build_modules_paths})
+"""
 
-conan_find_apple_frameworks({name}_FRAMEWORKS_FOUND{build_type_suffix} "${{{name}_FRAMEWORKS{build_type_suffix}}}" "${{{name}_FRAMEWORK_DIRS{build_type_suffix}}}")
 
-mark_as_advanced({name}_INCLUDE_DIRS{build_type_suffix}
-                 {name}_INCLUDE_DIR{build_type_suffix}
-                 {name}_INCLUDES{build_type_suffix}
-                 {name}_DEFINITIONS{build_type_suffix}
-                 {name}_LINKER_FLAGS{build_type_suffix}_LIST
-                 {name}_COMPILE_DEFINITIONS{build_type_suffix}
-                 {name}_COMPILE_OPTIONS{build_type_suffix}_LIST
-                 {name}_LIBRARIES{build_type_suffix}
-                 {name}_LIBS{build_type_suffix}
-                 {name}_LIBRARIES_TARGETS{build_type_suffix})
-
-# Find the real .lib/.a and add them to {name}_LIBS and {name}_LIBRARY_LIST
-set({name}_LIBRARY_LIST{build_type_suffix} {deps.libs})
-set({name}_LIB_DIRS{build_type_suffix} {deps.lib_paths})
+dynamic_variables_template = """
+set({name}_FRAMEWORKS_FOUND{build_type_suffix} "") # Will be filled later
+conan_find_apple_frameworks({name}_FRAMEWORKS_FOUND{build_type_suffix} "${{{name}_FRAMEWORKS{build_type_suffix}}}" "${{{name}_FRAMEWORK_DIRS{build_type_suffix}}}")
 
 # Gather all the libraries that should be linked to the targets (do not touch existing variables):
 set(_{name}_DEPENDENCIES{build_type_suffix} "${{{name}_FRAMEWORKS_FOUND{build_type_suffix}}} ${{{name}_SYSTEM_LIBS{build_type_suffix}}} {deps_names}")
 
-conan_package_library_targets("${{{name}_LIBRARY_LIST{build_type_suffix}}}"  # libraries
-                              "${{{name}_LIB_DIRS{build_type_suffix}}}"      # package_libdir
+set({name}_LIBRARIES_TARGETS{build_type_suffix} "") # Will be filled later, if CMake 3
+set({name}_LIBRARIES{build_type_suffix} "") # Will be filled later
+conan_package_library_targets("${{{name}_LIBS{build_type_suffix}}}"           # libraries
+                              "${{{name}_LIB_DIRS{build_type_suffix}}}"       # package_libdir
                               "${{_{name}_DEPENDENCIES{build_type_suffix}}}"  # deps
-                              {name}_LIBRARIES{build_type_suffix}            # out_libraries
-                              {name}_LIBRARIES_TARGETS{build_type_suffix}    # out_libraries_targets
-                              "{build_type_suffix}"                          # build_type
-                              "{name}")                                      # package_name
-
-set({name}_LIBS{build_type_suffix} ${{{name}_LIBRARIES{build_type_suffix}}})
+                              {name}_LIBRARIES{build_type_suffix}             # out_libraries
+                              {name}_LIBRARIES_TARGETS{build_type_suffix}     # out_libraries_targets
+                              "{build_type_suffix}"                           # build_type
+                              "{name}")                                       # package_name
 
 foreach(_FRAMEWORK ${{{name}_FRAMEWORKS_FOUND{build_type_suffix}}})
     list(APPEND {name}_LIBRARIES_TARGETS{build_type_suffix} ${{_FRAMEWORK}})
@@ -289,8 +274,13 @@ class CMakeDeps(object):
 
         # Load the debug and release library finders
         get_filename_component(_DIR "${{CMAKE_CURRENT_LIST_FILE}}" PATH)
-        file(GLOB CONFIG_FILES "${{_DIR}}/{filename}Target-*.cmake")
+        file(GLOB DATA_FILES "${{_DIR}}/{filename}-*-*-data.cmake")
+
+        foreach(f ${{DATA_FILES}})
+            include(${{f}})
+        endforeach()
 
+        file(GLOB CONFIG_FILES "${{_DIR}}/{filename}Target-*.cmake")
         foreach(f ${{CONFIG_FILES}})
             include(${{f}})
         endforeach()
@@ -356,15 +346,11 @@ class CMakeDeps(object):
         endif()
         """)
 
-    components_target_build_type_tpl = Template(textwrap.dedent("""\
-        ########## MACROS ###########################################################################
-        #############################################################################################
-        include(${CMAKE_CURRENT_LIST_DIR}/cmakedeps_macros.cmake)
-
+    components_variables_tpl = Template(textwrap.dedent("""\
         ########### VARIABLES #######################################################################
         #############################################################################################
 
-        {{ global_target_variables }}
+        {{ global_variables }}
         set({{ pkg_name }}_COMPONENTS_{{ build_type }} {{ pkg_components }})
 
         {%- for comp_name, comp in components %}
@@ -372,8 +358,6 @@ class CMakeDeps(object):
         ########### COMPONENT {{ comp_name }} VARIABLES #############################################
 
         set({{ pkg_name }}_{{ comp_name }}_INCLUDE_DIRS_{{ build_type }} {{ comp.include_paths }})
-        set({{ pkg_name }}_{{ comp_name }}_INCLUDE_DIR_{{ build_type }} {{ comp.include_path }})
-        set({{ pkg_name }}_{{ comp_name }}_INCLUDES_{{ build_type }} {{ comp.include_paths }})
         set({{ pkg_name }}_{{ comp_name }}_LIB_DIRS_{{ build_type }} {{ comp.lib_paths }})
         set({{ pkg_name }}_{{ comp_name }}_RES_DIRS_{{ build_type }} {{ comp.res_paths }})
         set({{ pkg_name }}_{{ comp_name }}_DEFINITIONS_{{ build_type }} {{ comp.defines }})
@@ -391,6 +375,20 @@ class CMakeDeps(object):
                 $<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,MODULE_LIBRARY>:{{ comp.sharedlinkflags_list }}>
                 $<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,EXECUTABLE>:{{ comp.exelinkflags_list }}>
         )
+        {%- endfor %}
+    """))
+
+    components_dynamic_variables_tpl = Template(textwrap.dedent("""\
+        ########## MACROS ###########################################################################
+        #############################################################################################
+        include(${CMAKE_CURRENT_LIST_DIR}/cmakedeps_macros.cmake)
+
+        ########### VARIABLES #######################################################################
+        #############################################################################################
+
+        {{ global_dynamic_variables }}
+
+        {%- for comp_name, comp in components %}
 
         ########## COMPONENT {{ comp_name }} FIND LIBRARIES & FRAMEWORKS / DYNAMIC VARS #############
 
@@ -426,6 +424,14 @@ class CMakeDeps(object):
             add_library({{ pkg_name }}::{{ pkg_name }} INTERFACE IMPORTED)
         endif()
 
+        # Load the debug and release variables
+        get_filename_component(_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
+        file(GLOB DATA_FILES "${_DIR}/{{ pkg_filename }}-*-*-data.cmake")
+
+        foreach(f ${DATA_FILES})
+            include(${f})
+        endforeach()
+
         # Load the debug and release library finders
         get_filename_component(_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
         file(GLOB CONFIG_FILES "${_DIR}/{{ pkg_filename }}Target-*.cmake")
@@ -536,7 +542,7 @@ class CMakeDeps(object):
 
     def __init__(self, conanfile):
         self._conanfile = conanfile
-
+        self.arch = str(self._conanfile.settings.arch)
         self.configuration = str(self._conanfile.settings.build_type)
         self.configurations = [v for v in conanfile.settings.build_type.values_range if v != "None"]
         # FIXME: Ugly way to define the output path
@@ -663,6 +669,24 @@ def content(self):
             config_version = self.config_version_template.format(version=pkg_version)
             ret[self._config_version_filename(pkg_filename)] = config_version
             if not cpp_info.components:
+                # If any config matches the build_type one, add it to the cpp_info
+                dep_cpp_info = extend(cpp_info, build_type.lower())
+                deps = DepsCppCmake(dep_cpp_info, self.name)
+                variables = {
+                    "{name}-{build_type}-{arch}-data.cmake".format(name=pkg_filename,
+                                                                   build_type=self.configuration.lower(),
+                                                                   arch=self.arch):
+                    variables_template.format(name=pkg_findname, deps=deps,
+                                              build_type_suffix=build_type_suffix)
+                             }
+                dynamic_variables = {
+                    "{}Target-{}.cmake".format(pkg_filename, self.configuration.lower()):
+                    dynamic_variables_template.format(name=pkg_findname, deps=deps,
+                                                      build_type_suffix=build_type_suffix,
+                                                      deps_names=deps_names)
+                }
+                ret.update(variables)
+                ret.update(dynamic_variables)
                 ret[self._config_filename(pkg_filename)] = self._config(
                     filename=pkg_filename,
                     name=pkg_findname,
@@ -671,14 +695,6 @@ def content(self):
                 )
                 ret["{}Targets.cmake".format(pkg_filename)] = self.targets_template.format(
                     filename=pkg_filename, name=pkg_findname)
-
-                # If any config matches the build_type one, add it to the cpp_info
-                dep_cpp_info = extend(cpp_info, build_type.lower())
-                deps = DepsCppCmake(dep_cpp_info, self.name)
-                find_lib = target_template.format(name=pkg_findname, deps=deps,
-                                                  build_type_suffix=build_type_suffix,
-                                                  deps_names=deps_names)
-                ret["{}Target-{}.cmake".format(pkg_filename, self.configuration.lower())] = find_lib
             else:
                 cpp_info = extend(cpp_info, build_type.lower())
                 pkg_info = DepsCppCmake(cpp_info, self.name)
@@ -686,17 +702,27 @@ def content(self):
                 # Note these are in reversed order, from more dependent to less dependent
                 pkg_components = " ".join(["{p}::{c}".format(p=pkg_findname, c=comp_findname) for
                                            comp_findname, _ in reversed(components)])
-                global_target_variables = target_template.format(name=pkg_findname, deps=pkg_info,
-                                                                 build_type_suffix=build_type_suffix,
-                                                                 deps_names=deps_names)
-                variables = self.components_target_build_type_tpl.render(
-                    pkg_name=pkg_findname,
-                    global_target_variables=global_target_variables,
-                    pkg_components=pkg_components,
-                    build_type=build_type,
-                    components=components
-                )
-                ret["{}Target-{}.cmake".format(pkg_filename, build_type.lower())] = variables
+                global_variables = variables_template.format(name=pkg_findname, deps=pkg_info,
+                                                             build_type_suffix=build_type_suffix,
+                                                             deps_names=deps_names)
+                variables = {
+                    "{}-{}-{}-data.cmake".format(pkg_filename, build_type.lower(), self.arch):
+                    self.components_variables_tpl.render(
+                        pkg_name=pkg_findname, global_variables=global_variables,
+                        pkg_components=pkg_components, build_type=build_type, components=components)
+                }
+                ret.update(variables)
+                global_dynamic_variables = dynamic_variables_template.format(name=pkg_findname,
+                                                                             deps=pkg_info,
+                                                                             build_type_suffix=build_type_suffix,
+                                                                             deps_names=deps_names)
+                dynamic_variables = {
+                    "{}Target-{}.cmake".format(pkg_filename, build_type.lower()):
+                    self.components_dynamic_variables_tpl.render(
+                        pkg_name=pkg_findname, global_dynamic_variables=global_dynamic_variables,
+                        pkg_components=pkg_components, build_type=build_type, components=components)
+                }
+                ret.update(dynamic_variables)
                 targets = self.components_targets_tpl.render(
                     pkg_name=pkg_findname,
                     pkg_filename=pkg_filename,


Test patch:
diff --git a/conans/test/unittests/tools/cmake/test_cmakedeps.py b/conans/test/unittests/tools/cmake/test_cmakedeps.py
--- a/conans/test/unittests/tools/cmake/test_cmakedeps.py
+++ b/conans/test/unittests/tools/cmake/test_cmakedeps.py
@@ -17,6 +17,8 @@ def test_cpp_info_name_cmakedeps():
                                    "compiler": ["gcc"],
                                    "build_type": ["Release"],
                                    "arch": ["x86"]}), EnvValues())
+    conanfile.settings.build_type = "Release"
+    conanfile.settings.arch = "x86"
 
     cpp_info = CppInfo("mypkg", "dummy_root_folder1")
     cpp_info.names["cmake_find_package_multi"] = "MySuperPkg1"
@@ -26,6 +28,7 @@ def test_cpp_info_name_cmakedeps():
     cmakedeps = CMakeDeps(conanfile)
     files = cmakedeps.content
     assert "TARGET MySuperPkg1::MySuperPkg1" in files["ComplexFileName1Config.cmake"]
+    assert "set(MySuperPkg1_INCLUDE_DIRS_RELEASE )" in files["ComplexFileName1-release-x86-data.cmake"]
 
     with pytest.raises(ConanException,
                        match="'mypkg' defines information for 'cmake_find_package_multi'"):
@@ -38,8 +41,10 @@ def test_cpp_info_name_cmakedeps_components():
     conanfile.settings = "os", "compiler", "build_type", "arch"
     conanfile.initialize(Settings({"os": ["Windows"],
                                    "compiler": ["gcc"],
-                                   "build_type": ["Release"],
-                                   "arch": ["x86"]}), EnvValues())
+                                   "build_type": ["Release", "Debug"],
+                                   "arch": ["x86", "x64"]}), EnvValues())
+    conanfile.settings.build_type = "Debug"
+    conanfile.settings.arch = "x64"
 
     cpp_info = CppInfo("mypkg", "dummy_root_folder1")
     cpp_info.names["cmake_find_package_multi"] = "GlobakPkgName1"
@@ -50,6 +55,8 @@ def test_cpp_info_name_cmakedeps_components():
     cmakedeps = CMakeDeps(conanfile)
     files = cmakedeps.content
     assert "TARGET GlobakPkgName1::MySuperPkg1" in files["ComplexFileName1Config.cmake"]
+    assert "set(GlobakPkgName1_INCLUDE_DIRS_DEBUG )" in files["ComplexFileName1-debug-x64-data.cmake"]
+    assert "set(GlobakPkgName1_MySuperPkg1_INCLUDE_DIRS_DEBUG )" in files["ComplexFileName1-debug-x64-data.cmake"]
 
     with pytest.raises(ConanException,
                        match="'mypkg' defines information for 'cmake_find_package_multi'"):