conan-io / conan

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

[question] Remove option if having a dependency to a certain package #16470

Closed MTomBosch closed 2 weeks ago

MTomBosch commented 2 weeks ago

What is your question?

Hello, we are using the most recent version of Conan 1.x.

We have a use case where an option is defined in a Conan base class that is used in many of our project components.

Now what I need to achieve is that in case a component A has a direct or indirect dependency to another predefined component C I need to remove this option from A.

PS. The whole use case is a bit more complicated but the above description reflects the state where I am currently stuck.

I have already figured out how to remove the option via the configure() method but I am struggling with figuring out how to remove the option only when the mentioned dependency is available and not always.

Any ideas how to accomplish this?

Thank you

Have you read the CONTRIBUTING guide?

memsharded commented 2 weeks ago

Hi @MTomBosch

Thanks for your question.

Some quick clarifications:

We have a use case where an option is defined in a Conan base class that is used in many of our project components.

Do you mean, with python_requires and python_requires_extend?

Options might not be directly inherited if the recipe contains its own options, are you using the init() method to compose the options? (https://docs.conan.io/1/extending/python_requires.html#python-requires)

I have already figured out how to remove the option via the configure() method but I am struggling with figuring out how to remove the option only when the mentioned dependency is available and not always.

It seems that this is that this is a chicken and egg problem, specially if the dependency is not a direct one but a transitive one. The configure() is evaluated when the graph is being computed, so the dependencies do not exist yet. But the decisions taken in the configure() also affects the dependencies, as there are often conditional requirements.

It seems that to resolve the chicken-and-egg, it would be necessary to abstract the conditions that make that dependency is available, and use that condition, instead of the dependency existence.

MTomBosch commented 2 weeks ago

I apologoize for not giving enough details. Yes we are using the python_requires mechanism and I am also aware of necessity to use the init() function to take over the options of the base class into the derived Conan recipe class.

Thanks for your hints.

MTomBosch commented 2 weeks ago

Regarding "It seems that to resolve the chicken-and-egg, it would be necessary to abstract the conditions that make that dependency is available, and use that condition, instead of the dependency existence." This is working in theory but in my projet there are many components with different ways of defining the dependencies. Harmonizing this to an abstract condition would be possible but would take a very long time. I will still try to get it done.

But is there in the meantime a more "pragmatic" (or someone would call it "hacky") way to remove the option, e.g. in the package() method, ... which I could try out?

Another short question: Initially I wanted to dynamically add an option (not a value but the option declaration).But when looking into other posts and the official doc I could not find any reference saying that this is possible at all. Is the assumption correct that all options always must be declared statically and I can only dynamically remove certain option from the package metadata if not required?

memsharded commented 2 weeks ago

What would be the goal or the desired effect of removing the option? So it doesn't affect the package_id?

Unused options are mostly not a problem at all in recipes, so depending on the problem to be solved, we could try to think of some possible other alternatives.

MTomBosch commented 2 weeks ago

Yes, one of the goals is to not get a new package variant/package id if the specific option is either set to a specific value or this package has no dependency to a predefined other package. Because of this I was also asking if it is possible to add an option dynamically depending on the above condition.

And as non-functional requirement I would like to achieve this with the least effort, meaning I want to change as few files (recipes) and as less code as possible.

What a colleague and mine have now come up with is following idea:

Does that make sense? Do you might have a better idea?

memsharded commented 2 weeks ago

Yes, one of the goals is to not get a new package variant/package id if the specific option is either set to a specific value or this package has no dependency to a predefined other package. Because of this I was also asking if it is possible to add an option dynamically depending on the above condition.

This is perfectly valid code, you can remove options from the package_id in the package_id() method, and you can condition that on dependencies:

def package_id(self):
    if self.dependencies.... # the check you want to do
          self.info.options.rm_safe("some_option")

Note the removal happens over the self.info object, not over the self.options object. Because the self.info is the one used to compute the final package_id value.

Because of this I was also asking if it is possible to add an option dynamically depending on the above condition.

Adding an option just for the package_id doesn't have "physical" sense. Different package-ids mean different binaries, because of different conditions. For this to happen, the option should have existed before to be able to condition the build(). And waiting until the dependency graph is evaluated to add an option would also be a chicken-and-egg problem, because the options do affect the dependency graph itself.

Make an analysis of the current dep tree and (ask the related development team to) add to any of its maintained packages that has a dependency to the predefined package the predefined option. The name and allowed values of the option shall be the same over all these package recipes.

Yes, this totally sounds like the "higher level abstraction" that I was suggesting, some way to represent the dependency existence.

And as non-functional requirement I would like to achieve this with the least effort, meaning I want to change as few files (recipes) and as less code as possible.

This might not be possible in Conan 1. Conan 2 has some better mechanisms to control package_id, for example it allows to inject into packages-ids any arbitrary conf value, and as confs can also be defined per-package, this could be used to force inject changes in package-ids of dependencies without having to touch the dependencies code at all. Seems a bit hacky though, and like a workaround for not having an upfront model for the binary variability, that recipes should explicitly declare.

MTomBosch commented 2 weeks ago

Ok. Thanks a lot for the hints.