From e743bd242aae22223b42cc2ed9bf010543ff7eec Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Mon, 20 May 2019 18:28:43 +0200 Subject: [PATCH 01/47] Added tests and first POC component class with recursive libs retrieval --- conans/model/build_info.py | 69 +++++++++++++++++++ .../test/unittests/model/build_info_test.py | 41 ++++++++++- 2 files changed, 109 insertions(+), 1 deletion(-) diff --git a/conans/model/build_info.py b/conans/model/build_info.py index 5d31a09bf66..f1495ee9236 100644 --- a/conans/model/build_info.py +++ b/conans/model/build_info.py @@ -3,6 +3,8 @@ import deprecation +from conans.errors import ConanException + DEFAULT_INCLUDE = "include" DEFAULT_LIB = "lib" DEFAULT_BIN = "bin" @@ -16,6 +18,9 @@ class _CppInfo(object): specific systems will be produced from this info """ def __init__(self): + self.name = None + self.exes = [] + self.system_deps = [] self.includedirs = [] # Ordered list of include paths self.srcdirs = [] # Ordered list of source paths self.libdirs = [] # Directories to find libraries @@ -132,6 +137,70 @@ def _get_cpp_info(): return self.configs.setdefault(config, _get_cpp_info()) +class Component(object): + + def __init__(self, name): + self.name = name + self.deps = OrderedComponentsDict() + self._lib = None + self._exe = None + self.system_deps = [] + + @property + def libs(self): + return self.deps.items() + + @property + def lib(self): + return self._lib + + @lib.setter + def lib(self, name): + if self._exe: + raise ConanException("exe is already set") + self._lib = name + + @property + def exe(self): + return self._exe + + @exe.setter + def exe(self, name): + if self._lib: + raise ConanException("lib is already set") + self._exe = name + + +class OrderedComponentsDict(object): + + def __init__(self): + self._components = OrderedDict() + + def __setitem__(self, key, value): + self._components[key] = value + + def __getitem__(self, key): + if key not in self._components: + self._components[key] = Component(key) + return self._components[key] + + def items(self): + values = [] + for k, v in self._components.items(): + items = self._components[k].deps.items() + if items: + values.extend(items) + if self._components[k].lib is not None: + values.append(self._components[k].lib) + else: + values.append(self._components[k].lib) + ret = [] + for v in values: + if v not in ret: + ret.append(v) + return ret + + class _BaseDepsCppInfo(_CppInfo): def __init__(self): super(_BaseDepsCppInfo, self).__init__() diff --git a/conans/test/unittests/model/build_info_test.py b/conans/test/unittests/model/build_info_test.py index 631aac1a03d..6bae2e61ac3 100644 --- a/conans/test/unittests/model/build_info_test.py +++ b/conans/test/unittests/model/build_info_test.py @@ -3,7 +3,8 @@ from collections import defaultdict, namedtuple from conans.client.generators import TXTGenerator -from conans.model.build_info import CppInfo, DepsCppInfo +from conans.errors import ConanException +from conans.model.build_info import CppInfo, DepsCppInfo, Component from conans.model.env_info import DepsEnvInfo, EnvInfo from conans.model.user_info import DepsUserInfo from conans.test.utils.test_files import temp_folder @@ -173,3 +174,41 @@ def cpp_info_test(self): self.assertEqual(info.lib_paths, [os.path.join(folder, "lib"), abs_lib]) self.assertEqual(info.bin_paths, [abs_bin, os.path.join(folder, "local_bindir")]) + + def cpp_info_components_test(self): + folder = temp_folder() + info = CppInfo(folder) + self.assertIsNone(info.name) + self.assertEquals(info.exes, []) + self.assertEquals(info.system_deps, []) + info.libs + + def basic_components_test(self): + component = Component("my_component") + self.assertIn(component.name, "my_component") + component.deps["hola"] + component.deps["hola"].lib = "libhola" + self.assertEquals(component.deps["hola"].lib, "libhola") + with self.assertRaisesRegexp(ConanException, "lib is already set"): + component.deps["hola"].exe = "hola.exe" + component.deps["hola"].lib = None + self.assertEquals(component.deps["hola"].lib, None) + component.deps["hola"].exe = "hola.exe" + self.assertEquals(component.deps["hola"].lib, None) + with self.assertRaisesRegexp(ConanException, "exe is already set"): + component.deps["hola"].lib = "libhola" + + def nested_components_test(self): + component = Component("Greetings") + self.assertIn(component.name, "Greetings") + component.deps["greet"].exe = "greet.exe" + component.deps["greet"].deps["hola"].lib = "libhola" + component.deps["greet"].deps["adios"].lib = "libadios" + component.deps["greet"].deps["hola"].deps["say"].lib = "libsay" + component.deps["greet"].deps["adios"].deps["say"].lib = "libsay" + component.deps["greet"].deps["hru"].lib = "libhru" + self.assertEquals(component.libs, ["libsay", "libhola", "libadios", "libhru"]) + self.assertEquals(component.deps["greet"].deps["hru"].libs, []) + self.assertEquals(component.deps["greet"].deps["hola"].libs, ["libsay"]) + self.assertEquals(component.deps["greet"].deps["adios"].libs, ["libsay"]) + self.assertEquals(component.deps["greet"].deps["adios"].deps["say"].libs, []) \ No newline at end of file From 7073291cf9555bc4c74bbc4245dc62acba80dce9 Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Tue, 21 May 2019 12:10:25 +0200 Subject: [PATCH 02/47] Removed ordered dict class and moved to component class --- conans/model/build_info.py | 83 ++++++++++++------- .../test/unittests/model/build_info_test.py | 69 ++++++++------- 2 files changed, 92 insertions(+), 60 deletions(-) diff --git a/conans/model/build_info.py b/conans/model/build_info.py index f1495ee9236..a24f8f84065 100644 --- a/conans/model/build_info.py +++ b/conans/model/build_info.py @@ -120,6 +120,19 @@ def __init__(self, root_folder): # public_deps is needed to accumulate list of deps for cmake targets self.public_deps = [] self.configs = {} + self._deps = OrderedDict() + + @property + def deps(self): + return self._deps.keys() + + def __setitem__(self, key, value): + self._deps[key] = value + + def __getitem__(self, key): + if key not in self.deps: + self._deps[key] = Component(key) + return self._deps[key] def __getattr__(self, config): @@ -141,14 +154,50 @@ class Component(object): def __init__(self, name): self.name = name - self.deps = OrderedComponentsDict() + self._deps = OrderedDict() self._lib = None self._exe = None self.system_deps = [] + self.includedirs = [] + self.libdirs = [] + self.resdirs = [] + self.bindirs = [] + self.builddirs = [] + self.defines = [] + self.cflags = [] + self.cppflags = [] + self.cxxflags = [] + self.sharedlinkflags = [] + self.exelinkflags = [] + + @property + def deps(self): + return self._deps.keys() + + def __setitem__(self, key, value): + self._deps[key] = value + + def __getitem__(self, key): + if key not in self._deps: + self._deps[key] = Component(key) + return self._deps[key] @property def libs(self): - return self.deps.items() + values = [] + for k, v in self._deps.items(): + items = self._deps[k]._deps.items() + if items: + values.extend(self._deps[k].libs) + if self._deps[k].lib is not None: + values.append(self._deps[k].lib) + else: + values.append(self._deps[k].lib) + ret = [] + for v in values: + if v not in ret: + ret.append(v) + return ret @property def lib(self): @@ -171,36 +220,6 @@ def exe(self, name): self._exe = name -class OrderedComponentsDict(object): - - def __init__(self): - self._components = OrderedDict() - - def __setitem__(self, key, value): - self._components[key] = value - - def __getitem__(self, key): - if key not in self._components: - self._components[key] = Component(key) - return self._components[key] - - def items(self): - values = [] - for k, v in self._components.items(): - items = self._components[k].deps.items() - if items: - values.extend(items) - if self._components[k].lib is not None: - values.append(self._components[k].lib) - else: - values.append(self._components[k].lib) - ret = [] - for v in values: - if v not in ret: - ret.append(v) - return ret - - class _BaseDepsCppInfo(_CppInfo): def __init__(self): super(_BaseDepsCppInfo, self).__init__() diff --git a/conans/test/unittests/model/build_info_test.py b/conans/test/unittests/model/build_info_test.py index 6bae2e61ac3..321cbd1fc40 100644 --- a/conans/test/unittests/model/build_info_test.py +++ b/conans/test/unittests/model/build_info_test.py @@ -175,40 +175,53 @@ def cpp_info_test(self): self.assertEqual(info.bin_paths, [abs_bin, os.path.join(folder, "local_bindir")]) - def cpp_info_components_test(self): - folder = temp_folder() - info = CppInfo(folder) - self.assertIsNone(info.name) - self.assertEquals(info.exes, []) - self.assertEquals(info.system_deps, []) - info.libs - def basic_components_test(self): component = Component("my_component") self.assertIn(component.name, "my_component") - component.deps["hola"] - component.deps["hola"].lib = "libhola" - self.assertEquals(component.deps["hola"].lib, "libhola") + component["hola"] + component["hola"].lib = "libhola" + self.assertEquals(component["hola"].lib, "libhola") with self.assertRaisesRegexp(ConanException, "lib is already set"): - component.deps["hola"].exe = "hola.exe" - component.deps["hola"].lib = None - self.assertEquals(component.deps["hola"].lib, None) - component.deps["hola"].exe = "hola.exe" - self.assertEquals(component.deps["hola"].lib, None) + component["hola"].exe = "hola.exe" + component["hola"].lib = None + self.assertEquals(component["hola"].lib, None) + component["hola"].exe = "hola.exe" + self.assertEquals(component["hola"].lib, None) with self.assertRaisesRegexp(ConanException, "exe is already set"): - component.deps["hola"].lib = "libhola" + component["hola"].lib = "libhola" - def nested_components_test(self): + def nested_components_libs_order_test(self): component = Component("Greetings") self.assertIn(component.name, "Greetings") - component.deps["greet"].exe = "greet.exe" - component.deps["greet"].deps["hola"].lib = "libhola" - component.deps["greet"].deps["adios"].lib = "libadios" - component.deps["greet"].deps["hola"].deps["say"].lib = "libsay" - component.deps["greet"].deps["adios"].deps["say"].lib = "libsay" - component.deps["greet"].deps["hru"].lib = "libhru" + component["greet"].exe = "greet.exe" + component["greet"]["hola"].lib = "libhola" + component["greet"]["adios"].lib = "libadios" + component["greet"]["hola"]["say"].lib = "libsay" + component["greet"]["adios"]["say"].lib = "libsay" + component["greet"]["hru"].lib = "libhru" self.assertEquals(component.libs, ["libsay", "libhola", "libadios", "libhru"]) - self.assertEquals(component.deps["greet"].deps["hru"].libs, []) - self.assertEquals(component.deps["greet"].deps["hola"].libs, ["libsay"]) - self.assertEquals(component.deps["greet"].deps["adios"].libs, ["libsay"]) - self.assertEquals(component.deps["greet"].deps["adios"].deps["say"].libs, []) \ No newline at end of file + self.assertEquals(component["greet"]["hru"].libs, []) + self.assertEquals(component["greet"]["hola"].libs, ["libsay"]) + self.assertEquals(component["greet"]["adios"].libs, ["libsay"]) + self.assertEquals(component["greet"]["adios"]["say"].libs, []) + + def components_deps_test(self): + component = Component("OpenSSL") + component["OpenSSL"]["Crypto"]["SSL"] + component["OpenSSL"]["Other"] + component["Another"] + self.assertEqual(component.deps, ["OpenSSL", "Another"]) + self.assertEqual(component["OpenSSL"].deps, ["Crypto", "Other"]) + self.assertEqual(component["OpenSSL"]["Crypto"].deps, ["SSL"]) + self.assertEqual(component["Another"].deps, []) + self.assertEqual(component["OpenSSL"]["Other"].deps, []) + self.assertEqual(component["OpenSSL"]["Crypto"]["SSL"].deps, []) + + def cppinfo_components_test(self): + folder = temp_folder() + info = CppInfo(folder) + info.name = "OpenSSL" + info["OpenSSL"].includedirs = ["include"] + info["OpenSSL"]["Crypto"].includedirs = ["headers"] + self.assertEqual(info["OpenSSL"].includedirs, ["include"]) + self.assertEqual(info["OpenSSL"]["Crypto"].includedirs, ["headers"]) From 66289a7fdeb1f5d9dedc2baa2a10c39e69aba2e9 Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Tue, 21 May 2019 13:58:51 +0200 Subject: [PATCH 03/47] Propagate lib and exe to cpp_info and maintain current behavior or libs --- conans/model/build_info.py | 101 +++++++++++++++++- .../test/unittests/model/build_info_test.py | 55 ++++++++++ 2 files changed, 152 insertions(+), 4 deletions(-) diff --git a/conans/model/build_info.py b/conans/model/build_info.py index a24f8f84065..1592b5dee6b 100644 --- a/conans/model/build_info.py +++ b/conans/model/build_info.py @@ -19,7 +19,6 @@ class _CppInfo(object): """ def __init__(self): self.name = None - self.exes = [] self.system_deps = [] self.includedirs = [] # Ordered list of include paths self.srcdirs = [] # Ordered list of source paths @@ -28,7 +27,7 @@ def __init__(self): self.bindirs = [] # Directories to find executables and shared libs self.builddirs = [] self.rootpaths = [] - self.libs = [] # The libs to link against + self._libs = [] # The libs to link against self.defines = [] # preprocessor definitions self.cflags = [] # pure C flags self.cxxflags = [] # C++ compilation flags @@ -121,15 +120,90 @@ def __init__(self, root_folder): self.public_deps = [] self.configs = {} self._deps = OrderedDict() + self._lib = None + self._exe = None @property def deps(self): return self._deps.keys() + @property + def lib(self): + return self._lib + + @lib.setter + def lib(self, name): + if self._exe: + raise ConanException("exe is already set") + if self._deps: + raise ConanException("Setting a first level lib is not supported when Components are " + "already in use") + self._lib = name + + @property + def libs(self): + if self._deps: + values = [] + for k, v in self._deps.items(): + if self._deps[k]._deps.items(): + values.extend(self._deps[k].libs) + if self._deps[k].lib is not None: + values.append(self._deps[k].lib) + else: + values.append(self._deps[k].lib) + ret = [] + for v in values: + if v not in ret: + ret.append(v) + return ret + else: + return self._libs + + @libs.setter + def libs(self, libs): + if self._deps: + raise ConanException("Setting a first level libs is not supported when Components are " + "already in use") + self._libs = libs + + @property + def exe(self): + return self._exe + + @exe.setter + def exe(self, name): + if self._lib: + raise ConanException("lib is already set") + if self._deps: + raise ConanException("Setting a first level exe is not supported when Components are " + "already in use") + self._exe = name + + @property + def exes(self): + if self._deps: + values = [] + for k, v in self._deps.items(): + if self._deps[k]._deps.items(): + if self._deps[k].exe is not None: + values.append(self._deps[k].exe) + values.extend(self._deps[k].exes) + else: + values.append(self._deps[k].exe) + return values + else: + return [self.exe] + def __setitem__(self, key, value): + if self._exe or self._lib: + raise ConanException("Usage of Components with 'exe' or 'lib' values is no allowed") + if self._libs or self._lib: + raise ConanException("Usage of Components with 'libs' values is no allowed") self._deps[key] = value def __getitem__(self, key): + if self._exe or self._lib: + raise ConanException("Usage of Components with 'exe' or 'lib' values is no allowed") if key not in self.deps: self._deps[key] = Component(key) return self._deps[key] @@ -186,8 +260,7 @@ def __getitem__(self, key): def libs(self): values = [] for k, v in self._deps.items(): - items = self._deps[k]._deps.items() - if items: + if self._deps[k]._deps.items(): values.extend(self._deps[k].libs) if self._deps[k].lib is not None: values.append(self._deps[k].lib) @@ -209,6 +282,18 @@ def lib(self, name): raise ConanException("exe is already set") self._lib = name + @property + def exes(self): + values = [] + for k, v in self._deps.items(): + if self._deps[k]._deps.items(): + if self._deps[k].exe is not None: + values.append(self._deps[k].exe) + values.extend(self._deps[k].exes) + else: + values.append(self._deps[k].exe) + return values + @property def exe(self): return self._exe @@ -248,6 +333,14 @@ def merge_lists(seq1, seq2): if not self.sysroot: self.sysroot = dep_cpp_info.sysroot + @property + def libs(self): + return self._libs + + @libs.setter + def libs(self, libs): + self._libs = libs + @property def include_paths(self): return self.includedirs diff --git a/conans/test/unittests/model/build_info_test.py b/conans/test/unittests/model/build_info_test.py index 321cbd1fc40..df44d6bf631 100644 --- a/conans/test/unittests/model/build_info_test.py +++ b/conans/test/unittests/model/build_info_test.py @@ -205,6 +205,61 @@ def nested_components_libs_order_test(self): self.assertEquals(component["greet"]["adios"].libs, ["libsay"]) self.assertEquals(component["greet"]["adios"]["say"].libs, []) + def cpp_info_nested_components_libs_order_test(self): + info = CppInfo(None) + info.name = "Greetings" + self.assertIn(info.name, "Greetings") + info["greet"].exe = "greet.exe" + info["greet"]["hola"].lib = "libhola" + info["greet"]["adios"].lib = "libadios" + info["greet"]["hola"]["say"].lib = "libsay" + info["greet"]["adios"]["say"].lib = "libsay" + info["greet"]["hru"].lib = "libhru" + self.assertEquals(info.libs, ["libsay", "libhola", "libadios", "libhru"]) + self.assertEquals(info["greet"]["hru"].libs, []) + self.assertEquals(info["greet"]["hola"].libs, ["libsay"]) + self.assertEquals(info["greet"]["adios"].libs, ["libsay"]) + self.assertEquals(info["greet"]["adios"]["say"].libs, []) + + def cpp_info_exes_test(self): + info = CppInfo(None) + info.name = "Greetings" + self.assertIn(info.name, "Greetings") + info["greet"].exe = "greet.exe" + info["hola"].exe = "hola.exe" + info["adios"].exe = "adios.exe" + info["say"].exe = "say.exe" + info["hru"].exe = "hru.exe" + self.assertEqual(["greet.exe", "hola.exe", "adios.exe", "say.exe", "hru.exe"], info.exes) + + def cpp_info_nested_exes_test(self): + info = CppInfo(None) + info.name = "Greetings" + self.assertIn(info.name, "Greetings") + info["greet"].exe = "greet.exe" + info["greet"]["hola"].exe = "hola.exe" + info["greet"]["hola"]["say"].exe = "say.exe" + info["greet"]["adios"].exe = "adios.exe" + info["hru"].exe = "hru.exe" + self.assertEqual(["greet.exe", "hola.exe", "say.exe", "adios.exe", "hru.exe"], info.exes) + + def cpp_info_exes_components_fail_test(self): + """ + Usage of .lib or .exe is not allowed in cpp_info when using components + """ + info = CppInfo(None) + info.name = "Greetings" + self.assertIn(info.name, "Greetings") + info.exe = "greet.exe" + with self.assertRaisesRegexp(ConanException, "Usage of Components with 'exe' or 'lib' " + "values is no allowed"): + info["hola"].exe = "hola.exe" + info.exe = None + info["hola"].exe = "hola.exe" + with self.assertRaisesRegexp(ConanException, "Setting a first level exe is not supported " + "when Components are already in use"): + info.exe = "greet.exe" + def components_deps_test(self): component = Component("OpenSSL") component["OpenSSL"]["Crypto"]["SSL"] From 07f90a730d1daa7d2c66cdab9a90ebf6f9049924 Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Tue, 21 May 2019 16:48:19 +0200 Subject: [PATCH 04/47] Removed multilevel components and recursivity --- conans/model/build_info.py | 120 ++---------------- .../test/unittests/model/build_info_test.py | 104 +++------------ 2 files changed, 27 insertions(+), 197 deletions(-) diff --git a/conans/model/build_info.py b/conans/model/build_info.py index 1592b5dee6b..7970035be0f 100644 --- a/conans/model/build_info.py +++ b/conans/model/build_info.py @@ -120,91 +120,27 @@ def __init__(self, root_folder): self.public_deps = [] self.configs = {} self._deps = OrderedDict() - self._lib = None - self._exe = None - - @property - def deps(self): - return self._deps.keys() - - @property - def lib(self): - return self._lib - - @lib.setter - def lib(self, name): - if self._exe: - raise ConanException("exe is already set") - if self._deps: - raise ConanException("Setting a first level lib is not supported when Components are " - "already in use") - self._lib = name @property def libs(self): if self._deps: - values = [] - for k, v in self._deps.items(): - if self._deps[k]._deps.items(): - values.extend(self._deps[k].libs) - if self._deps[k].lib is not None: - values.append(self._deps[k].lib) - else: - values.append(self._deps[k].lib) - ret = [] - for v in values: - if v not in ret: - ret.append(v) - return ret + deps = [v for v in self._deps.values()] + deps_sorted = sorted(deps, key=lambda component: len(component.deps)) + return [dep.lib for dep in deps_sorted if dep.lib is not None] else: return self._libs @libs.setter def libs(self, libs): if self._deps: - raise ConanException("Setting a first level libs is not supported when Components are " + raise ConanException("Setting first level libs is not supported when Components are " "already in use") self._libs = libs - @property - def exe(self): - return self._exe - - @exe.setter - def exe(self, name): - if self._lib: - raise ConanException("lib is already set") - if self._deps: - raise ConanException("Setting a first level exe is not supported when Components are " - "already in use") - self._exe = name - - @property - def exes(self): - if self._deps: - values = [] - for k, v in self._deps.items(): - if self._deps[k]._deps.items(): - if self._deps[k].exe is not None: - values.append(self._deps[k].exe) - values.extend(self._deps[k].exes) - else: - values.append(self._deps[k].exe) - return values - else: - return [self.exe] - - def __setitem__(self, key, value): - if self._exe or self._lib: - raise ConanException("Usage of Components with 'exe' or 'lib' values is no allowed") - if self._libs or self._lib: - raise ConanException("Usage of Components with 'libs' values is no allowed") - self._deps[key] = value - def __getitem__(self, key): - if self._exe or self._lib: - raise ConanException("Usage of Components with 'exe' or 'lib' values is no allowed") - if key not in self.deps: + if self._libs: + raise ConanException("Usage of Components with '.libs' values is not allowed") + if key not in self._deps.keys(): self._deps[key] = Component(key) return self._deps[key] @@ -228,7 +164,7 @@ class Component(object): def __init__(self, name): self.name = name - self._deps = OrderedDict() + self.deps = [] self._lib = None self._exe = None self.system_deps = [] @@ -244,34 +180,6 @@ def __init__(self, name): self.sharedlinkflags = [] self.exelinkflags = [] - @property - def deps(self): - return self._deps.keys() - - def __setitem__(self, key, value): - self._deps[key] = value - - def __getitem__(self, key): - if key not in self._deps: - self._deps[key] = Component(key) - return self._deps[key] - - @property - def libs(self): - values = [] - for k, v in self._deps.items(): - if self._deps[k]._deps.items(): - values.extend(self._deps[k].libs) - if self._deps[k].lib is not None: - values.append(self._deps[k].lib) - else: - values.append(self._deps[k].lib) - ret = [] - for v in values: - if v not in ret: - ret.append(v) - return ret - @property def lib(self): return self._lib @@ -282,18 +190,6 @@ def lib(self, name): raise ConanException("exe is already set") self._lib = name - @property - def exes(self): - values = [] - for k, v in self._deps.items(): - if self._deps[k]._deps.items(): - if self._deps[k].exe is not None: - values.append(self._deps[k].exe) - values.extend(self._deps[k].exes) - else: - values.append(self._deps[k].exe) - return values - @property def exe(self): return self._exe diff --git a/conans/test/unittests/model/build_info_test.py b/conans/test/unittests/model/build_info_test.py index df44d6bf631..e76add10467 100644 --- a/conans/test/unittests/model/build_info_test.py +++ b/conans/test/unittests/model/build_info_test.py @@ -178,105 +178,39 @@ def cpp_info_test(self): def basic_components_test(self): component = Component("my_component") self.assertIn(component.name, "my_component") - component["hola"] - component["hola"].lib = "libhola" - self.assertEquals(component["hola"].lib, "libhola") + component.lib = "libhola" + self.assertEquals(component.lib, "libhola") with self.assertRaisesRegexp(ConanException, "lib is already set"): - component["hola"].exe = "hola.exe" - component["hola"].lib = None - self.assertEquals(component["hola"].lib, None) - component["hola"].exe = "hola.exe" - self.assertEquals(component["hola"].lib, None) + component.exe = "hola.exe" + component.lib = None + component.exe = "hola.exe" + self.assertEquals(component.lib, None) with self.assertRaisesRegexp(ConanException, "exe is already set"): - component["hola"].lib = "libhola" + component.lib = "libhola" - def nested_components_libs_order_test(self): - component = Component("Greetings") - self.assertIn(component.name, "Greetings") - component["greet"].exe = "greet.exe" - component["greet"]["hola"].lib = "libhola" - component["greet"]["adios"].lib = "libadios" - component["greet"]["hola"]["say"].lib = "libsay" - component["greet"]["adios"]["say"].lib = "libsay" - component["greet"]["hru"].lib = "libhru" - self.assertEquals(component.libs, ["libsay", "libhola", "libadios", "libhru"]) - self.assertEquals(component["greet"]["hru"].libs, []) - self.assertEquals(component["greet"]["hola"].libs, ["libsay"]) - self.assertEquals(component["greet"]["adios"].libs, ["libsay"]) - self.assertEquals(component["greet"]["adios"]["say"].libs, []) - - def cpp_info_nested_components_libs_order_test(self): - info = CppInfo(None) - info.name = "Greetings" - self.assertIn(info.name, "Greetings") - info["greet"].exe = "greet.exe" - info["greet"]["hola"].lib = "libhola" - info["greet"]["adios"].lib = "libadios" - info["greet"]["hola"]["say"].lib = "libsay" - info["greet"]["adios"]["say"].lib = "libsay" - info["greet"]["hru"].lib = "libhru" - self.assertEquals(info.libs, ["libsay", "libhola", "libadios", "libhru"]) - self.assertEquals(info["greet"]["hru"].libs, []) - self.assertEquals(info["greet"]["hola"].libs, ["libsay"]) - self.assertEquals(info["greet"]["adios"].libs, ["libsay"]) - self.assertEquals(info["greet"]["adios"]["say"].libs, []) - - def cpp_info_exes_test(self): - info = CppInfo(None) - info.name = "Greetings" - self.assertIn(info.name, "Greetings") - info["greet"].exe = "greet.exe" - info["hola"].exe = "hola.exe" - info["adios"].exe = "adios.exe" - info["say"].exe = "say.exe" - info["hru"].exe = "hru.exe" - self.assertEqual(["greet.exe", "hola.exe", "adios.exe", "say.exe", "hru.exe"], info.exes) - - def cpp_info_nested_exes_test(self): - info = CppInfo(None) - info.name = "Greetings" - self.assertIn(info.name, "Greetings") - info["greet"].exe = "greet.exe" - info["greet"]["hola"].exe = "hola.exe" - info["greet"]["hola"]["say"].exe = "say.exe" - info["greet"]["adios"].exe = "adios.exe" - info["hru"].exe = "hru.exe" - self.assertEqual(["greet.exe", "hola.exe", "say.exe", "adios.exe", "hru.exe"], info.exes) - - def cpp_info_exes_components_fail_test(self): + def cpp_info_libs_components_fail_test(self): """ - Usage of .lib or .exe is not allowed in cpp_info when using components + Usage of .libs is not allowed in cpp_info when using Components """ info = CppInfo(None) info.name = "Greetings" self.assertIn(info.name, "Greetings") - info.exe = "greet.exe" - with self.assertRaisesRegexp(ConanException, "Usage of Components with 'exe' or 'lib' " - "values is no allowed"): + info.libs = ["libgreet"] + with self.assertRaisesRegexp(ConanException, "Usage of Components with '.libs' values is " + "not allowed"): info["hola"].exe = "hola.exe" - info.exe = None - info["hola"].exe = "hola.exe" - with self.assertRaisesRegexp(ConanException, "Setting a first level exe is not supported " - "when Components are already in use"): - info.exe = "greet.exe" - def components_deps_test(self): - component = Component("OpenSSL") - component["OpenSSL"]["Crypto"]["SSL"] - component["OpenSSL"]["Other"] - component["Another"] - self.assertEqual(component.deps, ["OpenSSL", "Another"]) - self.assertEqual(component["OpenSSL"].deps, ["Crypto", "Other"]) - self.assertEqual(component["OpenSSL"]["Crypto"].deps, ["SSL"]) - self.assertEqual(component["Another"].deps, []) - self.assertEqual(component["OpenSSL"]["Other"].deps, []) - self.assertEqual(component["OpenSSL"]["Crypto"]["SSL"].deps, []) + info.libs = [] + info["greet"].exe = "libgreet" + with self.assertRaisesRegexp(ConanException, "Setting first level libs is not supported " + "when Components are already in use"): + info.libs = ["libgreet"] def cppinfo_components_test(self): folder = temp_folder() info = CppInfo(folder) info.name = "OpenSSL" info["OpenSSL"].includedirs = ["include"] - info["OpenSSL"]["Crypto"].includedirs = ["headers"] + info["Crypto"].includedirs = ["headers"] self.assertEqual(info["OpenSSL"].includedirs, ["include"]) - self.assertEqual(info["OpenSSL"]["Crypto"].includedirs, ["headers"]) + self.assertEqual(info["Crypto"].includedirs, ["headers"]) From 25a27764c2f3893109e2ed41dc88e0a12b3ffe64 Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Tue, 21 May 2019 17:59:24 +0200 Subject: [PATCH 05/47] implemented inheritance of includedir directory --- conans/model/build_info.py | 20 +++++++++++---- .../test/unittests/model/build_info_test.py | 25 ++++++++++++++----- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/conans/model/build_info.py b/conans/model/build_info.py index 7970035be0f..c06e0d94729 100644 --- a/conans/model/build_info.py +++ b/conans/model/build_info.py @@ -141,7 +141,7 @@ def __getitem__(self, key): if self._libs: raise ConanException("Usage of Components with '.libs' values is not allowed") if key not in self._deps.keys(): - self._deps[key] = Component(key) + self._deps[key] = Component(self, key) return self._deps[key] def __getattr__(self, config): @@ -162,13 +162,14 @@ def _get_cpp_info(): class Component(object): - def __init__(self, name): + def __init__(self, parent, name): + self._parent = parent self.name = name self.deps = [] self._lib = None self._exe = None self.system_deps = [] - self.includedirs = [] + self._includedirs = [] self.libdirs = [] self.resdirs = [] self.bindirs = [] @@ -187,7 +188,7 @@ def lib(self): @lib.setter def lib(self, name): if self._exe: - raise ConanException("exe is already set") + raise ConanException("'.exe' is already set for this Component") self._lib = name @property @@ -197,9 +198,18 @@ def exe(self): @exe.setter def exe(self, name): if self._lib: - raise ConanException("lib is already set") + raise ConanException("'.lib' is already set for this Component") self._exe = name + @property + def includedirs(self): + includedirs = self._parent.includedirs + self._includedirs + return list(OrderedDict.fromkeys(includedirs)) + + @includedirs.setter + def includedirs(self, value): + self._includedirs = value + class _BaseDepsCppInfo(_CppInfo): def __init__(self): diff --git a/conans/test/unittests/model/build_info_test.py b/conans/test/unittests/model/build_info_test.py index e76add10467..0c123aa24ac 100644 --- a/conans/test/unittests/model/build_info_test.py +++ b/conans/test/unittests/model/build_info_test.py @@ -176,16 +176,17 @@ def cpp_info_test(self): os.path.join(folder, "local_bindir")]) def basic_components_test(self): - component = Component("my_component") + cpp_info = CppInfo(None) + component = cpp_info["my_component"] self.assertIn(component.name, "my_component") component.lib = "libhola" self.assertEquals(component.lib, "libhola") - with self.assertRaisesRegexp(ConanException, "lib is already set"): + with self.assertRaisesRegexp(ConanException, "'.lib' is already set for this Component"): component.exe = "hola.exe" component.lib = None component.exe = "hola.exe" self.assertEquals(component.lib, None) - with self.assertRaisesRegexp(ConanException, "exe is already set"): + with self.assertRaisesRegexp(ConanException, "'.exe' is already set for this Component"): component.lib = "libhola" def cpp_info_libs_components_fail_test(self): @@ -206,11 +207,23 @@ def cpp_info_libs_components_fail_test(self): "when Components are already in use"): info.libs = ["libgreet"] - def cppinfo_components_test(self): + def cppinfo_includedirs_test(self): folder = temp_folder() info = CppInfo(folder) info.name = "OpenSSL" info["OpenSSL"].includedirs = ["include"] info["Crypto"].includedirs = ["headers"] - self.assertEqual(info["OpenSSL"].includedirs, ["include"]) - self.assertEqual(info["Crypto"].includedirs, ["headers"]) + self.assertEqual(["include"], info["OpenSSL"].includedirs) + self.assertEqual(["include", "headers"], info["Crypto"].includedirs) + + info.includedirs = ["my_headers"] + self.assertEqual(["my_headers", "include"], info["OpenSSL"].includedirs) + self.assertEqual(["my_headers", "headers"], info["Crypto"].includedirs) + + info["Crypto"].includedirs = ["different_include"] + self.assertEqual(["my_headers", "different_include"], info["Crypto"].includedirs) + + info["Crypto"].includedirs.extend(["another_include"]) + # FIXME: + # self.assertEqual(["my_headers", "different_include", "another_include"], + # info["Crypto"].includedirs) From a100bc26eff135ddc9ef633e7303fea2d6b2e12f Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Wed, 22 May 2019 11:17:15 +0200 Subject: [PATCH 06/47] comment --- conans/test/unittests/model/build_info_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conans/test/unittests/model/build_info_test.py b/conans/test/unittests/model/build_info_test.py index 0c123aa24ac..16398d21c48 100644 --- a/conans/test/unittests/model/build_info_test.py +++ b/conans/test/unittests/model/build_info_test.py @@ -223,7 +223,7 @@ def cppinfo_includedirs_test(self): info["Crypto"].includedirs = ["different_include"] self.assertEqual(["my_headers", "different_include"], info["Crypto"].includedirs) - info["Crypto"].includedirs.extend(["another_include"]) # FIXME: + # info["Crypto"].includedirs.extend(["another_include"]) # self.assertEqual(["my_headers", "different_include", "another_include"], # info["Crypto"].includedirs) From e43b44268a37af578d9b6950c4bb2e254191f35c Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Tue, 28 May 2019 13:36:39 +0200 Subject: [PATCH 07/47] Directory propagation and integration test --- conans/model/build_info.py | 44 ++++++++++++++++-- conans/test/integration/package_info_test.py | 46 +++++++++++++++++++ .../test/unittests/model/build_info_test.py | 34 +++++++++++++- 3 files changed, 119 insertions(+), 5 deletions(-) diff --git a/conans/model/build_info.py b/conans/model/build_info.py index c06e0d94729..5772525f40a 100644 --- a/conans/model/build_info.py +++ b/conans/model/build_info.py @@ -170,10 +170,10 @@ def __init__(self, parent, name): self._exe = None self.system_deps = [] self._includedirs = [] - self.libdirs = [] - self.resdirs = [] - self.bindirs = [] - self.builddirs = [] + self._libdirs = [] + self._resdirs = [] + self._bindirs = [] + self._builddirs = [] self.defines = [] self.cflags = [] self.cppflags = [] @@ -210,6 +210,42 @@ def includedirs(self): def includedirs(self, value): self._includedirs = value + @property + def libdirs(self): + libdirs = self._parent.libdirs + self._libdirs + return list(OrderedDict.fromkeys(libdirs)) + + @libdirs.setter + def libdirs(self, value): + self._libdirs = value + + @property + def resdirs(self): + resdirs = self._parent.resdirs + self._resdirs + return list(OrderedDict.fromkeys(resdirs)) + + @resdirs.setter + def resdirs(self, value): + self._resdirs = value + + @property + def bindirs(self): + bindirs = self._parent.bindirs + self._bindirs + return list(OrderedDict.fromkeys(bindirs)) + + @bindirs.setter + def bindirs(self, value): + self._bindirs = value + + @property + def builddirs(self): + builddirs = self._parent.builddirs + self._builddirs + return list(OrderedDict.fromkeys(builddirs)) + + @builddirs.setter + def builddirs(self, value): + self._builddirs = value + class _BaseDepsCppInfo(_CppInfo): def __init__(self): diff --git a/conans/test/integration/package_info_test.py b/conans/test/integration/package_info_test.py index dad8b6ad4f0..22f6d0c3f7d 100644 --- a/conans/test/integration/package_info_test.py +++ b/conans/test/integration/package_info_test.py @@ -1,3 +1,4 @@ +import textwrap import unittest from conans.paths import CONANFILE, CONANFILE_TXT @@ -46,3 +47,48 @@ def package_info(self): client.run("install . -o *:switch=0 --build Lib3") self.assertIn("Lib3/1.0@conan/stable: WARN: Env var MYVAR=foo", client.out) + + def package_info_components_test(self): + dep = textwrap.dedent(""" + from conans import ConanFile + + class Dep(ConanFile): + + def package_info(self): + self.cpp_info.name = "Boost" + self.cpp_info.includedirs = ["boost"] + self.cpp_info["Accumulators"].includedirs = ["boost/accumulators"] + self.cpp_info["Accumulators"].lib = "libaccumulators" + self.cpp_info["Containers"].includedirs = ["boost/containers"] + self.cpp_info["Containers"].lib = "libcontainers" + self.cpp_info["Containers"].deps = ["Accumulators"] + self.cpp_info["SuperContainers"].includedirs = ["boost/supercontainers"] + self.cpp_info["SuperContainers"].lib = "libsupercontainers" + self.cpp_info["SuperContainers"].deps = ["Containers"] + """) + consumer = textwrap.dedent(""" + from conans import ConanFile + + class Consumer(ConanFile): + requires = "dep/1.0@us/ch" + + def build(self): + acc_includes = self.deps_cpp_info["dep"]["Accumulators"].includedirs + con_include = self.deps_cpp_info["dep"]["Containers"].includedirs + sup_include = self.deps_cpp_info["dep"]["SuperContainers"].includedirs + self.output.info("Name: %s" % self.deps_cpp_info["dep"].name) + self.output.info("Accumulators: %s" % acc_includes) + self.output.info("Containers: %s" % con_include) + self.output.info("SuperContainers: %s" % sup_include) + self.output.info("LIBS: %s" % self.deps_cpp_info["dep"].libs) + """) + + client = TestClient() + client.save({"conanfile_dep.py": dep, "conanfile_consumer.py": consumer}) + client.run("create conanfile_dep.py dep/1.0@us/ch") + client.run("create conanfile_consumer.py consumer/1.0@us/ch") + self.assertIn("Name: Boost", client.out) + self.assertIn("Accumulators: ['boost', 'boost/accumulators']", client.out) + self.assertIn("Containers: ['boost', 'boost/containers']", client.out) + self.assertIn("SuperContainers: ['boost', 'boost/supercontainers']", client.out) + self.assertIn("LIBS: ['libaccumulators', 'libcontainers', 'libsupercontainers']", client.out) diff --git a/conans/test/unittests/model/build_info_test.py b/conans/test/unittests/model/build_info_test.py index 16398d21c48..3958bcfb2a3 100644 --- a/conans/test/unittests/model/build_info_test.py +++ b/conans/test/unittests/model/build_info_test.py @@ -207,20 +207,52 @@ def cpp_info_libs_components_fail_test(self): "when Components are already in use"): info.libs = ["libgreet"] - def cppinfo_includedirs_test(self): + def cppinfo_dirs_test(self): folder = temp_folder() info = CppInfo(folder) info.name = "OpenSSL" info["OpenSSL"].includedirs = ["include"] + info["OpenSSL"].libdirs = ["lib"] + info["OpenSSL"].builddirs = ["build"] + info["OpenSSL"].bindirs = ["bin"] + info["OpenSSL"].resdirs = ["res"] info["Crypto"].includedirs = ["headers"] + info["Crypto"].libdirs = ["libraries"] + info["Crypto"].builddirs = ["build_scripts"] + info["Crypto"].bindirs = ["binaries"] + info["Crypto"].resdirs = ["resources"] self.assertEqual(["include"], info["OpenSSL"].includedirs) + self.assertEqual(["lib"], info["OpenSSL"].libdirs) + self.assertEqual(["", "build"], info["OpenSSL"].builddirs) + self.assertEqual(["bin"], info["OpenSSL"].bindirs) + self.assertEqual(["res"], info["OpenSSL"].resdirs) self.assertEqual(["include", "headers"], info["Crypto"].includedirs) + self.assertEqual(["lib", "libraries"], info["Crypto"].libdirs) + self.assertEqual(["", "build_scripts"], info["Crypto"].builddirs) + self.assertEqual(["bin", "binaries"], info["Crypto"].bindirs) + self.assertEqual(["res", "resources"], info["Crypto"].resdirs) info.includedirs = ["my_headers"] + info.libdirs = ["my_libraries"] + info.builddirs = ["my_build_scripts"] + info.bindirs = ["my_binaries"] + info.resdirs = ["my_resources"] self.assertEqual(["my_headers", "include"], info["OpenSSL"].includedirs) + self.assertEqual(["my_libraries", "lib"], info["OpenSSL"].libdirs) + self.assertEqual(["my_build_scripts", "build"], info["OpenSSL"].builddirs) + self.assertEqual(["my_binaries", "bin"], info["OpenSSL"].bindirs) + self.assertEqual(["my_resources", "res"], info["OpenSSL"].resdirs) self.assertEqual(["my_headers", "headers"], info["Crypto"].includedirs) + self.assertEqual(["my_libraries", "libraries"], info["Crypto"].libdirs) + self.assertEqual(["my_build_scripts", "build_scripts"], info["Crypto"].builddirs) + self.assertEqual(["my_binaries", "binaries"], info["Crypto"].bindirs) + self.assertEqual(["my_resources", "resources"], info["Crypto"].resdirs) info["Crypto"].includedirs = ["different_include"] + info["Crypto"].libdirs = ["different_lib"] + info["Crypto"].builddirs = ["different_build"] + info["Crypto"].bindirs = ["different_bin"] + info["Crypto"].resdirs = ["different_res"] self.assertEqual(["my_headers", "different_include"], info["Crypto"].includedirs) # FIXME: From 14dc5040b73aada340f144ff68ba17a4efdc3f57 Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Tue, 28 May 2019 18:10:48 +0200 Subject: [PATCH 08/47] Introduced DirList and completed tests --- conans/model/build_info.py | 47 +++++++++++++++---- .../test/unittests/model/build_info_test.py | 42 +++++++++++++++-- 2 files changed, 74 insertions(+), 15 deletions(-) diff --git a/conans/model/build_info.py b/conans/model/build_info.py index 5772525f40a..7a7a26cac26 100644 --- a/conans/model/build_info.py +++ b/conans/model/build_info.py @@ -203,8 +203,7 @@ def exe(self, name): @property def includedirs(self): - includedirs = self._parent.includedirs + self._includedirs - return list(OrderedDict.fromkeys(includedirs)) + return DirList(self._parent.includedirs, self._includedirs) @includedirs.setter def includedirs(self, value): @@ -212,8 +211,7 @@ def includedirs(self, value): @property def libdirs(self): - libdirs = self._parent.libdirs + self._libdirs - return list(OrderedDict.fromkeys(libdirs)) + return DirList(self._parent.libdirs, self._libdirs) @libdirs.setter def libdirs(self, value): @@ -221,8 +219,7 @@ def libdirs(self, value): @property def resdirs(self): - resdirs = self._parent.resdirs + self._resdirs - return list(OrderedDict.fromkeys(resdirs)) + return DirList(self._parent.resdirs, self._resdirs) @resdirs.setter def resdirs(self, value): @@ -230,8 +227,7 @@ def resdirs(self, value): @property def bindirs(self): - bindirs = self._parent.bindirs + self._bindirs - return list(OrderedDict.fromkeys(bindirs)) + return DirList(self._parent.bindirs, self._bindirs) @bindirs.setter def bindirs(self, value): @@ -239,14 +235,45 @@ def bindirs(self, value): @property def builddirs(self): - builddirs = self._parent.builddirs + self._builddirs - return list(OrderedDict.fromkeys(builddirs)) + return DirList(self._parent.builddirs, self._builddirs) @builddirs.setter def builddirs(self, value): self._builddirs = value +class DirList(object): + + def __init__(self, inherited_dirs=None, dirs=None): + self._inherited_dirs = inherited_dirs or [] + self._dirs = dirs or [] + + @property + def _complete_list(self): + return list(OrderedDict.fromkeys(self._inherited_dirs + self._dirs)) + + def append(self, directory): + self._dirs.append(directory) + + def extend(self, directories): + self._dirs.extend(directories) + + def __getitem__(self, index): + return self._complete_list[index] + + def __repr__(self): + return str(self._complete_list) + + def __eq__(self, other): + return self._complete_list == other + + def __len__(self): + return len(self._complete_list) + + def insert(self, index, directory): + self._dirs.insert(index, directory) + + class _BaseDepsCppInfo(_CppInfo): def __init__(self): super(_BaseDepsCppInfo, self).__init__() diff --git a/conans/test/unittests/model/build_info_test.py b/conans/test/unittests/model/build_info_test.py index 3958bcfb2a3..8902d9a0546 100644 --- a/conans/test/unittests/model/build_info_test.py +++ b/conans/test/unittests/model/build_info_test.py @@ -4,7 +4,7 @@ from conans.client.generators import TXTGenerator from conans.errors import ConanException -from conans.model.build_info import CppInfo, DepsCppInfo, Component +from conans.model.build_info import CppInfo, DepsCppInfo, Component, DirList from conans.model.env_info import DepsEnvInfo, EnvInfo from conans.model.user_info import DepsUserInfo from conans.test.utils.test_files import temp_folder @@ -254,8 +254,40 @@ def cppinfo_dirs_test(self): info["Crypto"].bindirs = ["different_bin"] info["Crypto"].resdirs = ["different_res"] self.assertEqual(["my_headers", "different_include"], info["Crypto"].includedirs) + self.assertEqual(["my_libraries", "different_lib"], info["Crypto"].libdirs) + self.assertEqual(["my_build_scripts", "different_build"], info["Crypto"].builddirs) + self.assertEqual(["my_binaries", "different_bin"], info["Crypto"].bindirs) + self.assertEqual(["my_resources", "different_res"], info["Crypto"].resdirs) - # FIXME: - # info["Crypto"].includedirs.extend(["another_include"]) - # self.assertEqual(["my_headers", "different_include", "another_include"], - # info["Crypto"].includedirs) + info["Crypto"].includedirs.extend(["another_include"]) + info["Crypto"].includedirs.append("another_other_include") + info["Crypto"].libdirs.extend(["another_lib"]) + info["Crypto"].libdirs.append("another_other_lib") + info["Crypto"].builddirs.extend(["another_build"]) + info["Crypto"].builddirs.append("another_other_build") + info["Crypto"].bindirs.extend(["another_bin"]) + info["Crypto"].bindirs.append("another_other_bin") + info["Crypto"].resdirs.extend(["another_res"]) + info["Crypto"].resdirs.append("another_other_res") + self.assertEqual(["my_headers", "different_include", "another_include", + "another_other_include"], info["Crypto"].includedirs) + self.assertEqual(["my_libraries", "different_lib", "another_lib", "another_other_lib"], + info["Crypto"].libdirs) + self.assertEqual(["my_build_scripts", "different_build", "another_build", + "another_other_build"], info["Crypto"].builddirs) + self.assertEqual(["my_binaries", "different_bin", "another_bin", "another_other_bin"], + info["Crypto"].bindirs) + self.assertEqual(["my_resources", "different_res", "another_res", "another_other_res"], + info["Crypto"].resdirs) + + def dirlist_test(self): + dirlist = DirList(["inc0"], ["inc1"]) + dirlist.append("inc2") + self.assertEqual(["inc0", "inc1", "inc2"], dirlist) + dirlist.extend(["inc3", "inc4"]) + self.assertEqual(["inc0", "inc1", "inc2", "inc3", "inc4"], dirlist) + + dirlist.insert(0, "inc5") + self.assertEqual(["inc0", "inc5", "inc1", "inc2", "inc3", "inc4"], dirlist) + dirlist.insert(2, "inc6") + self.assertEqual(["inc0", "inc5", "inc1", "inc6", "inc2", "inc3", "inc4"], dirlist) From b00a93c21cb987a954caeb31a87feb9df49ce624 Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Wed, 29 May 2019 17:20:44 +0200 Subject: [PATCH 09/47] small changes for paths --- conans/model/build_info.py | 34 +++++++++++++++++-- conans/test/integration/package_info_test.py | 14 ++++++-- .../test/unittests/model/build_info_test.py | 8 ++--- 3 files changed, 48 insertions(+), 8 deletions(-) diff --git a/conans/model/build_info.py b/conans/model/build_info.py index 7a7a26cac26..44eb6117a81 100644 --- a/conans/model/build_info.py +++ b/conans/model/build_info.py @@ -45,6 +45,30 @@ def __init__(self): self.description = None # Description of the conan package # When package is editable, filter_empty=False, so empty dirs are maintained self.filter_empty = True + self._deps = OrderedDict() + + @property + def libs(self): + if self._deps: + deps = [v for v in self._deps.values()] + deps_sorted = sorted(deps, key=lambda component: len(component.deps)) + return [dep.lib for dep in deps_sorted if dep.lib is not None] + else: + return self._libs + + @libs.setter + def libs(self, libs): + if self._deps: + raise ConanException("Setting first level libs is not supported when Components are " + "already in use") + self._libs = libs + + def __getitem__(self, key): + if self._libs: + raise ConanException("Usage of Components with '.libs' values is not allowed") + if key not in self._deps.keys(): + self._deps[key] = Component(self, key) + return self._deps[key] def _filter_paths(self, paths): abs_paths = [os.path.join(self.rootpath, p) @@ -57,7 +81,12 @@ def _filter_paths(self, paths): @property def include_paths(self): if self._include_paths is None: - self._include_paths = self._filter_paths(self.includedirs) + includedirs = self.includedirs + for key, value in self._deps.items(): + for directory in value.includedirs: + if directory not in includedirs: + includedirs.append(directory) + self._include_paths = self._filter_paths(includedirs) return self._include_paths @property @@ -275,6 +304,7 @@ def insert(self, index, directory): class _BaseDepsCppInfo(_CppInfo): + def __init__(self): super(_BaseDepsCppInfo, self).__init__() @@ -289,7 +319,7 @@ def merge_lists(seq1, seq2): self.bindirs = merge_lists(self.bindirs, dep_cpp_info.bin_paths) self.resdirs = merge_lists(self.resdirs, dep_cpp_info.res_paths) self.builddirs = merge_lists(self.builddirs, dep_cpp_info.build_paths) - self.libs = merge_lists(self.libs, dep_cpp_info.libs) + self.libs = merge_lists(self.libs, dep_cpp_info._libs) self.rootpaths.append(dep_cpp_info.rootpath) # Note these are in reverse order diff --git a/conans/test/integration/package_info_test.py b/conans/test/integration/package_info_test.py index 22f6d0c3f7d..c875be81762 100644 --- a/conans/test/integration/package_info_test.py +++ b/conans/test/integration/package_info_test.py @@ -20,7 +20,7 @@ class HelloConan(ConanFile): options = {"switch": ["1", "0"]} default_options = "switch=0" %s - + def build(self): self.output.warn("Env var MYVAR={0}.".format(os.getenv("MYVAR", ""))) @@ -53,6 +53,10 @@ def package_info_components_test(self): from conans import ConanFile class Dep(ConanFile): + exports_sources = "*" + + def package(self): + self.copy("*") def package_info(self): self.cpp_info.name = "Boost" @@ -81,10 +85,16 @@ def build(self): self.output.info("Containers: %s" % con_include) self.output.info("SuperContainers: %s" % sup_include) self.output.info("LIBS: %s" % self.deps_cpp_info["dep"].libs) + print("INCLUDE_PATHS: %s" % self.deps_cpp_info["dep"].include_paths) + print("INCLUDE_PATHS: %s" % self.deps_cpp_info.include_paths) """) client = TestClient() - client.save({"conanfile_dep.py": dep, "conanfile_consumer.py": consumer}) + client.save({"conanfile_dep.py": dep, "conanfile_consumer.py": consumer, + "boost/boost.h": "", + "boost/accumulators/accumulators.h": "", + "boost/containers/containers.h": "", + "boost/supercontainers/supercontainers.h": ""}) client.run("create conanfile_dep.py dep/1.0@us/ch") client.run("create conanfile_consumer.py consumer/1.0@us/ch") self.assertIn("Name: Boost", client.out) diff --git a/conans/test/unittests/model/build_info_test.py b/conans/test/unittests/model/build_info_test.py index 8902d9a0546..3cc86385b32 100644 --- a/conans/test/unittests/model/build_info_test.py +++ b/conans/test/unittests/model/build_info_test.py @@ -180,13 +180,13 @@ def basic_components_test(self): component = cpp_info["my_component"] self.assertIn(component.name, "my_component") component.lib = "libhola" - self.assertEquals(component.lib, "libhola") - with self.assertRaisesRegexp(ConanException, "'.lib' is already set for this Component"): + self.assertEqual(component.lib, "libhola") + with self.assertRaisesRegex(ConanException, "'.lib' is already set for this Component"): component.exe = "hola.exe" component.lib = None component.exe = "hola.exe" - self.assertEquals(component.lib, None) - with self.assertRaisesRegexp(ConanException, "'.exe' is already set for this Component"): + self.assertEqual(component.lib, None) + with self.assertRaisesRegex(ConanException, "'.exe' is already set for this Component"): component.lib = "libhola" def cpp_info_libs_components_fail_test(self): From 9b53334842c5852b562192604629a2e8e84bff08 Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Thu, 13 Jun 2019 18:37:48 +0200 Subject: [PATCH 10/47] Removed DirList and added system_deps --- conans/model/build_info.py | 201 +++++++++--------- conans/test/integration/package_info_test.py | 28 ++- .../test/unittests/model/build_info_test.py | 88 ++++---- 3 files changed, 162 insertions(+), 155 deletions(-) diff --git a/conans/model/build_info.py b/conans/model/build_info.py index 44eb6117a81..ffe26601cc7 100644 --- a/conans/model/build_info.py +++ b/conans/model/build_info.py @@ -10,6 +10,7 @@ DEFAULT_BIN = "bin" DEFAULT_RES = "res" DEFAULT_SHARE = "share" +DEFAULT_BUILD = "" class _CppInfo(object): @@ -28,6 +29,7 @@ def __init__(self): self.builddirs = [] self.rootpaths = [] self._libs = [] # The libs to link against + self._exes = [] self.defines = [] # preprocessor definitions self.cflags = [] # pure C flags self.cxxflags = [] # C++ compilation flags @@ -63,6 +65,21 @@ def libs(self, libs): "already in use") self._libs = libs + @property + def exes(self): + if self._deps: + deps = [v for v in self._deps.values()] + return [dep.exe for dep in deps if dep.exe is not None] + else: + return self._exes + + @exes.setter + def libs(self, libs): + if self._deps: + raise ConanException("Setting first level exes is not supported when Components are " + "already in use") + self._exes = exes + def __getitem__(self, key): if self._libs: raise ConanException("Usage of Components with '.libs' values is not allowed") @@ -78,46 +95,41 @@ def _filter_paths(self, paths): else: return abs_paths + def _get_paths(self, path_name): + if getattr(self, "_%s_paths" % path_name) is None: + if self._deps: + self.__dict__["_%s_paths" % path_name] = [] + for dep_value in self._deps.values(): + self.__dict__["_%s_paths" % path_name].extend( + self._filter_paths(getattr(dep_value, "%s_paths" % path_name))) + else: + self.__dict__["_%s_paths" % path_name] = self._filter_paths( + getattr(self, "%sdirs" % path_name)) + return getattr(self, "_%s_paths" % path_name) + @property def include_paths(self): - if self._include_paths is None: - includedirs = self.includedirs - for key, value in self._deps.items(): - for directory in value.includedirs: - if directory not in includedirs: - includedirs.append(directory) - self._include_paths = self._filter_paths(includedirs) - return self._include_paths + return self._get_paths("include") @property def lib_paths(self): - if self._lib_paths is None: - self._lib_paths = self._filter_paths(self.libdirs) - return self._lib_paths + return self._get_paths("lib") @property def src_paths(self): - if self._src_paths is None: - self._src_paths = self._filter_paths(self.srcdirs) - return self._src_paths + return self._get_paths("src") @property def bin_paths(self): - if self._bin_paths is None: - self._bin_paths = self._filter_paths(self.bindirs) - return self._bin_paths + return self._get_paths("bin") @property def build_paths(self): - if self._build_paths is None: - self._build_paths = self._filter_paths(self.builddirs) - return self._build_paths + return self._get_paths("build") @property def res_paths(self): - if self._res_paths is None: - self._res_paths = self._filter_paths(self.resdirs) - return self._res_paths + return self._get_paths("res") # Compatibility for 'cppflags' (old style property to allow decoration) @deprecation.deprecated(deprecated_in="1.13", removed_in="2.0", details="Use 'cxxflags' instead") @@ -144,18 +156,52 @@ def __init__(self, root_folder): self.libdirs.append(DEFAULT_LIB) self.bindirs.append(DEFAULT_BIN) self.resdirs.append(DEFAULT_RES) - self.builddirs.append("") + self.builddirs.append(DEFAULT_BUILD) # public_deps is needed to accumulate list of deps for cmake targets self.public_deps = [] self.configs = {} self._deps = OrderedDict() + def _check_dirs_values(self): + default_dirs_mapping = { + "includedirs": [DEFAULT_INCLUDE], + "libdirs": [DEFAULT_LIB], + "bindirs": [DEFAULT_BIN], + "resdirs": [DEFAULT_RES], + "builddirs": [DEFAULT_BUILD], + "srcdirs": [] + } + msg_template = "Using Components and global '{}' values ('{}') is not supported" + for dir_name in ["includedirs", "libdirs", "bindirs", "builddirs"]: + dirs_value = getattr(self, dir_name) + if dirs_value is not None and dirs_value != default_dirs_mapping[dir_name]: + raise ConanException(msg_template.format(dir_name, dirs_value)) + + def _clear_dirs_values(self): + default_dirs_mapping = { + "includedirs": [DEFAULT_INCLUDE], + "libdirs": [DEFAULT_LIB], + "bindirs": [DEFAULT_BIN], + "resdirs": [DEFAULT_RES], + "builddirs": [DEFAULT_BUILD], + "srcdirs": [] + } + for dir_name in ["includedirs", "libdirs", "bindirs", "builddirs"]: + if getattr(self, dir_name) == default_dirs_mapping[dir_name]: + self.__dict__[dir_name] = None + @property def libs(self): if self._deps: deps = [v for v in self._deps.values()] deps_sorted = sorted(deps, key=lambda component: len(component.deps)) - return [dep.lib for dep in deps_sorted if dep.lib is not None] + result = [] + for dep in deps_sorted: + for sys_dep in dep.system_deps: + if sys_dep not in result: + result.append(sys_dep) + result.append(dep.lib) + return result else: return self._libs @@ -167,10 +213,12 @@ def libs(self, libs): self._libs = libs def __getitem__(self, key): - if self._libs: - raise ConanException("Usage of Components with '.libs' values is not allowed") + if self._libs or self._exes: + raise ConanException("Usage of Components with '.libs' or '.exes' values is not allowed") + self._clear_dirs_values() + self._check_dirs_values() if key not in self._deps.keys(): - self._deps[key] = Component(self, key) + self._deps[key] = Component(key, self.rootpath) return self._deps[key] def __getattr__(self, config): @@ -191,24 +239,34 @@ def _get_cpp_info(): class Component(object): - def __init__(self, parent, name): - self._parent = parent + def __init__(self, name, root_folder): + self._rootpath = root_folder self.name = name self.deps = [] self._lib = None self._exe = None self.system_deps = [] - self._includedirs = [] - self._libdirs = [] - self._resdirs = [] - self._bindirs = [] - self._builddirs = [] + self.includedirs = [] + self.libdirs = [] + self.resdirs = [] + self.bindirs = [] + self.builddirs = [] + self.srcdirs = [] self.defines = [] self.cflags = [] self.cppflags = [] self.cxxflags = [] self.sharedlinkflags = [] self.exelinkflags = [] + self._filter_empty = True + + def _filter_paths(self, paths): + abs_paths = [os.path.join(self._rootpath, p) + if not os.path.isabs(p) else p for p in paths] + if self._filter_empty: + return [p for p in abs_paths if os.path.isdir(p)] + else: + return abs_paths @property def lib(self): @@ -231,76 +289,28 @@ def exe(self, name): self._exe = name @property - def includedirs(self): - return DirList(self._parent.includedirs, self._includedirs) - - @includedirs.setter - def includedirs(self, value): - self._includedirs = value + def include_paths(self): + return self._filter_paths(self.includedirs) @property - def libdirs(self): - return DirList(self._parent.libdirs, self._libdirs) - - @libdirs.setter - def libdirs(self, value): - self._libdirs = value + def lib_paths(self): + return self._filter_paths(self.libdirs) @property - def resdirs(self): - return DirList(self._parent.resdirs, self._resdirs) - - @resdirs.setter - def resdirs(self, value): - self._resdirs = value + def bin_paths(self): + return self._filter_paths(self.bindirs) @property - def bindirs(self): - return DirList(self._parent.bindirs, self._bindirs) - - @bindirs.setter - def bindirs(self, value): - self._bindirs = value + def build_paths(self): + return self._filter_paths(self.builddirs) @property - def builddirs(self): - return DirList(self._parent.builddirs, self._builddirs) - - @builddirs.setter - def builddirs(self, value): - self._builddirs = value - - -class DirList(object): - - def __init__(self, inherited_dirs=None, dirs=None): - self._inherited_dirs = inherited_dirs or [] - self._dirs = dirs or [] + def res_paths(self): + return self._filter_paths(self.resdirs) @property - def _complete_list(self): - return list(OrderedDict.fromkeys(self._inherited_dirs + self._dirs)) - - def append(self, directory): - self._dirs.append(directory) - - def extend(self, directories): - self._dirs.extend(directories) - - def __getitem__(self, index): - return self._complete_list[index] - - def __repr__(self): - return str(self._complete_list) - - def __eq__(self, other): - return self._complete_list == other - - def __len__(self): - return len(self._complete_list) - - def insert(self, index, directory): - self._dirs.insert(index, directory) + def src_paths(self): + return self._filter_paths(self.srcdirs) class _BaseDepsCppInfo(_CppInfo): @@ -402,3 +412,4 @@ def update_deps_cpp_info(self, dep_cpp_info): assert isinstance(dep_cpp_info, DepsCppInfo) for pkg_name, cpp_info in dep_cpp_info.dependencies: self.update(cpp_info, pkg_name) + diff --git a/conans/test/integration/package_info_test.py b/conans/test/integration/package_info_test.py index c875be81762..f3872b7e1a8 100644 --- a/conans/test/integration/package_info_test.py +++ b/conans/test/integration/package_info_test.py @@ -1,8 +1,10 @@ +import os import textwrap import unittest +from conans.model.ref import ConanFileReference, PackageReference from conans.paths import CONANFILE, CONANFILE_TXT -from conans.test.utils.tools import TestClient +from conans.test.utils.tools import TestClient, NO_SETTINGS_PACKAGE_ID class TestPackageInfo(unittest.TestCase): @@ -50,6 +52,7 @@ def package_info(self): def package_info_components_test(self): dep = textwrap.dedent(""" + import os from conans import ConanFile class Dep(ConanFile): @@ -60,8 +63,7 @@ def package(self): def package_info(self): self.cpp_info.name = "Boost" - self.cpp_info.includedirs = ["boost"] - self.cpp_info["Accumulators"].includedirs = ["boost/accumulators"] + self.cpp_info["Accumulators"].includedirs = [os.path.join("boost", "accumulators")] self.cpp_info["Accumulators"].lib = "libaccumulators" self.cpp_info["Containers"].includedirs = ["boost/containers"] self.cpp_info["Containers"].lib = "libcontainers" @@ -77,9 +79,9 @@ class Consumer(ConanFile): requires = "dep/1.0@us/ch" def build(self): - acc_includes = self.deps_cpp_info["dep"]["Accumulators"].includedirs - con_include = self.deps_cpp_info["dep"]["Containers"].includedirs - sup_include = self.deps_cpp_info["dep"]["SuperContainers"].includedirs + acc_includes = self.deps_cpp_info["dep"]["Accumulators"].include_paths + con_include = self.deps_cpp_info["dep"]["Containers"].include_paths + sup_include = self.deps_cpp_info["dep"]["SuperContainers"].include_paths self.output.info("Name: %s" % self.deps_cpp_info["dep"].name) self.output.info("Accumulators: %s" % acc_includes) self.output.info("Containers: %s" % con_include) @@ -95,10 +97,18 @@ def build(self): "boost/accumulators/accumulators.h": "", "boost/containers/containers.h": "", "boost/supercontainers/supercontainers.h": ""}) + dep_ref = ConanFileReference("dep", "1.0", "us", "ch") + dep_pref = PackageReference(dep_ref, NO_SETTINGS_PACKAGE_ID) + print("package_folder1: ", client.cache.package_layout(dep_ref).package(dep_pref)) client.run("create conanfile_dep.py dep/1.0@us/ch") client.run("create conanfile_consumer.py consumer/1.0@us/ch") + package_folder = client.cache.package_layout(dep_ref).package(dep_pref) + accumulators_expected = os.path.join(package_folder, "boost", "accumulators") + print("package_folder2: ", client.cache.package_layout(dep_ref).package(dep_pref)) self.assertIn("Name: Boost", client.out) - self.assertIn("Accumulators: ['boost', 'boost/accumulators']", client.out) - self.assertIn("Containers: ['boost', 'boost/containers']", client.out) - self.assertIn("SuperContainers: ['boost', 'boost/supercontainers']", client.out) + print("EXPECTED: ", "Accumulators: ['%s']" % accumulators_expected) + print("RESULT: ", client.out) self.assertIn("LIBS: ['libaccumulators', 'libcontainers', 'libsupercontainers']", client.out) + #FIXME: self.assertIn("Accumulators: ['%s']" % accumulators_expected, client.out) + #FIXME: self.assertIn("Containers: ['boost', 'boost/containers']", client.out) + #FIXME: self.assertIn("SuperContainers: ['boost', 'boost/supercontainers']", client.out) diff --git a/conans/test/unittests/model/build_info_test.py b/conans/test/unittests/model/build_info_test.py index 3cc86385b32..c42e784a6d9 100644 --- a/conans/test/unittests/model/build_info_test.py +++ b/conans/test/unittests/model/build_info_test.py @@ -4,7 +4,7 @@ from conans.client.generators import TXTGenerator from conans.errors import ConanException -from conans.model.build_info import CppInfo, DepsCppInfo, Component, DirList +from conans.model.build_info import CppInfo, DepsCppInfo, Component from conans.model.env_info import DepsEnvInfo, EnvInfo from conans.model.user_info import DepsUserInfo from conans.test.utils.test_files import temp_folder @@ -170,6 +170,7 @@ def cpp_info_test(self): info.libdirs.append(abs_lib) info.bindirs.append(abs_bin) info.bindirs.append("local_bindir") + print("result: ", info.include_paths, info.lib_paths, info.bin_paths) self.assertEqual(info.include_paths, [os.path.join(folder, "include"), abs_include]) self.assertEqual(info.lib_paths, [os.path.join(folder, "lib"), abs_lib]) self.assertEqual(info.bin_paths, [abs_bin, @@ -181,12 +182,12 @@ def basic_components_test(self): self.assertIn(component.name, "my_component") component.lib = "libhola" self.assertEqual(component.lib, "libhola") - with self.assertRaisesRegex(ConanException, "'.lib' is already set for this Component"): + with self.assertRaisesRegexp(ConanException, "'.lib' is already set for this Component"): component.exe = "hola.exe" component.lib = None component.exe = "hola.exe" self.assertEqual(component.lib, None) - with self.assertRaisesRegex(ConanException, "'.exe' is already set for this Component"): + with self.assertRaisesRegexp(ConanException, "'.exe' is already set for this Component"): component.lib = "libhola" def cpp_info_libs_components_fail_test(self): @@ -197,8 +198,8 @@ def cpp_info_libs_components_fail_test(self): info.name = "Greetings" self.assertIn(info.name, "Greetings") info.libs = ["libgreet"] - with self.assertRaisesRegexp(ConanException, "Usage of Components with '.libs' values is " - "not allowed"): + with self.assertRaisesRegexp(ConanException, "Usage of Components with '.libs' or '.exes' " + "values is not allowed"): info["hola"].exe = "hola.exe" info.libs = [] @@ -207,6 +208,19 @@ def cpp_info_libs_components_fail_test(self): "when Components are already in use"): info.libs = ["libgreet"] + def cpp_info_libs_system_deps_order_test(self): + info = CppInfo(None) + info["LIB1"].lib = "lib1" + info["LIB1"].system_deps = ["sys1", "sys11"] + info["LIB1"].deps = ["LIB2"] + info["LIB2"].lib = "lib2" + info["LIB2"].system_deps = ["sys2"] + info["LIB1"].deps = ["LIB3"] + info["LIB3"].lib = "lib3" + info["LIB3"].system_deps = ["sys3", "sys2"] + self.assertEqual(['sys2', 'lib2', 'sys3', 'lib3', 'sys1', 'sys11', 'lib1'], info.libs) + print(info.libs) + def cppinfo_dirs_test(self): folder = temp_folder() info = CppInfo(folder) @@ -223,41 +237,25 @@ def cppinfo_dirs_test(self): info["Crypto"].resdirs = ["resources"] self.assertEqual(["include"], info["OpenSSL"].includedirs) self.assertEqual(["lib"], info["OpenSSL"].libdirs) - self.assertEqual(["", "build"], info["OpenSSL"].builddirs) + self.assertEqual(["build"], info["OpenSSL"].builddirs) self.assertEqual(["bin"], info["OpenSSL"].bindirs) self.assertEqual(["res"], info["OpenSSL"].resdirs) - self.assertEqual(["include", "headers"], info["Crypto"].includedirs) - self.assertEqual(["lib", "libraries"], info["Crypto"].libdirs) - self.assertEqual(["", "build_scripts"], info["Crypto"].builddirs) - self.assertEqual(["bin", "binaries"], info["Crypto"].bindirs) - self.assertEqual(["res", "resources"], info["Crypto"].resdirs) - - info.includedirs = ["my_headers"] - info.libdirs = ["my_libraries"] - info.builddirs = ["my_build_scripts"] - info.bindirs = ["my_binaries"] - info.resdirs = ["my_resources"] - self.assertEqual(["my_headers", "include"], info["OpenSSL"].includedirs) - self.assertEqual(["my_libraries", "lib"], info["OpenSSL"].libdirs) - self.assertEqual(["my_build_scripts", "build"], info["OpenSSL"].builddirs) - self.assertEqual(["my_binaries", "bin"], info["OpenSSL"].bindirs) - self.assertEqual(["my_resources", "res"], info["OpenSSL"].resdirs) - self.assertEqual(["my_headers", "headers"], info["Crypto"].includedirs) - self.assertEqual(["my_libraries", "libraries"], info["Crypto"].libdirs) - self.assertEqual(["my_build_scripts", "build_scripts"], info["Crypto"].builddirs) - self.assertEqual(["my_binaries", "binaries"], info["Crypto"].bindirs) - self.assertEqual(["my_resources", "resources"], info["Crypto"].resdirs) + self.assertEqual(["headers"], info["Crypto"].includedirs) + self.assertEqual(["libraries"], info["Crypto"].libdirs) + self.assertEqual(["build_scripts"], info["Crypto"].builddirs) + self.assertEqual(["binaries"], info["Crypto"].bindirs) + self.assertEqual(["resources"], info["Crypto"].resdirs) info["Crypto"].includedirs = ["different_include"] info["Crypto"].libdirs = ["different_lib"] info["Crypto"].builddirs = ["different_build"] info["Crypto"].bindirs = ["different_bin"] info["Crypto"].resdirs = ["different_res"] - self.assertEqual(["my_headers", "different_include"], info["Crypto"].includedirs) - self.assertEqual(["my_libraries", "different_lib"], info["Crypto"].libdirs) - self.assertEqual(["my_build_scripts", "different_build"], info["Crypto"].builddirs) - self.assertEqual(["my_binaries", "different_bin"], info["Crypto"].bindirs) - self.assertEqual(["my_resources", "different_res"], info["Crypto"].resdirs) + self.assertEqual(["different_include"], info["Crypto"].includedirs) + self.assertEqual(["different_lib"], info["Crypto"].libdirs) + self.assertEqual(["different_build"], info["Crypto"].builddirs) + self.assertEqual(["different_bin"], info["Crypto"].bindirs) + self.assertEqual(["different_res"], info["Crypto"].resdirs) info["Crypto"].includedirs.extend(["another_include"]) info["Crypto"].includedirs.append("another_other_include") @@ -269,25 +267,13 @@ def cppinfo_dirs_test(self): info["Crypto"].bindirs.append("another_other_bin") info["Crypto"].resdirs.extend(["another_res"]) info["Crypto"].resdirs.append("another_other_res") - self.assertEqual(["my_headers", "different_include", "another_include", - "another_other_include"], info["Crypto"].includedirs) - self.assertEqual(["my_libraries", "different_lib", "another_lib", "another_other_lib"], + self.assertEqual(["different_include", "another_include", "another_other_include"], + info["Crypto"].includedirs) + self.assertEqual(["different_lib", "another_lib", "another_other_lib"], info["Crypto"].libdirs) - self.assertEqual(["my_build_scripts", "different_build", "another_build", - "another_other_build"], info["Crypto"].builddirs) - self.assertEqual(["my_binaries", "different_bin", "another_bin", "another_other_bin"], + self.assertEqual(["different_build", "another_build", "another_other_build"], + info["Crypto"].builddirs) + self.assertEqual(["different_bin", "another_bin", "another_other_bin"], info["Crypto"].bindirs) - self.assertEqual(["my_resources", "different_res", "another_res", "another_other_res"], + self.assertEqual(["different_res", "another_res", "another_other_res"], info["Crypto"].resdirs) - - def dirlist_test(self): - dirlist = DirList(["inc0"], ["inc1"]) - dirlist.append("inc2") - self.assertEqual(["inc0", "inc1", "inc2"], dirlist) - dirlist.extend(["inc3", "inc4"]) - self.assertEqual(["inc0", "inc1", "inc2", "inc3", "inc4"], dirlist) - - dirlist.insert(0, "inc5") - self.assertEqual(["inc0", "inc5", "inc1", "inc2", "inc3", "inc4"], dirlist) - dirlist.insert(2, "inc6") - self.assertEqual(["inc0", "inc5", "inc1", "inc6", "inc2", "inc3", "inc4"], dirlist) From 61981a20d3335937217abada94bcb01b04dad2fe Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Fri, 14 Jun 2019 11:51:24 +0200 Subject: [PATCH 11/47] fix exes --- conans/model/build_info.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conans/model/build_info.py b/conans/model/build_info.py index ffe26601cc7..5e281ba6753 100644 --- a/conans/model/build_info.py +++ b/conans/model/build_info.py @@ -74,7 +74,7 @@ def exes(self): return self._exes @exes.setter - def libs(self, libs): + def exes(self, exes): if self._deps: raise ConanException("Setting first level exes is not supported when Components are " "already in use") From 55096381f28cf632bfc5f67654ab6920f17944fd Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Mon, 17 Jun 2019 11:44:02 +0200 Subject: [PATCH 12/47] fixed deprecation warning in tests --- conans/test/unittests/model/build_info_test.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/conans/test/unittests/model/build_info_test.py b/conans/test/unittests/model/build_info_test.py index c42e784a6d9..e0db89642db 100644 --- a/conans/test/unittests/model/build_info_test.py +++ b/conans/test/unittests/model/build_info_test.py @@ -1,4 +1,5 @@ import os +import six import unittest from collections import defaultdict, namedtuple @@ -182,12 +183,12 @@ def basic_components_test(self): self.assertIn(component.name, "my_component") component.lib = "libhola" self.assertEqual(component.lib, "libhola") - with self.assertRaisesRegexp(ConanException, "'.lib' is already set for this Component"): + with six.assertRaisesRegex(self, ConanException, "'.lib' is already set for this Component"): component.exe = "hola.exe" component.lib = None component.exe = "hola.exe" self.assertEqual(component.lib, None) - with self.assertRaisesRegexp(ConanException, "'.exe' is already set for this Component"): + with six.assertRaisesRegex(self, ConanException, "'.exe' is already set for this Component"): component.lib = "libhola" def cpp_info_libs_components_fail_test(self): @@ -198,14 +199,14 @@ def cpp_info_libs_components_fail_test(self): info.name = "Greetings" self.assertIn(info.name, "Greetings") info.libs = ["libgreet"] - with self.assertRaisesRegexp(ConanException, "Usage of Components with '.libs' or '.exes' " - "values is not allowed"): + with six.assertRaisesRegex(self, ConanException, "Usage of Components with '.libs' or " + "'.exes' values is not allowed"): info["hola"].exe = "hola.exe" info.libs = [] info["greet"].exe = "libgreet" - with self.assertRaisesRegexp(ConanException, "Setting first level libs is not supported " - "when Components are already in use"): + with six.assertRaisesRegex(self, ConanException, "Setting first level libs is not supported " + "when Components are already in use"): info.libs = ["libgreet"] def cpp_info_libs_system_deps_order_test(self): From f6df3651de8688a16329296ff5c465e5962c26b6 Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Mon, 17 Jun 2019 11:46:53 +0200 Subject: [PATCH 13/47] Fixed cpp_info libs value in json output --- conans/client/recorder/action_recorder.py | 5 +++-- conans/model/build_info.py | 5 ++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/conans/client/recorder/action_recorder.py b/conans/client/recorder/action_recorder.py index b5e81d89534..9efa287a76a 100644 --- a/conans/client/recorder/action_recorder.py +++ b/conans/client/recorder/action_recorder.py @@ -25,7 +25,7 @@ def _cpp_info_to_dict(cpp_info): doc = {} for it, value in vars(cpp_info).items(): - if it.startswith("_") or not value: + if (it.startswith("_") and it != "_libs") or not value: continue if it == "configs": @@ -35,7 +35,8 @@ def _cpp_info_to_dict(cpp_info): doc["configs"] = configs_data continue - doc[it] = value + key = "libs" if it == "_libs" else it + doc[key] = value return doc diff --git a/conans/model/build_info.py b/conans/model/build_info.py index 5e281ba6753..6d0a70e95af 100644 --- a/conans/model/build_info.py +++ b/conans/model/build_info.py @@ -54,9 +54,8 @@ def libs(self): if self._deps: deps = [v for v in self._deps.values()] deps_sorted = sorted(deps, key=lambda component: len(component.deps)) - return [dep.lib for dep in deps_sorted if dep.lib is not None] - else: - return self._libs + self._libs = [dep.lib for dep in deps_sorted if dep.lib is not None] + return self._libs @libs.setter def libs(self, libs): From e88b6f10da2ccec9085f22d2d523d4940ec3a809 Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Mon, 17 Jun 2019 12:35:32 +0200 Subject: [PATCH 14/47] fix test --- conans/test/integration/package_info_test.py | 23 +++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/conans/test/integration/package_info_test.py b/conans/test/integration/package_info_test.py index f3872b7e1a8..61bd9bea3dc 100644 --- a/conans/test/integration/package_info_test.py +++ b/conans/test/integration/package_info_test.py @@ -31,8 +31,8 @@ def package_info(self): self.env_info.MYVAR = "foo" else: self.env_info.MYVAR = "bar" - ''' + for index in range(4): requires = "requires = 'Lib%s/1.0@conan/stable'" % index if index > 0 else "" conanfile = conanfile_tmp % ("Lib%s" % (index + 1), requires) @@ -65,10 +65,11 @@ def package_info(self): self.cpp_info.name = "Boost" self.cpp_info["Accumulators"].includedirs = [os.path.join("boost", "accumulators")] self.cpp_info["Accumulators"].lib = "libaccumulators" - self.cpp_info["Containers"].includedirs = ["boost/containers"] + self.cpp_info["Containers"].includedirs = [os.path.join("boost", "containers")] self.cpp_info["Containers"].lib = "libcontainers" self.cpp_info["Containers"].deps = ["Accumulators"] - self.cpp_info["SuperContainers"].includedirs = ["boost/supercontainers"] + self.cpp_info["SuperContainers"].includedirs = [os.path.join("boost", + "supercontainers")] self.cpp_info["SuperContainers"].lib = "libsupercontainers" self.cpp_info["SuperContainers"].deps = ["Containers"] """) @@ -87,8 +88,6 @@ def build(self): self.output.info("Containers: %s" % con_include) self.output.info("SuperContainers: %s" % sup_include) self.output.info("LIBS: %s" % self.deps_cpp_info["dep"].libs) - print("INCLUDE_PATHS: %s" % self.deps_cpp_info["dep"].include_paths) - print("INCLUDE_PATHS: %s" % self.deps_cpp_info.include_paths) """) client = TestClient() @@ -99,16 +98,14 @@ def build(self): "boost/supercontainers/supercontainers.h": ""}) dep_ref = ConanFileReference("dep", "1.0", "us", "ch") dep_pref = PackageReference(dep_ref, NO_SETTINGS_PACKAGE_ID) - print("package_folder1: ", client.cache.package_layout(dep_ref).package(dep_pref)) client.run("create conanfile_dep.py dep/1.0@us/ch") client.run("create conanfile_consumer.py consumer/1.0@us/ch") package_folder = client.cache.package_layout(dep_ref).package(dep_pref) - accumulators_expected = os.path.join(package_folder, "boost", "accumulators") - print("package_folder2: ", client.cache.package_layout(dep_ref).package(dep_pref)) + accumulators_expected = [os.path.join(package_folder, "boost", "accumulators")] + containers_expected = [os.path.join(package_folder, "boost", "containers")] + supercontainers_expected = [os.path.join(package_folder, "boost", "supercontainers")] self.assertIn("Name: Boost", client.out) - print("EXPECTED: ", "Accumulators: ['%s']" % accumulators_expected) - print("RESULT: ", client.out) self.assertIn("LIBS: ['libaccumulators', 'libcontainers', 'libsupercontainers']", client.out) - #FIXME: self.assertIn("Accumulators: ['%s']" % accumulators_expected, client.out) - #FIXME: self.assertIn("Containers: ['boost', 'boost/containers']", client.out) - #FIXME: self.assertIn("SuperContainers: ['boost', 'boost/supercontainers']", client.out) + self.assertIn("Accumulators: %s" % accumulators_expected, client.out) + self.assertIn("Containers: %s" % containers_expected, client.out) + self.assertIn("SuperContainers: %s" % supercontainers_expected, client.out) From 6c8bd403a8c21da7de734f9f0982fa333a4f1724 Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Wed, 19 Jun 2019 11:08:12 +0200 Subject: [PATCH 15/47] Add description to _get_paths() --- conans/model/build_info.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/conans/model/build_info.py b/conans/model/build_info.py index 6d0a70e95af..e08654a16cb 100644 --- a/conans/model/build_info.py +++ b/conans/model/build_info.py @@ -95,6 +95,13 @@ def _filter_paths(self, paths): return abs_paths def _get_paths(self, path_name): + """ + Get the absolute paths either composing the lists from components or from the global + variables. Also filter the values checking if the folders exist or not. This paths are + calculated once and then the result is cached. + :param path_name: name of the path variable to get (include_paths, res_paths...) + :return: List of absolute paths + """ if getattr(self, "_%s_paths" % path_name) is None: if self._deps: self.__dict__["_%s_paths" % path_name] = [] From 831172c97f5d279debd1344132db0ae05189985d Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Wed, 19 Jun 2019 11:08:55 +0200 Subject: [PATCH 16/47] removed prints --- conans/test/unittests/model/build_info_test.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/conans/test/unittests/model/build_info_test.py b/conans/test/unittests/model/build_info_test.py index e0db89642db..cec1e3b6478 100644 --- a/conans/test/unittests/model/build_info_test.py +++ b/conans/test/unittests/model/build_info_test.py @@ -171,7 +171,6 @@ def cpp_info_test(self): info.libdirs.append(abs_lib) info.bindirs.append(abs_bin) info.bindirs.append("local_bindir") - print("result: ", info.include_paths, info.lib_paths, info.bin_paths) self.assertEqual(info.include_paths, [os.path.join(folder, "include"), abs_include]) self.assertEqual(info.lib_paths, [os.path.join(folder, "lib"), abs_lib]) self.assertEqual(info.bin_paths, [abs_bin, @@ -220,7 +219,6 @@ def cpp_info_libs_system_deps_order_test(self): info["LIB3"].lib = "lib3" info["LIB3"].system_deps = ["sys3", "sys2"] self.assertEqual(['sys2', 'lib2', 'sys3', 'lib3', 'sys1', 'sys11', 'lib1'], info.libs) - print(info.libs) def cppinfo_dirs_test(self): folder = temp_folder() From 058ed4e434a32b719c9bc1f7e0a09629ad2fbc31 Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Wed, 19 Jun 2019 11:20:09 +0200 Subject: [PATCH 17/47] Add exes test --- conans/test/unittests/model/build_info_test.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/conans/test/unittests/model/build_info_test.py b/conans/test/unittests/model/build_info_test.py index cec1e3b6478..e51e58e8bc8 100644 --- a/conans/test/unittests/model/build_info_test.py +++ b/conans/test/unittests/model/build_info_test.py @@ -276,3 +276,15 @@ def cppinfo_dirs_test(self): info["Crypto"].bindirs) self.assertEqual(["different_res", "another_res", "another_other_res"], info["Crypto"].resdirs) + + def cppinfo_exes_test(self): + info = CppInfo(None) + info.name = "OpenSSL" + info["Exe1"].exe = "the_exe1" + info["Exe2"].exe = "the_exe2" + self.assertEqual(["the_exe1", "the_exe2"], info.exes) + + with six.assertRaisesRegex(self, ConanException, "Setting first level exes is not supported " + "when Components are already in use"): + info.exes = ["another_exe"] + From 0d9ba39d0c2161a2436726500d5abaea014706cf Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Wed, 19 Jun 2019 11:33:28 +0200 Subject: [PATCH 18/47] Test wrong cpp_info raises on create --- conans/test/integration/package_info_test.py | 23 ++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/conans/test/integration/package_info_test.py b/conans/test/integration/package_info_test.py index 61bd9bea3dc..d201d45fb0c 100644 --- a/conans/test/integration/package_info_test.py +++ b/conans/test/integration/package_info_test.py @@ -2,6 +2,9 @@ import textwrap import unittest +import six + +from conans.errors import ConanException from conans.model.ref import ConanFileReference, PackageReference from conans.paths import CONANFILE, CONANFILE_TXT from conans.test.utils.tools import TestClient, NO_SETTINGS_PACKAGE_ID @@ -109,3 +112,23 @@ def build(self): self.assertIn("Accumulators: %s" % accumulators_expected, client.out) self.assertIn("Containers: %s" % containers_expected, client.out) self.assertIn("SuperContainers: %s" % supercontainers_expected, client.out) + + def package_info_wrong_cpp_info_test(self): + conanfile = textwrap.dedent(""" + import os + from conans import ConanFile + + class Dep(ConanFile): + + def package_info(self): + self.cpp_info.name = "Boost" + self.cpp_info["Accumulators"].includedirs = [os.path.join("boost", "accumulators")] + self.cpp_info.libs = ["hello"] + """) + + client = TestClient() + client.save({"conanfile.py": conanfile}) + client.run("export . name/1.0@us/ch") # Does NOT fail on export + client.run("create . name/1.0@us/ch", assert_error=True) + self.assertIn("Setting first level libs is not supported when Components are already in use", + client.out) From db8b873d14eb24c00a7c510d09dc9d18e31523a2 Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Wed, 19 Jun 2019 11:42:18 +0200 Subject: [PATCH 19/47] Added system_deps test --- conans/model/build_info.py | 7 ++++--- conans/test/unittests/model/build_info_test.py | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/conans/model/build_info.py b/conans/model/build_info.py index e08654a16cb..66e5642a4f2 100644 --- a/conans/model/build_info.py +++ b/conans/model/build_info.py @@ -68,7 +68,7 @@ def libs(self, libs): def exes(self): if self._deps: deps = [v for v in self._deps.values()] - return [dep.exe for dep in deps if dep.exe is not None] + return [dep.exe for dep in deps if dep.exe] else: return self._exes @@ -204,9 +204,10 @@ def libs(self): result = [] for dep in deps_sorted: for sys_dep in dep.system_deps: - if sys_dep not in result: + if sys_dep and sys_dep not in result: result.append(sys_dep) - result.append(dep.lib) + if dep.lib: + result.append(dep.lib) return result else: return self._libs diff --git a/conans/test/unittests/model/build_info_test.py b/conans/test/unittests/model/build_info_test.py index e51e58e8bc8..a4f95842057 100644 --- a/conans/test/unittests/model/build_info_test.py +++ b/conans/test/unittests/model/build_info_test.py @@ -208,7 +208,25 @@ def cpp_info_libs_components_fail_test(self): "when Components are already in use"): info.libs = ["libgreet"] + def cpp_info_system_test(self): + """ + System deps are composed in '.libs' attribute even if there are no '.lib' in the component. + Also make sure None values are discarded + """ + info = CppInfo(None) + info["LIB1"].system_deps = ["sys1", "sys11"] + info["LIB1"].deps = ["LIB2"] + info["LIB2"].system_deps = ["sys2"] + info["LIB1"].deps = ["LIB3"] + info["LIB3"].system_deps = ["sys3", "sys2"] + self.assertEqual(['sys2', 'sys3', 'sys1', 'sys11'], info.libs) + info["LIB3"].system_deps = [None, "sys2"] + self.assertEqual(['sys2', 'sys1', 'sys11'], info.libs) + def cpp_info_libs_system_deps_order_test(self): + """ + Check the order of libs and system_deps and discard repeated values + """ info = CppInfo(None) info["LIB1"].lib = "lib1" info["LIB1"].system_deps = ["sys1", "sys11"] From b098c12d0e46d469692ca08f2f05b46f32aea97a Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Wed, 19 Jun 2019 15:39:40 +0200 Subject: [PATCH 20/47] Adds complete test --- conans/model/build_info.py | 40 +++++--- conans/test/integration/package_info_test.py | 101 +++++++++++++++++++ 2 files changed, 127 insertions(+), 14 deletions(-) diff --git a/conans/model/build_info.py b/conans/model/build_info.py index 66e5642a4f2..73ffe7f7b81 100644 --- a/conans/model/build_info.py +++ b/conans/model/build_info.py @@ -97,21 +97,28 @@ def _filter_paths(self, paths): def _get_paths(self, path_name): """ Get the absolute paths either composing the lists from components or from the global - variables. Also filter the values checking if the folders exist or not. This paths are - calculated once and then the result is cached. + variables. Also filter the values checking if the folders exist or not and avoid repeated + values. The paths are calculated once and then the result is cached. :param path_name: name of the path variable to get (include_paths, res_paths...) :return: List of absolute paths """ - if getattr(self, "_%s_paths" % path_name) is None: + def get_paths_value(): + return getattr(self, "_%s_paths" % path_name) + + if get_paths_value() is None: if self._deps: self.__dict__["_%s_paths" % path_name] = [] for dep_value in self._deps.values(): - self.__dict__["_%s_paths" % path_name].extend( - self._filter_paths(getattr(dep_value, "%s_paths" % path_name))) + abs_paths = self._filter_paths(getattr(dep_value, "%s_paths" % path_name)) + if not get_paths_value(): + self.__dict__["_%s_paths" % path_name].extend(abs_paths) + for path in abs_paths: + if path not in get_paths_value(): + self.__dict__["_%s_paths" % path_name].append(path) else: - self.__dict__["_%s_paths" % path_name] = self._filter_paths( - getattr(self, "%sdirs" % path_name)) - return getattr(self, "_%s_paths" % path_name) + abs_paths = self._filter_paths(getattr(self, "%sdirs" % path_name)) + self.__dict__["_%s_paths" % path_name] = abs_paths + return get_paths_value() @property def include_paths(self): @@ -228,6 +235,10 @@ def __getitem__(self, key): self._deps[key] = Component(key, self.rootpath) return self._deps[key] + @property + def deps(self): + return self._deps + def __getattr__(self, config): def _get_cpp_info(): @@ -253,11 +264,11 @@ def __init__(self, name, root_folder): self._lib = None self._exe = None self.system_deps = [] - self.includedirs = [] - self.libdirs = [] - self.resdirs = [] - self.bindirs = [] - self.builddirs = [] + self.includedirs = [DEFAULT_INCLUDE] + self.libdirs = [DEFAULT_LIB] + self.resdirs = [DEFAULT_RES] + self.bindirs = [DEFAULT_BIN] + self.builddirs = [DEFAULT_BUILD] self.srcdirs = [] self.defines = [] self.cflags = [] @@ -336,7 +347,8 @@ def merge_lists(seq1, seq2): self.bindirs = merge_lists(self.bindirs, dep_cpp_info.bin_paths) self.resdirs = merge_lists(self.resdirs, dep_cpp_info.res_paths) self.builddirs = merge_lists(self.builddirs, dep_cpp_info.build_paths) - self.libs = merge_lists(self.libs, dep_cpp_info._libs) + self.libs = merge_lists(self.libs, dep_cpp_info.libs) + self.exes = merge_lists(self.exes, dep_cpp_info.exes) self.rootpaths.append(dep_cpp_info.rootpath) # Note these are in reverse order diff --git a/conans/test/integration/package_info_test.py b/conans/test/integration/package_info_test.py index d201d45fb0c..cd62385bac6 100644 --- a/conans/test/integration/package_info_test.py +++ b/conans/test/integration/package_info_test.py @@ -132,3 +132,104 @@ def package_info(self): client.run("create . name/1.0@us/ch", assert_error=True) self.assertIn("Setting first level libs is not supported when Components are already in use", client.out) + + def package_info_components_complete_test(self): + dep = textwrap.dedent(""" + import os + from conans import ConanFile + + class Dep(ConanFile): + exports_sources = "*" + + def package(self): + self.copy("*") + + def package_info(self): + self.cpp_info.name = "Galaxy" + self.cpp_info["Starlight"].includedirs = [os.path.join("galaxy", "starlight")] + self.cpp_info["Starlight"].lib = "libstarlight" + + self.cpp_info["Planet"].includedirs = [os.path.join("galaxy", "planet")] + self.cpp_info["Planet"].lib = "libplanet" + self.cpp_info["Planet"].deps = ["Starlight"] + + self.cpp_info["Launcher"].exe = "exelauncher" + self.cpp_info["Launcher"].system_deps = ["ground"] + + self.cpp_info["ISS"].includedirs = [os.path.join("galaxy", "iss")] + self.cpp_info["ISS"].lib = "libiss" + self.cpp_info["ISS"].libdirs = ["iss_libs"] + self.cpp_info["ISS"].system_deps = ["solar", "magnetism"] + self.cpp_info["ISS"].deps = ["Starlight", "Launcher"] + """) + consumer = textwrap.dedent(""" + from conans import ConanFile + + class Consumer(ConanFile): + requires = "dep/1.0@us/ch" + + def build(self): + # Global values + self.output.info("GLOBAL Include Paths: %s" % self.deps_cpp_info.include_paths) + self.output.info("GLOBAL Library Paths: %s" % self.deps_cpp_info.lib_paths) + self.output.info("GLOBAL Binary Paths: %s" % self.deps_cpp_info.bin_paths) + self.output.info("GLOBAL Libs: %s" % self.deps_cpp_info.libs) + self.output.info("GLOBAL Exes: %s" % self.deps_cpp_info.exes) + # Deps values + for dep_key, dep_value in self.deps_cpp_info.dependencies: + self.output.info("DEPS Include paths: %s" % dep_value.include_paths) + self.output.info("DEPS Library paths: %s" % dep_value.lib_paths) + self.output.info("DEPS Binary paths: %s" % dep_value.bin_paths) + self.output.info("DEPS Libs: %s" % dep_value.libs) + self.output.info("DEPS Exes: %s" % dep_value.exes) + # Components values + for dep_key, dep_value in self.deps_cpp_info.dependencies: + for comp_name, comp_value in dep_value.deps.items(): + self.output.info("COMP %s Include paths: %s" % (comp_name, + comp_value.include_paths)) + self.output.info("COMP %s Library paths: %s" % (comp_name, comp_value.lib_paths)) + self.output.info("COMP %s Binary paths: %s" % (comp_name, comp_value.bin_paths)) + self.output.info("COMP %s Lib: %s" % (comp_name, comp_value.lib)) + self.output.info("COMP %s Exe: %s" % (comp_name, comp_value.exe)) + self.output.info("COMP %s Deps: %s" % (comp_name, comp_value.deps)) + """) + + client = TestClient() + client.save({"conanfile_dep.py": dep, "conanfile_consumer.py": consumer, + "galaxy/starlight/starlight.h": "", + "lib/libstarlight": "", + "galaxy/planet/planet.h": "", + "lib/libplanet": "", + "galaxy/iss/iss.h": "", + "iss_libs/libiss": "", + "bin/exelauncher": ""}) + dep_ref = ConanFileReference("dep", "1.0", "us", "ch") + dep_pref = PackageReference(dep_ref, NO_SETTINGS_PACKAGE_ID) + client.run("create conanfile_dep.py dep/1.0@us/ch") + client.run("create conanfile_consumer.py consumer/1.0@us/ch") + package_folder = client.cache.package_layout(dep_ref).package(dep_pref) + + expected_global_include_paths = [os.path.join(package_folder, "galaxy", "starlight"), + os.path.join(package_folder, "galaxy", "planet"), + os.path.join(package_folder, "galaxy", "iss")] + expected_global_library_paths = [os.path.join(package_folder, "lib"), + os.path.join(package_folder, "iss_libs")] + expected_global_binary_paths = [os.path.join(package_folder, "bin")] + expected_global_libs = ["libstarlight", "ground", "libplanet", "solar", "magnetism", "libiss"] + expected_global_exes = ["exelauncher"] + fromatted1 = "GLOBAL Include Paths: %s" % expected_global_include_paths + self.assertIn(fromatted1, client.out) + self.assertIn("GLOBAL Library Paths: %s" % expected_global_library_paths, client.out) + self.assertIn("GLOBAL Binary Paths: %s" % expected_global_binary_paths, client.out) + self.assertIn("GLOBAL Libs: %s" % expected_global_libs, client.out) + self.assertIn("GLOBAL Exes: %s" % expected_global_exes, client.out) + + formatted = "GLOBAL Include Paths: {}".format(expected_global_include_paths) + print(formatted) + self.assertIn(formatted, client.out) + self.assertIn("DEPS Library Paths: %s" % expected_global_library_paths, client.out) + self.assertIn("DEPS Binary Paths: %s" % expected_global_binary_paths, client.out) + self.assertIn("DEPS Libs: %s" % expected_global_libs, client.out) + self.assertIn("DEPS Exes: %s" % expected_global_exes, client.out) + + #TODO: Complete the test checking the output of the components From 6ab1bdbeb8c3858b1922ee2cdb56bc9a25ab8334 Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Wed, 19 Jun 2019 15:52:04 +0200 Subject: [PATCH 21/47] Add system_deps global behavior --- conans/model/build_info.py | 24 ++++++++++++++++++- .../test/unittests/model/build_info_test.py | 12 ++++++++-- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/conans/model/build_info.py b/conans/model/build_info.py index 73ffe7f7b81..c34385bd51d 100644 --- a/conans/model/build_info.py +++ b/conans/model/build_info.py @@ -20,7 +20,7 @@ class _CppInfo(object): """ def __init__(self): self.name = None - self.system_deps = [] + self._system_deps = [] self.includedirs = [] # Ordered list of include paths self.srcdirs = [] # Ordered list of source paths self.libdirs = [] # Directories to find libraries @@ -79,6 +79,28 @@ def exes(self, exes): "already in use") self._exes = exes + @property + def system_deps(self): + if self._deps: + deps = [v for v in self._deps.values()] + deps_sorted = sorted(deps, key=lambda component: len(component.deps)) + result = [] + for dep in deps_sorted: + if dep.system_deps: + for system_dep in dep.system_deps: + if system_dep and system_dep not in result: + result.append(system_dep) + return result + else: + return self._system_deps + + @system_deps.setter + def system_deps(self, system_deps): + if self._deps: + raise ConanException("Setting first level system_deps is not supported when Components " + "are already in use") + self._system_deps = system_deps + def __getitem__(self, key): if self._libs: raise ConanException("Usage of Components with '.libs' values is not allowed") diff --git a/conans/test/unittests/model/build_info_test.py b/conans/test/unittests/model/build_info_test.py index a4f95842057..b81094dc86f 100644 --- a/conans/test/unittests/model/build_info_test.py +++ b/conans/test/unittests/model/build_info_test.py @@ -208,10 +208,11 @@ def cpp_info_libs_components_fail_test(self): "when Components are already in use"): info.libs = ["libgreet"] - def cpp_info_system_test(self): + def cpp_info_system_deps_test(self): """ System deps are composed in '.libs' attribute even if there are no '.lib' in the component. - Also make sure None values are discarded + Also make sure None values are discarded. + Same for '.system_deps' making sure that mixing Components and global use is not supported. """ info = CppInfo(None) info["LIB1"].system_deps = ["sys1", "sys11"] @@ -223,6 +224,12 @@ def cpp_info_system_test(self): info["LIB3"].system_deps = [None, "sys2"] self.assertEqual(['sys2', 'sys1', 'sys11'], info.libs) + with six.assertRaisesRegex(self, ConanException, "Setting first level system_deps is not " + "supported when Components are already in " + "use"): + info.system_deps = ["random_system"] + self.assertEqual(['sys2', 'sys1', 'sys11'], info.system_deps) + def cpp_info_libs_system_deps_order_test(self): """ Check the order of libs and system_deps and discard repeated values @@ -237,6 +244,7 @@ def cpp_info_libs_system_deps_order_test(self): info["LIB3"].lib = "lib3" info["LIB3"].system_deps = ["sys3", "sys2"] self.assertEqual(['sys2', 'lib2', 'sys3', 'lib3', 'sys1', 'sys11', 'lib1'], info.libs) + self.assertEqual(['sys2', 'sys3', 'sys1', 'sys11'], info.system_deps) def cppinfo_dirs_test(self): folder = temp_folder() From d1d2ffc8e7eaec85b2eee81602ddbf8f26c126ba Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Thu, 20 Jun 2019 12:34:20 +0200 Subject: [PATCH 22/47] Indent text --- conans/test/integration/package_info_test.py | 129 +++++++++---------- 1 file changed, 63 insertions(+), 66 deletions(-) diff --git a/conans/test/integration/package_info_test.py b/conans/test/integration/package_info_test.py index cd62385bac6..ae357ab9325 100644 --- a/conans/test/integration/package_info_test.py +++ b/conans/test/integration/package_info_test.py @@ -55,42 +55,42 @@ def package_info(self): def package_info_components_test(self): dep = textwrap.dedent(""" - import os - from conans import ConanFile - - class Dep(ConanFile): - exports_sources = "*" - - def package(self): - self.copy("*") - - def package_info(self): - self.cpp_info.name = "Boost" - self.cpp_info["Accumulators"].includedirs = [os.path.join("boost", "accumulators")] - self.cpp_info["Accumulators"].lib = "libaccumulators" - self.cpp_info["Containers"].includedirs = [os.path.join("boost", "containers")] - self.cpp_info["Containers"].lib = "libcontainers" - self.cpp_info["Containers"].deps = ["Accumulators"] - self.cpp_info["SuperContainers"].includedirs = [os.path.join("boost", - "supercontainers")] - self.cpp_info["SuperContainers"].lib = "libsupercontainers" - self.cpp_info["SuperContainers"].deps = ["Containers"] + import os + from conans import ConanFile + + class Dep(ConanFile): + exports_sources = "*" + + def package(self): + self.copy("*") + + def package_info(self): + self.cpp_info.name = "Boost" + self.cpp_info["Accumulators"].includedirs = [os.path.join("boost", "accumulators")] + self.cpp_info["Accumulators"].lib = "libaccumulators" + self.cpp_info["Containers"].includedirs = [os.path.join("boost", "containers")] + self.cpp_info["Containers"].lib = "libcontainers" + self.cpp_info["Containers"].deps = ["Accumulators"] + self.cpp_info["SuperContainers"].includedirs = [os.path.join("boost", + "supercontainers")] + self.cpp_info["SuperContainers"].lib = "libsupercontainers" + self.cpp_info["SuperContainers"].deps = ["Containers"] """) consumer = textwrap.dedent(""" - from conans import ConanFile - - class Consumer(ConanFile): - requires = "dep/1.0@us/ch" - - def build(self): - acc_includes = self.deps_cpp_info["dep"]["Accumulators"].include_paths - con_include = self.deps_cpp_info["dep"]["Containers"].include_paths - sup_include = self.deps_cpp_info["dep"]["SuperContainers"].include_paths - self.output.info("Name: %s" % self.deps_cpp_info["dep"].name) - self.output.info("Accumulators: %s" % acc_includes) - self.output.info("Containers: %s" % con_include) - self.output.info("SuperContainers: %s" % sup_include) - self.output.info("LIBS: %s" % self.deps_cpp_info["dep"].libs) + from conans import ConanFile + + class Consumer(ConanFile): + requires = "dep/1.0@us/ch" + + def build(self): + acc_includes = self.deps_cpp_info["dep"]["Accumulators"].include_paths + con_include = self.deps_cpp_info["dep"]["Containers"].include_paths + sup_include = self.deps_cpp_info["dep"]["SuperContainers"].include_paths + self.output.info("Name: %s" % self.deps_cpp_info["dep"].name) + self.output.info("Accumulators: %s" % acc_includes) + self.output.info("Containers: %s" % con_include) + self.output.info("SuperContainers: %s" % sup_include) + self.output.info("LIBS: %s" % self.deps_cpp_info["dep"].libs) """) client = TestClient() @@ -115,15 +115,15 @@ def build(self): def package_info_wrong_cpp_info_test(self): conanfile = textwrap.dedent(""" - import os - from conans import ConanFile + import os + from conans import ConanFile - class Dep(ConanFile): + class Dep(ConanFile): - def package_info(self): - self.cpp_info.name = "Boost" - self.cpp_info["Accumulators"].includedirs = [os.path.join("boost", "accumulators")] - self.cpp_info.libs = ["hello"] + def package_info(self): + self.cpp_info.name = "Boost" + self.cpp_info["Accumulators"].includedirs = [os.path.join("boost", "accumulators")] + self.cpp_info.libs = ["hello"] """) client = TestClient() @@ -135,32 +135,32 @@ def package_info(self): def package_info_components_complete_test(self): dep = textwrap.dedent(""" - import os - from conans import ConanFile + import os + from conans import ConanFile - class Dep(ConanFile): - exports_sources = "*" + class Dep(ConanFile): + exports_sources = "*" - def package(self): - self.copy("*") + def package(self): + self.copy("*") - def package_info(self): - self.cpp_info.name = "Galaxy" - self.cpp_info["Starlight"].includedirs = [os.path.join("galaxy", "starlight")] - self.cpp_info["Starlight"].lib = "libstarlight" + def package_info(self): + self.cpp_info.name = "Galaxy" + self.cpp_info["Starlight"].includedirs = [os.path.join("galaxy", "starlight")] + self.cpp_info["Starlight"].lib = "libstarlight" - self.cpp_info["Planet"].includedirs = [os.path.join("galaxy", "planet")] - self.cpp_info["Planet"].lib = "libplanet" - self.cpp_info["Planet"].deps = ["Starlight"] + self.cpp_info["Planet"].includedirs = [os.path.join("galaxy", "planet")] + self.cpp_info["Planet"].lib = "libplanet" + self.cpp_info["Planet"].deps = ["Starlight"] - self.cpp_info["Launcher"].exe = "exelauncher" - self.cpp_info["Launcher"].system_deps = ["ground"] + self.cpp_info["Launcher"].exe = "exelauncher" + self.cpp_info["Launcher"].system_deps = ["ground"] - self.cpp_info["ISS"].includedirs = [os.path.join("galaxy", "iss")] - self.cpp_info["ISS"].lib = "libiss" - self.cpp_info["ISS"].libdirs = ["iss_libs"] - self.cpp_info["ISS"].system_deps = ["solar", "magnetism"] - self.cpp_info["ISS"].deps = ["Starlight", "Launcher"] + self.cpp_info["ISS"].includedirs = [os.path.join("galaxy", "iss")] + self.cpp_info["ISS"].lib = "libiss" + self.cpp_info["ISS"].libdirs = ["iss_libs"] + self.cpp_info["ISS"].system_deps = ["solar", "magnetism"] + self.cpp_info["ISS"].deps = ["Starlight", "Launcher"] """) consumer = textwrap.dedent(""" from conans import ConanFile @@ -217,16 +217,13 @@ def build(self): expected_global_binary_paths = [os.path.join(package_folder, "bin")] expected_global_libs = ["libstarlight", "ground", "libplanet", "solar", "magnetism", "libiss"] expected_global_exes = ["exelauncher"] - fromatted1 = "GLOBAL Include Paths: %s" % expected_global_include_paths - self.assertIn(fromatted1, client.out) + self.assertIn("GLOBAL Include Paths: %s" % expected_global_include_paths, client.out) self.assertIn("GLOBAL Library Paths: %s" % expected_global_library_paths, client.out) self.assertIn("GLOBAL Binary Paths: %s" % expected_global_binary_paths, client.out) self.assertIn("GLOBAL Libs: %s" % expected_global_libs, client.out) self.assertIn("GLOBAL Exes: %s" % expected_global_exes, client.out) - formatted = "GLOBAL Include Paths: {}".format(expected_global_include_paths) - print(formatted) - self.assertIn(formatted, client.out) + self.assertIn("DEPS Include Paths: {}".format(expected_global_include_paths), client.out) self.assertIn("DEPS Library Paths: %s" % expected_global_library_paths, client.out) self.assertIn("DEPS Binary Paths: %s" % expected_global_binary_paths, client.out) self.assertIn("DEPS Libs: %s" % expected_global_libs, client.out) From be74c0d83438de4accc1166495187b40048196cd Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Thu, 20 Jun 2019 12:35:13 +0200 Subject: [PATCH 23/47] Review and move libs properties. Use function to get components sorted --- conans/model/build_info.py | 76 ++++++++++++++------------------------ 1 file changed, 27 insertions(+), 49 deletions(-) diff --git a/conans/model/build_info.py b/conans/model/build_info.py index c34385bd51d..73a43c60a88 100644 --- a/conans/model/build_info.py +++ b/conans/model/build_info.py @@ -49,13 +49,27 @@ def __init__(self): self.filter_empty = True self._deps = OrderedDict() + def _get_components_sorted(self): + """ + Sort components from less dependent to the most one (less items in .deps attribute) + :return: ordered list of components + """ + components = [v for v in self._deps.values()] + return sorted(components, key=lambda component: len(component.deps)) + @property def libs(self): if self._deps: - deps = [v for v in self._deps.values()] - deps_sorted = sorted(deps, key=lambda component: len(component.deps)) - self._libs = [dep.lib for dep in deps_sorted if dep.lib is not None] - return self._libs + result = [] + for component in self._get_components_sorted(): + for sys_dep in component.system_deps: + if sys_dep and sys_dep not in result: + result.append(sys_dep) + if component.lib: + result.append(component.lib) + return result + else: + return self._libs @libs.setter def libs(self, libs): @@ -67,8 +81,7 @@ def libs(self, libs): @property def exes(self): if self._deps: - deps = [v for v in self._deps.values()] - return [dep.exe for dep in deps if dep.exe] + return [component.exe for component in self._deps.values() if component.exe] else: return self._exes @@ -82,12 +95,10 @@ def exes(self, exes): @property def system_deps(self): if self._deps: - deps = [v for v in self._deps.values()] - deps_sorted = sorted(deps, key=lambda component: len(component.deps)) result = [] - for dep in deps_sorted: - if dep.system_deps: - for system_dep in dep.system_deps: + for component in self._get_components_sorted(): + if component.system_deps: + for system_dep in component.system_deps: if system_dep and system_dep not in result: result.append(system_dep) return result @@ -109,8 +120,7 @@ def __getitem__(self, key): return self._deps[key] def _filter_paths(self, paths): - abs_paths = [os.path.join(self.rootpath, p) - if not os.path.isabs(p) else p for p in paths] + abs_paths = [os.path.join(self.rootpath, p) for p in paths] if self.filter_empty: return [p for p in abs_paths if os.path.isdir(p)] else: @@ -207,7 +217,7 @@ def _check_dirs_values(self): "srcdirs": [] } msg_template = "Using Components and global '{}' values ('{}') is not supported" - for dir_name in ["includedirs", "libdirs", "bindirs", "builddirs"]: + for dir_name in default_dirs_mapping: dirs_value = getattr(self, dir_name) if dirs_value is not None and dirs_value != default_dirs_mapping[dir_name]: raise ConanException(msg_template.format(dir_name, dirs_value)) @@ -221,33 +231,10 @@ def _clear_dirs_values(self): "builddirs": [DEFAULT_BUILD], "srcdirs": [] } - for dir_name in ["includedirs", "libdirs", "bindirs", "builddirs"]: + for dir_name in default_dirs_mapping: if getattr(self, dir_name) == default_dirs_mapping[dir_name]: self.__dict__[dir_name] = None - @property - def libs(self): - if self._deps: - deps = [v for v in self._deps.values()] - deps_sorted = sorted(deps, key=lambda component: len(component.deps)) - result = [] - for dep in deps_sorted: - for sys_dep in dep.system_deps: - if sys_dep and sys_dep not in result: - result.append(sys_dep) - if dep.lib: - result.append(dep.lib) - return result - else: - return self._libs - - @libs.setter - def libs(self, libs): - if self._deps: - raise ConanException("Setting first level libs is not supported when Components are " - "already in use") - self._libs = libs - def __getitem__(self, key): if self._libs or self._exes: raise ConanException("Usage of Components with '.libs' or '.exes' values is not allowed") @@ -271,7 +258,7 @@ def _get_cpp_info(): result.libdirs.append(DEFAULT_LIB) result.bindirs.append(DEFAULT_BIN) result.resdirs.append(DEFAULT_RES) - result.builddirs.append("") + result.builddirs.append(DEFAULT_BUILD) return result return self.configs.setdefault(config, _get_cpp_info()) @@ -301,8 +288,7 @@ def __init__(self, name, root_folder): self._filter_empty = True def _filter_paths(self, paths): - abs_paths = [os.path.join(self._rootpath, p) - if not os.path.isabs(p) else p for p in paths] + abs_paths = [os.path.join(self._rootpath, p) for p in paths] if self._filter_empty: return [p for p in abs_paths if os.path.isdir(p)] else: @@ -383,14 +369,6 @@ def merge_lists(seq1, seq2): if not self.sysroot: self.sysroot = dep_cpp_info.sysroot - @property - def libs(self): - return self._libs - - @libs.setter - def libs(self, libs): - self._libs = libs - @property def include_paths(self): return self.includedirs From 1e6e1fdafd8b7eb3e106aedfa48c97257789ee9e Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Thu, 20 Jun 2019 12:49:13 +0200 Subject: [PATCH 24/47] Renamed .deps to .components --- conans/model/build_info.py | 49 ++++++++++---------- conans/test/integration/package_info_test.py | 2 +- 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/conans/model/build_info.py b/conans/model/build_info.py index 73a43c60a88..0544a56c69a 100644 --- a/conans/model/build_info.py +++ b/conans/model/build_info.py @@ -47,21 +47,21 @@ def __init__(self): self.description = None # Description of the conan package # When package is editable, filter_empty=False, so empty dirs are maintained self.filter_empty = True - self._deps = OrderedDict() + self._components = OrderedDict() - def _get_components_sorted(self): + @property + def _sorted_components(self): """ - Sort components from less dependent to the most one (less items in .deps attribute) + Sorted components from less dependent to the most one (less items in .deps attribute) :return: ordered list of components """ - components = [v for v in self._deps.values()] - return sorted(components, key=lambda component: len(component.deps)) + return sorted(self._components.values(), key=lambda component: len(component.deps)) @property def libs(self): - if self._deps: + if self._components: result = [] - for component in self._get_components_sorted(): + for component in self._sorted_components: for sys_dep in component.system_deps: if sys_dep and sys_dep not in result: result.append(sys_dep) @@ -73,30 +73,30 @@ def libs(self): @libs.setter def libs(self, libs): - if self._deps: + if self._components: raise ConanException("Setting first level libs is not supported when Components are " "already in use") self._libs = libs @property def exes(self): - if self._deps: - return [component.exe for component in self._deps.values() if component.exe] + if self._components: + return [component.exe for component in self._components.values() if component.exe] else: return self._exes @exes.setter def exes(self, exes): - if self._deps: + if self._components: raise ConanException("Setting first level exes is not supported when Components are " "already in use") self._exes = exes @property def system_deps(self): - if self._deps: + if self._components: result = [] - for component in self._get_components_sorted(): + for component in self._sorted_components: if component.system_deps: for system_dep in component.system_deps: if system_dep and system_dep not in result: @@ -107,7 +107,7 @@ def system_deps(self): @system_deps.setter def system_deps(self, system_deps): - if self._deps: + if self._components: raise ConanException("Setting first level system_deps is not supported when Components " "are already in use") self._system_deps = system_deps @@ -115,9 +115,9 @@ def system_deps(self, system_deps): def __getitem__(self, key): if self._libs: raise ConanException("Usage of Components with '.libs' values is not allowed") - if key not in self._deps.keys(): - self._deps[key] = Component(self, key) - return self._deps[key] + if key not in self._components.keys(): + self._components[key] = Component(self, key) + return self._components[key] def _filter_paths(self, paths): abs_paths = [os.path.join(self.rootpath, p) for p in paths] @@ -138,9 +138,9 @@ def get_paths_value(): return getattr(self, "_%s_paths" % path_name) if get_paths_value() is None: - if self._deps: + if self._components: self.__dict__["_%s_paths" % path_name] = [] - for dep_value in self._deps.values(): + for dep_value in self._components.values(): abs_paths = self._filter_paths(getattr(dep_value, "%s_paths" % path_name)) if not get_paths_value(): self.__dict__["_%s_paths" % path_name].extend(abs_paths) @@ -205,7 +205,6 @@ def __init__(self, root_folder): # public_deps is needed to accumulate list of deps for cmake targets self.public_deps = [] self.configs = {} - self._deps = OrderedDict() def _check_dirs_values(self): default_dirs_mapping = { @@ -240,13 +239,13 @@ def __getitem__(self, key): raise ConanException("Usage of Components with '.libs' or '.exes' values is not allowed") self._clear_dirs_values() self._check_dirs_values() - if key not in self._deps.keys(): - self._deps[key] = Component(key, self.rootpath) - return self._deps[key] + if key not in self._components: + self._components[key] = Component(key, self.rootpath) + return self._components[key] @property - def deps(self): - return self._deps + def components(self): + return self._components def __getattr__(self, config): diff --git a/conans/test/integration/package_info_test.py b/conans/test/integration/package_info_test.py index ae357ab9325..14495ffa16b 100644 --- a/conans/test/integration/package_info_test.py +++ b/conans/test/integration/package_info_test.py @@ -184,7 +184,7 @@ def build(self): self.output.info("DEPS Exes: %s" % dep_value.exes) # Components values for dep_key, dep_value in self.deps_cpp_info.dependencies: - for comp_name, comp_value in dep_value.deps.items(): + for comp_name, comp_value in dep_value.components.items(): self.output.info("COMP %s Include paths: %s" % (comp_name, comp_value.include_paths)) self.output.info("COMP %s Library paths: %s" % (comp_name, comp_value.lib_paths)) From 6a2e2f7eda360f6748d9facb64d11c3d924a8a79 Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Thu, 20 Jun 2019 13:24:30 +0200 Subject: [PATCH 25/47] simplified get paths --- conans/model/build_info.py | 56 ++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/conans/model/build_info.py b/conans/model/build_info.py index 0544a56c69a..7350e4308d9 100644 --- a/conans/model/build_info.py +++ b/conans/model/build_info.py @@ -130,51 +130,59 @@ def _get_paths(self, path_name): """ Get the absolute paths either composing the lists from components or from the global variables. Also filter the values checking if the folders exist or not and avoid repeated - values. The paths are calculated once and then the result is cached. + values. :param path_name: name of the path variable to get (include_paths, res_paths...) :return: List of absolute paths """ - def get_paths_value(): - return getattr(self, "_%s_paths" % path_name) - - if get_paths_value() is None: - if self._components: - self.__dict__["_%s_paths" % path_name] = [] - for dep_value in self._components.values(): - abs_paths = self._filter_paths(getattr(dep_value, "%s_paths" % path_name)) - if not get_paths_value(): - self.__dict__["_%s_paths" % path_name].extend(abs_paths) - for path in abs_paths: - if path not in get_paths_value(): - self.__dict__["_%s_paths" % path_name].append(path) - else: - abs_paths = self._filter_paths(getattr(self, "%sdirs" % path_name)) - self.__dict__["_%s_paths" % path_name] = abs_paths - return get_paths_value() + result = [] + + if self._components: + for dep_value in self._components.values(): + abs_paths = self._filter_paths(getattr(dep_value, "%s_paths" % path_name)) + if not getattr(self, "_%s_paths" % path_name): + result.extend(abs_paths) + for path in abs_paths: + if path not in result: + result.append(path) + else: + result = self._filter_paths(getattr(self, "%sdirs" % path_name)) + return result @property def include_paths(self): - return self._get_paths("include") + if not self._include_paths: + self._include_paths = self._get_paths("include") + return self._include_paths @property def lib_paths(self): - return self._get_paths("lib") + if not self._lib_paths: + self._lib_paths = self._get_paths("lib") + return self._lib_paths @property def src_paths(self): - return self._get_paths("src") + if not self._src_paths: + self._src_paths = self._get_paths("src") + return self._src_paths @property def bin_paths(self): - return self._get_paths("bin") + if not self._bin_paths: + self._bin_paths = self._get_paths("bin") + return self._bin_paths @property def build_paths(self): - return self._get_paths("build") + if not self._build_paths: + self._build_paths = self._get_paths("build") + return self._build_paths @property def res_paths(self): - return self._get_paths("res") + if not self._res_paths: + self._res_paths = self._get_paths("res") + return self._res_paths # Compatibility for 'cppflags' (old style property to allow decoration) @deprecation.deprecated(deprecated_in="1.13", removed_in="2.0", details="Use 'cxxflags' instead") From b32e3b9785d97a01d55c6c1ff1e95715ed09dc6f Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Thu, 20 Jun 2019 17:38:07 +0200 Subject: [PATCH 26/47] Fix link order and added test --- conans/model/build_info.py | 20 +++++++- conans/test/integration/package_info_test.py | 2 +- .../test/unittests/model/build_info_test.py | 50 +++++++++++++++++++ 3 files changed, 69 insertions(+), 3 deletions(-) diff --git a/conans/model/build_info.py b/conans/model/build_info.py index 7350e4308d9..f98f39980f7 100644 --- a/conans/model/build_info.py +++ b/conans/model/build_info.py @@ -52,10 +52,26 @@ def __init__(self): @property def _sorted_components(self): """ - Sorted components from less dependent to the most one (less items in .deps attribute) + Sorted components from less dependent to the most one :return: ordered list of components """ - return sorted(self._components.values(), key=lambda component: len(component.deps)) + # Sort first elements with less items in .deps attribute + comps = sorted(self._components.values(), key=lambda component: len(component.deps)) + # Save name of unsorted elements + unsorted_names = [comp.name for comp in comps] + + sorted_comps = [] + while unsorted_names: + for comp in comps: + # If element is already sorted, continue + if comp.name not in unsorted_names: + continue + # If element does not have deps or all of its deps are already sorted, sort this + # element and remove it from the unsorted list + elif not comp.deps or not [dep for dep in comp.deps if dep in unsorted_names]: + sorted_comps.append(comp) + unsorted_names.remove(comp.name) + return sorted_comps @property def libs(self): diff --git a/conans/test/integration/package_info_test.py b/conans/test/integration/package_info_test.py index 14495ffa16b..a142abd1070 100644 --- a/conans/test/integration/package_info_test.py +++ b/conans/test/integration/package_info_test.py @@ -223,7 +223,7 @@ def build(self): self.assertIn("GLOBAL Libs: %s" % expected_global_libs, client.out) self.assertIn("GLOBAL Exes: %s" % expected_global_exes, client.out) - self.assertIn("DEPS Include Paths: {}".format(expected_global_include_paths), client.out) + self.assertIn("DEPS Include Paths: %s" % expected_global_include_paths, client.out) self.assertIn("DEPS Library Paths: %s" % expected_global_library_paths, client.out) self.assertIn("DEPS Binary Paths: %s" % expected_global_binary_paths, client.out) self.assertIn("DEPS Libs: %s" % expected_global_libs, client.out) diff --git a/conans/test/unittests/model/build_info_test.py b/conans/test/unittests/model/build_info_test.py index b81094dc86f..2db051e84d6 100644 --- a/conans/test/unittests/model/build_info_test.py +++ b/conans/test/unittests/model/build_info_test.py @@ -246,6 +246,56 @@ def cpp_info_libs_system_deps_order_test(self): self.assertEqual(['sys2', 'lib2', 'sys3', 'lib3', 'sys1', 'sys11', 'lib1'], info.libs) self.assertEqual(['sys2', 'sys3', 'sys1', 'sys11'], info.system_deps) + def cpp_info_link_order_test(self): + + def _assert_link_order(sorted_libs): + for num, lib in enumerate(sorted_libs): + component_name = lib[-1] + for dep in info[component_name].deps: + self.assertIn(info[dep].lib, sorted_libs[:num]) + + info = CppInfo(None) + info["F"].lib = "libF" + info["F"].deps = ["D", "E"] + info["E"].lib = "libE" + info["E"].deps = ["B"] + info["D"].lib = "libD" + info["D"].deps = ["A"] + info["C"].lib = "libC" + info["C"].deps = ["A"] + info["A"].lib = "libA" + info["A"].deps = ["B"] + info["B"].lib = "libB" + info["B"].deps = [] + _assert_link_order(info.libs) + + info = CppInfo(None) + info["K"].lib = "libK" + info["K"].deps = ["G", "H"] + info["J"].lib = "libJ" + info["J"].deps = ["F"] + info["G"].lib = "libG" + info["G"].deps = ["F"] + info["H"].lib = "libH" + info["H"].deps = ["F", "E"] + info["L"].lib = "libL" + info["L"].deps = ["I"] + info["F"].lib = "libF" + info["F"].deps = ["C", "D"] + info["I"].lib = "libI" + info["I"].deps = ["E"] + info["C"].lib = "libC" + info["C"].deps = ["A"] + info["D"].lib = "libD" + info["D"].deps = ["A"] + info["E"].lib = "libE" + info["E"].deps = ["A", "B"] + info["A"].lib = "libA" + info["A"].deps = [] + info["B"].lib = "libB" + info["B"].deps = [] + _assert_link_order(info.libs) + def cppinfo_dirs_test(self): folder = temp_folder() info = CppInfo(folder) From 4bb2db219cb2cc8643de142e3ac6cb6ac5b20549 Mon Sep 17 00:00:00 2001 From: Daniel <danimanzaneque@gmail.com> Date: Thu, 20 Jun 2019 17:42:57 +0200 Subject: [PATCH 27/47] Update conans/test/unittests/model/build_info_test.py Co-Authored-By: Javier G. Sogo <jgsogo@gmail.com> --- conans/test/unittests/model/build_info_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conans/test/unittests/model/build_info_test.py b/conans/test/unittests/model/build_info_test.py index 2db051e84d6..26323be8d0b 100644 --- a/conans/test/unittests/model/build_info_test.py +++ b/conans/test/unittests/model/build_info_test.py @@ -179,7 +179,7 @@ def cpp_info_test(self): def basic_components_test(self): cpp_info = CppInfo(None) component = cpp_info["my_component"] - self.assertIn(component.name, "my_component") + self.assertEqual(component.name, "my_component") component.lib = "libhola" self.assertEqual(component.lib, "libhola") with six.assertRaisesRegex(self, ConanException, "'.lib' is already set for this Component"): From 4b490268ca7e70ad86fa56907cf39056b5ef00dd Mon Sep 17 00:00:00 2001 From: Daniel <danimanzaneque@gmail.com> Date: Thu, 20 Jun 2019 17:43:08 +0200 Subject: [PATCH 28/47] Update conans/test/unittests/model/build_info_test.py Co-Authored-By: Javier G. Sogo <jgsogo@gmail.com> --- conans/test/unittests/model/build_info_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conans/test/unittests/model/build_info_test.py b/conans/test/unittests/model/build_info_test.py index 26323be8d0b..c0f6ea26e69 100644 --- a/conans/test/unittests/model/build_info_test.py +++ b/conans/test/unittests/model/build_info_test.py @@ -196,7 +196,7 @@ def cpp_info_libs_components_fail_test(self): """ info = CppInfo(None) info.name = "Greetings" - self.assertIn(info.name, "Greetings") + self.assertEqual(info.name, "Greetings") info.libs = ["libgreet"] with six.assertRaisesRegex(self, ConanException, "Usage of Components with '.libs' or " "'.exes' values is not allowed"): From 62a9782b959bf6829df4dd513e53443d82df6f98 Mon Sep 17 00:00:00 2001 From: Daniel <danimanzaneque@gmail.com> Date: Thu, 20 Jun 2019 17:53:13 +0200 Subject: [PATCH 29/47] Update conans/test/integration/package_info_test.py Co-Authored-By: Javier G. Sogo <jgsogo@gmail.com> --- conans/test/integration/package_info_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conans/test/integration/package_info_test.py b/conans/test/integration/package_info_test.py index a142abd1070..ecb639d655b 100644 --- a/conans/test/integration/package_info_test.py +++ b/conans/test/integration/package_info_test.py @@ -224,7 +224,7 @@ def build(self): self.assertIn("GLOBAL Exes: %s" % expected_global_exes, client.out) self.assertIn("DEPS Include Paths: %s" % expected_global_include_paths, client.out) - self.assertIn("DEPS Library Paths: %s" % expected_global_library_paths, client.out) + self.assertIn("DEPS Library paths: %s" % expected_global_library_paths, client.out) self.assertIn("DEPS Binary Paths: %s" % expected_global_binary_paths, client.out) self.assertIn("DEPS Libs: %s" % expected_global_libs, client.out) self.assertIn("DEPS Exes: %s" % expected_global_exes, client.out) From b756503bee5cbf6fa3ac0eccb94de279595351f2 Mon Sep 17 00:00:00 2001 From: Daniel <danimanzaneque@gmail.com> Date: Thu, 20 Jun 2019 17:53:22 +0200 Subject: [PATCH 30/47] Update conans/test/integration/package_info_test.py Co-Authored-By: Javier G. Sogo <jgsogo@gmail.com> --- conans/test/integration/package_info_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conans/test/integration/package_info_test.py b/conans/test/integration/package_info_test.py index ecb639d655b..98ea92998fb 100644 --- a/conans/test/integration/package_info_test.py +++ b/conans/test/integration/package_info_test.py @@ -225,7 +225,7 @@ def build(self): self.assertIn("DEPS Include Paths: %s" % expected_global_include_paths, client.out) self.assertIn("DEPS Library paths: %s" % expected_global_library_paths, client.out) - self.assertIn("DEPS Binary Paths: %s" % expected_global_binary_paths, client.out) + self.assertIn("DEPS Binary paths: %s" % expected_global_binary_paths, client.out) self.assertIn("DEPS Libs: %s" % expected_global_libs, client.out) self.assertIn("DEPS Exes: %s" % expected_global_exes, client.out) From aef1a51a2bc46a98e035c1753bdeec795d9ffaac Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Thu, 20 Jun 2019 18:15:07 +0200 Subject: [PATCH 31/47] asserts --- conans/model/build_info.py | 7 ++++++- conans/test/integration/package_info_test.py | 14 +++++++------- conans/test/unittests/model/build_info_test.py | 3 ++- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/conans/model/build_info.py b/conans/model/build_info.py index f98f39980f7..54360a0be99 100644 --- a/conans/model/build_info.py +++ b/conans/model/build_info.py @@ -89,6 +89,7 @@ def libs(self): @libs.setter def libs(self, libs): + assert isinstance(libs, list), "'libs' attribute should be a list of strings" if self._components: raise ConanException("Setting first level libs is not supported when Components are " "already in use") @@ -97,12 +98,13 @@ def libs(self, libs): @property def exes(self): if self._components: - return [component.exe for component in self._components.values() if component.exe] + return [component.exe for component in self._sorted_components if component.exe] else: return self._exes @exes.setter def exes(self, exes): + assert isinstance(exes, list), "'exes' attribute should be a list of strings" if self._components: raise ConanException("Setting first level exes is not supported when Components are " "already in use") @@ -123,6 +125,7 @@ def system_deps(self): @system_deps.setter def system_deps(self, system_deps): + assert isinstance(system_deps, list), "'system_deps' attribute should be a list of strings" if self._components: raise ConanException("Setting first level system_deps is not supported when Components " "are already in use") @@ -323,6 +326,7 @@ def lib(self): @lib.setter def lib(self, name): + assert isinstance(name, str), "'lib' attribute should be a string" if self._exe: raise ConanException("'.exe' is already set for this Component") self._lib = name @@ -333,6 +337,7 @@ def exe(self): @exe.setter def exe(self, name): + assert isinstance(name, str), "'exe' attribute should be a string" if self._lib: raise ConanException("'.lib' is already set for this Component") self._exe = name diff --git a/conans/test/integration/package_info_test.py b/conans/test/integration/package_info_test.py index 98ea92998fb..df4fb7f40f3 100644 --- a/conans/test/integration/package_info_test.py +++ b/conans/test/integration/package_info_test.py @@ -170,9 +170,9 @@ class Consumer(ConanFile): def build(self): # Global values - self.output.info("GLOBAL Include Paths: %s" % self.deps_cpp_info.include_paths) - self.output.info("GLOBAL Library Paths: %s" % self.deps_cpp_info.lib_paths) - self.output.info("GLOBAL Binary Paths: %s" % self.deps_cpp_info.bin_paths) + self.output.info("GLOBAL Include paths: %s" % self.deps_cpp_info.include_paths) + self.output.info("GLOBAL Library paths: %s" % self.deps_cpp_info.lib_paths) + self.output.info("GLOBAL Binary paths: %s" % self.deps_cpp_info.bin_paths) self.output.info("GLOBAL Libs: %s" % self.deps_cpp_info.libs) self.output.info("GLOBAL Exes: %s" % self.deps_cpp_info.exes) # Deps values @@ -217,13 +217,13 @@ def build(self): expected_global_binary_paths = [os.path.join(package_folder, "bin")] expected_global_libs = ["libstarlight", "ground", "libplanet", "solar", "magnetism", "libiss"] expected_global_exes = ["exelauncher"] - self.assertIn("GLOBAL Include Paths: %s" % expected_global_include_paths, client.out) - self.assertIn("GLOBAL Library Paths: %s" % expected_global_library_paths, client.out) - self.assertIn("GLOBAL Binary Paths: %s" % expected_global_binary_paths, client.out) + self.assertIn("GLOBAL Include paths: %s" % expected_global_include_paths, client.out) + self.assertIn("GLOBAL Library paths: %s" % expected_global_library_paths, client.out) + self.assertIn("GLOBAL Binary paths: %s" % expected_global_binary_paths, client.out) self.assertIn("GLOBAL Libs: %s" % expected_global_libs, client.out) self.assertIn("GLOBAL Exes: %s" % expected_global_exes, client.out) - self.assertIn("DEPS Include Paths: %s" % expected_global_include_paths, client.out) + self.assertIn("DEPS Include paths: %s" % expected_global_include_paths, client.out) self.assertIn("DEPS Library paths: %s" % expected_global_library_paths, client.out) self.assertIn("DEPS Binary paths: %s" % expected_global_binary_paths, client.out) self.assertIn("DEPS Libs: %s" % expected_global_libs, client.out) diff --git a/conans/test/unittests/model/build_info_test.py b/conans/test/unittests/model/build_info_test.py index c0f6ea26e69..c89af8c1be8 100644 --- a/conans/test/unittests/model/build_info_test.py +++ b/conans/test/unittests/model/build_info_test.py @@ -184,7 +184,8 @@ def basic_components_test(self): self.assertEqual(component.lib, "libhola") with six.assertRaisesRegex(self, ConanException, "'.lib' is already set for this Component"): component.exe = "hola.exe" - component.lib = None + + component = cpp_info["my_other_component"] component.exe = "hola.exe" self.assertEqual(component.lib, None) with six.assertRaisesRegex(self, ConanException, "'.exe' is already set for this Component"): From b0852118b9d65e31b7e0848f59a990b16a66084e Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Thu, 20 Jun 2019 18:31:02 +0200 Subject: [PATCH 32/47] fix path repetition --- conans/model/build_info.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/conans/model/build_info.py b/conans/model/build_info.py index 54360a0be99..0c1febfab27 100644 --- a/conans/model/build_info.py +++ b/conans/model/build_info.py @@ -158,8 +158,6 @@ def _get_paths(self, path_name): if self._components: for dep_value in self._components.values(): abs_paths = self._filter_paths(getattr(dep_value, "%s_paths" % path_name)) - if not getattr(self, "_%s_paths" % path_name): - result.extend(abs_paths) for path in abs_paths: if path not in result: result.append(path) From ebd80e39939129ac45fcb69aeccee8a5e77c7b89 Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Thu, 20 Jun 2019 18:31:23 +0200 Subject: [PATCH 33/47] remove endline --- conans/test/unittests/model/build_info_test.py | 1 - 1 file changed, 1 deletion(-) diff --git a/conans/test/unittests/model/build_info_test.py b/conans/test/unittests/model/build_info_test.py index c89af8c1be8..b88878994dc 100644 --- a/conans/test/unittests/model/build_info_test.py +++ b/conans/test/unittests/model/build_info_test.py @@ -364,4 +364,3 @@ def cppinfo_exes_test(self): with six.assertRaisesRegex(self, ConanException, "Setting first level exes is not supported " "when Components are already in use"): info.exes = ["another_exe"] - From 63f8235e4682fe694953475345debe18f0d39a8a Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Thu, 20 Jun 2019 18:31:38 +0200 Subject: [PATCH 34/47] move default values dict --- conans/model/build_info.py | 48 ++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/conans/model/build_info.py b/conans/model/build_info.py index 0c1febfab27..106c8b6de86 100644 --- a/conans/model/build_info.py +++ b/conans/model/build_info.py @@ -222,17 +222,7 @@ class CppInfo(_CppInfo): def __init__(self, root_folder): super(CppInfo, self).__init__() self.rootpath = root_folder # the full path of the package in which the conans is found - self.includedirs.append(DEFAULT_INCLUDE) - self.libdirs.append(DEFAULT_LIB) - self.bindirs.append(DEFAULT_BIN) - self.resdirs.append(DEFAULT_RES) - self.builddirs.append(DEFAULT_BUILD) - # public_deps is needed to accumulate list of deps for cmake targets - self.public_deps = [] - self.configs = {} - - def _check_dirs_values(self): - default_dirs_mapping = { + self._default_dirs_values = { "includedirs": [DEFAULT_INCLUDE], "libdirs": [DEFAULT_LIB], "bindirs": [DEFAULT_BIN], @@ -240,23 +230,25 @@ def _check_dirs_values(self): "builddirs": [DEFAULT_BUILD], "srcdirs": [] } + self.includedirs.extend(self._default_dirs_values["includedirs"]) + self.libdirs.extend(self._default_dirs_values["libdirs"]) + self.bindirs.extend(self._default_dirs_values["bindirs"]) + self.resdirs.extend(self._default_dirs_values["resdirs"]) + self.builddirs.extend(self._default_dirs_values["builddirs"]) + # public_deps is needed to accumulate list of deps for cmake targets + self.public_deps = [] + self.configs = {} + + def _check_dirs_values(self): msg_template = "Using Components and global '{}' values ('{}') is not supported" - for dir_name in default_dirs_mapping: + for dir_name in self._default_dirs_values: dirs_value = getattr(self, dir_name) - if dirs_value is not None and dirs_value != default_dirs_mapping[dir_name]: + if dirs_value is not None and dirs_value != self._default_dirs_values[dir_name]: raise ConanException(msg_template.format(dir_name, dirs_value)) def _clear_dirs_values(self): - default_dirs_mapping = { - "includedirs": [DEFAULT_INCLUDE], - "libdirs": [DEFAULT_LIB], - "bindirs": [DEFAULT_BIN], - "resdirs": [DEFAULT_RES], - "builddirs": [DEFAULT_BUILD], - "srcdirs": [] - } - for dir_name in default_dirs_mapping: - if getattr(self, dir_name) == default_dirs_mapping[dir_name]: + for dir_name in self._default_dirs_values: + if getattr(self, dir_name) == self._default_dirs_values[dir_name]: self.__dict__[dir_name] = None def __getitem__(self, key): @@ -278,11 +270,11 @@ def _get_cpp_info(): result = _CppInfo() result.rootpath = self.rootpath result.sysroot = self.sysroot - result.includedirs.append(DEFAULT_INCLUDE) - result.libdirs.append(DEFAULT_LIB) - result.bindirs.append(DEFAULT_BIN) - result.resdirs.append(DEFAULT_RES) - result.builddirs.append(DEFAULT_BUILD) + result.includedirs.extend(self._default_dirs_values["includedirs"]) + result.libdirs.extend(self._default_dirs_values["libdirs"]) + result.bindirs.extend(self._default_dirs_values["bindirs"]) + result.resdirs.extend(self._default_dirs_values["resdirs"]) + result.builddirs.extend(self._default_dirs_values["builddirs"]) return result return self.configs.setdefault(config, _get_cpp_info()) From 2c3e3d74d12b683a754f129cc69e0d5137a57d72 Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Thu, 20 Jun 2019 18:34:24 +0200 Subject: [PATCH 35/47] Use is none --- conans/model/build_info.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/conans/model/build_info.py b/conans/model/build_info.py index 106c8b6de86..ca47b8e10cb 100644 --- a/conans/model/build_info.py +++ b/conans/model/build_info.py @@ -167,37 +167,37 @@ def _get_paths(self, path_name): @property def include_paths(self): - if not self._include_paths: + if self._include_paths is None: self._include_paths = self._get_paths("include") return self._include_paths @property def lib_paths(self): - if not self._lib_paths: + if self._lib_paths is None: self._lib_paths = self._get_paths("lib") return self._lib_paths @property def src_paths(self): - if not self._src_paths: + if self._src_paths is None: self._src_paths = self._get_paths("src") return self._src_paths @property def bin_paths(self): - if not self._bin_paths: + if self._bin_paths is None: self._bin_paths = self._get_paths("bin") return self._bin_paths @property def build_paths(self): - if not self._build_paths: + if self._build_paths is None: self._build_paths = self._get_paths("build") return self._build_paths @property def res_paths(self): - if not self._res_paths: + if self._res_paths is None: self._res_paths = self._get_paths("res") return self._res_paths From c01ba50510b10f30ecd80df7c5ba9844827eaf38 Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Fri, 21 Jun 2019 10:00:05 +0200 Subject: [PATCH 36/47] Completed test --- conans/test/integration/package_info_test.py | 74 +++++++++++++++++--- 1 file changed, 65 insertions(+), 9 deletions(-) diff --git a/conans/test/integration/package_info_test.py b/conans/test/integration/package_info_test.py index df4fb7f40f3..2af8f3f7571 100644 --- a/conans/test/integration/package_info_test.py +++ b/conans/test/integration/package_info_test.py @@ -209,14 +209,44 @@ def build(self): client.run("create conanfile_consumer.py consumer/1.0@us/ch") package_folder = client.cache.package_layout(dep_ref).package(dep_pref) - expected_global_include_paths = [os.path.join(package_folder, "galaxy", "starlight"), - os.path.join(package_folder, "galaxy", "planet"), - os.path.join(package_folder, "galaxy", "iss")] - expected_global_library_paths = [os.path.join(package_folder, "lib"), - os.path.join(package_folder, "iss_libs")] - expected_global_binary_paths = [os.path.join(package_folder, "bin")] - expected_global_libs = ["libstarlight", "ground", "libplanet", "solar", "magnetism", "libiss"] - expected_global_exes = ["exelauncher"] + expected_comp_starlight_include_paths = [os.path.join(package_folder, "galaxy", "starlight")] + expected_comp_planet_include_paths = [os.path.join(package_folder, "galaxy", "planet")] + expected_comp_launcher_include_paths = [] + expected_comp_iss_include_paths = [os.path.join(package_folder, "galaxy", "iss")] + expected_comp_starlight_library_paths = [os.path.join(package_folder, "lib")] + expected_comp_launcher_library_paths = [os.path.join(package_folder, "lib")] + expected_comp_planet_library_paths = [os.path.join(package_folder, "lib")] + expected_comp_iss_library_paths = [os.path.join(package_folder, "iss_libs")] + expected_comp_starlight_binary_paths = [os.path.join(package_folder, "bin")] + expected_comp_launcher_binary_paths = [os.path.join(package_folder, "bin")] + expected_comp_planet_binary_paths = [os.path.join(package_folder, "bin")] + expected_comp_iss_binary_paths = [os.path.join(package_folder, "bin")] + expected_comp_starlight_lib = "libstarlight" + expected_comp_planet_lib = "libplanet" + expected_comp_launcher_lib = None + expected_comp_iss_lib = "libiss" + expected_comp_starlight_system_deps = [] + expected_comp_planet_system_deps = [] + expected_comp_launcher_system_deps = ["ground"] + expected_comp_iss_system_deps = ["solar", "magnetism"] + expected_comp_starlight_exe = "" + expected_comp_planet_exe = "" + expected_comp_launcher_exe = "exelauncher" + expected_comp_iss_exe = "" + + expected_global_include_paths = expected_comp_starlight_include_paths + \ + expected_comp_planet_include_paths + expected_comp_iss_include_paths + expected_global_library_paths = expected_comp_starlight_library_paths + \ + expected_comp_iss_library_paths + expected_global_binary_paths = expected_comp_starlight_binary_paths + expected_global_libs = expected_comp_starlight_system_deps + expected_global_libs.append(expected_comp_starlight_lib) + expected_global_libs.extend(expected_comp_launcher_system_deps) + expected_global_libs.append(expected_comp_planet_lib) + expected_global_libs.extend(expected_comp_iss_system_deps) + expected_global_libs.append(expected_comp_iss_lib) + expected_global_exes = [expected_comp_launcher_exe] + self.assertIn("GLOBAL Include paths: %s" % expected_global_include_paths, client.out) self.assertIn("GLOBAL Library paths: %s" % expected_global_library_paths, client.out) self.assertIn("GLOBAL Binary paths: %s" % expected_global_binary_paths, client.out) @@ -229,4 +259,30 @@ def build(self): self.assertIn("DEPS Libs: %s" % expected_global_libs, client.out) self.assertIn("DEPS Exes: %s" % expected_global_exes, client.out) - #TODO: Complete the test checking the output of the components + self.assertIn("COMP Starlight Include paths: %s" % expected_comp_starlight_include_paths, + client.out) + self.assertIn("COMP Planet Include paths: %s" % expected_comp_planet_include_paths, + client.out) + self.assertIn("COMP Launcher Include paths: %s" % expected_comp_launcher_include_paths, + client.out) + self.assertIn("COMP ISS Include paths: %s" % expected_comp_iss_include_paths, client.out) + self.assertIn("COMP Starlight Library paths: %s" % expected_comp_starlight_library_paths, + client.out) + self.assertIn("COMP Planet Library paths: %s" % expected_comp_planet_library_paths, + client.out) + self.assertIn("COMP Launcher Library paths: %s" % expected_comp_launcher_library_paths, + client.out) + self.assertIn("COMP ISS Library paths: %s" % expected_comp_iss_library_paths, client.out) + self.assertIn("COMP Starlight Binary paths: %s" % expected_comp_iss_binary_paths, client.out) + self.assertIn("COMP Planet Binary paths: %s" % expected_comp_planet_binary_paths, client.out) + self.assertIn("COMP Launcher Binary paths: %s" % expected_comp_launcher_binary_paths, + client.out) + self.assertIn("COMP ISS Binary paths: %s" % expected_comp_iss_binary_paths, client.out) + self.assertIn("COMP Starlight Lib: %s" % expected_comp_starlight_lib, client.out) + self.assertIn("COMP Planet Lib: %s" % expected_comp_planet_lib, client.out) + self.assertIn("COMP Launcher Lib: %s" % expected_comp_launcher_lib, client.out) + self.assertIn("COMP ISS Lib: %s" % expected_comp_iss_lib, client.out) + self.assertIn("COMP Starlight Exe: %s" % expected_comp_starlight_exe, client.out) + self.assertIn("COMP Planet Exe: %s" % expected_comp_planet_exe, client.out) + self.assertIn("COMP Launcher Exe: %s" % expected_comp_launcher_exe, client.out) + self.assertIn("COMP ISS Exe: %s" % expected_comp_iss_exe, client.out) From d15006048e9ec273d5a45f7423ac5096cd5c5a45 Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Fri, 21 Jun 2019 10:11:29 +0200 Subject: [PATCH 37/47] Added deps_cpp_info.system_deps global --- conans/model/build_info.py | 1 + conans/test/integration/package_info_test.py | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/conans/model/build_info.py b/conans/model/build_info.py index ca47b8e10cb..02d5352fbde 100644 --- a/conans/model/build_info.py +++ b/conans/model/build_info.py @@ -383,6 +383,7 @@ def merge_lists(seq1, seq2): self.cflags = merge_lists(dep_cpp_info.cflags, self.cflags) self.sharedlinkflags = merge_lists(dep_cpp_info.sharedlinkflags, self.sharedlinkflags) self.exelinkflags = merge_lists(dep_cpp_info.exelinkflags, self.exelinkflags) + self.system_deps = merge_lists(dep_cpp_info.system_deps, self.system_deps) if not self.sysroot: self.sysroot = dep_cpp_info.sysroot diff --git a/conans/test/integration/package_info_test.py b/conans/test/integration/package_info_test.py index 2af8f3f7571..8a884df10ec 100644 --- a/conans/test/integration/package_info_test.py +++ b/conans/test/integration/package_info_test.py @@ -175,6 +175,7 @@ def build(self): self.output.info("GLOBAL Binary paths: %s" % self.deps_cpp_info.bin_paths) self.output.info("GLOBAL Libs: %s" % self.deps_cpp_info.libs) self.output.info("GLOBAL Exes: %s" % self.deps_cpp_info.exes) + self.output.info("GLOBAL System deps: %s" % self.deps_cpp_info.system_deps) # Deps values for dep_key, dep_value in self.deps_cpp_info.dependencies: self.output.info("DEPS Include paths: %s" % dep_value.include_paths) @@ -182,6 +183,7 @@ def build(self): self.output.info("DEPS Binary paths: %s" % dep_value.bin_paths) self.output.info("DEPS Libs: %s" % dep_value.libs) self.output.info("DEPS Exes: %s" % dep_value.exes) + self.output.info("DEPS System deps: %s" % dep_value.system_deps) # Components values for dep_key, dep_value in self.deps_cpp_info.dependencies: for comp_name, comp_value in dep_value.components.items(): @@ -192,6 +194,7 @@ def build(self): self.output.info("COMP %s Lib: %s" % (comp_name, comp_value.lib)) self.output.info("COMP %s Exe: %s" % (comp_name, comp_value.exe)) self.output.info("COMP %s Deps: %s" % (comp_name, comp_value.deps)) + self.output.info("COMP %s System deps: %s" % (comp_name, comp_value.system_deps)) """) client = TestClient() @@ -239,25 +242,27 @@ def build(self): expected_global_library_paths = expected_comp_starlight_library_paths + \ expected_comp_iss_library_paths expected_global_binary_paths = expected_comp_starlight_binary_paths - expected_global_libs = expected_comp_starlight_system_deps - expected_global_libs.append(expected_comp_starlight_lib) + expected_global_libs = expected_comp_starlight_system_deps + [expected_comp_starlight_lib] expected_global_libs.extend(expected_comp_launcher_system_deps) expected_global_libs.append(expected_comp_planet_lib) expected_global_libs.extend(expected_comp_iss_system_deps) expected_global_libs.append(expected_comp_iss_lib) expected_global_exes = [expected_comp_launcher_exe] + expected_global_system_deps = expected_comp_launcher_system_deps + expected_comp_iss_system_deps self.assertIn("GLOBAL Include paths: %s" % expected_global_include_paths, client.out) self.assertIn("GLOBAL Library paths: %s" % expected_global_library_paths, client.out) self.assertIn("GLOBAL Binary paths: %s" % expected_global_binary_paths, client.out) self.assertIn("GLOBAL Libs: %s" % expected_global_libs, client.out) self.assertIn("GLOBAL Exes: %s" % expected_global_exes, client.out) + self.assertIn("GLOBAL System deps: %s" % expected_global_system_deps, client.out) self.assertIn("DEPS Include paths: %s" % expected_global_include_paths, client.out) self.assertIn("DEPS Library paths: %s" % expected_global_library_paths, client.out) self.assertIn("DEPS Binary paths: %s" % expected_global_binary_paths, client.out) self.assertIn("DEPS Libs: %s" % expected_global_libs, client.out) self.assertIn("DEPS Exes: %s" % expected_global_exes, client.out) + self.assertIn("DEPS System deps: %s" % expected_global_system_deps, client.out) self.assertIn("COMP Starlight Include paths: %s" % expected_comp_starlight_include_paths, client.out) @@ -286,3 +291,9 @@ def build(self): self.assertIn("COMP Planet Exe: %s" % expected_comp_planet_exe, client.out) self.assertIn("COMP Launcher Exe: %s" % expected_comp_launcher_exe, client.out) self.assertIn("COMP ISS Exe: %s" % expected_comp_iss_exe, client.out) + self.assertIn("COMP Starlight System deps: %s" % expected_comp_starlight_system_deps, + client.out) + self.assertIn("COMP Planet System deps: %s" % expected_comp_planet_system_deps, client.out) + self.assertIn("COMP Launcher System deps: %s" % expected_comp_launcher_system_deps, + client.out) + self.assertIn("COMP ISS System deps: %s" % expected_comp_iss_system_deps, client.out) From f61e2d99ec097bc525705c23b3458b3768b7a9e3 Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Fri, 21 Jun 2019 11:40:44 +0200 Subject: [PATCH 38/47] simplified link order property, added test and fixed other ones --- conans/model/build_info.py | 28 ++++++++++--------- .../test/unittests/model/build_info_test.py | 17 ++++++++--- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/conans/model/build_info.py b/conans/model/build_info.py index 02d5352fbde..550d8234ea1 100644 --- a/conans/model/build_info.py +++ b/conans/model/build_info.py @@ -55,22 +55,24 @@ def _sorted_components(self): Sorted components from less dependent to the most one :return: ordered list of components """ - # Sort first elements with less items in .deps attribute - comps = sorted(self._components.values(), key=lambda component: len(component.deps)) # Save name of unsorted elements - unsorted_names = [comp.name for comp in comps] - + unsorted_names = self._components.keys() sorted_comps = [] + element = unsorted_names[0] while unsorted_names: - for comp in comps: - # If element is already sorted, continue - if comp.name not in unsorted_names: - continue - # If element does not have deps or all of its deps are already sorted, sort this - # element and remove it from the unsorted list - elif not comp.deps or not [dep for dep in comp.deps if dep in unsorted_names]: - sorted_comps.append(comp) - unsorted_names.remove(comp.name) + try: + deps = self._components[element].deps + except KeyError as e: + raise ConanException("Component %s not found in cpp_info object" % e) + if all(dep in [c.name for c in sorted_comps] for dep in deps): + sorted_comps.append(self._components[element]) + unsorted_names.remove(element) + element = unsorted_names[0] if unsorted_names else None + else: + for dep in deps: + if dep not in [c.name for c in sorted_comps]: + element = dep + break return sorted_comps @property diff --git a/conans/test/unittests/model/build_info_test.py b/conans/test/unittests/model/build_info_test.py index b88878994dc..3fa5f43a377 100644 --- a/conans/test/unittests/model/build_info_test.py +++ b/conans/test/unittests/model/build_info_test.py @@ -221,7 +221,7 @@ def cpp_info_system_deps_test(self): info["LIB2"].system_deps = ["sys2"] info["LIB1"].deps = ["LIB3"] info["LIB3"].system_deps = ["sys3", "sys2"] - self.assertEqual(['sys2', 'sys3', 'sys1', 'sys11'], info.libs) + self.assertEqual(['sys3', 'sys2', 'sys1', 'sys11'], info.libs) info["LIB3"].system_deps = [None, "sys2"] self.assertEqual(['sys2', 'sys1', 'sys11'], info.libs) @@ -241,15 +241,16 @@ def cpp_info_libs_system_deps_order_test(self): info["LIB1"].deps = ["LIB2"] info["LIB2"].lib = "lib2" info["LIB2"].system_deps = ["sys2"] - info["LIB1"].deps = ["LIB3"] + info["LIB2"].deps = ["LIB3"] info["LIB3"].lib = "lib3" info["LIB3"].system_deps = ["sys3", "sys2"] - self.assertEqual(['sys2', 'lib2', 'sys3', 'lib3', 'sys1', 'sys11', 'lib1'], info.libs) - self.assertEqual(['sys2', 'sys3', 'sys1', 'sys11'], info.system_deps) + self.assertEqual(['sys3', 'sys2', 'lib3', 'lib2', 'sys1', 'sys11', 'lib1'], info.libs) + self.assertEqual(['sys3', 'sys2', 'sys1', 'sys11'], info.system_deps) def cpp_info_link_order_test(self): def _assert_link_order(sorted_libs): + assert sorted_libs, "'sorted_libs' is empty" for num, lib in enumerate(sorted_libs): component_name = lib[-1] for dep in info[component_name].deps: @@ -297,6 +298,14 @@ def _assert_link_order(sorted_libs): info["B"].deps = [] _assert_link_order(info.libs) + def cppinfo_inexistent_component_dep_test(self): + info = CppInfo(None) + info["LIB1"].lib = "lib1" + info["LIB1"].deps = ["LIB2"] + with six.assertRaisesRegex(self, ConanException, "Component 'LIB2' not found in cpp_info " + "object"): + info.libs + def cppinfo_dirs_test(self): folder = temp_folder() info = CppInfo(folder) From 0dbb94303389aa49edeb954f2d2caf47df09605a Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Fri, 21 Jun 2019 11:56:04 +0200 Subject: [PATCH 39/47] get paths in order too --- conans/model/build_info.py | 4 ++-- conans/test/integration/package_info_test.py | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/conans/model/build_info.py b/conans/model/build_info.py index 550d8234ea1..d958f13aa1a 100644 --- a/conans/model/build_info.py +++ b/conans/model/build_info.py @@ -56,7 +56,7 @@ def _sorted_components(self): :return: ordered list of components """ # Save name of unsorted elements - unsorted_names = self._components.keys() + unsorted_names = list(self._components.keys()) sorted_comps = [] element = unsorted_names[0] while unsorted_names: @@ -158,7 +158,7 @@ def _get_paths(self, path_name): result = [] if self._components: - for dep_value in self._components.values(): + for dep_value in self._sorted_components: abs_paths = self._filter_paths(getattr(dep_value, "%s_paths" % path_name)) for path in abs_paths: if path not in result: diff --git a/conans/test/integration/package_info_test.py b/conans/test/integration/package_info_test.py index 8a884df10ec..d5aec0e09b9 100644 --- a/conans/test/integration/package_info_test.py +++ b/conans/test/integration/package_info_test.py @@ -243,8 +243,9 @@ def build(self): expected_comp_iss_library_paths expected_global_binary_paths = expected_comp_starlight_binary_paths expected_global_libs = expected_comp_starlight_system_deps + [expected_comp_starlight_lib] - expected_global_libs.extend(expected_comp_launcher_system_deps) + expected_global_libs.extend(expected_comp_planet_system_deps) expected_global_libs.append(expected_comp_planet_lib) + expected_global_libs.extend(expected_comp_launcher_system_deps) expected_global_libs.extend(expected_comp_iss_system_deps) expected_global_libs.append(expected_comp_iss_lib) expected_global_exes = [expected_comp_launcher_exe] From c3da77016481679f13d223a99d8d38dc92615657 Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Fri, 21 Jun 2019 11:59:29 +0200 Subject: [PATCH 40/47] docstring --- conans/model/build_info.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/conans/model/build_info.py b/conans/model/build_info.py index d958f13aa1a..5e67d680aae 100644 --- a/conans/model/build_info.py +++ b/conans/model/build_info.py @@ -134,6 +134,9 @@ def system_deps(self, system_deps): self._system_deps = system_deps def __getitem__(self, key): + """ + This is called when the user accesses to a component: self.cpp_info["whatever"] + """ if self._libs: raise ConanException("Usage of Components with '.libs' values is not allowed") if key not in self._components.keys(): From 195665cbc6a499016d982d68b47c80a001b1b728 Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Fri, 21 Jun 2019 12:06:24 +0200 Subject: [PATCH 41/47] improve system_deps test --- conans/test/unittests/model/build_info_test.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/conans/test/unittests/model/build_info_test.py b/conans/test/unittests/model/build_info_test.py index 3fa5f43a377..5a5dc66cd15 100644 --- a/conans/test/unittests/model/build_info_test.py +++ b/conans/test/unittests/model/build_info_test.py @@ -219,17 +219,18 @@ def cpp_info_system_deps_test(self): info["LIB1"].system_deps = ["sys1", "sys11"] info["LIB1"].deps = ["LIB2"] info["LIB2"].system_deps = ["sys2"] - info["LIB1"].deps = ["LIB3"] + info["LIB2"].deps = ["LIB3"] info["LIB3"].system_deps = ["sys3", "sys2"] self.assertEqual(['sys3', 'sys2', 'sys1', 'sys11'], info.libs) + self.assertEqual(['sys3', 'sys2', 'sys1', 'sys11'], info.system_deps) info["LIB3"].system_deps = [None, "sys2"] self.assertEqual(['sys2', 'sys1', 'sys11'], info.libs) + self.assertEqual(['sys2', 'sys1', 'sys11'], info.system_deps) with six.assertRaisesRegex(self, ConanException, "Setting first level system_deps is not " "supported when Components are already in " "use"): info.system_deps = ["random_system"] - self.assertEqual(['sys2', 'sys1', 'sys11'], info.system_deps) def cpp_info_libs_system_deps_order_test(self): """ From ff6fca347443be6f1216100833c3d0655c6980f1 Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Fri, 21 Jun 2019 13:15:30 +0200 Subject: [PATCH 42/47] merge methods --- conans/model/build_info.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/conans/model/build_info.py b/conans/model/build_info.py index 5e67d680aae..e0b7fbcaea0 100644 --- a/conans/model/build_info.py +++ b/conans/model/build_info.py @@ -244,23 +244,19 @@ def __init__(self, root_folder): self.public_deps = [] self.configs = {} - def _check_dirs_values(self): - msg_template = "Using Components and global '{}' values ('{}') is not supported" + def _check_and_clear_dirs_values(self): for dir_name in self._default_dirs_values: dirs_value = getattr(self, dir_name) if dirs_value is not None and dirs_value != self._default_dirs_values[dir_name]: + msg_template = "Using Components and global '{}' values ('{}') is not supported" raise ConanException(msg_template.format(dir_name, dirs_value)) - - def _clear_dirs_values(self): - for dir_name in self._default_dirs_values: - if getattr(self, dir_name) == self._default_dirs_values[dir_name]: + else: self.__dict__[dir_name] = None def __getitem__(self, key): if self._libs or self._exes: raise ConanException("Usage of Components with '.libs' or '.exes' values is not allowed") - self._clear_dirs_values() - self._check_dirs_values() + self._check_and_clear_dirs_values() if key not in self._components: self._components[key] = Component(key, self.rootpath) return self._components[key] From 1c95d9b773e065b27a74b527cd88e2936c431031 Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Fri, 21 Jun 2019 17:13:57 +0200 Subject: [PATCH 43/47] Added components to the cpp_info json output --- conans/client/recorder/action_recorder.py | 17 +++++++-- conans/model/build_info.py | 10 +++++ .../functional/command/json_output_test.py | 37 +++++++++++++++++++ 3 files changed, 60 insertions(+), 4 deletions(-) diff --git a/conans/client/recorder/action_recorder.py b/conans/client/recorder/action_recorder.py index 9efa287a76a..0be7610b0e9 100644 --- a/conans/client/recorder/action_recorder.py +++ b/conans/client/recorder/action_recorder.py @@ -24,18 +24,27 @@ def _cpp_info_to_dict(cpp_info): doc = {} - for it, value in vars(cpp_info).items(): - if (it.startswith("_") and it != "_libs") or not value: + items = vars(cpp_info).items() + if not cpp_info._components: + items = items + [("libs", cpp_info.libs), ("exes", cpp_info.exes), + ("system_deps", cpp_info.system_deps)] + for key, value in items: + if key.startswith("_components") and value: + doc["components"] = {} + for comp_key, comp_value in value.items(): + doc["components"][comp_key] = comp_value.as_dict() + continue + + if key.startswith("_") or not value: continue - if it == "configs": + if key == "configs": configs_data = {} for cfg_name, cfg_cpp_info in value.items(): configs_data[cfg_name] = _cpp_info_to_dict(cfg_cpp_info) doc["configs"] = configs_data continue - key = "libs" if it == "_libs" else it doc[key] = value return doc diff --git a/conans/model/build_info.py b/conans/model/build_info.py index e0b7fbcaea0..ec949b52965 100644 --- a/conans/model/build_info.py +++ b/conans/model/build_info.py @@ -304,6 +304,16 @@ def __init__(self, name, root_folder): self.exelinkflags = [] self._filter_empty = True + def as_dict(self): + result = {} + for key, value in vars(self).items(): + if key.startswith("_"): + continue + result[key] = value + result["lib"] = self.lib + result["exe"] = self.exe + return result + def _filter_paths(self, paths): abs_paths = [os.path.join(self._rootpath, p) for p in paths] if self._filter_empty: diff --git a/conans/test/functional/command/json_output_test.py b/conans/test/functional/command/json_output_test.py index ef6c72d5c0c..b9a84271112 100644 --- a/conans/test/functional/command/json_output_test.py +++ b/conans/test/functional/command/json_output_test.py @@ -218,3 +218,40 @@ def package_info(self): for dupe in dupe_nodes: self.assertEqual(cpp_info[dupe], cpp_info_debug[dupe]) self.assertEqual(cpp_info[dupe], cpp_info_release[dupe]) + + def test_json_create_cpp_info_components(self): + conanfile = textwrap.dedent(""" + from conans import ConanFile + + class Lib(ConanFile): + def package_info(self): + self.cpp_info.name = "Boost" + self.cpp_info["whatever"].lib = "libwhaterver" + self.cpp_info["whatever"].system_deps = ["sysdep1", "sysdep2"] + self.cpp_info["whenever"].lib = "libwhenever" + self.cpp_info["whenever"].deps = ["whatever"] + self.cpp_info["however"].exe = "exehowever" + self.cpp_info["however"].system_deps = ["pthread"] + self.cpp_info["however"].deps = ["whenever"] + """) + self.client.save({'conanfile.py': conanfile}) + self.client.run("create . name/version@user/channel --json=myfile.json") + my_json = load(os.path.join(self.client.current_folder, "myfile.json")) + my_json = json.loads(my_json) + + # Nodes with cpp_info + cpp_info = my_json["installed"][0]["packages"][0]["cpp_info"] + + self.assertEqual("Boost", cpp_info["name"]) + self.assertFalse("includedirs" in cpp_info) + self.assertFalse("includedirs" in cpp_info) + self.assertFalse("includedirs" in cpp_info) + self.assertFalse("includedirs" in cpp_info) + self.assertFalse("libs" in cpp_info) + self.assertFalse("exes" in cpp_info) + self.assertFalse("system_deps" in cpp_info) + self.assertEqual("libwhaterver", cpp_info["components"]["whatever"]["lib"]) + self.assertEqual("libwhenever", cpp_info["components"]["whenever"]["lib"]) + self.assertEqual("exehowever", cpp_info["components"]["however"]["exe"]) + self.assertEqual(["pthread"], cpp_info["components"]["however"]["system_deps"]) + self.assertEqual(["sysdep1", "sysdep2"], cpp_info["components"]["whatever"]["system_deps"]) From 6cdda0f604f917a4ac09e85071ebc0cd9643a4b0 Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Mon, 24 Jun 2019 19:18:24 +0200 Subject: [PATCH 44/47] loop check with test --- conans/model/build_info.py | 10 +++++++ .../test/unittests/model/build_info_test.py | 26 +++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/conans/model/build_info.py b/conans/model/build_info.py index ec949b52965..74130b4a947 100644 --- a/conans/model/build_info.py +++ b/conans/model/build_info.py @@ -59,6 +59,7 @@ def _sorted_components(self): unsorted_names = list(self._components.keys()) sorted_comps = [] element = unsorted_names[0] + search_buffer = [] while unsorted_names: try: deps = self._components[element].deps @@ -67,10 +68,19 @@ def _sorted_components(self): if all(dep in [c.name for c in sorted_comps] for dep in deps): sorted_comps.append(self._components[element]) unsorted_names.remove(element) + search_buffer = [] element = unsorted_names[0] if unsorted_names else None else: for dep in deps: if dep not in [c.name for c in sorted_comps]: + if dep in search_buffer: + if len(search_buffer) > 1: + search_buffer.remove(dep) + raise ConanException("Detected loop calculating the link order of " + "components. Please check the '.deps' and resolve " + "the circular depency of '%s' with %s" % + (dep, search_buffer)) + search_buffer.append(dep) element = dep break return sorted_comps diff --git a/conans/test/unittests/model/build_info_test.py b/conans/test/unittests/model/build_info_test.py index 5a5dc66cd15..8e97d8e858d 100644 --- a/conans/test/unittests/model/build_info_test.py +++ b/conans/test/unittests/model/build_info_test.py @@ -307,6 +307,32 @@ def cppinfo_inexistent_component_dep_test(self): "object"): info.libs + def cpp_info_components_dep_loop_test(self): + info = CppInfo(None) + info["LIB1"].lib = "lib1" + info["LIB1"].deps = ["LIB1"] + msg_template = "Detected loop calculating the link order of components. Please check the " \ + "'.deps' and resolve the circular depency of '{}' with {}" + with six.assertRaisesRegex(self, ConanException, msg_template.format("LIB1", ["LIB1"])): + info.libs + info = CppInfo(None) + info["LIB1"].lib = "lib1" + info["LIB1"].deps = ["LIB2"] + info["LIB2"].lib = "lib2" + info["LIB2"].deps = ["LIB1", "LIB2"] + with six.assertRaisesRegex(self, ConanException, msg_template.format("LIB2", ["LIB1"])): + info.libs + info = CppInfo(None) + info["LIB1"].lib = "lib1" + info["LIB1"].deps = ["LIB2"] + info["LIB2"].lib = "lib2" + info["LIB2"].deps = ["LIB3"] + info["LIB3"].lib = "lib3" + info["LIB3"].deps = ["LIB1"] + with six.assertRaisesRegex(self, ConanException, + msg_template.format("LIB3", ["LIB1", "LIB2"])): + info.libs + def cppinfo_dirs_test(self): folder = temp_folder() info = CppInfo(folder) From 93f6c8d931cd54cc6aa5d0e9df498209cdf6f200 Mon Sep 17 00:00:00 2001 From: Luis Martinez de Bartolome <lasote@gmail.com> Date: Tue, 25 Jun 2019 09:44:28 +0200 Subject: [PATCH 45/47] 5090 fixes --- conans/client/recorder/action_recorder.py | 2 +- conans/model/build_info.py | 48 +++++++------------ conans/test/integration/package_info_test.py | 3 -- .../test/unittests/model/build_info_test.py | 14 +++--- 4 files changed, 23 insertions(+), 44 deletions(-) diff --git a/conans/client/recorder/action_recorder.py b/conans/client/recorder/action_recorder.py index 0be7610b0e9..f612d6bc843 100644 --- a/conans/client/recorder/action_recorder.py +++ b/conans/client/recorder/action_recorder.py @@ -24,7 +24,7 @@ def _cpp_info_to_dict(cpp_info): doc = {} - items = vars(cpp_info).items() + items = list(vars(cpp_info).items()) if not cpp_info._components: items = items + [("libs", cpp_info.libs), ("exes", cpp_info.exes), ("system_deps", cpp_info.system_deps)] diff --git a/conans/model/build_info.py b/conans/model/build_info.py index 74130b4a947..430520b0357 100644 --- a/conans/model/build_info.py +++ b/conans/model/build_info.py @@ -51,39 +51,23 @@ def __init__(self): @property def _sorted_components(self): - """ - Sorted components from less dependent to the most one - :return: ordered list of components - """ - # Save name of unsorted elements - unsorted_names = list(self._components.keys()) - sorted_comps = [] - element = unsorted_names[0] - search_buffer = [] - while unsorted_names: - try: - deps = self._components[element].deps - except KeyError as e: - raise ConanException("Component %s not found in cpp_info object" % e) - if all(dep in [c.name for c in sorted_comps] for dep in deps): - sorted_comps.append(self._components[element]) - unsorted_names.remove(element) - search_buffer = [] - element = unsorted_names[0] if unsorted_names else None + ordered = OrderedDict() + while len(ordered) != len(self._components): + # Search for next element to be processed + for comp_name, comp in self._components.items(): + if comp_name in ordered: + continue + # check if all the deps are declared + if not all([dep in self._components for dep in comp.deps]): + raise ConanException("Component '%s' declares a missing dependency" % comp.name) + # check if all the deps are already added to ordered + if all([dep in ordered for dep in comp.deps]): + break else: - for dep in deps: - if dep not in [c.name for c in sorted_comps]: - if dep in search_buffer: - if len(search_buffer) > 1: - search_buffer.remove(dep) - raise ConanException("Detected loop calculating the link order of " - "components. Please check the '.deps' and resolve " - "the circular depency of '%s' with %s" % - (dep, search_buffer)) - search_buffer.append(dep) - element = dep - break - return sorted_comps + raise ConanException("There is a loop between your cpp_info declared components") + + ordered[comp_name] = comp + return ordered.values() @property def libs(self): diff --git a/conans/test/integration/package_info_test.py b/conans/test/integration/package_info_test.py index d5aec0e09b9..da5a6959116 100644 --- a/conans/test/integration/package_info_test.py +++ b/conans/test/integration/package_info_test.py @@ -2,9 +2,6 @@ import textwrap import unittest -import six - -from conans.errors import ConanException from conans.model.ref import ConanFileReference, PackageReference from conans.paths import CONANFILE, CONANFILE_TXT from conans.test.utils.tools import TestClient, NO_SETTINGS_PACKAGE_ID diff --git a/conans/test/unittests/model/build_info_test.py b/conans/test/unittests/model/build_info_test.py index 8e97d8e858d..cb79f3a377e 100644 --- a/conans/test/unittests/model/build_info_test.py +++ b/conans/test/unittests/model/build_info_test.py @@ -303,24 +303,23 @@ def cppinfo_inexistent_component_dep_test(self): info = CppInfo(None) info["LIB1"].lib = "lib1" info["LIB1"].deps = ["LIB2"] - with six.assertRaisesRegex(self, ConanException, "Component 'LIB2' not found in cpp_info " - "object"): + with six.assertRaisesRegex(self, ConanException, "Component 'LIB1' " + "declares a missing dependency"): info.libs def cpp_info_components_dep_loop_test(self): info = CppInfo(None) info["LIB1"].lib = "lib1" info["LIB1"].deps = ["LIB1"] - msg_template = "Detected loop calculating the link order of components. Please check the " \ - "'.deps' and resolve the circular depency of '{}' with {}" - with six.assertRaisesRegex(self, ConanException, msg_template.format("LIB1", ["LIB1"])): + msg = "There is a loop between your cpp_info declared components" + with six.assertRaisesRegex(self, ConanException, msg): info.libs info = CppInfo(None) info["LIB1"].lib = "lib1" info["LIB1"].deps = ["LIB2"] info["LIB2"].lib = "lib2" info["LIB2"].deps = ["LIB1", "LIB2"] - with six.assertRaisesRegex(self, ConanException, msg_template.format("LIB2", ["LIB1"])): + with six.assertRaisesRegex(self, ConanException, msg): info.libs info = CppInfo(None) info["LIB1"].lib = "lib1" @@ -329,8 +328,7 @@ def cpp_info_components_dep_loop_test(self): info["LIB2"].deps = ["LIB3"] info["LIB3"].lib = "lib3" info["LIB3"].deps = ["LIB1"] - with six.assertRaisesRegex(self, ConanException, - msg_template.format("LIB3", ["LIB1", "LIB2"])): + with six.assertRaisesRegex(self, ConanException, msg): info.libs def cppinfo_dirs_test(self): From 1036bd8467dca05372a1d63bb75217680f3638ac Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Tue, 25 Jun 2019 10:08:40 +0200 Subject: [PATCH 46/47] improved message --- conans/model/build_info.py | 3 ++- conans/test/unittests/model/build_info_test.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/conans/model/build_info.py b/conans/model/build_info.py index 430520b0357..60a43566abf 100644 --- a/conans/model/build_info.py +++ b/conans/model/build_info.py @@ -64,7 +64,8 @@ def _sorted_components(self): if all([dep in ordered for dep in comp.deps]): break else: - raise ConanException("There is a loop between your cpp_info declared components") + raise ConanException("There is a dependency loop in the components declared in " + "'self.cpp_info'") ordered[comp_name] = comp return ordered.values() diff --git a/conans/test/unittests/model/build_info_test.py b/conans/test/unittests/model/build_info_test.py index cb79f3a377e..bfe26c21380 100644 --- a/conans/test/unittests/model/build_info_test.py +++ b/conans/test/unittests/model/build_info_test.py @@ -311,7 +311,7 @@ def cpp_info_components_dep_loop_test(self): info = CppInfo(None) info["LIB1"].lib = "lib1" info["LIB1"].deps = ["LIB1"] - msg = "There is a loop between your cpp_info declared components" + msg = "There is a dependency loop in the components declared in 'self.cpp_info'" with six.assertRaisesRegex(self, ConanException, msg): info.libs info = CppInfo(None) From 9696a4a8f4f29360059093904c1c522a0a4a943d Mon Sep 17 00:00:00 2001 From: danimtb <danimanzaneque@gmail.com> Date: Tue, 25 Jun 2019 12:30:46 +0200 Subject: [PATCH 47/47] remove cppflags from component class --- conans/model/build_info.py | 1 - 1 file changed, 1 deletion(-) diff --git a/conans/model/build_info.py b/conans/model/build_info.py index 60a43566abf..0b22d271ebc 100644 --- a/conans/model/build_info.py +++ b/conans/model/build_info.py @@ -293,7 +293,6 @@ def __init__(self, name, root_folder): self.srcdirs = [] self.defines = [] self.cflags = [] - self.cppflags = [] self.cxxflags = [] self.sharedlinkflags = [] self.exelinkflags = []