-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
Describe the bug
Conan version 2.22.1
How to reproduce it
lib_a/conanfile.py
from conan import ConanFile
class ConanLibA(ConanFile):
name = "lib_a"
package_type = "header-library"conan export lib_a --version 1.0
conan export lib_a --version 1.1
conan export lib_a --version 1.2
lib_b/conanfile.py
from conan import ConanFile
class ConanLibB(ConanFile):
name="lib_b"
version="1.0"
package_type = "static-library"
def requirements(self):
self.requires("lib_a/[>=1]")conan export lib_b
lib_c/conanfile.py
from conan import ConanFile
class ConanLibC(ConanFile):
name="lib_c"
version="1.0"
package_type = "shared-library"
def requirements(self):
self.requires("lib_b/1.0", visible=False)
self.requires("lib_a/1.1", visible=True)Happy path (this is the expected outcome)
conan graph info lib_c --format html > graph.html --no-remote
Requirements
lib_a/1.1#6a0c16aa1e2f729b87c13ce846c6fd24:da39a3ee5e6b4b0d3255bfef95601890afd80709 - Missing
lib_b/1.0#3ed7aadc114623df36e0697db429e9a8:fcdabf9ba48019c6920aec36e9d7e15d8446b678 - Missing
Buggy path? (I found this outcome unexpected and unwanted...)
swap the order of those two lines in requirements, so lib_a comes first:
def requirements(self):
+ self.requires("lib_a/1.1", visible=True)
self.requires("lib_b/1.0", visible=False)
- self.requires("lib_a/1.1", visible=True)Now the override/forced resolution doesn't happen, and I get a dependency graph with both lib_a/1.1 and lib_a/1.2
Requirements
lib_a/1.1#6a0c16aa1e2f729b87c13ce846c6fd24 - Cache
lib_a/1.2#6a0c16aa1e2f729b87c13ce846c6fd24 - Cache
lib_b/1.0#3ed7aadc114623df36e0697db429e9a8 - Cache
Resolved version ranges
lib_a/[>=1]: lib_a/1.2
Seemingly now the usage of lib_a/1.1 doesn't get propagated to its upstream lib_b, so the version range in lib_b just resolved to the latest (lib_a/1.2). Now both versions of lib_a are visible in the the self.dependencies of lib_c if I add
def generate(self):
for require, dependency in self.dependencies.items():
self.output.info(f"{require} -> {dependency}")conan install lib_c --no-remote --build missing
conanfile.py (lib_c/1.0): lib_a/1.1, Traits: build=False, headers=True, libs=False, run=False, visible=True -> lib_a/1.1
conanfile.py (lib_c/1.0): lib_b/1.0, Traits: build=False, headers=True, libs=True, run=False, visible=False -> lib_b/1.0
conanfile.py (lib_c/1.0): lib_a/1.2, Traits: build=False, headers=False, libs=False, run=False, visible=False -> lib_a/1.2
This seems wrong in several ways:
- The upstream/downstream relationships certainly matter, but I did not expect the order sibling edges (lib_c -> lib_a and lib_c -> lib_b) are added to change the resulting dependency graph. Nothing in https://docs.conan.io/2/reference/conanfile/methods/requirements.html suggests that order requirements are listed within a single recipe matters... just upstream/downstream relationships.
- As I understand it,
visible=Falseis supposed to affect whether a require is propagated downstream. So I didn't expect that to change anything about what is (or isn't) present in the current recipe's self.dependencies, or what gets forced upstream. - The latter outcome (having lib_c depend directly on lib_a/1.1, and transitively on lib_a/1.2 via lib_b) would lead to undefined behavior in linking lib_c - the object files in lib_b (a static-library) will have embedded symbols from lib_a/1.2 (a header-library), while sources directly compiled in lib_c will embed lib_a/1.1, so linking these both into lib_c's shared module is (probably) an ODR violation.