1#!/bin/bash -e
2
3# Copyright (c) 2011 The Chromium Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
7# Script to install everything needed to build chromium (well, ideally, anyway)
8# See http://code.google.com/p/chromium/wiki/LinuxBuildInstructions
9# and http://code.google.com/p/chromium/wiki/LinuxBuild64Bit
10
11usage() {
12  echo "Usage: $0 [--options]"
13  echo "Options:"
14  echo "--[no-]syms: enable or disable installation of debugging symbols"
15  echo "--[no-]gold: enable or disable installation of gold linker"
16  echo "--[no-]lib32: enable or disable installation of 32 bit libraries"
17  echo "Script will prompt interactively if options not given."
18  exit 1
19}
20
21while test "$1" != ""
22do
23  case "$1" in
24  --syms)     do_inst_syms=1;;
25  --no-syms)  do_inst_syms=0;;
26  --gold)     do_inst_gold=1;;
27  --no-gold)  do_inst_gold=0;;
28  --lib32)    do_inst_lib32=1;;
29  --no-lib32) do_inst_lib32=0;;
30  *) usage;;
31  esac
32  shift
33done
34
35install_gold() {
36  # Gold is optional; it's a faster replacement for ld,
37  # and makes life on 2GB machines much more pleasant.
38
39  # First make sure root can access this directory, as that's tripped
40  # up some folks.
41  if sudo touch xyz.$$
42  then
43    sudo rm xyz.$$
44  else
45    echo root cannot write to the current directory, not installing gold
46    return
47  fi
48
49  BINUTILS=binutils-2.21
50  BINUTILS_URL=http://ftp.gnu.org/gnu/binutils/$BINUTILS.tar.bz2
51  BINUTILS_SHA1=ef93235588eb443e4c4a77f229a8d131bccaecc6
52
53  test -f $BINUTILS.tar.bz2 || wget $BINUTILS_URL
54  if test "`sha1sum $BINUTILS.tar.bz2|cut -d' ' -f1`" != "$BINUTILS_SHA1"
55  then
56    echo Bad sha1sum for $BINUTILS.tar.bz2
57    exit 1
58  fi
59
60  tar -xjvf $BINUTILS.tar.bz2
61  cd $BINUTILS
62  patch -p1 <<EOF
63diff -u -r1.103 -r1.103.2.1
64--- src/gold/object.h	2010/09/08 23:54:51	1.103
65+++ src/gold/object.h	2011/02/10 01:15:28	1.103.2.1
66@@ -1,6 +1,6 @@
67 // object.h -- support for an object file for linking in gold  -*- C++ -*-
68 
69-// Copyright 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
70+// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
71 // Written by Ian Lance Taylor <iant@google.com>.
72 
73 // This file is part of gold.
74@@ -2165,15 +2165,6 @@
75 		      Output_symtab_xindex*,
76 		      Output_symtab_xindex*);
77 
78-  // Clear the local symbol information.
79-  void
80-  clear_local_symbols()
81-  {
82-    this->local_values_.clear();
83-    this->local_got_offsets_.clear();
84-    this->local_plt_offsets_.clear();
85-  }
86-
87   // Record a mapping from discarded section SHNDX to the corresponding
88   // kept section.
89   void
90diff -u -r1.60 -r1.60.2.1
91--- src/gold/reloc.cc	2010/10/14 22:10:22	1.60
92+++ src/gold/reloc.cc	2011/02/10 01:15:28	1.60.2.1
93@@ -1,6 +1,6 @@
94 // reloc.cc -- relocate input files for gold.
95 
96-// Copyright 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
97+// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
98 // Written by Ian Lance Taylor <iant@google.com>.
99 
100 // This file is part of gold.
101@@ -685,9 +685,6 @@
102   // Write out the local symbols.
103   this->write_local_symbols(of, layout->sympool(), layout->dynpool(),
104 			    layout->symtab_xindex(), layout->dynsym_xindex());
105-
106-  // We should no longer need the local symbol values.
107-  this->clear_local_symbols();
108 }
109 
110 // Sort a Read_multiple vector by file offset.
111EOF
112  ./configure --prefix=/usr/local/gold --enable-gold --enable-threads
113  make maybe-all-binutils maybe-all-gold -j4
114  if sudo make maybe-install-binutils maybe-install-gold
115  then
116    # Still need to figure out graceful way of pointing gyp to use
117    # /usr/local/gold/bin/ld without requiring him to set environment
118    # variables.  That will go into bootstrap-linux.sh when it's ready.
119    echo "Installing gold as /usr/bin/ld."
120    echo "To uninstall, do 'cd /usr/bin; sudo rm ld; sudo mv ld.orig ld'"
121    test -f /usr/bin/ld && test ! -f /usr/bin/ld.orig && \
122        sudo mv /usr/bin/ld /usr/bin/ld.orig
123    sudo strip /usr/local/gold/bin/ld
124    sudo ln -fs /usr/local/gold/bin/ld /usr/bin/ld.gold
125    sudo ln -fs /usr/bin/ld.gold /usr/bin/ld
126  else
127    echo "make install failed, not installing gold"
128  fi
129}
130
131if ! egrep -q \
132    'Ubuntu (8\.04|8\.10|9\.04|9\.10|10\.04|10\.10|karmic|lucid|maverick)' \
133    /etc/issue; then
134  echo "Only Ubuntu 8.04 (hardy) through 10.10 (maverick) are currently" \
135      "supported" >&2
136  exit 1
137fi
138
139if ! uname -m | egrep -q "i686|x86_64"; then
140  echo "Only x86 architectures are currently supported" >&2
141  exit
142fi
143
144if [ "x$(id -u)" != x0 ]; then
145  echo "Running as non-root user."
146  echo "You might have to enter your password one or more times for 'sudo'."
147  echo
148fi
149
150# Packages needed for chromeos only
151chromeos_dev_list="libpulse-dev"
152
153# Packages need for development
154dev_list="bison fakeroot flex g++ gperf libapache2-mod-php5 libasound2-dev
155          libbz2-dev libcairo2-dev libdbus-glib-1-dev libgconf2-dev
156          libgl1-mesa-dev libglu1-mesa-dev libglib2.0-dev libgnome-keyring-dev
157          libgtk2.0-dev libjpeg62-dev libnspr4-dev libnss3-dev libpam0g-dev
158          libsctp-dev libsqlite3-dev libxslt1-dev libxss-dev libxtst-dev
159          mesa-common-dev msttcorefonts patch perl php5-cgi pkg-config python
160          python-dev rpm subversion ttf-dejavu-core ttf-kochi-gothic
161          ttf-kochi-mincho wdiff libcurl4-gnutls-dev
162          $chromeos_dev_list"
163
164# Run-time libraries required by chromeos only
165chromeos_lib_list="libpulse0 libbz2-1.0 libcurl4-gnutls-dev"
166
167# Full list of required run-time libraries
168lib_list="libatk1.0-0 libc6 libasound2 libcairo2 libdbus-glib-1-2 libexpat1
169          libfontconfig1 libfreetype6 libglib2.0-0 libgnome-keyring0 libgtk2.0-0
170          libnspr4-0d libnss3-1d libpam0g libpango1.0-0 libpcre3 libpixman-1-0
171          libpng12-0 libstdc++6 libsqlite3-0 libx11-6 libxau6 libxcb1
172          libxcomposite1 libxcursor1 libxdamage1 libxdmcp6 libxext6 libxfixes3
173          libxi6 libxinerama1 libxrandr2 libxrender1 libxtst6 zlib1g
174          $chromeos_lib_list"
175
176# Debugging symbols for all of the run-time libraries
177dbg_list="libatk1.0-dbg libc6-dbg libcairo2-dbg
178          libfontconfig1-dbg libglib2.0-0-dbg libgtk2.0-0-dbg libnspr4-0d-dbg
179          libnss3-1d-dbg libpango1.0-0-dbg libpcre3-dbg libpixman-1-0-dbg
180          libx11-6-dbg libxau6-dbg libxcb1-dbg libxcomposite1-dbg
181          libxcursor1-dbg libxdamage1-dbg libxdmcp6-dbg libxext6-dbg
182          libxfixes3-dbg libxi6-dbg libxinerama1-dbg libxrandr2-dbg
183          libxrender1-dbg libxtst6-dbg zlib1g-dbg"
184
185# CUPS package changed its name from hardy to the next version. Include
186# proper package here depending on the system.
187if egrep -q 'Ubuntu (8\.04|8\.10)' /etc/issue; then
188  dev_list="${dev_list} libcupsys2-dev"
189else
190  dev_list="${dev_list} libcups2-dev"
191fi
192
193# apache2.2-bin package was introduced in karmic.
194if egrep -q 'Ubuntu (8\.04|8\.10|9\.04)' /etc/issue; then
195  dev_list="${dev_list} apache2"
196else
197  dev_list="${dev_list} apache2.2-bin"
198fi
199
200# Waits for the user to press 'Y' or 'N'. Either uppercase of lowercase is
201# accepted. Returns 0 for 'Y' and 1 for 'N'. If an optional parameter has
202# been provided to yes_no(), the function also accepts RETURN as a user input.
203# The parameter specifies the exit code that should be returned in that case.
204# The function will echo the user's selection followed by a newline character.
205# Users can abort the function by pressing CTRL-C. This will call "exit 1".
206yes_no() {
207  local c
208  while :; do
209    c="$(trap 'stty echo -iuclc icanon 2>/dev/null' EXIT INT TERM QUIT
210         stty -echo iuclc -icanon 2>/dev/null
211         dd count=1 bs=1 2>/dev/null | od -An -tx1)"
212    case "$c" in
213      " 0a") if [ -n "$1" ]; then
214               [ $1 -eq 0 ] && echo "Y" || echo "N"
215               return $1
216             fi
217             ;;
218      " 79") echo "Y"
219             return 0
220             ;;
221      " 6e") echo "N"
222             return 1
223             ;;
224      "")    echo "Aborted" >&2
225             exit 1
226             ;;
227      *)     # The user pressed an unrecognized key. As we are not echoing
228             # any incorrect user input, alert the user by ringing the bell.
229             (tput bel) 2>/dev/null
230             ;;
231    esac
232  done
233}
234
235if test "$do_inst_syms" = ""
236then
237  echo "This script installs all tools and libraries needed to build Chromium."
238  echo ""
239  echo "For most of the libraries, it can also install debugging symbols, which"
240  echo "will allow you to debug code in the system libraries. Most developers"
241  echo "won't need these symbols."
242  echo -n "Do you want me to install them for you (y/N) "
243  if yes_no 1; then
244    do_inst_syms=1
245  fi
246fi
247if test "$do_inst_syms" = "1"; then
248  echo "Installing debugging symbols."
249else
250  echo "Skipping installation of debugging symbols."
251  dbg_list=
252fi
253
254sudo apt-get update
255
256# We initially run "apt-get" with the --reinstall option and parse its output.
257# This way, we can find all the packages that need to be newly installed
258# without accidentally promoting any packages from "auto" to "manual".
259# We then re-run "apt-get" with just the list of missing packages.
260echo "Finding missing packages..."
261packages="${dev_list} ${lib_list} ${dbg_list}"
262# Intentially leaving $packages unquoted so it's more readable.
263echo "Packages required: " $packages
264echo
265new_list_cmd="sudo apt-get install --reinstall $(echo $packages)"
266if new_list="$(yes n | LANG=C $new_list_cmd)"; then
267  # We probably never hit this following line.
268  echo "No missing packages, and the packages are up-to-date."
269elif [ $? -eq 1 ]; then
270  # We expect apt-get to have exit status of 1.
271  # This indicates that we canceled the install with "yes n|".
272  new_list=$(echo "$new_list" |
273    sed -e '1,/The following NEW packages will be installed:/d;s/^  //;t;d')
274  new_list=$(echo "$new_list" | sed 's/ *$//')
275  if [ -z "$new_list" ] ; then
276    echo "No missing packages, and the packages are up-to-date."
277  else
278    echo "Installing missing packages: $new_list."
279    sudo apt-get install ${new_list}
280  fi
281  echo
282else
283  # An apt-get exit status of 100 indicates that a real error has occurred.
284
285  # I am intentionally leaving out the '"'s around new_list_cmd,
286  # as this makes it easier to cut and paste the output
287  echo "The following command failed: " ${new_list_cmd}
288  echo
289  echo "It produces the following output:"
290  yes n | $new_list_cmd || true
291  echo
292  echo "You will have to install the above packages yourself."
293  echo
294  exit 100
295fi
296
297# Some operating systems already ship gold (on recent Debian and
298# Ubuntu you can do "apt-get install binutils-gold" to get it), but
299# older releases didn't.  Additionally, gold 2.20 (included in Ubuntu
300# Lucid) makes binaries that just segfault, and 2.20.1 does not support
301# --map-whole-files.
302# So install from source if we don't have a good version.
303
304case `ld --version` in
305*gold*2.2[1-9].*) ;;
306* )
307  if test "$do_inst_gold" = ""
308  then
309    echo "Gold is a new linker that links Chrome 5x faster than ld."
310    echo "Don't use it if you need to link other apps (e.g. valgrind, wine)"
311    echo -n "REPLACE SYSTEM LINKER ld with gold and back up ld? (y/N) "
312    if yes_no 1; then
313      do_inst_gold=1
314    fi
315  fi
316  if test "$do_inst_gold" = "1"
317  then
318    # If the system provides a good version of gold, just install it.
319    if apt-cache show binutils-gold | grep -Eq 'Version: 2.2[1-9].*'; then
320      echo "Installing binutils-gold. Backing up ld as ld.single."
321      sudo apt-get install binutils-gold
322    else
323      # FIXME: avoid installing as /usr/bin/ld
324      echo "Building binutils. Backing up ld as ld.orig."
325      install_gold || exit 99
326    fi
327  else
328    echo "Not installing gold."
329  fi
330esac
331
332# Install 32bit backwards compatibility support for 64bit systems
333if [ "$(uname -m)" = "x86_64" ]; then
334  if test "$do_inst_lib32" = ""
335  then
336    echo "Installing 32bit libraries not already provided by the system"
337    echo
338    echo "This is only needed to build a 32-bit Chrome on your 64-bit system."
339    echo
340    echo "While we only need to install a relatively small number of library"
341    echo "files, we temporarily need to download a lot of large *.deb packages"
342    echo "that contain these files. We will create new *.deb packages that"
343    echo "include just the 32bit libraries. These files will then be found on"
344    echo "your system in places like /lib32, /usr/lib32, /usr/lib/debug/lib32,"
345    echo "/usr/lib/debug/usr/lib32. If you ever need to uninstall these files,"
346    echo "look for packages named *-ia32.deb."
347    echo "Do you want me to download all packages needed to build new 32bit"
348    echo -n "package files (Y/n) "
349    if yes_no 0; then
350      do_inst_lib32=1
351    fi
352  fi
353  if test "$do_inst_lib32" != "1"
354  then
355    echo "Exiting without installing any 32bit libraries."
356    exit 0
357  fi
358
359  # Standard 32bit compatibility libraries
360  echo "First, installing the limited existing 32-bit support..."
361  cmp_list="ia32-libs lib32asound2-dev lib32readline5-dev lib32stdc++6 lib32z1
362            lib32z1-dev libc6-dev-i386 libc6-i386 g++-multilib"
363  sudo apt-get install $cmp_list
364
365  tmp=/tmp/install-32bit.$$
366  trap 'rm -rf "${tmp}"' EXIT INT TERM QUIT
367  mkdir -p "${tmp}/apt/lists/partial" "${tmp}/cache" "${tmp}/partial"
368  touch "${tmp}/status"
369
370  [ -r /etc/apt/apt.conf ] && cp /etc/apt/apt.conf "${tmp}/apt/"
371  cat >>"${tmp}/apt/apt.conf" <<EOF
372        Apt::Architecture "i386";
373        Dir::Cache "${tmp}/cache";
374        Dir::Cache::Archives "${tmp}/";
375        Dir::State::Lists "${tmp}/apt/lists/";
376        Dir::State::status "${tmp}/status";
377EOF
378
379  # Download 32bit packages
380  echo "Computing list of available 32bit packages..."
381  sudo apt-get -c="${tmp}/apt/apt.conf" update
382
383  echo "Downloading available 32bit packages..."
384  sudo apt-get -c="${tmp}/apt/apt.conf" \
385          --yes --download-only --force-yes --reinstall install \
386          ${lib_list} ${dbg_list}
387
388  # Open packages, remove everything that is not a library, move the
389  # library to a lib32 directory and package everything as a *.deb file.
390  echo "Repackaging and installing 32bit packages for use on 64bit systems..."
391  for i in ${lib_list} ${dbg_list}; do
392    orig="$(echo "${tmp}/${i}"_*_i386.deb)"
393    compat="$(echo "${orig}" |
394              sed -e 's,\(_[^_/]*_\)i386\(.deb\),-ia32\1amd64\2,')"
395    rm -rf "${tmp}/staging"
396    msg="$(fakeroot -u sh -exc '
397      # Unpack 32bit Debian archive
398      umask 022
399      mkdir -p "'"${tmp}"'/staging/dpkg/DEBIAN"
400      cd "'"${tmp}"'/staging"
401      ar x "'${orig}'"
402      tar zCfx dpkg data.tar.gz
403      tar zCfx dpkg/DEBIAN control.tar.gz
404
405      # Create a posix extended regular expression fragment that will
406      # recognize the includes which have changed. Should be rare,
407      # will almost always be empty.
408      includes=`sed -n -e "s/^[0-9a-z]*  //g" \
409                       -e "\,usr/include/,p" dpkg/DEBIAN/md5sums |
410                  xargs -n 1 -I FILE /bin/sh -c \
411                    "cmp -s dpkg/FILE /FILE || echo FILE" |
412                  tr "\n" "|" |
413                  sed -e "s,|$,,"`
414
415      # If empty, set it to not match anything.
416      test -z "$includes" && includes="^//"
417
418      # Turn the conflicts into an extended RE for removal from the
419      # Provides line.
420      conflicts=`sed -n -e "/Conflicts/s/Conflicts: *//;T;s/, */|/g;p" \
421                   dpkg/DEBIAN/control`
422
423      # Rename package, change architecture, remove conflicts and dependencies
424      sed -r -i                              \
425          -e "/Package/s/$/-ia32/"           \
426          -e "/Architecture/s/:.*$/: amd64/" \
427          -e "/Depends/s/:.*/: ia32-libs/"   \
428          -e "/Provides/s/($conflicts)(, *)?//g;T1;s/, *$//;:1"   \
429          -e "/Recommends/d"                 \
430          -e "/Conflicts/d"                  \
431        dpkg/DEBIAN/control
432
433      # Only keep files that live in "lib" directories or the includes
434      # that have changed.
435      sed -r -i                                                               \
436          -e "/\/lib64\//d" -e "/\/.?bin\//d"                                 \
437          -e "\,$includes,s,[ /]include/,&32/,g;s,include/32/,include32/,g"   \
438          -e "s, lib/, lib32/,g"                                              \
439          -e "s,/lib/,/lib32/,g"                                              \
440          -e "t;d"                                                            \
441          -e "\,^/usr/lib32/debug\(.*/lib32\),s,^/usr/lib32/debug,/usr/lib/debug," \
442        dpkg/DEBIAN/md5sums
443
444      # Re-run ldconfig after installation/removal
445      { echo "#!/bin/sh"; echo "[ \"x\$1\" = xconfigure ]&&ldconfig||:"; } \
446        >dpkg/DEBIAN/postinst
447      { echo "#!/bin/sh"; echo "[ \"x\$1\" = xremove ]&&ldconfig||:"; } \
448        >dpkg/DEBIAN/postrm
449      chmod 755 dpkg/DEBIAN/postinst dpkg/DEBIAN/postrm
450
451      # Remove any other control files
452      find dpkg/DEBIAN -mindepth 1 "(" -name control -o -name md5sums -o \
453                       -name postinst -o -name postrm ")" -o -print |
454        xargs -r rm -rf
455
456      # Remove any files/dirs that live outside of "lib" directories,
457      # or are not in our list of changed includes.
458      find dpkg -mindepth 1 -regextype posix-extended \
459          "(" -name DEBIAN -o -name lib -o -regex "dpkg/($includes)" ")" \
460          -prune -o -print | tac |
461        xargs -r -n 1 sh -c "rm \$0 2>/dev/null || rmdir \$0 2>/dev/null || : "
462      find dpkg -name lib64 -o -name bin -o -name "?bin" |
463        tac | xargs -r rm -rf
464
465      # Remove any symbolic links that were broken by the above steps.
466      find -L dpkg -type l -print | tac | xargs -r rm -rf
467
468      # Rename lib to lib32, but keep debug symbols in /usr/lib/debug/usr/lib32
469      # That is where gdb looks for them.
470      find dpkg -type d -o -path "*/lib/*" -print |
471        xargs -r -n 1 sh -c "
472          i=\$(echo \"\${0}\" |
473               sed -e s,/lib/,/lib32/,g \
474               -e s,/usr/lib32/debug\\\\\(.*/lib32\\\\\),/usr/lib/debug\\\\1,);
475          mkdir -p \"\${i%/*}\";
476          mv \"\${0}\" \"\${i}\""
477
478      # Rename include to include32.
479      [ -d "dpkg/usr/include" ] && mv "dpkg/usr/include" "dpkg/usr/include32"
480
481      # Prune any empty directories
482      find dpkg -type d | tac | xargs -r -n 1 rmdir 2>/dev/null || :
483
484      # Create our own Debian package
485      cd ..
486      dpkg --build staging/dpkg .' 2>&1)"
487    compat="$(eval echo $(echo "${compat}" |
488                          sed -e 's,_[^_/]*_amd64.deb,_*_amd64.deb,'))"
489    [ -r "${compat}" ] || {
490      echo "${msg}" >&2
491      echo "Failed to build new Debian archive!" >&2
492      exit 1
493    }
494
495    msg="$(sudo dpkg -i "${compat}" 2>&1)" && {
496        echo "Installed ${compat##*/}"
497      } || {
498        # echo "${msg}" >&2
499        echo "Skipped ${compat##*/}"
500      }
501  done
502
503  # Add symbolic links for developing 32bit code
504  echo "Adding missing symbolic links, enabling 32bit code development..."
505  for i in $(find /lib32 /usr/lib32 -maxdepth 1 -name \*.so.\* |
506             sed -e 's/[.]so[.][0-9].*/.so/' |
507             sort -u); do
508    [ "x${i##*/}" = "xld-linux.so" ] && continue
509    [ -r "$i" ] && continue
510    j="$(ls "$i."* | sed -e 's/.*[.]so[.]\([^.]*\)$/\1/;t;d' |
511         sort -n | tail -n 1)"
512    [ -r "$i.$j" ] || continue
513    sudo ln -s "${i##*/}.$j" "$i"
514  done
515fi
516