Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CMakeDeps/CMakeToolchain: Several improvements for open issues #9455

Merged
merged 11 commits into from Sep 1, 2021
45 changes: 31 additions & 14 deletions conan/tools/cmake/cmakedeps/cmakedeps.py
@@ -1,4 +1,5 @@
import os
from fnmatch import fnmatch

from conan.tools._check_build_profile import check_using_build_profile
from conan.tools.cmake.cmakedeps.templates.config import ConfigTemplate
Expand Down Expand Up @@ -27,6 +28,9 @@ def __init__(self, conanfile):
# a suffix. It is necessary in case of same require and build_require and will cause an error
self.build_context_suffix = {}

# Patterns to be excluded
self.excluded_requirement_patterns = []

check_using_build_profile(self._conanfile)

# Enable/Disable checking if a component target exists or not
Expand Down Expand Up @@ -75,26 +79,39 @@ def content(self):
if dep.is_build_context and dep.ref.name not in self.build_context_activated:
continue

# Skip from the consumer
if any(fnmatch(str(dep.ref), pattern) for pattern in self.excluded_requirement_patterns):
self._conanfile.output.info("CMakeDeps: Skipped '{}'".format(dep.ref))
continue

# Skip from the requirement
if dep.new_cpp_info.get_property("skip_deps_file", "CMakeDeps"):
# Skip the generation of config files for this node, it will be located externally
continue

config_version = ConfigVersionTemplate(self, require, dep)
ret[config_version.filename] = config_version.render()
generate_find_module = dep.new_cpp_info.get_property("cmake_module_file_name",
"CMakeDeps") is not None

for find_module_mode in ([False, True] if generate_find_module else [False]):
lasote marked this conversation as resolved.
Show resolved Hide resolved
if not find_module_mode:
config_version = ConfigVersionTemplate(self, require, dep)
ret[config_version.filename] = config_version.render()

data_target = ConfigDataTemplate(self, require, dep, find_module_mode)
ret[data_target.filename] = data_target.render()

data_target = ConfigDataTemplate(self, require, dep)
ret[data_target.filename] = data_target.render()
target_configuration = TargetConfigurationTemplate(self, require, dep,
find_module_mode)
ret[target_configuration.filename] = target_configuration.render()

target_configuration = TargetConfigurationTemplate(self, require, dep)
ret[target_configuration.filename] = target_configuration.render()
targets = TargetsTemplate(self, require, dep, find_module_mode)
ret[targets.filename] = targets.render()

targets = TargetsTemplate(self, require, dep)
ret[targets.filename] = targets.render()
config = ConfigTemplate(self, require, dep, find_module_mode)
# Check if the XXConfig.cmake exists to keep the first generated configuration
# to only include the build_modules from the first conan install. The rest of the
# file is common for the different configurations.
if not os.path.exists(config.filename):
ret[config.filename] = config.render()

config = ConfigTemplate(self, require, dep)
# Check if the XXConfig.cmake exists to keep the first generated configuration
# to only include the build_modules from the first conan install. The rest of the
# file is common for the different configurations.
if not os.path.exists(config.filename):
ret[config.filename] = config.render()
return ret
62 changes: 34 additions & 28 deletions conan/tools/cmake/cmakedeps/templates/__init__.py
Expand Up @@ -7,22 +7,23 @@

class CMakeDepsFileTemplate(object):

def __init__(self, cmakedeps, require, conanfile):
def __init__(self, cmakedeps, require, conanfile, find_module_mode=False):
self.cmakedeps = cmakedeps
self.require = require
self.conanfile = conanfile
self.find_module_mode = find_module_mode

@property
def pkg_name(self):
return self.conanfile.ref.name + self.suffix

@property
def target_namespace(self):
return get_target_namespace(self.conanfile) + self.suffix
return self.get_target_namespace(self.conanfile) + self.suffix

@property
def file_name(self):
return get_file_name(self.conanfile) + self.suffix
return get_file_name(self.conanfile, self.find_module_mode) + self.suffix

@property
def suffix(self):
Expand Down Expand Up @@ -74,29 +75,34 @@ def arch(self):
def config_suffix(self):
return "_{}".format(self.configuration.upper()) if self.configuration else ""

def get_target_namespace(self):
return get_target_namespace(self.conanfile)

def get_file_name(self):
return get_file_name(self.conanfile)


def get_target_namespace(req):
ret = req.new_cpp_info.get_property("cmake_target_name", "CMakeDeps")
if not ret:
ret = req.cpp_info.get_name("cmake_find_package_multi", default_name=False)
return ret or req.ref.name


def get_component_alias(req, comp_name):
if comp_name not in req.new_cpp_info.components:
# foo::foo might be referencing the root cppinfo
if req.ref.name == comp_name:
return get_target_namespace(req)
raise ConanException("Component '{name}::{cname}' not found in '{name}' "
"package requirement".format(name=req.ref.name, cname=comp_name))
ret = req.new_cpp_info.components[comp_name].get_property("cmake_target_name", "CMakeDeps")
if not ret:
ret = req.cpp_info.components[comp_name].get_name("cmake_find_package_multi",
default_name=False)
return ret or comp_name
return get_file_name(self.conanfile, find_module_mode=self.find_module_mode)

def get_target_namespace(self, req):
if self.find_module_mode:
ret = req.new_cpp_info.get_property("cmake_module_target_name", "CMakeDeps")
if ret:
return ret

ret = req.new_cpp_info.get_property("cmake_target_name", "CMakeDeps")
lasote marked this conversation as resolved.
Show resolved Hide resolved
if not ret:
ret = req.cpp_info.get_name("cmake_find_package_multi", default_name=False)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No fallback to "cmake_find_package" for module?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been greping conan-center-index and the name is always set for both of them:

        self.cpp_info.names["cmake_find_package"] = "Crc32c"
        self.cpp_info.names["cmake_find_package_multi"] = "Crc32c"

So the fallback looks enough. We introduce this fallback mostly for Conan center.

return ret or req.ref.name

def get_component_alias(self, req, comp_name):
if comp_name not in req.new_cpp_info.components:
# foo::foo might be referencing the root cppinfo
if req.ref.name == comp_name:
return self.get_target_namespace(req)
raise ConanException("Component '{name}::{cname}' not found in '{name}' "
"package requirement".format(name=req.ref.name, cname=comp_name))
if self.find_module_mode:
ret = req.new_cpp_info.components[comp_name].get_property("cmake_module_target_name",
"CMakeDeps")
if ret:
return ret
ret = req.new_cpp_info.components[comp_name].get_property("cmake_target_name", "CMakeDeps")
if not ret:
ret = req.cpp_info.components[comp_name].get_name("cmake_find_package_multi",
default_name=False)
return ret or comp_name
16 changes: 11 additions & 5 deletions conan/tools/cmake/cmakedeps/templates/config.py
Expand Up @@ -14,18 +14,24 @@ class ConfigTemplate(CMakeDepsFileTemplate):

@property
def filename(self):
if self.file_name == self.file_name.lower():
return "{}-config.cmake".format(self.file_name)
if self.find_module_mode:
lasote marked this conversation as resolved.
Show resolved Hide resolved
return "Find{}.cmake".format(self.file_name)
else:
return "{}Config.cmake".format(self.file_name)
if self.file_name == self.file_name.lower():
return "{}-config.cmake".format(self.file_name)
else:
return "{}Config.cmake".format(self.file_name)

@property
def context(self):
targets_include = "" if not self.find_module_mode else "module-"
targets_include += "{}Targets.cmake".format(self.file_name)
return {"file_name": self.file_name,
"pkg_name": self.pkg_name,
"config_suffix": self.config_suffix,
"target_namespace": self.target_namespace,
"check_components_exist": self.cmakedeps.check_components_exist}
"check_components_exist": self.cmakedeps.check_components_exist,
"targets_include_file": targets_include}

@property
def template(self):
Expand All @@ -38,7 +44,7 @@ def template(self):
endif()

include(${CMAKE_CURRENT_LIST_DIR}/cmakedeps_macros.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/{{ file_name }}Targets.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/{{ targets_include_file }})
include(CMakeFindDependencyMacro)

foreach(_DEPENDENCY {{ '${' + pkg_name + '_FIND_DEPENDENCY_NAMES' + '}' }} )
Expand Down
17 changes: 8 additions & 9 deletions conan/tools/cmake/cmakedeps/templates/target_configuration.py
@@ -1,7 +1,6 @@
import textwrap

from conan.tools.cmake.cmakedeps.templates import CMakeDepsFileTemplate, get_component_alias, \
get_target_namespace
from conan.tools.cmake.cmakedeps.templates import CMakeDepsFileTemplate

"""

Expand All @@ -14,8 +13,9 @@ class TargetConfigurationTemplate(CMakeDepsFileTemplate):

@property
def filename(self):
return "{}Target-{}.cmake".format(self.file_name,
self.cmakedeps.configuration.lower())
name = "" if not self.find_module_mode else "module-"
lasote marked this conversation as resolved.
Show resolved Hide resolved
name += "{}-Target-{}.cmake".format(self.file_name, self.cmakedeps.configuration.lower())
return name

@property
def context(self):
Expand Down Expand Up @@ -147,7 +147,7 @@ def get_required_components_names(self):
ret = []
sorted_comps = self.conanfile.new_cpp_info.get_sorted_components()
for comp_name, comp in sorted_comps.items():
ret.append(get_component_alias(self.conanfile, comp_name))
ret.append(self.get_component_alias(self.conanfile, comp_name))
ret.reverse()
return ret

Expand All @@ -163,16 +163,15 @@ def get_deps_targets_names(self):
for dep_name, component_name in self.conanfile.new_cpp_info.required_components:
if not dep_name:
# Internal dep (no another component)
dep_name = get_target_namespace(self.conanfile)
req = self.conanfile
else:
req = self.conanfile.dependencies.host[dep_name]
dep_name = get_target_namespace(req)

component_name = get_component_alias(req, component_name)
dep_name = self.get_target_namespace(req)
component_name = self.get_component_alias(req, component_name)
ret.append("{}::{}".format(dep_name, component_name))
elif self.conanfile.dependencies.direct_host:
# Regular external "conanfile.requires" declared, not cpp_info requires
ret = ["{p}::{p}".format(p=get_target_namespace(r))
ret = ["{p}::{p}".format(p=self.get_target_namespace(r))
for r in self.conanfile.dependencies.direct_host.values()]
return ret
20 changes: 10 additions & 10 deletions conan/tools/cmake/cmakedeps/templates/target_data.py
@@ -1,8 +1,7 @@
import os
import textwrap

from conan.tools.cmake.cmakedeps.templates import CMakeDepsFileTemplate, get_component_alias, \
get_target_namespace
from conan.tools.cmake.cmakedeps.templates import CMakeDepsFileTemplate
from conan.tools.cmake.utils import get_file_name

"""
Expand All @@ -16,7 +15,8 @@ class ConfigDataTemplate(CMakeDepsFileTemplate):

@property
def filename(self):
data_fname = "{}-{}".format(self.file_name, self.configuration.lower())
data_fname = "" if not self.find_module_mode else "module-"
data_fname += "{}-{}".format(self.file_name, self.configuration.lower())
if self.arch:
data_fname += "-{}".format(self.arch)
data_fname += "-data.cmake"
Expand Down Expand Up @@ -122,14 +122,14 @@ def get_required_components_cpp(self):
if "::" in require: # Points to a component of a different package
pkg, cmp_name = require.split("::")
req = self.conanfile.dependencies.direct_host[pkg]
public_comp_deps.append("{}::{}".format(get_target_namespace(req),
get_component_alias(req, cmp_name)))
public_comp_deps.append("{}::{}".format(self.get_target_namespace(req),
self.get_component_alias(req, cmp_name)))
else: # Points to a component of same package
public_comp_deps.append("{}::{}".format(self.target_namespace,
get_component_alias(self.conanfile,
require)))
self.get_component_alias(self.conanfile,
require)))
deps_cpp_cmake.public_deps = " ".join(public_comp_deps)
component_rename = get_component_alias(self.conanfile, comp_name)
component_rename = self.get_component_alias(self.conanfile, comp_name)
ret.append((component_rename, deps_cpp_cmake))
ret.reverse()
return ret
Expand All @@ -143,9 +143,9 @@ def _get_dependency_filenames(self):
for dep_name, _ in self.conanfile.new_cpp_info.required_components:
if dep_name and dep_name not in ret: # External dep
req = direct_host[dep_name]
ret.append(get_file_name(req))
ret.append(get_file_name(req, self.find_module_mode))
elif direct_host:
ret = [get_file_name(r) for r in direct_host.values()]
ret = [get_file_name(r, self.find_module_mode) for r in direct_host.values()]

return ret

Expand Down
17 changes: 13 additions & 4 deletions conan/tools/cmake/cmakedeps/templates/targets.py
Expand Up @@ -13,21 +13,30 @@ class TargetsTemplate(CMakeDepsFileTemplate):

@property
def filename(self):
return "{}Targets.cmake".format(self.file_name)
name = "" if not self.find_module_mode else "module-"
name += self.file_name + "Targets.cmake"
return name

@property
def context(self):
data_pattern = "${_DIR}/" if not self.find_module_mode else "${_DIR}/module-"
data_pattern += "{}-*-data.cmake".format(self.file_name)

target_pattern = "" if not self.find_module_mode else "module-"
target_pattern += "{}-Target-*.cmake".format(self.file_name)

ret = {"pkg_name": self.pkg_name,
"target_namespace": self.target_namespace,
"file_name": self.file_name}
"data_pattern": data_pattern,
"target_pattern": target_pattern}
return ret

@property
def template(self):
return textwrap.dedent("""\
# Load the debug and release variables
get_filename_component(_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
file(GLOB DATA_FILES "${_DIR}/{{ file_name }}-*-data.cmake")
file(GLOB DATA_FILES "{{data_pattern}}")

foreach(f ${DATA_FILES})
include(${f})
Expand All @@ -48,7 +57,7 @@ def template(self):

# Load the debug and release library finders
get_filename_component(_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
file(GLOB CONFIG_FILES "${_DIR}/{{ file_name }}Target-*.cmake")
file(GLOB CONFIG_FILES "${_DIR}/{{ target_pattern }}")

foreach(f ${CONFIG_FILES})
include(${f})
Expand Down