Gentoo Archives: gentoo-dev

From: Alexis Ballier <aballier@g.o>
To: gentoo-dev@l.g.o
Subject: Re: [gentoo-dev] [RFC] Forced/automatic USE flag constraints (codename: ENFORCED_USE)
Date: Sat, 03 Jun 2017 16:58:52
Message-Id: 20170603185835.57741ff0@gentoo.org
In Reply to: Re: [gentoo-dev] [RFC] Forced/automatic USE flag constraints (codename: ENFORCED_USE) by "Michał Górny"
1 On Sat, 03 Jun 2017 17:33:09 +0200
2 Michał Górny <mgorny@g.o> wrote:
3
4 > On sob, 2017-06-03 at 13:00 +0200, Alexis Ballier wrote:
5 > > This whole thing definitely needs more thought and feedback but for
6 > > now those extra restrictions seem quite natural to me, allow easy
7 > > solving on the PM side and allow to have useful feedback from
8 > > repoman.
9 >
10 > Well, I'll try to figure out the magic you were telling me later but
11 > as a quick note, my specific use case for this are Python targets, so
12 > I'm going throw a few basic concepts that need to work for you to
13 > play with ;-).
14 >
15 > In the following samples pt1,2,.. stands for PYTHON_TARGETS;
16 > pst1,2,... for PYTHON_SINGLE_TARGET. Eventually I'd like to kill the
17 > latter but that depends on how well the autosolving works.
18 >
19 > 1. ^^ ( pst1 pst2 pst3.. ) pst1? ( pt1 ) pst2? ( pt2 ) pst3? ( pt3 )..
20
21 the pt{1,2,...} part does not matter here: they all fail point 4 when
22 compared as 2nd clause to the others (each ptX appears only once in the
23 whole expression), so this boils down to solving n-ary ^^, and to how
24 those are translated: you can have several translations but some would
25 not work properly. Let's try:
26 (a) pst1? ( !pst2 !pst3 )
27 (b) pst2? ( !pst3 )
28 (c) !pst3? ( !pst2? ( pst1 ) )
29
30 Between (a) and (c), points 1 to 3 hold (those points are reflexive).
31 For point 4, "a q'_j is some p_i" will hold in both ways, so we do
32 actually have a cycle between them. Bad luck.
33
34 Let's write (c) as:
35 (c) !pst3? ( !pst2? ( !pst1? ( pst1 ) ) )
36
37 Now, (c) can't break (a) because of point 1: pst1 in (a) vs !pst1 in
38 (c).
39
40
41 (b) can't break (a) because of point 2: q_i=!pst2 is the negation of
42 p_j=pst2.
43
44 (c) can't break (b) because pst2 vs !pst2 (point 1).
45
46
47 So, this formulation works:
48 (a) pst1? ( !pst2 !pst3 )
49 (b) pst2? ( !pst3 )
50 (c) !pst3? ( !pst2? ( !pst1? ( pst1 ) ) )
51
52 USE="pst1 whatever" will enable only pst1. USE="-pst1 pst2 whatever"
53 will enable only pst2. USE="-pst1 -pst2 pst3" will leave it alone.
54 USE="-pst{1,2,3}" will enable pst1.
55
56
57
58 Note that "pst1? ( pt1 ) pst2? ( pt2 ) pst3? ( pt3 ) ^^ ( pst1 pst2
59 pst3.. )" is a different story: (c) expanded as above can break 'pst1?
60 ( pt1 )' (point 4: a q'_j is some p_i) and you can actually check that
61 with USE="-pt* -pst*"; you'll need 2 passes to get the proper solution.
62 Fortunately, this is still a DAG and repoman would be able to propose an
63 ordering requiring only one pass.
64
65
66 [...]
67 > 2. ^^ ( pst1 pst2.. ) pst1? ( pt1 ) pst2? ( pt2 ).. ^^ ( pt1 pt2 )
68 >
69 > This is a possible extension of the above for the migration period.
70 > The idea is that exactly one PST must be selected, and only the
71 > matching PT must be selected (others are implicitly disabled).
72
73 If we expand '^^ ( pt1 pt2 )' as above we get:
74 (d) pt1? ( !pt2 )
75 (e) !pt2? ( !pt1? ( pt1 ) )
76
77 Here, (d) is annoying: it can break and be broken by 'pst2? ( pt2 )'.
78 There would be a cycle and this would be rejected/notified.
79
80 If you think about it, this would mean I have set USE="-* pt1 pst2";
81 pst2 forcing to enable pt2 but '^^ ( pt1 pt2 )' with pt1 enabled would
82 prefer pt1 and disable pt2 again... This hints the solution: You need
83 to define who wins between pt and pst.
84
85 Instead you could write it:
86 ^^ ( pst1 pst2.. ) pst1? ( pt1 !pt2 ... ) pst2? ( !pt1 pt2 ... )..
87 But then 'pst2? ( !pt1 pt2 ... )' can break each other with 'pst1?
88 ( pt1 !pt2 ... )' in the sense I defined because of point 4 (A q_i is
89 the negation of a q_'j); you'll get the repoman notification about a
90 cycle. This is a case of a perfectly valid constraint that is rejected
91 by the restriction.
92
93 It is valid because we know we are guaranteed exactly one pstX will
94 be enabled. We can hint the solver with that by writing:
95 ^^ ( pst1 pst2.. )
96 pst1? ( pt1 !pt2 ... )
97 pst2? ( !pt1? ( pt2 !pt3 ... ) )
98 pst3? ( !pt1? ( !pt2? ( pt3 !pt4 ... ) ) )
99
100
101 Now we're good: For j>i, solving a pst{j} line does not break a pst{i}
102 one because of point 2: A q_i (pt{i}) is the negation of a p'_j
103 (!pt{i}).
104
105
106
107 It's getting a bit ugly but it's probably bearable with good reporting
108 from static checkers (repoman).
109
110
111
112 > 3. doc? ( || ( pt3 pt4 ) ) || ( pt1 pt2 pt3 pt4 )
113 >
114 > This is distutils-r1 with USE=doc requiring python2. Note that it's
115 > an example where the second || is added via eclass [NB: we've checked
116 > and PMS says eclass values are appended to ebuild value].
117
118
119 Much simpler here:
120 (a) doc? ( !pt4? ( pt3 ) )
121 (b) !pt4? ( !pt3? ( !pt2? ( pt1 ) )
122
123 (b) can't break (a) because of point 4: Neither 'a q_i is
124 the negation of a q_'j' nor 'a q'_j is some p_i' hold. We're good.
125
126
127 USE="-* doc" will enable pt3 only. USE="-* pt{whatever} doc" will
128 enable pt3 (if not enabled) unless pt{whatever} contains pt4.
129
130 Alexis.

Replies