Gentoo Archives: gentoo-dev

From: James Le Cuirot <chewi@g.o>
To: gentoo-dev <gentoo-dev@l.g.o>
Subject: [gentoo-dev] [EAPI 7] Cross-compile improvements (BDEPEND, BROOT, sysroot)
Date: Tue, 01 Dec 2015 22:59:30
Message-Id: 20151201225855.20b17a34@symphony.aura-online.co.uk
1 Sorry for the length of this but you really need to consider the bigger
2 picture with this stuff and not all devs are familiar with it.
3
4 For EAPI 7, mgorny and I are seeking to address some cross-compiling
5 issues. This is a subject I've long had an interest in and before I
6 became a developer, I created a project called cross-boss that, to be
7 blunt, hacks its way through the shortcomings in Portage and the tree.
8 It does (or at least did when I last worked on it) achieve a higher
9 success rate than you would get from crossdev alone and allows you to
10 install a brand new standalone system from scratch as opposed to one
11 under /usr/${CHOST}.
12
13 I have heard some developers say that cross-compiling is simply not
14 worth the effort but I have succeeded in building some big ticket items
15 including MariaDB, GTK+, Qt4, and LibreOffice. This is one area where
16 Gentoo can really shine so I would like to exploit that potential.
17
18 It is unlikely that I'll be able to negate the need for cross-boss
19 entirely as some packages can be really stubborn but these changes
20 should at least allow some of the hacks to be removed.
21
22 The first change is a long-standing one and adds BDEPEND to the list of
23 dependency types. For those familiar with the experimental HDEPEND
24 implementation, this is the same thing under a different name that many
25 developers have said they prefer. It means "build depend" for packages
26 to be installed on / aka the CBUILD system.
27
28 You may be thinking that is what DEPEND is for but sometimes you need
29 to differentiate between build-time dependencies that are needed in /
30 for execution and those that are needed in ROOT for headers, static
31 libraries, and other things.
32
33 This is best illustrated with an example. pam currently DEPENDs on
34 flex as it links against libfl.a. By default, Portage will not install
35 DEPEND packages to ROOT so this fails when cross-compiling. flex could
36 be added to RDEPEND but that is suboptimal and may not be feasible in
37 other cases. We could run emerge with --root-deps but this tends to
38 pull in many more packages that play havoc when cross-compiling.
39
40 This feature can also be particularly useful for packages like autogen
41 and dbus-glib that execute themselves during the build. This doesn't
42 always work when cross-compiling but you can use BDEPEND in conjunction
43 with the targetroot USE flag (see man 5 ebuild) to install that package
44 to / first and then use that version to complete the cross build.
45
46 So when cross-compiling under EAPI 7, the traditional defaults change.
47 BDEPEND is installed to / as already stated and DEPEND is now installed
48 to ROOT. The --root-deps options have no effect. Won't this break
49 cross-compiling for future EAPI 7 ebuilds and eclasses that haven't
50 been given the BDEPEND treatment? Yes and no. crossdev's cross-emerge
51 wrapper has long included the --root-deps=rdeps option by default,
52 which simply throws DEPEND away and this is equally broken already.
53
54 So why did crossdev include --root-deps=rdeps in the first place if it
55 breaks things? The commit message doesn't really say and solar doesn't
56 seem to be around to answer that question. I'm guessing it was a
57 trade-off to save time. Portage currently installs all of DEPEND to /
58 by default even though most of those dependencies are solely needed
59 for headers and libraries. This means that when cross-compiling on a
60 minimal build host, you spend almost half the time building things that
61 you don't even need. This trade-off will no longer be necessary as
62 BDEPEND will allow us to make that saving while avoiding the breakages
63 at the same time.
64
65 We do not expect all developers to be mindful of BDEPEND going
66 forwards. mgorny said that this could be thought of in the same way
67 that we currently don't beat developers up over mishandling of EPREFIX.
68 This will mean that I or others may occasionally swoop in to apply
69 BDEPEND to your packages and I hope that this isn't seen as rude or
70 invasive. It should have no effect on the non-cross case and for what
71 it's worth, I think I'm quite careful. :)
72
73 Also on the table is a variable called BROOT, which has arisen from bug
74 #509568. When calling executables from the build host, you can usually
75 rely on the PATH but sometimes the binary you need isn't in the PATH.
76 This obviously calls for an absolute path but what if the build host is
77 prefixed? EPREFIX always refers to the target host so how can you find
78 the prefix of the build host? Since the build host is always anchored
79 to / and we always refer to it absolutely, a BPREFIX variable is of
80 little use so we have therefore chosen BROOT. It's basically EROOT for
81 the build host.
82
83 Up to this point, I have referred to just the cross and non-cross cases
84 for simplicity. It may really be this simple but we should explore the
85 possibilities to make sure because I think one particular use case is a
86 little less clear cut.
87
88 --------
89
90 1. Regular native
91 CHOST = CBUILD, PORTAGE_CONFIGROOT = /, ROOT = /
92
93 The traditional setup we're all familiar with. Everything goes to / so
94 the distinction between BDEPEND and DEPEND is irrelevant here.
95
96 2. Rooted native, same config
97 CHOST = CBUILD, PORTAGE_CONFIGROOT = /, ROOT != /
98
99 This is almost exactly like #1 but the packages are not installed to /
100 at the end. Headers and libraries are still sourced from / and as such,
101 BDEPEND still doesn't apply. Despite an identical Portage configuration,
102 unexpected problems can arise. I did an experiment while writing this
103 and confirmed that having older libraries installed in / can lead to
104 breakages.
105
106 For example, say you have ncurses:0/5 installed in / and then attempt
107 to install i7z in a brand new ROOT. It will install ncurses:0/6 to ROOT
108 but then link the new i7z against libncurses.so.5. Furthermore, Portage
109 will record it as having been built against 0/6.
110
111 I think the easiest way to avoid problems like this is to ensure your
112 build host is up to date before you start installing things to ROOT.
113 Portage doesn't check this for you. Maybe it should?
114
115 3. Cross
116 CHOST != CBUILD, PORTAGE_CONFIGROOT != /, ROOT != /
117
118 For all its difficulties, the theory is quite simple. You build using
119 ROOT as much as possible except when you need to execute something.
120 This includes headers, which must never be sourced from / as this
121 quickly leads to breakages. Ensuring this happens is probably easier
122 than you think. More on that later.
123
124 4. Rooted native, different config
125 CHOST = CBUILD, PORTAGE_CONFIGROOT != /, ROOT != /
126
127 This is the messy one and one I'd like some feedback on as to what
128 people expect from it and whether it should even be supported at all.
129 Out of the box, it suffers from the same problems as #2 but keeping
130 your build host up to date is no longer sufficient. The target's USE
131 flags could potentially be entirely different, meaning that even the
132 same version of the same library could differ significantly between /
133 and ROOT. Even the headers could differ.
134
135 As far as I can see, the only sane way to deal with this is to build
136 against headers and libraries in ROOT instead, much like you would when
137 cross-compiling in #3. However, this just leaves you with the same
138 problem in reverse. Since you wouldn't really be cross-compiling, the
139 build may attempt to execute something that was just built. This
140 execution will occur in the context of the build host, which may not
141 have the necessary libraries available.
142
143 Perhaps you could force it to treat the build like a cross-compile by
144 overriding various checks in eclasses and build systems. This does
145 sound painful though. Another way would be to install an alternative
146 toolchain like x86_64-cross-linux-gnu. I know of one user who
147 successfully used this approach with cross-boss. It's probably not
148 bullet proof though as not all build systems respect CHOST and CBUILD.
149 I'm leaning towards the idea that this scenario should simply be
150 unsupported. You might as well start with a stage tarball and chroot
151 like usual. Do you have any better ideas?
152
153 It may seem like I have drifted off the point but I mention this use
154 case because we need to decide exactly when BDEPEND should apply. If
155 headers and libraries are sourced from ROOT then it needs to apply,
156 regardless of whether it is treated as a cross-compile or not.
157
158 --------
159
160 Still with me? ;)
161
162 I raised one further point with mgorny that he feels could potentially
163 go into EAPI 7 but I think could remain an implementation detail. In
164 cases #3 and #4 (basically when ROOT != / and PORTAGE_CONFIGROOT != /),
165 the toolchain needs to know how to source headers and libraries from
166 ROOT instead of /.
167
168 gcc and friends support a --sysroot argument. It used to be the case
169 that this didn't work on a toolchain configured without a sysroot,
170 possibly creating issues for #4, but I've tested and it now works
171 regardless.
172
173 In cross-boss, this argument is injected through some wrappers present
174 in the PATH, in a similar manner to distcc wrappers. This is remarkably
175 effective but doesn't quite cover everything.
176
177 CMake supports a CMAKE_SYSROOT argument that you set in the toolchain
178 file. We currently don't set this but it could easily be added to
179 cmake-utils.eclass as well as (or instead of?) the similar variables
180 that we already do set.
181
182 The vast majority of configure scripts (using libtool and not ancient)
183 support a --with-sysroot argument that can easily be detected by
184 grepping for lt_sysroot. The behaviour of econf is largely defined by
185 PMS, hence why mgorny thinks this particular detail could go into
186 EAPI 7, but it only says which arguments must be passed and doesn't say
187 that the PM can't pass additional ones. I don't wish this force this
188 stuff upon Paludis and pkgcore unnecessarily.
189
190 There's also a further complication here that I forgot to mention to
191 mgorny. While calling configure with --with-sysroot certainly helps,
192 it still stumbles on a significant number of packages that do
193 relinking at the end of the build if elibtoolize hasn't been called.
194 elibtoolize has long patched ltmain.sh with ELT-patches/cross/link-ROOT
195 when cross-compiling and this still applies to the very latest libtool.
196 I filed several bugs about this before realising that fixing this
197 globally would be better. elibtoolize doesn't require anything to be
198 installed and the description does say "this function should always be
199 safe to run" but I suppose calling it unconditionally might screw up
200 patching in some isolated cases. What do you think?
201
202 Phew, I'm done. Please be gentle! :)
203
204 --
205 James Le Cuirot (chewi)
206 Gentoo Linux Developer

Replies