Home | History | Annotate | Download | only in build
      1 #!/bin/bash -e
      2 
      3 # Copyright (c) 2012 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 
     11 usage() {
     12   echo "Usage: $0 [--options]"
     13   echo "Options:"
     14   echo "--[no-]syms: enable or disable installation of debugging symbols"
     15   echo "--[no-]lib32: enable or disable installation of 32 bit libraries"
     16   echo "--[no-]arm: enable or disable installation of arm cross toolchain"
     17   echo "--[no-]chromeos-fonts: enable or disable installation of Chrome OS"\
     18        "fonts"
     19   echo "--no-prompt: silently select standard options/defaults"
     20   echo "Script will prompt interactively if options not given."
     21   exit 1
     22 }
     23 
     24 # Checks whether a particular package is available in the repos.
     25 # USAGE: $ package_exists <package name>
     26 package_exists() {
     27   apt-cache pkgnames | grep -x "$1" > /dev/null 2>&1
     28 }
     29 
     30 while test "$1" != ""
     31 do
     32   case "$1" in
     33   --syms)                   do_inst_syms=1;;
     34   --no-syms)                do_inst_syms=0;;
     35   --lib32)                  do_inst_lib32=1;;
     36   --no-lib32)               do_inst_lib32=0;;
     37   --arm)                    do_inst_arm=1;;
     38   --no-arm)                 do_inst_arm=0;;
     39   --chromeos-fonts)         do_inst_chromeos_fonts=1;;
     40   --no-chromeos-fonts)      do_inst_chromeos_fonts=0;;
     41   --no-prompt)              do_default=1
     42                             do_quietly="-qq --assume-yes"
     43     ;;
     44   --unsupported)            do_unsupported=1;;
     45   *) usage;;
     46   esac
     47   shift
     48 done
     49 
     50 ubuntu_versions="10\.04|10\.10|11\.04|11\.10|12\.04|12\.10|13\.04"
     51 ubuntu_codenames="lucid|maverick|natty|oneiric|precise|quantal|raring"
     52 ubuntu_issue="Ubuntu ($ubuntu_versions|$ubuntu_codenames)"
     53 # GCEL is an Ubuntu-derived VM image used on Google Compute Engine; /etc/issue
     54 # doesn't contain a version number so just trust that the user knows what
     55 # they're doing.
     56 gcel_issue="^GCEL"
     57 
     58 if [ 0 -eq "${do_unsupported-0}" ] ; then
     59   if ! egrep -q "($ubuntu_issue|$gcel_issue)" /etc/issue; then
     60     echo "ERROR: Only Ubuntu 10.04 (lucid) through 13.04 (raring) are"\
     61         "currently supported" >&2
     62     exit 1
     63   fi
     64 
     65   if ! uname -m | egrep -q "i686|x86_64"; then
     66     echo "Only x86 architectures are currently supported" >&2
     67     exit
     68   fi
     69 fi
     70 
     71 if [ "x$(id -u)" != x0 ]; then
     72   echo "Running as non-root user."
     73   echo "You might have to enter your password one or more times for 'sudo'."
     74   echo
     75 fi
     76 
     77 # Packages needed for chromeos only
     78 chromeos_dev_list="libbluetooth-dev"
     79 
     80 # Packages need for development
     81 dev_list="apache2.2-bin bison curl elfutils fakeroot flex g++ gperf
     82           language-pack-fr libapache2-mod-php5 libasound2-dev libbz2-dev
     83           libcairo2-dev libcups2-dev libcurl4-gnutls-dev libelf-dev
     84           libgconf2-dev libgl1-mesa-dev libglib2.0-dev libglu1-mesa-dev
     85           libgnome-keyring-dev libgtk2.0-dev libkrb5-dev libnspr4-dev
     86           libnss3-dev libpam0g-dev libpci-dev libpulse-dev libsctp-dev
     87           libspeechd-dev libsqlite3-dev libssl-dev libudev-dev libwww-perl
     88           libxslt1-dev libxss-dev libxt-dev libxtst-dev mesa-common-dev
     89           metacity patch perl php5-cgi pkg-config python python-cherrypy3
     90           python-dev python-psutil rpm ruby subversion ttf-dejavu-core
     91           ttf-indic-fonts ttf-kochi-gothic ttf-kochi-mincho ttf-thai-tlwg
     92           wdiff git-core
     93           $chromeos_dev_list"
     94 
     95 # 64-bit systems need a minimum set of 32-bit compat packages for the pre-built
     96 # NaCl binaries. These are always needed, regardless of whether or not we want
     97 # the full 32-bit "cross-compile" support (--lib32).
     98 if [ "$(uname -m)" = "x86_64" ]; then
     99   dev_list="${dev_list} libc6-i386 lib32gcc1 lib32stdc++6"
    100 fi
    101 
    102 # Run-time libraries required by chromeos only
    103 chromeos_lib_list="libpulse0 libbz2-1.0 libcurl4-gnutls-dev"
    104 
    105 # Full list of required run-time libraries
    106 lib_list="libatk1.0-0 libc6 libasound2 libcairo2 libcups2 libexpat1
    107           libfontconfig1 libfreetype6 libglib2.0-0 libgnome-keyring0
    108           libgtk2.0-0 libpam0g libpango1.0-0 libpci3 libpcre3 libpixman-1-0
    109           libpng12-0 libspeechd2 libstdc++6 libsqlite3-0 libx11-6
    110           libxau6 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxdmcp6
    111           libxext6 libxfixes3 libxi6 libxinerama1 libxrandr2 libxrender1
    112           libxtst6 zlib1g $chromeos_lib_list"
    113 
    114 # Debugging symbols for all of the run-time libraries
    115 dbg_list="libatk1.0-dbg libc6-dbg libcairo2-dbg libfontconfig1-dbg
    116           libglib2.0-0-dbg libgtk2.0-0-dbg libpango1.0-0-dbg libpcre3-dbg
    117           libpixman-1-0-dbg libsqlite3-0-dbg libx11-6-dbg libxau6-dbg
    118           libxcb1-dbg libxcomposite1-dbg libxcursor1-dbg libxdamage1-dbg
    119           libxdmcp6-dbg libxext6-dbg libxfixes3-dbg libxi6-dbg libxinerama1-dbg
    120           libxrandr2-dbg libxrender1-dbg libxtst6-dbg zlib1g-dbg"
    121 
    122 # arm cross toolchain packages needed to build chrome on arm
    123 arm_list="libc6-armel-cross libc6-dev-armel-cross libgcc1-armel-cross
    124           libgomp1-armel-cross linux-libc-dev-armel-cross
    125           libgcc1-dbg-armel-cross libgomp1-dbg-armel-cross
    126           binutils-arm-linux-gnueabi cpp-arm-linux-gnueabi
    127           gcc-arm-linux-gnueabi g++-arm-linux-gnueabi
    128           libmudflap0-dbg-armel-cross"
    129 
    130 
    131 # Some package names have changed over time
    132 if package_exists ttf-mscorefonts-installer; then
    133   dev_list="${dev_list} ttf-mscorefonts-installer"
    134 else
    135   dev_list="${dev_list} msttcorefonts"
    136 fi
    137 if package_exists libnspr4-dbg; then
    138   dbg_list="${dbg_list} libnspr4-dbg libnss3-dbg"
    139   lib_list="${lib_list} libnspr4 libnss3"
    140 else
    141   dbg_list="${dbg_list} libnspr4-0d-dbg libnss3-1d-dbg"
    142   lib_list="${lib_list} libnspr4-0d libnss3-1d"
    143 fi
    144 if package_exists libjpeg-dev; then
    145   dev_list="${dev_list} libjpeg-dev"
    146 else
    147   dev_list="${dev_list} libjpeg62-dev"
    148 fi
    149 if package_exists libudev1; then
    150   dev_list="${dev_list} libudev1"
    151 else
    152   dev_list="${dev_list} libudev0"
    153 fi
    154 
    155 
    156 # Some packages are only needed, if the distribution actually supports
    157 # installing them.
    158 if package_exists appmenu-gtk; then
    159   lib_list="$lib_list appmenu-gtk"
    160 fi
    161 
    162 # Waits for the user to press 'Y' or 'N'. Either uppercase of lowercase is
    163 # accepted. Returns 0 for 'Y' and 1 for 'N'. If an optional parameter has
    164 # been provided to yes_no(), the function also accepts RETURN as a user input.
    165 # The parameter specifies the exit code that should be returned in that case.
    166 # The function will echo the user's selection followed by a newline character.
    167 # Users can abort the function by pressing CTRL-C. This will call "exit 1".
    168 yes_no() {
    169   if [ 0 -ne "${do_default-0}" ] ; then
    170     return $1
    171   fi
    172   local c
    173   while :; do
    174     c="$(trap 'stty echo -iuclc icanon 2>/dev/null' EXIT INT TERM QUIT
    175          stty -echo iuclc -icanon 2>/dev/null
    176          dd count=1 bs=1 2>/dev/null | od -An -tx1)"
    177     case "$c" in
    178       " 0a") if [ -n "$1" ]; then
    179                [ $1 -eq 0 ] && echo "Y" || echo "N"
    180                return $1
    181              fi
    182              ;;
    183       " 79") echo "Y"
    184              return 0
    185              ;;
    186       " 6e") echo "N"
    187              return 1
    188              ;;
    189       "")    echo "Aborted" >&2
    190              exit 1
    191              ;;
    192       *)     # The user pressed an unrecognized key. As we are not echoing
    193              # any incorrect user input, alert the user by ringing the bell.
    194              (tput bel) 2>/dev/null
    195              ;;
    196     esac
    197   done
    198 }
    199 
    200 if test "$do_inst_syms" = ""
    201 then
    202   echo "This script installs all tools and libraries needed to build Chromium."
    203   echo ""
    204   echo "For most of the libraries, it can also install debugging symbols, which"
    205   echo "will allow you to debug code in the system libraries. Most developers"
    206   echo "won't need these symbols."
    207   echo -n "Do you want me to install them for you (y/N) "
    208   if yes_no 1; then
    209     do_inst_syms=1
    210   fi
    211 fi
    212 if test "$do_inst_syms" = "1"; then
    213   echo "Installing debugging symbols."
    214 else
    215   echo "Skipping installation of debugging symbols."
    216   dbg_list=
    217 fi
    218 
    219 # Install the Chrome OS default fonts.
    220 if test "$do_inst_chromeos_fonts" != "0"; then
    221   echo
    222   echo "Installing Chrome OS fonts."
    223   dir=`echo $0 | sed -r -e 's/\/[^/]+$//'`
    224   if ! sudo $dir/linux/install-chromeos-fonts.py; then
    225     echo "ERROR: The installation of the Chrome OS default fonts failed."
    226     if [ `stat -f -c %T $dir` == "nfs" ]; then
    227       echo "The reason is that your repo is installed on a remote file system."
    228     else
    229       echo "This is expected if your repo is installed on a remote file system."
    230     fi
    231     echo "It is recommended to install your repo on a local file system."
    232     echo "You can skip the installation of the Chrome OS default founts with"
    233     echo "the command line option: --no-chromeos-fonts."
    234     exit 1
    235   fi
    236 else
    237   echo "Skipping installation of Chrome OS fonts."
    238 fi
    239 
    240 # When cross building for arm on 64-bit systems the host binaries
    241 # that are part of v8 need to be compiled with -m32 which means
    242 # that basic multilib support is needed.
    243 if [ "$(uname -m)" = "x86_64" ]; then
    244   arm_list="$arm_list g++-multilib"
    245 fi
    246 
    247 if test "$do_inst_arm" = "1"; then
    248   . /etc/lsb-release
    249   if test "$DISTRIB_CODENAME" != "precise"; then
    250     echo "ERROR: Installing the ARM cross toolchain is only available on" \
    251          "Ubuntu precise." >&2
    252     exit 1
    253   fi
    254   echo "Installing ARM cross toolchain."
    255 else
    256   echo "Skipping installation of ARM cross toolchain."
    257   arm_list=
    258 fi
    259 
    260 sudo apt-get update
    261 
    262 # We initially run "apt-get" with the --reinstall option and parse its output.
    263 # This way, we can find all the packages that need to be newly installed
    264 # without accidentally promoting any packages from "auto" to "manual".
    265 # We then re-run "apt-get" with just the list of missing packages.
    266 echo "Finding missing packages..."
    267 packages="${dev_list} ${lib_list} ${dbg_list} ${arm_list}"
    268 # Intentionally leaving $packages unquoted so it's more readable.
    269 echo "Packages required: " $packages
    270 echo
    271 new_list_cmd="sudo apt-get install --reinstall $(echo $packages)"
    272 if new_list="$(yes n | LANGUAGE=en LANG=C $new_list_cmd)"; then
    273   # We probably never hit this following line.
    274   echo "No missing packages, and the packages are up-to-date."
    275 elif [ $? -eq 1 ]; then
    276   # We expect apt-get to have exit status of 1.
    277   # This indicates that we cancelled the install with "yes n|".
    278   new_list=$(echo "$new_list" |
    279     sed -e '1,/The following NEW packages will be installed:/d;s/^  //;t;d')
    280   new_list=$(echo "$new_list" | sed 's/ *$//')
    281   if [ -z "$new_list" ] ; then
    282     echo "No missing packages, and the packages are up-to-date."
    283   else
    284     echo "Installing missing packages: $new_list."
    285     sudo apt-get install ${do_quietly-} ${new_list}
    286   fi
    287   echo
    288 else
    289   # An apt-get exit status of 100 indicates that a real error has occurred.
    290 
    291   # I am intentionally leaving out the '"'s around new_list_cmd,
    292   # as this makes it easier to cut and paste the output
    293   echo "The following command failed: " ${new_list_cmd}
    294   echo
    295   echo "It produces the following output:"
    296   yes n | $new_list_cmd || true
    297   echo
    298   echo "You will have to install the above packages yourself."
    299   echo
    300   exit 100
    301 fi
    302 
    303 # Install 32bit backwards compatibility support for 64bit systems
    304 if [ "$(uname -m)" = "x86_64" ]; then
    305   if test "$do_inst_lib32" != "1"
    306   then
    307     echo "NOTE: If you were expecting the option to install 32bit libs,"
    308     echo "please run with the --lib32 flag."
    309     echo
    310     echo "Installation complete."
    311     exit 0
    312   else
    313     # This conditional statement has been added to deprecate and eventually
    314     # remove support for 32bit libraries on 64bit systems. But for the time
    315     # being, we still have to support a few legacy systems (e.g. bots), where
    316     # this feature is needed.
    317     # We only even give the user the option to install these libraries, if
    318     # they explicitly requested doing so by setting the --lib32 command line
    319     # flag.
    320     # And even then, we interactively ask them one more time whether they are
    321     # absolutely sure.
    322     # In order for that to work, we must reset the ${do_inst_lib32} variable.
    323     # There are other ways to achieve the same goal. But resetting the
    324     # variable is the best way to document the intended behavior -- and to
    325     # allow us to gradually deprecate and then remove the obsolete code.
    326     do_inst_lib32=
    327   fi
    328 
    329   echo "WARNING"
    330   echo
    331   echo "We no longer recommend that you use this script to install"
    332   echo "32bit libraries on a 64bit system. Instead, consider using the"
    333   echo "install-chroot.sh script to help you set up a 32bit environment"
    334   echo "for building and testing 32bit versions of Chrome."
    335   echo
    336   echo "The code for installing 32bit libraries on a 64bit system is"
    337   echo "unmaintained and might not work with modern versions of Ubuntu"
    338   echo "or Debian."
    339   echo
    340   echo -n "Are you sure you want to proceed (y/N) "
    341   if yes_no 1; then
    342     do_inst_lib32=1
    343   fi
    344   if test "$do_inst_lib32" != "1"
    345   then
    346     exit 0
    347   fi
    348 
    349   # Standard 32bit compatibility libraries
    350   echo "First, installing the limited existing 32-bit support..."
    351   cmp_list="ia32-libs lib32asound2-dev lib32stdc++6 lib32z1
    352             lib32z1-dev libc6-dev-i386 libc6-i386 g++-multilib"
    353   if [ -n "`apt-cache search lib32readline-gplv2-dev 2>/dev/null`" ]; then
    354     cmp_list="${cmp_list} lib32readline-gplv2-dev"
    355   else
    356     cmp_list="${cmp_list} lib32readline5-dev"
    357   fi
    358   sudo apt-get install ${do_quietly-} $cmp_list
    359 
    360   tmp=/tmp/install-32bit.$$
    361   trap 'rm -rf "${tmp}"' EXIT INT TERM QUIT
    362   mkdir -p "${tmp}/apt/lists/partial" "${tmp}/cache" "${tmp}/partial"
    363   touch "${tmp}/status"
    364 
    365   [ -r /etc/apt/apt.conf ] && cp /etc/apt/apt.conf "${tmp}/apt/"
    366   cat >>"${tmp}/apt/apt.conf" <<EOF
    367         Apt::Architecture "i386";
    368         Dir::Cache "${tmp}/cache";
    369         Dir::Cache::Archives "${tmp}/";
    370         Dir::State::Lists "${tmp}/apt/lists/";
    371         Dir::State::status "${tmp}/status";
    372 EOF
    373 
    374   # Download 32bit packages
    375   echo "Computing list of available 32bit packages..."
    376   sudo apt-get -c="${tmp}/apt/apt.conf" update
    377 
    378   echo "Downloading available 32bit packages..."
    379   sudo apt-get -c="${tmp}/apt/apt.conf" \
    380           --yes --download-only --force-yes --reinstall install \
    381           ${lib_list} ${dbg_list}
    382 
    383   # Open packages, remove everything that is not a library, move the
    384   # library to a lib32 directory and package everything as a *.deb file.
    385   echo "Repackaging and installing 32bit packages for use on 64bit systems..."
    386   for i in ${lib_list} ${dbg_list}; do
    387     orig="$(echo "${tmp}/${i}"_*_i386.deb)"
    388     compat="$(echo "${orig}" |
    389               sed -e 's,\(_[^_/]*_\)i386\(.deb\),-ia32\1amd64\2,')"
    390     rm -rf "${tmp}/staging"
    391     msg="$(fakeroot -u sh -exc '
    392       # Unpack 32bit Debian archive
    393       umask 022
    394       mkdir -p "'"${tmp}"'/staging/dpkg/DEBIAN"
    395       cd "'"${tmp}"'/staging"
    396       ar x "'${orig}'"
    397       tar Cfx dpkg data.tar*
    398       tar zCfx dpkg/DEBIAN control.tar.gz
    399 
    400       # Create a posix extended regular expression fragment that will
    401       # recognize the includes which have changed. Should be rare,
    402       # will almost always be empty.
    403       includes=`sed -n -e "s/^[0-9a-z]*  //g" \
    404                        -e "\,usr/include/,p" dpkg/DEBIAN/md5sums |
    405                   xargs -n 1 -I FILE /bin/sh -c \
    406                     "cmp -s dpkg/FILE /FILE || echo FILE" |
    407                   tr "\n" "|" |
    408                   sed -e "s,|$,,"`
    409 
    410       # If empty, set it to not match anything.
    411       test -z "$includes" && includes="^//"
    412 
    413       # Turn the conflicts into an extended RE for removal from the
    414       # Provides line.
    415       conflicts=`sed -n -e "/Conflicts/s/Conflicts: *//;T;s/, */|/g;p" \
    416                    dpkg/DEBIAN/control`
    417 
    418       # Rename package, change architecture, remove conflicts and dependencies
    419       sed -r -i                              \
    420           -e "/Package/s/$/-ia32/"           \
    421           -e "/Architecture/s/:.*$/: amd64/" \
    422           -e "/Depends/s/:.*/: ia32-libs/"   \
    423           -e "/Provides/s/($conflicts)(, *)?//g;T1;s/, *$//;:1"   \
    424           -e "/Recommends/d"                 \
    425           -e "/Conflicts/d"                  \
    426         dpkg/DEBIAN/control
    427 
    428       # Only keep files that live in "lib" directories or the includes
    429       # that have changed.
    430       sed -r -i                                                               \
    431           -e "/\/lib64\//d" -e "/\/.?bin\//d"                                 \
    432           -e "\,$includes,s,[ /]include/,&32/,g;s,include/32/,include32/,g"   \
    433           -e "s, lib/, lib32/,g"                                              \
    434           -e "s,/lib/,/lib32/,g"                                              \
    435           -e "t;d"                                                            \
    436           -e "\,^/usr/lib32/debug\(.*/lib32\),s,^/usr/lib32/debug,/usr/lib/debug," \
    437         dpkg/DEBIAN/md5sums
    438 
    439       # Re-run ldconfig after installation/removal
    440       { echo "#!/bin/sh"; echo "[ \"x\$1\" = xconfigure ]&&ldconfig||:"; } \
    441         >dpkg/DEBIAN/postinst
    442       { echo "#!/bin/sh"; echo "[ \"x\$1\" = xremove ]&&ldconfig||:"; } \
    443         >dpkg/DEBIAN/postrm
    444       chmod 755 dpkg/DEBIAN/postinst dpkg/DEBIAN/postrm
    445 
    446       # Remove any other control files
    447       find dpkg/DEBIAN -mindepth 1 "(" -name control -o -name md5sums -o \
    448                        -name postinst -o -name postrm ")" -o -print |
    449         xargs -r rm -rf
    450 
    451       # Remove any files/dirs that live outside of "lib" directories,
    452       # or are not in our list of changed includes.
    453       find dpkg -mindepth 1 -regextype posix-extended \
    454           "(" -name DEBIAN -o -name lib -o -regex "dpkg/($includes)" ")" \
    455           -prune -o -print | tac |
    456         xargs -r -n 1 sh -c "rm \$0 2>/dev/null || rmdir \$0 2>/dev/null || : "
    457       find dpkg -name lib64 -o -name bin -o -name "?bin" |
    458         tac | xargs -r rm -rf
    459 
    460       # Remove any symbolic links that were broken by the above steps.
    461       find -L dpkg -type l -print | tac | xargs -r rm -rf
    462 
    463       # Rename lib to lib32, but keep debug symbols in /usr/lib/debug/usr/lib32
    464       # That is where gdb looks for them.
    465       find dpkg -type d -o -path "*/lib/*" -print |
    466         xargs -r -n 1 sh -c "
    467           i=\$(echo \"\${0}\" |
    468                sed -e s,/lib/,/lib32/,g \
    469                -e s,/usr/lib32/debug\\\\\(.*/lib32\\\\\),/usr/lib/debug\\\\1,);
    470           mkdir -p \"\${i%/*}\";
    471           mv \"\${0}\" \"\${i}\""
    472 
    473       # Rename include to include32.
    474       [ -d "dpkg/usr/include" ] && mv "dpkg/usr/include" "dpkg/usr/include32"
    475 
    476       # Prune any empty directories
    477       find dpkg -type d | tac | xargs -r -n 1 rmdir 2>/dev/null || :
    478 
    479       # Create our own Debian package
    480       cd ..
    481       dpkg --build staging/dpkg .' 2>&1)"
    482     compat="$(eval echo $(echo "${compat}" |
    483                           sed -e 's,_[^_/]*_amd64.deb,_*_amd64.deb,'))"
    484     [ -r "${compat}" ] || {
    485       echo "${msg}" >&2
    486       echo "Failed to build new Debian archive!" >&2
    487       exit 1
    488     }
    489 
    490     msg="$(sudo dpkg -i "${compat}" 2>&1)" && {
    491         echo "Installed ${compat##*/}"
    492       } || {
    493         # echo "${msg}" >&2
    494         echo "Skipped ${compat##*/}"
    495       }
    496   done
    497 
    498   # Add symbolic links for developing 32bit code
    499   echo "Adding missing symbolic links, enabling 32bit code development..."
    500   for i in $(find /lib32 /usr/lib32 -maxdepth 1 -name \*.so.\* |
    501              sed -e 's/[.]so[.][0-9].*/.so/' |
    502              sort -u); do
    503     [ "x${i##*/}" = "xld-linux.so" ] && continue
    504     [ -r "$i" ] && continue
    505     j="$(ls "$i."* | sed -e 's/.*[.]so[.]\([^.]*\)$/\1/;t;d' |
    506          sort -n | tail -n 1)"
    507     [ -r "$i.$j" ] || continue
    508     sudo ln -s "${i##*/}.$j" "$i"
    509   done
    510 fi
    511