Bug 41137: Build gcc-cross and tor-expert-bundle for linux-aarch64
Merge Info
Related Issues
Backporting
Timeline
-
Immediate: patchset needed as soon as possible -
Next Minor Stable Release: patchset that needs to be verified in nightly before backport -
Eventually: patchset that needs to be verified in alpha before backport -
No Backport (preferred): patchset for the next major stable
(Optional) Justification
-
Emergency security update: patchset fixes CVEs, 0-days, etc -
Censorship event: patchset enables censorship circumvention -
Critical bug-fix: patchset fixes a bug in core-functionality -
Consistency: patchset which would make development easier if it were in both the alpha and release branches; developer tools, build system changes, etc -
Sponsor required: patchset required for sponsor -
Other: please explain
Issue Tracking
-
Link resolved issues with appropriate Release Prep issue for changelog generation
Review
Request Reviewer
-
Request review from an applications developer depending on modified system: -
NOTE: if the MR modifies multiple areas, please
/cc
all the relevant reviewers (since gitlab only allows 1 reviewer) - accessibility : henry
- android : clairehurst, dan
- build system : boklm
- extensions : ma1
- firefox internals (XUL/JS/XPCOM) : ma1
- fonts : pierov
- frontend (implementation) : henry
- frontend (review) : donuts, richard
- localization : henry, pierov
- macos : clairehurst, dan
- nightly builds : boklm
- rebases/release-prep : boklm, dan, ma1, pierov, richard
- security : ma1
- signing : boklm, richard
- updater : pierov
- misc/other : pierov, richard
-
NOTE: if the MR modifies multiple areas, please
Change Description
This MR adds support for building a gcc
toolchain and the tor-expert-bundle
for linux-aarch64
. It does so by
- rationalizing the process of cross-compiling a linux target (
linux-cross
) and making it extensible to other archs - adding a
gcc-cross
project - making small changes to
container-image
,binutils
,openssl
,go-bootstrap
andgo
- building
tor
forlinux-cross
targets
The gcc-cross
and tor-expert-bundle
projects, and any project in between, can be built using
./rbm/rbm build $project --target alpha --target torbrowser-linux-$arch
where $arch
is one of aarch64
or arm
. linux-arm
is not within the main scope of this MR, but enabling it only required a couple of minor changes, and it serves as a check that the cross-compilation logic is solid for generic linux targets.
In what follows I will detail the cross-compilation logic and some of the changes contained in this patchset. You can skip the cross-compilation logic if you are not interested, the patchset will still work! But in the future more work is likely to be done on linux-cross
targets if this MR is accepted, so it's best if I lay it out here.
Cross-compilation logic
The linux-cross
target defines the compiler and the generic configure options for linux cross-compiled targets. When cross-compiling, there are a few things we must take into account:
- we need to build both a native compiler (to build the host tools) and a cross compiler (to build the target binaries)
- some projects are built for the host, others are built for the target, others still are built for the host and will build binaries for the target.
linux-cross
needs a way to select which of the above compilers to use for each project - projects built for the host which build binaries for the target may need both the compilers (e.g.
rust
apparently does, whileclang
doesn't while buildingclang
, but does while buildingfirefox
) - we don't want to build the host tools multiple times (think about
cmake
,python
, etc.), so their projects must have the native compiler alone among their dependencies
In light of the above, this MR implements linux cross-compilation as follows. First, a copy of the native compiler (and of cross-binutils), separately built as dependencies, are embedded into the cross-compiler artifact. This avoids huge headaches with passing headers and library paths around when building rust
and firefox
(admittedly outside the scope of this MR, but something we must take into account from the get-go if we don't want to re-write the cross compiler from scratch later).
Second, by default, projects built for the linux-cross
target will use the cross-compiler. However, to avoid tens of unmanageable target_replace
, projects which only build host tools and whose building does not need the cross compiler are marked with a no_crosscompile
variable, and are built using the native compiler. Selecting the native compiler when no_crosscompile: 1
is done automatically by the linux-cross
target via the definition of compiler
in rbm.conf
.
In general, a project should be marked as no_crosscompile
if:
- it is built using the
linux-cross
target - its building requires a compiler, and that compiler is the native compiler
However, this is not enough to comply with point 4. above. The reason for this is Jeremy Rand sneaked in a quite useful change in projects/container-image
: in current main
, when building for target linux-cross
, the build container calls dpkg --add-architecture $debian_arch
before installing packages. Since this changes the container's setup and thus its id
, all projects built in a container under the linux-cross
target in current main
, and all projects which depend on such projects, have different ids and will be built twice, whether or not they are actually cross-compiling anything. This includes the host tools.
To fix this, I deactivated dpkg --add-architecture $debian_arch
in the container's setup when no_crosscompile
is set for the container's parent project. Thanks to this change, to comply with point 4., a project must be marked as no_crosscompile
if:
- it is built using the
linux-cross
target (either directly or indirectly, as a dependence of another project) - its building does not require the cross-compiler
- it is built in a container
On the other hand, it must not be marked as no_crosscompile
if it requires the cross-compiler (unless the project's own linux-cross
targets defines no_crosscompile: 0
of course).
Details
Some of the changes are explained in the commit messages, in comments or in patch headers. In addition to those:
-
binutils
is the only project in alltor-browser-build
which needs to be both compiled and cross-compiled (meaning that it provides cross-binutils) and which does not need a separate build script for cross compilation. It is not natively compiled in this MR, but it will be eventually, when building the browser. It must be called with thelinux-cross
target when and only when we want cross-binutils -
gcc
and the crossgcc
toolchain are built in completely different ways, so I separated the cross toolchain into agcc-cross
project. As mentioned previously,gcc-cross
contains a copy of the cross binutils and of the native compiler, which are built separately and imported as dependencies - in
gcc-cross
, twoglibc
patches are backported to overcome build failures due to linking issues. These are specific tolinux-aarch64
, and to this version ofglibc
(I chose v2.24 because this is the last version which, when used as part of thegcc
cross-toolchain, is able to compile binaries which work on Debian Stretch). The*.patch
files bear the names of the original authors and the hashes of the original commit, so you can easily find them in theglibc
git repo. However I had to refresh them for theglibc
version contained in this MR. In more detail:-
glibc-cross-linux-aarch64.patch
overcomesrelocation R_AARCH64_ABS32 against 'a local symbol' can not be used when making a shared object
. More info here -
glibc-cross-linux-aarch64-2.patch
overcomesrelocation R_AARCH64_ADR_PREL_PG_HI21 against symbol '_dl_argv' which may bind externally can not be used when making a shared object
. More info here
-
- there are of course a lot of details regarding how
gcc-cross
is built. As a general rule, I started from Jeremy's code (which is still there and makes up for the majority of thegcc-cross
build script I believe) and changed it until I got a cross compiler which is able to fully build the browser -
(does not apply when building with thego-bootstrap
is correctly built once for all targets.go
would be too for alllinux
targets ifosname
was not in itsfilename
, but I'm not going to change this now because it is outside of the scope of this MRtorbrowser-linux-$arch
target)
How Tested
I tested the gcc-cross
compiler by building tor-expert-bundle
for both linux-aarch64
and linux-arm
. I tested the tor-expert-bundle
as part of a full linux-aarch64
build of the Tor Browser using this linux-cross branch, which is a rewrite of !920 (closed) that avoids rebuilding the host tools and that does not contain the native linux-aarch64
build enablement patches. The linux-arm
tor-expert-bundle
artifact is untested (although I checked that all the binaries contained therein are for the correct architecture).
A note
I talked to Jeremy Rand and, from what I understood, he is fine with me changing his linux-cross
code as long as openssl
still builds the linux-arm
target (i.e. if there are no regressions in the code). This MR builds a full linux-arm
tor-expert-bundle
(and it's the base for cross-building a whole linux-aarch64
Tor Browser), so I think we're good from this perspective, although as I mentioned those binaries are untested.