Gentoo Archives: gentoo-dev

From: "Michał Górny" <mgorny@g.o>
To: gentoo-dev <gentoo-dev@l.g.o>
Subject: [gentoo-dev] [RFC] Forced/automatic USE flag constraints (codename: ENFORCED_USE)
Date: Mon, 29 May 2017 15:33:29
Message-Id: 1496071993.31087.1.camel@gentoo.org
1 Hello,
2
3 For a long time we seem to be missing appropriate tools to handle USE
4 flag constraints efficiently. EAPI 4 brought REQUIRED_USE but all things
5 considered, it has proven to be far from an optimal solution. I would
6 therefore like to discuss adding a better tool to amend or replace it,
7 to allow for automated handling of USE flag constraints.
8
9
10 1. Motivation
11 =============
12
13 [[This section is purely informational. It is not up for discussion. If
14 you really can't help yourself and need to discuss superiority of
15 example A over example B, then please have mercy and wait for a few days
16 to give developers a chance to stay focused on the proposal at hand.]]
17
18 EAPI 4 provides REQUIRED_USE as a simple tool to enforce USE flag
19 constraints for packages. It can be used to express dependencies between
20 flags (e.g. A requires B). However, it poses a few problems which
21 results in developers being reluctant to use them and which limit their
22 use cases. Most notably:
23
24 1. They require an explicit action from the user. A large number of USE
25 flag constraints can be frustrating, especially when most of them are
26 trivial to solve.
27
28 2. They can cause a significant clutter in package.use. As a result,
29 changing past decisions becomes hard as the user may need to find
30 past USE flag changes and revert them.
31
32 3. The constraint output is sometimes considered hard to comprehend.
33
34 Those issues have resulted in developers sometimes avoiding REQUIRED_USE
35 in favor of other solutions such as implicit behavior (ignoring USE
36 flags), additional control flags (think PYTHON_SINGLE_TARGET) or
37 pkg_pretend() (which is horribly slow).
38
39 I think that the problems are most visible when dealing with 'provider
40 flags', that is USE flags that are used to choose between different
41 libraries providing the same feature. There are three basic approaches
42 to the problem:
43
44 A. Binary provider flags (+ feature flags), e.g.:
45
46 USE='[ssl] libressl' -> use LibreSSL
47 USE='[ssl] -libressl' -> use OpenSSL
48 USE='-ssl' -> disable SSL/TLS (USE=libressl ignored)
49
50 B. Unary provider flags with REQUIRED_USE:
51
52 USE='libressl -openssl' -> use LibreSSL
53 USE='-libressl openssl' -> use OpenSSL
54 USE='libressl openssl' -> invalid
55 USE='-libressl -openssl' -> disable SSL/TLS or invalid
56
57 C. Unary provider flags without REQUIRED_USE:
58
59 USE='libressl -openssl' -> use LibreSSL
60 USE='-libressl openssl' -> use OpenSSL
61 USE='libressl openssl' -> use LibreSSL or OpenSSL, depending on pkg
62 USE='-libressl -openssl' -> disable SSL/TLS or as above
63
64 Sometimes solutions B and C are amended with additional feature flags to
65 reduce the confusion.
66
67 Each of these solutions has its disadvantages. What's worse, they are
68 sometimes not even used consistently within a single ecosystem -- going
69 as far as using the same USE flag with slightly different meaning.
70 The Gentoo developer attitude 'my package, my way' does not help here.
71
72 Solving all of the listed problems is not possible with the existing
73 tools as each of the possible solutions has its own issues, and it is
74 impossible to get developers to agree on one of them.
75
76
77 2. Specification
78 ================
79
80 2.1. Forced USE flag constraints
81 ================================
82
83 This proposal introduces USE flag constraints that are meant to be
84 solved automatically by the package manager. This is somewhat similar to
85 REQUIRED_USE, except that it does not require the user to take any
86 explicit action. In that regard, it is closer to conditional
87 package.use.force/mask.
88
89 In the basic form, it can be used to conditionally force a specific flag
90 to be enabled or disabled. For example:
91
92 foo? ( bar )
93
94 would mean that the bar flag is implicitly enabled (forced) if foo is
95 enabled as well. Appropriately:
96
97 foo? ( !bar )
98
99 would mean that the bar flag is implicitly disabled (masked) in that
100 case.
101
102 It can also be used with multi-flag ??, ^^ and || constraints, i.e.:
103
104 - ?? means that at most one of the flags can be enabled. If user
105 configuration causes more than one of the flags to be enabled,
106 additional flags are implicitly disabled (masked) to satisfy
107 the constraint.
108
109 - || means that at least one of the flags must be enabled. If user
110 configuration causes none of the flags to be enabled, one of them is
111 enabled implicitly (forced).
112
113 - ^^ means that exactly one of the flags must be enabled. The behavior
114 is a combination of both above constraints.
115
116 The automated solving of USE constraints would require the developers to
117 consider the implicit effect of the constraints they are writing.
118
119
120 2.2. UI implications
121 ====================
122
123 The automated flag handling would require an appropriate UI changes, to
124 clearly indicate whenever the flags are being altered automatically.
125 Otherwise, users might be confused of their requested USE flags not
126 being applied correctly.
127
128 In the most basic form, a solution similar to use.force/use.mask can be
129 used, e.g.:
130
131 USE="[bar] [-baz] foo"
132
133 with square brackets indicating that the flags have been forced/masked
134 by other USE flags on the list. It would also be necessary for
135 the package manager to provide more verbose information on USE flag
136 constraints being applied, either implicitly or on request.
137
138 For simple constraints, the visual presentation can be even included
139 in place, e.g.:
140
141 USE="foo -> [bar -baz]"
142
143 indicating that both constraints were forced by the flag 'foo' (i.e.
144 that disabling 'foo' would loosen them).
145
146 For multi-flag constraints (??, ^^, ||), the package manager could even
147 go as far to group the flags together with explicit constraint notation,
148 e.g.:
149
150 USE="^^ [ foo -bar -baz ]"
151
152 The exact UI design is left to the package manager developers. Those are
153 merely proof-of-concept ideas.
154
155
156 2.3. Configuration bits
157 =======================
158
159 In its most basic form, this proposal does not require explicit
160 configuration -- all flags are applied automatically. However, a few
161 bits might be useful.
162
163 Firstly, the package manager might provide a way to explicitly forbid
164 switching specific flags or automatically applying the constraints
165 completely. If the user uses that, it will just fail in the same way as
166 REQUIRED_USE fails now.
167
168 Secondly, it might be reasonable to provide configurable priorities for
169 solving multi-flag constraints. For example, we could use rightmost-
170 preferred logic for package.use, e.g.:
171
172 */* PROVIDER_SSL: openssl gnutls
173 dev-util/foo PROVIDER_SSL: polarssl
174
175 which would mean that for all packages, gnutls is preferred over openssl
176 (i.e. if ?? or ^^ applies, openssl will be disabled and gnutls will be
177 used), and polarssl is additionally preferred over everything else for
178 dev-util/foo.
179
180
181 2.4. Backwards compatibility
182 ============================
183
184 Before choosing the exact way of implementing this, we need to answer
185 how far we want to provide backwards compatibility. In particular:
186
187 a. Do we need the REQUIRED_USE requiring explicit user selection? Or can
188 we rely completely on other solutions (automatic solving,
189 pkg_pretend())?
190
191 b. Would changing REQUIRED_USE behavior in place cause unintended side
192 effects? Are we going to accept those effects until the packages are
193 fixed? (e.g. selecting less preferred solution of constraint)
194
195 If we can agree on doing the change in place (retroactively), I think we
196 can start solving a few major issues. For example, I would be really
197 happy to kill PYTHON_SINGLE_TARGET flags in favor of constraints on
198 PYTHON_TARGETS being solved automatically. We could also look into
199 unifying provider flags into PROVIDER_SSL, PROVIDER_AV etc.
200
201 I should point out that strictly speaking, PMS does not define any
202 specific handling of REQUIRED_USE. It only defines that the ebuild must
203 not be used if the constraints are not met:
204
205 | If the package manager encounters a package version where REQUIRED_USE
206 | assertions are not met, it must treat this package version as if
207 it      
208 | was masked. No phase functions must be
209 called.                                                                 
210                                  
211
212 In other words, it does not define whether the package manager should
213 request the user to explicitly solve the problem or whether it should be
214 solved automatically. However, from past discussions I recall that
215 the original intent of REQUIRED_USE was for machine processing, and so I
216 would consider it reasonable to start using it.
217
218
219 2.5. Ebuild interface
220 =====================
221
222 This section is most flexible as I don't really care how it's done,
223 as long as it's done. Depending on our preferences, and the answers to
224 questions in the preceding section, the options include:
225
226 1. changing behavior of REQUIRED_USE retroactively -- i.e. making
227 Portage start solving USE constraints automatically, and being able to
228 rely on that a few months from now,
229
230 2. changing behavior of REQUIRED_USE in a future EAPI,
231
232 3. adding ENFORCED_USE with the new behavior in a future EAPI
233 (and either keeping or removing REQUIRED_USE),
234
235 4. adding special syntax to REQUIRED_USE to indicate which constraints
236 can be solved automatically,
237
238 5. adding special syntax to IUSE to indicate which flags can be enabled
239 or disabled automatically via REQUIRED_USE (a little different from
240 the exact proposal),
241
242 6. adding a dedicated variable to indicate USE_EXPAND sets that can be
243 solved automatically via REQUIRED_USE (partial solution).
244
245
246 3. Rationale
247 ============
248
249 I believe this solution to be quite optimal. It solves most of
250 the issues with the REQUIRED_USE, making it a feasible solution to many
251 of the existing problems, including those that were not even worth
252 considering with the current REQUIRED_USE semantics.
253
254 Reusing the existing syntax has the advantage of lowering the learning
255 curve and simplifying the specification. We can even enable the new
256 semantics without changing the PMS (provided that variant 1. is chosen),
257 or with as little duplication as possible. However, the developers will
258 be required to start considering the implicit effects of their
259 constraints (as a matter of policy).
260
261 Automatically solving USE constraints solve all three fore-mentioned
262 issues with REQUIRED_USE. By default, no user intervention is required
263 to solve USE constraints and package.use needs to be modified only to
264 enforce a non-standard solutons. While the 'readability of output' is
265 not really changed per se, most of the time users wouldn't have to read
266 it.
267
268 As pointed out throughout the text, automatically solved USE constraints
269 can be used to replace existing hacks for different kinds of problems:
270
271 A. Packages supporting selecting a subset of possible targets, e.g.
272 Python implementations. Currently we have packages supporting 'any
273 number of implementations', 'one implementation only' and 'one python2*
274 + one python3*'. For user convenience, we hacked the second into
275 separate PYTHON_SINGLE_TARGET flags which encumbered the implementation
276 seriously, and we discouraged the third case completely. With
277 automatically solved USE constraints, we'd just use PYTHON_TARGETS for
278 everything, and let the constraints handle invalid combinations, e.g.:
279
280 PYTHON_TARGETS="python2_7 python3_5 {-python3_4} {-python3_6} ..."
281
282 B. Provider flags. With automatically solved constraints, we can easily
283 move them all into unary USE_EXPAND sets with USE constraints, and let
284 the PM handle selecting the one most preferred automatically, e.g.:
285
286 USE="[ssl]" PROVIDER_SSL="gnutls {-openssl} {-libressl} ..."
287
288 What's important, the automatic flags have the advantage of being both
289 clearer in meaning than implicit flags, and more convenient than
290 REQUIRED_USE. In other words, the user clearly sees which implementation
291 (provider) is used, and can change that in a relatively easy way.
292
293 Furthermore, the explicit visibility of selection reduces the number of
294 USE flag combinations in binary packages. That is, we can easily reduce
295 the number of different apparent sets of USE flags that build the same
296 package, making it easier for binary packages to match.
297
298
299 4. Comments
300 ===========
301
302 What do you think?
303
304
305 --
306 Best regards,
307 Michał Górny

Attachments

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

Replies