Gentoo Archives: gentoo-dev

From: "Michał Górny" <mgorny@g.o>
To: gentoo-dev@l.g.o
Cc: pms-bugs@g.o, dev-portage@g.o
Subject: [gentoo-dev] The meaning of || ( a:= b:= ) dependencies
Date: Sun, 03 Aug 2014 22:44:42
Message-Id: 20140804004450.5aa146ec@pomiot.lan
1 Hello, everyone.
3 I would like to hear your opinion on what should be the meaning and use
4 of '|| ( A:= B:= )' dependencies.
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:
11 || ( A B )
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.
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.
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).
31 At the moment, some developers already started mixing subslot
32 and any-of operator syntax:
34 || ( A:= B:= )
36 However, this breeds a really weird behavior in Portage.
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'.
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.
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.
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.
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.
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.
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 || ()).
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 :).
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).
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.
89 In particular, I was thinking we could reuse this syntax:
91 || ( A:= B:= )
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].
97 [1]:
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.
105 If the order would matter, the package would need to be rebuilt when:
107 1. first satisfied dependency changes subslot,
109 2. [optionally] package preceding the first currently satisfied
110 dependency is installed,
112 3. first currently satisfied dependency is uninstalled (but another is
113 installed).
115 If the order wouldn't matter, the package would need to be rebuilt when:
117 1. any of satisfied dependencies changes subslot (since we don't know
118 which one package links to),
120 2. [optionally] any of the remaining packages is installed,
122 3. any of satisfied dependencies is uninstalled.
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.
128 Remaining issues:
130 a. behavior of || ( A:= B:= C ) -- should C cause complete provider
131 switching rebuilds?
133 b. do we need ||= ( A B C ) -- i.e. provider switching rebuilds
134 without subslot rebuilds?
137 What do you think?
139 --
140 Best regards,
141 Michał Górny


File name MIME type
signature.asc application/pgp-signature