1 |
Hello, everyone. |
2 |
|
3 |
I would like to hear your opinion on what should be the meaning and use |
4 |
of '|| ( A:= B:= )' dependencies. |
5 |
|
6 |
|
7 |
By the PMS-y definition, any-of dependency can be satisfied by either |
8 |
branch of it, and the provider can be safely switched at runtime. That |
9 |
is: |
10 |
|
11 |
|| ( A B ) |
12 |
|
13 |
means that either a or b has to be installed. If you built the package |
14 |
against A, you can install B, uninstall A and everything is supposed to |
15 |
work without rebuilding. That doesn't really happen when linking is |
16 |
involved. |
17 |
|
18 |
With help of subslots and virtuals we were able to partially solve |
19 |
the issue. For example, look at virtual/libudev. It binds subslot of |
20 |
the virtual to matching subslots of provider libraries. This way, you |
21 |
can safely switch providers as long as they have matching ABI; and if |
22 |
you want to upgrade the provider to another ABI version, you need to |
23 |
upgrade the virtual as well, and therefore rebuild the revdeps. |
24 |
|
25 |
Sadly, virtuals like this can only work when you can expect providers |
26 |
to have matching ABIs. This won't happen e.g. in krb5 providers |
27 |
(the two have incompatible ABIs) or libav* providers (ABIs of some of |
28 |
the libraries differ from version to version). |
29 |
|
30 |
|
31 |
At the moment, some developers already started mixing subslot |
32 |
and any-of operator syntax: |
33 |
|
34 |
|| ( A:= B:= ) |
35 |
|
36 |
However, this breeds a really weird behavior in Portage. |
37 |
|
38 |
With static dependency model, it's partially understandable. ':=' atoms |
39 |
are expanded into specific subslots when matching package is installed, |
40 |
otherwise left unspecified. 'Unspecified' here means that any subslot |
41 |
satisfies the dependency -- like it was plain 'A' or 'B'. |
42 |
|
43 |
So, if during the build only A was installed, further upgrades to A can |
44 |
cause subslot rebuilds. If only B was installed, rebuilds are caused by |
45 |
B likewise. |
46 |
|
47 |
However, if afterwards the other package is installed, it satisfies |
48 |
the other branch of the dependency without subslot, so package doesn't |
49 |
get rebuild on any upgrades of A or B (since the unspecific dep always |
50 |
matches). This happens until the package is manually rebuild and gets |
51 |
the other subslot written. |
52 |
|
53 |
Even more curious behavior is caused if both A and B are installed at |
54 |
build time. In this case, subslots for both packages are expanded. |
55 |
And since || means that either of the branches must match, the subslots |
56 |
of both packages must change for the package to trigger subslot rebuild. |
57 |
|
58 |
In other words, || ( A:= B:= ) means that subslot rebuilds happen only |
59 |
if you consistently use a single provider. Provider switching or having |
60 |
both providers installed break it. |
61 |
|
62 |
|
63 |
Dynamic deps partially fix it. Since the current := support code is |
64 |
very dumb, it doesn't notice the '||' and respects all expanded |
65 |
subslots found in vardb. |
66 |
|
67 |
The main difference is that installing the other dependency doesn't |
68 |
prevent subslot rebuilds from the first one from happening. For |
69 |
example, if you built the package against A and install B afterwards, |
70 |
upgrade of A will still force rebuild of the package (because |
71 |
dynamic-deps code accidentally moves the A:0/1= dep out of || ()). |
72 |
|
73 |
The code also makes the behavior with both providers installed saner. |
74 |
Since both subslots are expanded, both are copied and rebuild of either |
75 |
would cause the rebuild of package. However, in practice it usually |
76 |
causes emerge to fail with slot conflict :). |
77 |
|
78 |
It should be also noted that the dyndeps behavior makes it impossible |
79 |
to uninstall either A or B when both were installed at the reverse |
80 |
dependency build time (since both are added to depgraph). |
81 |
|
82 |
|
83 |
The question would be -- which behavior is desired? I'm pretty sure |
84 |
Ciaran will say that the static dep behavior is correct per definitions |
85 |
but I don't think it's really useful to have slot operator dependencies |
86 |
which work only randomly. Instead, we may decide to redefine it into |
87 |
something useful in a future EAPI. |
88 |
|
89 |
In particular, I was thinking we could reuse this syntax: |
90 |
|
91 |
|| ( A:= B:= ) |
92 |
|
93 |
to express any-of dependencies that do not support runtime switching of |
94 |
providers -- since that is pretty much what := does to slots. This |
95 |
would save us from creating a new syntax like '||= ()' [1]. |
96 |
|
97 |
[1]:https://bugs.gentoo.org/show_bug.cgi?id=489458 |
98 |
|
99 |
|
100 |
If we go this way, we also need to decide whether the order in such |
101 |
block would matter or not. In other words, whether the application can |
102 |
be expected to link to the first installed package in the list, or can |
103 |
link to any of them. |
104 |
|
105 |
If the order would matter, the package would need to be rebuilt when: |
106 |
|
107 |
1. first satisfied dependency changes subslot, |
108 |
|
109 |
2. [optionally] package preceding the first currently satisfied |
110 |
dependency is installed, |
111 |
|
112 |
3. first currently satisfied dependency is uninstalled (but another is |
113 |
installed). |
114 |
|
115 |
If the order wouldn't matter, the package would need to be rebuilt when: |
116 |
|
117 |
1. any of satisfied dependencies changes subslot (since we don't know |
118 |
which one package links to), |
119 |
|
120 |
2. [optionally] any of the remaining packages is installed, |
121 |
|
122 |
3. any of satisfied dependencies is uninstalled. |
123 |
|
124 |
The first option seems more refined, and causes less rebuilds. However, |
125 |
it diverges further from the basic || () definition. The second tries |
126 |
to fit || () and := with minimal changes. |
127 |
|
128 |
Remaining issues: |
129 |
|
130 |
a. behavior of || ( A:= B:= C ) -- should C cause complete provider |
131 |
switching rebuilds? |
132 |
|
133 |
b. do we need ||= ( A B C ) -- i.e. provider switching rebuilds |
134 |
without subslot rebuilds? |
135 |
|
136 |
|
137 |
What do you think? |
138 |
|
139 |
-- |
140 |
Best regards, |
141 |
Michał Górny |