New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[bug] test_requires causing cycle/loop in the dependency graph #15412
Comments
Hi @DoDoENT Thanks for your report. So far it seems this is not a bug. The graph, defined as such, is causing an infinite cycle/loop in the dependency graph, not even related to The issue seems to be in the The following test shows that limiting the test-require in abseil works and can correctly construct the dependency graph: def test_test_require_loop(self):
# https://github.com/conan-io/conan/issues/15412
self._cache_recipe("gtest/1.11", GenConanfile())
self._cache_recipe("abseil/1.0", GenConanfile().with_test_requires("gtest/[>=1 <1.14]"))
self._cache_recipe("gtest/1.14", GenConanfile().with_requires("abseil/1.0"))
deps_graph = self.build_graph(GenConanfile("opencv", "1.0").with_test_requires("gtest/1.14"))
self.assertEqual(4, len(deps_graph.nodes))
opencv = deps_graph.root
gtest14 = opencv.dependencies[0].dst
abseil = gtest14.dependencies[0].dst
gtest11 = abseil.dependencies[0].dst
self._check_node(opencv, "opencv/1.0@", deps=[gtest14], dependents=[])
self._check_node(gtest14, "gtest/1.14#123", deps=[abseil], dependents=[opencv])
self._check_node(abseil, "abseil/1.0#123", deps=[gtest11], dependents=[gtest14])
self._check_node(gtest11, "gtest/1.11#123", deps=[], dependents=[abseil]) |
I understand your point when building the Isn't the purpose of |
The dependency graph is always computed first, even before computing which binaries do exist. It is not possible to decide: I already have a binary for this package, then I no longer expand the dependency graph, because the binaries themselves depends on the versions of the dependencies. Then it is necessary to compute the whole dependency graph of versions before computing and deciding which binaries do exists.
Still the whole graph, including |
I understand that, and this brings me back to the question I think I had already on some other issue or even during tribe discussion: why are I understand that I think we should make a clear distinction between requirements specified as |
Because several reasons:
Delaying these to a later stage can be from impossible in some cases like the Furthermore the lack of locking in lockfiles when the graph was not fully expanded was a major pain in Conan 1.X. Also the missing information for buildInfo, package migrations from server to server in CI pipelines, etc. This resulted in the decision that the dependency graph is always fully computed in Conan 2.0. The cost of downloading one |
I'm 100% sure that
For
Again, completely makes sense for This is not the case at the moment, which makes it difficult to understand the purpose of the If you take all combinations of Here is my current understanding of the intentions of traits:
|
When you are expanding the graph, you don't even know what package binary to check for in the cache, because you don't have the All the traits combinations that you are describing are still irrelevant to this problem. Conan 2.0 is designed to always expand the full dependency graph, the traits are just indicators about how some information is propagated down the graph, and it can affect how dependencies can conflict or how This issue of having only partial graphs, not fully expanded to include tool and test requires was one of the most common and problematic issues in Conan 1.X, and Conan 2.0 will not compute partial graphs (at least at the moment, there are plans to investigate further the Users that want to control the graph expansion, at their own responsibility, can introduce conditional requirements. Users can introduce or use options or confs to conditionally require
It is not used by Conan propagation or linkage, but it is used to print it in the command output and it also allows users to clearly differentiate dependencies that are needed for testing and those that not, for example if some test_requires transitively depend on |
So, is there absolutely no difference between If so, then please document that, because the current documentation implies that Also, this sentence:
contradicts the fact that |
Sure, this can be better documented. The current documentation reads:
It means that the includes and libraries ("included and linked") will not be propagated downstream. It doesn't mean that there cannot be cycles, but we can certainly clarify that in the docs. To make it clear, even with
No matter how much
A reference can appear in the |
The problematic part in the documentation that confuses both me and most of the people I work with (and talked about conan) is when you say "It's not propagated downstream". What we understand here is that "downstream will not see it". So, imagine then the confusion when this dependency causes conflicts or cycles downstream, where it's not supposed to be visible, because "it's not propagated". Documentation needs to clearly define what "propagating downstream" actually means (i.e. only in C++ terms, the actual libraries don't get linked into the downstream dependency; but the conan package itself does get propagated and can cause conflicts and dependency cycles). And then, we need to find a suggested solution for cases like mine - where the package truly does not want to propagate its dependencies downstream, meaning downstream will never see my dependencies - neither in the lock file, nor in the dependency graph, nor in build system integration, nor anywhere. |
I don't think it will create conflicts. So, if we go back to the root issue reported in this thread, the case is the "cycle/infinite-loop" of dependencies, which is a very different case than conflicts. I understand that propagation and dependency graph computation is not completely obvious in all cases, and maybe there is error to improve the error message, but if we state the root problem of this issue I think we can state that the dependencies:
Is an infinite loop, that cannot be realized, and as such is an error, no matter what any package manager or tool tries to do, no matter what traits or visibility we try to define to Conan. That is an impossible infinite loop. It is not even about the propagation downstream, the graph cannot be computed, because it would be infinite. And that the only solution to break that infinite loop is not depend freely on |
I agree. However, I would like this to be contained to abseil <-> gtest, but not also leaked to every single dependency that test_requires
I actually tried that yesterday, but it quickly escalated. At first, I contained the dependency on For now, my solution is to simply build gtest without abseil/re2 dependencies, as they are still optional, and after they become mandatory, I will try to find some other solution outside of conan. |
How is this possible? |
Yes. We are augmenting So, we need to test all those additional features, so our (I really hope that we will be able to open source our augmentations one day, as they could be really beneficial to others as well). |
I am afraid that without knowing the details, it is difficult to understand the scope. It is not the dependency to gtest that cannot be upgraded, my test |
I'll try to get back to this and maybe even create an open-source reproducer when I find some free time. At the moment I've opted into building |
Having a similar issue here: My test depends on cgal, which depends on GMP/MPFR, and they are all LGPL licensed and conan center has only static libraries available for them. My project does not need CGAL, but it depends on GMP/MPFR which are supposed to be linked dynamically. However, when I try to build my project, the dependency resolve to the static conan GMP/MPFR packages, thus my project will be statically linked to GMP/MPFR. Now I have to remove CGAL from my conan file as a walkaround. Conan is a great tool and would very much appreciate that this could be resolved so I can get back to use Conan. |
Hi @Ruwei-Liu I think that what you are reporting is a different issue, could you please open it as an independent new issue? Thanks |
Environment details
Steps to reproduce
It appears that
test_requires
dependencies somehow get leaked and thus causing the cycles/loops when they shouldn't be.Here is my setup:
abseil/20230802.1.0@company/stable
test_requiresgtest/[~1]@company/stable
re2/20231101.0.0@company/stable
requiresabseil/[^20230802]@company/stable
and test_requiresgtest/[~1]@company/stable
gtest/1.11.0@company/stable
has no dependenciesgtest/1.14.0@company/stable
requires bothabseil/[^20230802]@company/stable
andre2/[^20231101]@company/stable
.The build order is the following:
gtest/1.11.0@company/stable
abseil/202300802.1.0@company/stable
which usedgtest/1.11.0@company/stable
for its testing purposesre2/20231101.0.0@company/stable
which usedgtest/1.11.0@company/stable
for its testing purposes and has a real dependency onabseil/20230802.1.0@company/stable
gtest
to v1.14 and added dependencies toabseil
andre2
, and built the newgtest
package.gtest/1.14.0@company/stable
as test_requires from some other package (e.g.opencv
), fails with the following error:I don't see how this would be a cycle because:
opencv
test_requriesgtest
, which requiresabseil
andre2
(which also requiresabseil
)abseil
andre2
test_requiregtest
should not be leaked toopencv
, as it's not relevant (it may appear in the lock file, but should not enter dependency resolution)Currently, I can still build
gtest/1.14
withoutabseil
andre2
dependencies as they are still optional, and this is my workaround.However, Google has announced that soon gtest will depend on abseil (which itself test-depends on gtest), so this issue needs to be resolved.
Logs
No response
The text was updated successfully, but these errors were encountered: