conan-io / conan

Conan - The open-source C and C++ package manager
https://conan.io
MIT License
8.11k stars 963 forks source link

[question] Dependent package is not rebuilt when triggering conan install --build=missing #16635

Open NilsKlimanis opened 1 month ago

NilsKlimanis commented 1 month ago

What is your question?

Hi! We are using Conan 2.4.1 with a mixture of packages of different origins, some open source, some are our own libraries. Now we have the following situation: Let's say we have three packages A, B, C and M (leaving out other dependencies, but I think they shouldn't matter) M depends on all packages. C depends on A and B, B depends on A. A is a header-only library, B is a shared library, C is currently a static library. M is the "main" recipe of our product.

We generate a lockfile for M and then basically do a conan install --build=missing when we want to build updated packages. Initially, only package A had a package-type set ("header-library"), the others didn't had any package-type set.

First experiment: When I now change recipe A and trigger conan install --build=missing then only packages A (obviously) and package B are rebuilt. But against my expectation, C is not rebuilt.

Second experiment: I added the appropriate package-types to package B and C and then changed recipe A again. This time A, B, and C were being rebuilt, as expected.

Third experiment: Now I changed recipe B, and triggered the rebuild. But this time, only B was rebuilt, but not C. The conaninfo.txt for package C in the [requires] section contains references to A and B that look like this:

A/x.y@user/channel#***:***
B/x.y@user/channel

This means, that the reference for A contains the revision and package id but B does not.

How can this be explained? I would have thought, that dependent packages are all automatically rebuilt? What could block this?

Have you read the CONTRIBUTING guide?

memsharded commented 1 month ago

Hi @NilsKlimanis

Thanks for your question.

only package A had a package-type set ("header-library"), the others didn't had any package-type set.

This doesn't matter if the packages B, C have the shared option defined. If they have it, they will automatically deduce the package-type. Otherwise, it would be very important to define the package_type to have the right propagation of information.

Second experiment: I added the appropriate package-types to package B and C and then changed recipe A again. This time A, B, and C were being rebuilt, as expected.

Exactly, it is necessary to do it

Third experiment: Now I changed recipe B, and triggered the rebuild. But this time, only B was rebuilt, but not C. The conaninfo.txt for package C in the [requires] section contains references to A and B that look like this:

This is where the versioning becomes very important. Not all changes trigger rebuilds, depending on the package types, that define an "embed-mode" or "non-embed-mode", the rebuilding is triggered by versioning.

When there is "embed-mode" then basically every change in recipes will trigger rebuilds. But when there is "non-embed-mode", then only minor version updates trigger rebuilds, but not patches. This way it is extremely efficient to do a change in a .cpp file of a static library, you can update a dependency graph of dozens of other static library packages depending on this one, and no one will need a rebuild, if you only bump the patch version of that package.

You can read more about it in https://docs.conan.io/2/reference/binary_model/dependencies.html, and also https://docs.conan.io/2/reference/conanfile/attributes.html#reference-conanfile-attributes-package-id-modes might have some interesting further details

marlamb commented 1 month ago

Hi @memsharded ,

I have some follow-up questions. As far as I understand the main reason to use the non-embed mode is to get rid of redundant builds saving compute times. On the down-side this requires quite some detailed control over the software built. I have two examples were I would be interested how they are meant to be. Both are basically targeting the restriction mentioned in the documentation

This assumes that there are not inlined functionalities in the dependency headers, and the headers are pure interface and not implementation.

I could imagine one very common use-case are patches, e.g. to compile libraries with another compiler or newer language standards. Patches applied by at the beginning of the build step are IMO in general a very powerful tool. Now to my understanding the patch should not change the actual version of the packaged software (at least I have not seen something like that in the conan-center-index, even for patches that are changing header files and could therefore even be seen as major), mainly because we should not use potential future release numbers. Does that mean every recipe patched that way should also be flagged with the package_id_non_embed_mode attribute to full_mode? Currently grepping through the conan-center-index there is only one match for package_id_non_embed_mode (which is even setting it the the value it is by default anyhow), which looks pretty optimistic to me.

The second example are templates. As far as I can see many open source libraries are using a mixture of templates and non-templated code. We can use opencv as a prominent and widely-used example. What would be the correct annotation for this kind of library? It isn't header-only, but it contains templated code, such that the restriction for the "non-embed mode" is very difficult to track down (we could of course assume that the maintainers consider every change in a header as a breaking major change, but it would very much surprise me if that would work in reality...). However, I currently assume that the library is either considered a shared-library or a static-library from conan point of view, depending on the options and conan will use that information to deduce if it can use the "non-embed mode", correct? If that is true, what would be the best annotation for such a library to state a mixture of "header" and "non-header" library?

Looking forward to understand a little more about the design decisions and ideas how to use conan most efficiently :smile: .

memsharded commented 1 month ago

Thanks for the feedback @marlamb

I could imagine one very common use-case are patches, e.g. to compile libraries with another compiler or newer language standards. Patches applied by at the beginning of the build step are IMO in general a very powerful tool. Now to my understanding the patch should not change the actual version of the packaged software (at least I have not seen something like that in the conan-center-index, even for patches that are changing header files and could therefore even be seen as major), mainly because we should not use potential future release numbers. Does that mean every recipe patched that way should also be flagged with the package_id_non_embed_mode attribute to full_mode? Currently grepping through the conan-center-index there is only one match for package_id_non_embed_mode (which is even setting it the the value it is by default anyhow), which looks pretty optimistic to me.

There are two very different use cases here:

The assumption is that patches in ConanCenter are exclusively or almost exclusively to do the minimal adaptations necessary to build system scripts to allow them build and integrate with other dependencies. Patches to C/C++ source code are very discouraged, and most of them should be rejected nowadays in ConanCenter, unless there are very strong reasons. It is true that in the past it was a bit more relaxed but not anymore. Source changes should be done in the upstream repos, not in ConanCenter recipes. So when doing patches to ConanCenter recipes, the assumption is that they will not be changing the public interfaces of the package, and then the default package_id modes will still be pretty safe.

The second example are templates. As far as I can see many open source libraries are using a mixture of templates and non-templated code. We can use opencv as a prominent and widely-used example. What would be the correct annotation for this kind of library? It isn't header-only, but it contains templated code, such that the restriction for the "non-embed mode" is very difficult to track down (we could of course assume that the maintainers consider every change in a header as a breaking major change, but it would very much surprise me if that would work in reality...). However, I currently assume that the library is either considered a shared-library or a static-library from conan point of view, depending on the options and conan will use that information to deduce if it can use the "non-embed mode", correct? If that is true, what would be the best annotation for such a library to state a mixture of "header" and "non-header" library?

The current package_type = "library" is good, and then let it behave as static library or shared library depending on the options. When there are new changes to opencv source code, that will imply new versions for opencv package, not new revisions. If the project versioning bumps only a patch version but is doing changes to public interfaces, that wouldn't be very semver-compliance. In that case it would be good to change the non-embed-mode to patch_mode instead of the current minor_mode. But so far this hasn't been reported.

As a summary:

memsharded commented 1 month ago

Any further question @marlamb ?

Maybe we can close the ticket as responded, you can always create new tickets for any new question or issue. Thanks!

marlamb commented 1 month ago

From my point of view sufficiently answered. Perhaps we should also ask @NilsKlimanis if he has any further questions?

memsharded commented 1 month ago

Sure, sorry, I didn't see @NilsKlimanis was the OP