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

improvements deduce locations incubating cmakedeps #17594

Open
wants to merge 1 commit into
base: develop2
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 51 additions & 21 deletions conan/internal/model/cpp_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ def type(self):

@type.setter
def type(self, value):
self._type = value
self._type = PackageType(value) if value is not None else None

@property
def location(self):
Expand Down Expand Up @@ -538,6 +538,7 @@ def _find_matching(dirs, pattern):
static_location = None
shared_location = None
dll_location = None
deduced_type = None
# libname is exactly the pattern, e.g., ["mylib.a"] instead of ["mylib"]
_, ext = os.path.splitext(libname)
if ext in (".lib", ".a", ".dll", ".so", ".dylib"):
Expand All @@ -562,52 +563,78 @@ def _find_matching(dirs, pattern):
if shared_location:
out.warning(f"Lib {libname} has both static {static_location} and "
f"shared {shared_location} in the same package")
if pkg_type is PackageType.STATIC:
if self._type is PackageType.STATIC or pkg_type is PackageType.STATIC:
self._location = static_location
self._type = PackageType.STATIC
deduced_type = PackageType.STATIC
else:
self._location = shared_location
self._type = PackageType.SHARED
deduced_type = PackageType.SHARED
elif dll_location:
self._location = dll_location
self._link_location = static_location
self._type = PackageType.SHARED
deduced_type = PackageType.SHARED
else:
self._location = static_location
self._type = PackageType.STATIC
deduced_type = PackageType.STATIC
elif shared_location:
self._location = shared_location
self._type = PackageType.SHARED
deduced_type = PackageType.SHARED
elif dll_location:
# Only .dll but no link library
self._location = dll_location
self._type = PackageType.SHARED
deduced_type = PackageType.SHARED
if not self._location:
raise ConanException(f"{conanfile}: Cannot obtain 'location' for library '{libname}' "
f"in {libdirs}. You can specify 'cpp_info.location' directly "
f"or report in github.com/conan-io/conan/issues if you think it "
f"should have been deduced correctly.")
if self._type is not None and self._type != deduced_type:
ConanException(f"{conanfile}: Incorrect deduced type '{deduced_type}' for library"
f" '{libname}' that declared .type='{self._type}'")
self._type = deduced_type
if self._type != pkg_type:
out.warning(f"Lib {libname} deduced as '{self._type}, but 'package_type={pkg_type}'")

def deduce_locations(self, conanfile, component_name=""):
name = f'{conanfile} cpp_info.components["{component_name}"]' if component_name \
else f'{conanfile} cpp_info'
# executable
if self._exe: # exe is a new field, it should have the correct location
if self._type is None:
self._type = PackageType.APP
if self._type is not PackageType.APP:
raise ConanException(f"{name} incorrect .type {self._type} for .exe {self._exe}")
if self.libs:
raise ConanException(f"{name} has both .exe and .libs")
if not self.location:
raise ConanException(f"{name} has .exe and no .location")
return
if self._location or self._link_location:
if self._type is None or self._type is PackageType.HEADER:
raise ConanException("Incorrect cpp_info defining location without type or header")
if self._type is PackageType.APP:
# old school Conan application packages withoud defining an exe, not an error
return
if self._type not in [None, PackageType.SHARED, PackageType.STATIC, PackageType.APP]:

# libraries
if len(self.libs) > 1: # it could be 0, as the libs itself is not necessary
raise ConanException(f"{name} has more than 1 library in .libs: {self.libs}, "
"cannot deduce locations")
# fully defined by user in conanfile, nothing to do.
if self._location or self._link_location:
if self._type not in [PackageType.SHARED, PackageType.STATIC]:
raise ConanException(f"{name} location defined without defined library type")
return
num_libs = len(self.libs)
if num_libs == 0:

# possible header only, which allows also an empty header-only only for common flags
if len(self.libs) == 0:
if self._type is None:
self._type = PackageType.HEADER
return
elif num_libs > 1:
raise ConanException(
f"More than 1 library defined in cpp_info.libs, cannot deduce CPS ({num_libs} libraries found)")
else:
# If no location is defined, it's time to guess the location
self._auto_deduce_locations(conanfile, component_name=component_name)

# automatic location deduction from a single .lib=["lib"]
if self._type not in [None, PackageType.SHARED, PackageType.STATIC]:
raise ConanException(f"{name} has a library but .type {self._type} is not static/shared")

# If no location is defined, it's time to guess the location
self._auto_deduce_locations(conanfile, component_name=component_name)


class CppInfo:
Expand Down Expand Up @@ -779,6 +806,9 @@ def required_components(self):
return ret

def deduce_full_cpp_info(self, conanfile):
if conanfile.cpp_info.has_components and (conanfile.cpp_info.exe or conanfile.cpp_info.libs):
raise ConanException(f"{conanfile}: 'cpp_info' contains components and .exe or .libs")

result = CppInfo() # clone it

if self.libs and len(self.libs) > 1: # expand in multiple components
Expand All @@ -796,7 +826,7 @@ def deduce_full_cpp_info(self, conanfile):

common = self._package.clone()
common.libs = []
common.type = str(PackageType.HEADER) # the type of components is a string!
common.type = PackageType.HEADER # the type of components is a string!
common.requires = list(result.components.keys()) + (self.requires or [])
result.components["_common"] = common
else:
Expand Down
4 changes: 0 additions & 4 deletions conan/tools/cmake/cmakedeps2/target_configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,6 @@ def _get_exes(self, cpp_info, pkg_name, pkg_folder, pkg_folder_var):
exes = {}

if cpp_info.has_components:
assert not cpp_info.exe, "Package has components and exe"
assert not cpp_info.libs, "Package has components and libs"
for name, comp in cpp_info.components.items():
if comp.exe or comp.type is PackageType.APP:
target_name = self._cmakedeps.get_property("cmake_target_name", self._conanfile,
Expand All @@ -228,8 +226,6 @@ def _get_exes(self, cpp_info, pkg_name, pkg_folder, pkg_folder_var):
exes[target] = exe_location
else:
if cpp_info.exe:
assert not cpp_info.libs, "Package has exe and libs"
assert cpp_info.location, "Package has exe and no location"
target_name = self._cmakedeps.get_property("cmake_target_name", self._conanfile)
target = target_name or f"{pkg_name}::{pkg_name}"
exe_location = self._path(cpp_info.location, pkg_folder, pkg_folder_var)
Expand Down
Loading