1#!/bin/bash
2#
3# Compiles and installs a Linux/x86_64 -> Linux/ARM crosstool based on LLVM and
4# LLVM-GCC-4.2 using SVN snapshots in provided tarballs.
5
6set -o nounset
7set -o errexit
8
9echo -n "Welcome to LLVM Linux/X86_64 -> Linux/ARM crosstool "
10echo "builder/installer; some steps will require sudo privileges."
11
12readonly INSTALL_ROOT="${INSTALL_ROOT:-/usr/local/crosstool}"
13# Both $USER and root *must* have read/write access to this dir.
14readonly SCRATCH_ROOT=$(mktemp -d "${TMPDIR:-/tmp}/llvm-project.XXXXXX")
15readonly SRC_ROOT="${SCRATCH_ROOT}/src"
16readonly OBJ_ROOT="${SCRATCH_ROOT}/obj"
17
18readonly CROSS_HOST="x86_64-unknown-linux-gnu"
19readonly CROSS_TARGET="arm-none-linux-gnueabi"
20readonly CROSS_MARCH="${CROSS_MARCH:-armv6}"
21
22readonly CODE_SOURCERY="${INSTALL_ROOT}/codesourcery"
23readonly CODE_SOURCERY_PKG_PATH="${CODE_SOURCERY_PKG_PATH:-${HOME}/codesourcery}"
24readonly CODE_SOURCERY_HTTP="http://www.codesourcery.com/sgpp/lite/arm/portal/package1787/public"
25readonly CODE_SOURCERY_PKG="arm-2007q3-51-arm-none-linux-gnueabi-i686-pc-linux-gnu.tar.bz2"
26readonly CODE_SOURCERY_ROOT="${CODE_SOURCERY}/arm-2007q3"
27readonly CODE_SOURCERY_BIN="${CODE_SOURCERY_ROOT}/bin"
28# Make sure ${CROSS_TARGET}-* binutils are in command path
29export PATH="${CODE_SOURCERY_BIN}:${PATH}"
30
31readonly CROSS_TARGET_AS="${CODE_SOURCERY_BIN}/${CROSS_TARGET}-as"
32readonly CROSS_TARGET_LD="${CODE_SOURCERY_BIN}/${CROSS_TARGET}-ld"
33
34readonly SYSROOT="${CODE_SOURCERY_ROOT}/${CROSS_TARGET}/libc"
35
36readonly LLVM_PKG_PATH="${LLVM_PKG_PATH:-${HOME}/llvm-project/snapshots}"
37
38# Latest SVN revisions known to be working in this configuration.
39readonly LLVM_DEFAULT_REV="74530"
40readonly LLVMGCC_DEFAULT_REV="74535"
41
42readonly LLVM_PKG="llvm-${LLVM_SVN_REV:-${LLVM_DEFAULT_REV}}.tar.bz2"
43readonly LLVM_SRC_DIR="${SRC_ROOT}/llvm"
44readonly LLVM_OBJ_DIR="${OBJ_ROOT}/llvm"
45readonly LLVM_INSTALL_DIR="${INSTALL_ROOT}/${CROSS_TARGET}/llvm"
46
47readonly LLVMGCC_PKG="llvm-gcc-4.2-${LLVMGCC_SVN_REV:-${LLVMGCC_DEFAULT_REV}}.tar.bz2"
48readonly LLVMGCC_SRC_DIR="${SRC_ROOT}/llvm-gcc-4.2"
49readonly LLVMGCC_OBJ_DIR="${OBJ_ROOT}/llvm-gcc-4.2"
50readonly LLVMGCC_INSTALL_DIR="${INSTALL_ROOT}/${CROSS_TARGET}/llvm-gcc-4.2"
51
52readonly MAKE_OPTS="${MAKE_OPTS:--j2}"
53
54# Params:
55#   $1: directory to be created
56#   $2: optional mkdir command prefix, e.g. "sudo"
57createDir() {
58  if [[ ! -e $1 ]]; then
59    ${2:-} mkdir -p $1
60  elif [[ -e $1 && ! -d $1 ]]; then
61    echo "$1 exists but is not a directory; exiting."
62    exit 3
63  fi
64}
65
66sudoCreateDir() {
67  createDir $1 sudo
68  sudo chown ${USER} $1
69}
70
71# Prints out and runs the command, but without logging -- intended for use with
72# lightweight commands that don't have useful output to parse, e.g. mkdir, tar,
73# etc.
74runCommand() {
75  local message="$1"
76  shift
77  echo "=> $message"
78  echo "==> Running: $*"
79  $*
80}
81
82runAndLog() {
83  local message="$1"
84  local log_file="$2"
85  shift 2
86  echo "=> $message; log in $log_file"
87  echo "==> Running: $*"
88  # Pop-up a terminal with the output of the current command?
89  # e.g.: xterm -e /bin/bash -c "$* >| tee $log_file"
90  $* &> $log_file
91  if [[ $? != 0 ]]; then
92    echo "Error occurred: see most recent log file for details."
93    exit
94  fi
95}
96
97installCodeSourcery() {
98  # Unpack the tarball, creating the CodeSourcery dir, if necessary.
99  if [[ ! -d ${CODE_SOURCERY_ROOT} ]]; then
100    sudoCreateDir ${CODE_SOURCERY}
101    cd ${CODE_SOURCERY}
102    if [[ -e ${CODE_SOURCERY_PKG_PATH}/${CODE_SOURCERY_PKG} ]]; then
103      runCommand "Unpacking CodeSourcery in ${CODE_SOURCERY}" \
104          tar jxf ${CODE_SOURCERY_PKG_PATH}/${CODE_SOURCERY_PKG}
105    else
106      echo -n "CodeSourcery tarball not found in "
107      echo "${CODE_SOURCERY_PKG_PATH}/${CODE_SOURCERY_PKG}"
108      echo -n "Fix the path or download it from "
109      echo "${CODE_SOURCERY_HTTP}/${CROSS_TARGET}/${CODE_SOURCERY_PKG}"
110      exit
111    fi
112  else
113    echo "CodeSourcery install dir already exists; skipping."
114  fi
115
116  # Verify our CodeSourcery toolchain installation.
117  if [[ ! -d "${SYSROOT}" ]]; then
118    echo -n "Error: CodeSourcery does not contain libc for ${CROSS_TARGET}: "
119    echo "${SYSROOT} not found."
120    exit
121  fi
122
123  for tool in ${CROSS_TARGET_AS} ${CROSS_TARGET_LD}; do
124    if [[ ! -e $tool ]]; then
125      echo "${tool} not found; exiting."
126      exit
127    fi
128  done
129}
130
131installLLVM() {
132  if [[ -d ${LLVM_INSTALL_DIR} ]]; then
133    echo "LLVM install dir ${LLVM_INSTALL_DIR} exists; skipping."
134    return
135  fi
136
137  sudoCreateDir ${LLVM_INSTALL_DIR}
138
139  # Unpack LLVM tarball; should create the directory "llvm".
140  cd ${SRC_ROOT}
141  runCommand "Unpacking LLVM" tar jxf ${LLVM_PKG_PATH}/${LLVM_PKG}
142
143  # Configure, build, and install LLVM.
144  createDir ${LLVM_OBJ_DIR}
145  cd ${LLVM_OBJ_DIR}
146  runAndLog "Configuring LLVM" ${LLVM_OBJ_DIR}/llvm-configure.log \
147      ${LLVM_SRC_DIR}/configure \
148      --disable-jit \
149      --enable-optimized \
150      --prefix=${LLVM_INSTALL_DIR} \
151      --target=${CROSS_TARGET} \
152      --with-llvmgccdir=${LLVMGCC_INSTALL_DIR}
153  runAndLog "Building LLVM" ${LLVM_OBJ_DIR}/llvm-build.log \
154      make ${MAKE_OPTS}
155  runAndLog "Installing LLVM" ${LLVM_OBJ_DIR}/llvm-install.log \
156      make ${MAKE_OPTS} install
157}
158
159installLLVMGCC() {
160  if [[ -d ${LLVMGCC_INSTALL_DIR} ]]; then
161    echo "LLVM-GCC install dir ${LLVMGCC_INSTALL_DIR} exists; skipping."
162    return
163  fi
164
165  sudoCreateDir ${LLVMGCC_INSTALL_DIR}
166
167  # Unpack LLVM-GCC tarball; should create the directory "llvm-gcc-4.2".
168  cd ${SRC_ROOT}
169  runCommand "Unpacking LLVM-GCC" tar jxf ${LLVM_PKG_PATH}/${LLVMGCC_PKG}
170
171  # Configure, build, and install LLVM-GCC.
172  createDir ${LLVMGCC_OBJ_DIR}
173  cd ${LLVMGCC_OBJ_DIR}
174  runAndLog "Configuring LLVM-GCC" ${LLVMGCC_OBJ_DIR}/llvmgcc-configure.log \
175      ${LLVMGCC_SRC_DIR}/configure \
176      --enable-languages=c,c++ \
177      --enable-llvm=${LLVM_INSTALL_DIR} \
178      --prefix=${LLVMGCC_INSTALL_DIR} \
179      --program-prefix=llvm- \
180      --target=${CROSS_TARGET} \
181      --with-arch=${CROSS_MARCH} \
182      --with-as=${CROSS_TARGET_AS} \
183      --with-ld=${CROSS_TARGET_LD} \
184      --with-sysroot=${SYSROOT}
185  runAndLog "Building LLVM-GCC" ${LLVMGCC_OBJ_DIR}/llvmgcc-build.log \
186      make
187  runAndLog "Installing LLVM-GCC" ${LLVMGCC_OBJ_DIR}/llvmgcc-install.log \
188      make install
189}
190
191echo "Building in ${SCRATCH_ROOT}; installing in ${INSTALL_ROOT}"
192
193createDir ${SRC_ROOT}
194createDir ${OBJ_ROOT}
195
196installCodeSourcery
197installLLVM
198installLLVMGCC
199
200echo "Done."
201