Skip to content

Commit

Permalink
tc-build: Add initial scripts and update README
Browse files Browse the repository at this point in the history
Signed-off-by: Nathan Chancellor <natechancellor@gmail.com>
  • Loading branch information
nathanchance committed Mar 27, 2019
1 parent 945a02c commit e9200f4
Show file tree
Hide file tree
Showing 6 changed files with 633 additions and 2 deletions.
61 changes: 59 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,59 @@
# tc-build
A set of scripts to build LLVM and binutils
# Toolchain build scripts

There are times where a tip of tree LLVM build will have some issue fixed and it isn't available to you, maybe because it isn't in a release or it isn't available through your distribution's package management system. At that point, to get that fix, LLVM needs to be compiled, which sounds scary but is [rather simple](https://llvm.org/docs/GettingStarted.html). The `build-llvm.sh` script takes it a step farther by trying to optimize both LLVM's build time by:

* Trimming down a lot of things that kernel developers don't care about:
* Documentation
* LLVM tests
* Ocaml bindings
* libfuzzer
* Building with the faster tools available (in order of fastest to slowest):
* clang + lld
* clang/gcc + ld.gold
* clang/gcc + ld.bfd

It also aims to make kernel compilation go a little bit faster by generating a toolchain that is optimized for the host CPU (using `-O2 -march=native -mtune=native`).

## Getting started

These scripts have been tested in a Docker image of the following distributions, with the following packages installed:

* ### Debian/Ubuntu

```
apt install ca-certificates ccache clang cmake curl file gcc g++ git make ninja-build python texinfo zlib1g-dev
```

On Debian Buster or Ubuntu Bionic/Cosmic/Disco, `apt-get install lld` should be added as well for faster compiles.

* ### Fedora

```
dnf install ccache clang cmake gcc gcc-c++ git lld ninja-build python zlib-devel
```

* ### Arch Linux

```
pacman -S base-devel ccache clang cmake git lld ninja python
```

These scripts should be distribution agnostic. Please feel free to add different distribution install commands here through a pull request.

## build-llvm.sh

By default, `./build-llvm.sh` will clone LLVM, grab the latest binutils tarball (for the LLVMgold.so plugin), and build LLVM, clang, and lld. Run `./build-llvm.sh -h` for more options.

## build-binutils.sh

This script builds a standalone copy of binutils. This might be needed because certain distributions like Arch Linux (whose options the script uses) might symlink `/usr/lib/LLVMgold.so` to `/usr/lib/bfd-plugins` ([source](https://bugs.archlinux.org/task/28479)), which can cause issues when using the system's linker for LTO (even with `LD_LIBRARY_PATH`):

```
bfd plugin: LLVM gold plugin has failed to create LTO module: Unknown attribute kind (60) (Producer: 'LLVM9.0.0svn' Reader: 'LLVM 7.0.1')
```

Having a standalone copy of binutils (ideally in the same folder at the LLVM toolchain so that one `PATH` modification is needed) works around this without any adverse side effects. Another workaround is bind mounting the new `LLVMgold.so` to `/usr/lib/LLVMgold.so`.

## Getting help

Please open an issue on this repo and include your distribution, shell, the command you ran, and the error output.
20 changes: 20 additions & 0 deletions build-binutils-usage.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Usage: ./build-binutils.sh [options]

Description: Fetchs and builds binutils

Parameters:
-I | --install-folder:
By default, the script will create a "usr" folder in the same folder as this script
and install binutils there. If you'd like to have it installed somewhere else, pass
it to this parameter. This can either be an absolute or relative path.

For example: -I ~/binutils

-t | --target:
The script can build binutils targeting arm-linux-gnueabi, aarch64-linux-gnu,
powerpc-linux-gnu, powerpc64le-linux-gnu, and x86_64-linux-gnu (host if on x86_64).

You can either pass the full target or just the first part (arm, aarch64, etc) or all
if you want to build all targets.

Example: -t all, -t aarch64, -t arm-linux-gnueabi
144 changes: 144 additions & 0 deletions build-binutils.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
#!/usr/bin/env bash
# shellcheck disable=SC2191
# SPDX-License-Identifier: Apache-2.0
# Copyright (C) 2019 The ClangBuiltLinux Authors
# Description: Builds a standalone copy of binutils


# Properly set target if on x86_64 machine
function x86_64_target() {
if [[ $(uname -m) = "x86_64" ]]; then
echo "host"
else
echo "x86_64-linux-gnu"
fi
}


# Initialize helper functions and export current working directory for absolute paths later
function script_setup {
# Move into the folder that this script is called from (no message because this will never happen)
cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" || exit
source common.sh
ROOT=${PWD}
}


# Parse the script parameters
function parse_parameters() {
TARGETS=()
while (( ${#} )); do
case ${1} in
"-t"|"--target")
shift
[[ ${#} -lt 1 ]] && die "-t flag requires a value!"
case ${1} in
"all") TARGETS=( aarch64-linux-gnu arm-linux-gnueabi
powerpc-linux-gnu powerpc64le-linux-gnu
"$(x86_64_target)" ) ;;
arm*) TARGETS+=( arm-linux-gnueabi ) ;;
aarch64*) TARGETS+=( aarch64-linux-gnu ) ;;
powerpc64le*) TARGETS+=( powerpc64-linux-gnu ) ;;
powerpc*) TARGETS+=( powerpc-linux-gnu ) ;;
x86*|"host") TARGETS+=( "$(x86_64_target)" ) ;;
esac ;;
"-h"|"--help") cat build-binutils-usage.txt; builtin exit 0 ;;
*) die "Invalid parameter '${1}' specified! Run './build-binutils.sh -h' to see all options." ;;
esac
shift
done
[[ -z ${TARGETS[*]} ]] && die "No targets specified! Please run './build-binutils.sh' to see all the options."
}


# Setup the build folder
function setup_build_folder() {
BUILD_FOLDER=${ROOT}/build/binutils/${TARGET}
rm -rf "${BUILD_FOLDER}"
mkdir -p "${BUILD_FOLDER}"
cd "${BUILD_FOLDER}" || die "Couldn't create build folder??"
}


# Configure binutils
function configure_binutils() {
COMMON_FLAGS=( --prefix="${INSTALL_FOLDER:="${ROOT}"/usr}"
--enable-deterministic-archives
--enable-gold
--enable-ld=default
--enable-plugins
--quiet
CFLAGS="-O2 -march=native -mtune=native"
CXXFLAGS="-O2 -march=native -mtune=native" )
CONFIGURE=${ROOT}/${BINUTILS}/configure

case ${TARGET} in
arm-*|aarch64-*)
"${CONFIGURE}" \
--disable-multilib \
--disable-nls \
--program-prefix="${TARGET}"- \
--target="${TARGET}" \
--with-gnu-as \
--with-gnu-ld \
--with-sysroot="${INSTALL_FOLDER}/${TUPLE}" \
"${COMMON_FLAGS[@]}" ;;
powerpc*)
"${CONFIGURE}" \
--enable-lto \
--enable-relro \
--enable-shared \
--enable-threads \
--disable-gdb \
--disable-sim \
--disable-werror \
--program-prefix="${TARGET}"- \
--target="${TARGET}" \
--with-pic \
--with-system-zlib \
"${COMMON_FLAGS[@]}" ;;
x86*|host)
"${CONFIGURE}" \
--enable-lto \
--enable-relro \
--enable-shared \
--enable-targets=x86_64-pep \
--enable-threads \
--disable-gdb \
--disable-werror \
"$([[ $(uname -m) != x86_64 ]] && echo "--program-prefix=${TARGET}- --target=${TARGET}")" \
--with-pic \
--with-system-zlib \
"${COMMON_FLAGS[@]}"
[[ ${TARGET} = "host" ]] && make -s configure-host V=0 ;;
esac
}


# Build binutils
function build_binutils() {
time make -s -j"$(nproc)" V=0 || die "Error building ${TARGET} binutils"
}


# Install binutils
function install_binutils {
make -s prefix="${INSTALL_FOLDER}" install V=0 || die "Error installing ${TARGET} binutils"
}


# Main for loop
function for_all_targets() {
for TARGET in "${TARGETS[@]}"; do
setup_build_folder
configure_binutils
build_binutils
install_binutils
done
}


script_setup
parse_parameters "${@}"
dwnld_binutils
for_all_targets
73 changes: 73 additions & 0 deletions build-llvm-usage.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
Usage: ./build-llvm.sh [options]

Description: Fetchs LLVM and binutils then builds a LLVM, clang, lld, and the LLVMgold plugin.

Environment variables:
The script can take into account specific environment variables. They can be
invoked in one of three ways:
$ export VAR=value && ./build-llvm.sh
$ VAR=value ./build-llvm.sh
$ ./build-llvm.sh VAR=value

CC:
Path to or name of the C compiler. If unset, the script will try to use
clang if it is available, falling back to gcc if necessary.

CXX:
Path to or name of the C++ compiler. If unset, the script will use clang++
if CC is clang or g++ if CC is gcc.

LD:
Path to or name of the linker. If unset and using clang, the script will
attempt to find ld.lld then ld.gold, falling back to ld.bfd (because they
are objectively faster).

Parameters:
-b | --branch:
By default, the script builds the master branch (tip of tree) of LLVM. If you would
like to build an older branch, use this parameter. This may be helpful in tracking
down an older bug to properly bisect. This value is just passed along to 'git checkout'
so it can be a branch name, tag name, or hash.

NOTE: Some of the cmake defines may not work on older branches!

Example: -b release/8.x

-d | --debug:
By default, the script builds LLVM in the release configuration with all of
the tests turned off and optimization at O2. This disables that optimization,
builds the tests, and changes the configuration to debug. This can help with
reporting problems to LLVM developers but will make compilation of both LLVM
and the kernel go slower.

-i | --incremental:
By default, the script removes all build artifacts from previous compiles. This
prevents that, allowing for dirty builds and faster compiles.

-I | --install-folder:
By default, the script will create a "usr" folder in the same folder as this script
and install the LLVM toolchain there. If you'd like to have it installed somewhere
else, pass it to this parameter. This can either be an absolute or relative path.

Example: -I ~/llvm

-n | --no-pull:
By default, the script always updates the LLVM repo before building. This prevents
that, which can be helpful during something like bisecting.

-p | --projects:
Currently, the script only enables the clang, compiler-rt, and lld folders in LLVM. If
you would like to override this, you can use this parameter and supply a list that is
supported by LLVM_ENABLE_PROJECTS.

See step #5 here: https://llvm.org/docs/GettingStarted.html#getting-started-quickly-a-summary

Example: -p "clang;lld;libcxx"

-t | --targets:
LLVM is multitargeted by default. Currently, this script only enables the arm32, aarch64,
powerpc, and x86 backends because that's what the Linux kernel is currently concerned with.
If you would like to override this, you can use this parameter and supply a list that is
supported by LLVM_TARGETS_TO_BUILD: https://llvm.org/docs/CMake.html#llvm-specific-variables

Example: -t "AArch64;X86"
Loading

0 comments on commit e9200f4

Please sign in to comment.