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 https://chromium.googlesource.com/chromium/src/+/master/docs/linux_build_instructions.md
      9 
     10 usage() {
     11   echo "Usage: $0 [--options]"
     12   echo "Options:"
     13   echo "--[no-]syms: enable or disable installation of debugging symbols"
     14   echo "--lib32: enable installation of 32-bit libraries, e.g. for V8 snapshot"
     15   echo "--[no-]arm: enable or disable installation of arm cross toolchain"
     16   echo "--[no-]chromeos-fonts: enable or disable installation of Chrome OS"\
     17        "fonts"
     18   echo "--[no-]nacl: enable or disable installation of prerequisites for"\
     19        "building standalone NaCl and all its toolchains"
     20   echo "--no-prompt: silently select standard options/defaults"
     21   echo "--quick-check: quickly try to determine if dependencies are installed"
     22   echo "               (this avoids interactive prompts and sudo commands,"
     23   echo "               so might not be 100% accurate)"
     24   echo "--unsupported: attempt installation even on unsupported systems"
     25   echo "Script will prompt interactively if options not given."
     26   exit 1
     27 }
     28 
     29 # Checks whether a particular package is available in the repos.
     30 # USAGE: $ package_exists <package name>
     31 package_exists() {
     32   apt-cache pkgnames | grep -x "$1" > /dev/null 2>&1
     33 }
     34 
     35 # These default to on because (some) bots need them and it keeps things
     36 # simple for the bot setup if all bots just run the script in its default
     37 # mode.  Developers who don't want stuff they don't need installed on their
     38 # own workstations can pass --no-arm --no-nacl when running the script.
     39 do_inst_arm=1
     40 do_inst_nacl=1
     41 
     42 while test "$1" != ""
     43 do
     44   case "$1" in
     45   --syms)                   do_inst_syms=1;;
     46   --no-syms)                do_inst_syms=0;;
     47   --lib32)                  do_inst_lib32=1;;
     48   --arm)                    do_inst_arm=1;;
     49   --no-arm)                 do_inst_arm=0;;
     50   --chromeos-fonts)         do_inst_chromeos_fonts=1;;
     51   --no-chromeos-fonts)      do_inst_chromeos_fonts=0;;
     52   --nacl)                   do_inst_nacl=1;;
     53   --no-nacl)                do_inst_nacl=0;;
     54   --no-prompt)              do_default=1
     55                             do_quietly="-qq --assume-yes"
     56     ;;
     57   --quick-check)            do_quick_check=1;;
     58   --unsupported)            do_unsupported=1;;
     59   *) usage;;
     60   esac
     61   shift
     62 done
     63 
     64 if test "$do_inst_arm" = "1"; then
     65   do_inst_lib32=1
     66 fi
     67 
     68 # Check for lsb_release command in $PATH
     69 if ! which lsb_release > /dev/null; then
     70   echo "ERROR: lsb_release not found in \$PATH" >&2
     71   exit 1;
     72 fi
     73 
     74 lsb_release=$(lsb_release --codename --short)
     75 ubuntu_codenames="(precise|trusty|utopic|vivid|wily|xenial)"
     76 if [ 0 -eq "${do_unsupported-0}" ] && [ 0 -eq "${do_quick_check-0}" ] ; then
     77   if [[ ! $lsb_release =~ $ubuntu_codenames ]]; then
     78     echo "ERROR: Only Ubuntu 12.04 (precise), 14.04 (trusty), " \
     79       "14.10 (utopic), 15.04 (vivid), 15.10 (wily) and 16.04 (xenial) " \
     80       "are currently supported" >&2
     81     exit 1
     82   fi
     83 
     84   if ! uname -m | egrep -q "i686|x86_64"; then
     85     echo "Only x86 architectures are currently supported" >&2
     86     exit
     87   fi
     88 fi
     89 
     90 if [ "x$(id -u)" != x0 ] && [ 0 -eq "${do_quick_check-0}" ]; then
     91   echo "Running as non-root user."
     92   echo "You might have to enter your password one or more times for 'sudo'."
     93   echo
     94 fi
     95 
     96 # Packages needed for chromeos only
     97 chromeos_dev_list="libbluetooth-dev libxkbcommon-dev realpath"
     98 
     99 # Packages needed for development
    100 dev_list="bison cdbs curl dpkg-dev elfutils devscripts fakeroot
    101           flex fonts-thai-tlwg g++ git-core git-svn gperf language-pack-da
    102           language-pack-fr language-pack-he language-pack-zh-hant
    103           libasound2-dev libbrlapi-dev libav-tools
    104           libbz2-dev libcairo2-dev libcap-dev libcups2-dev libcurl4-gnutls-dev
    105           libdrm-dev libelf-dev libffi-dev libgconf2-dev libglib2.0-dev
    106           libglu1-mesa-dev libgnome-keyring-dev libgtk2.0-dev libkrb5-dev
    107           libnspr4-dev libnss3-dev libpam0g-dev libpci-dev libpulse-dev
    108           libsctp-dev libspeechd-dev libsqlite3-dev libssl-dev libudev-dev
    109           libwww-perl libxslt1-dev libxss-dev libxt-dev libxtst-dev openbox
    110           patch perl pkg-config python python-cherrypy3 python-crypto
    111           python-dev python-numpy python-opencv python-openssl python-psutil
    112           python-yaml rpm ruby subversion ttf-dejavu-core wdiff zip
    113           $chromeos_dev_list"
    114 
    115 # 64-bit systems need a minimum set of 32-bit compat packages for the pre-built
    116 # NaCl binaries.
    117 if file -L /sbin/init | grep -q 'ELF 64-bit'; then
    118   dev_list="${dev_list} libc6-i386 lib32gcc1 lib32stdc++6"
    119 fi
    120 
    121 # Run-time libraries required by chromeos only
    122 chromeos_lib_list="libpulse0 libbz2-1.0"
    123 
    124 # Full list of required run-time libraries
    125 lib_list="libatk1.0-0 libc6 libasound2 libcairo2 libcap2 libcups2 libexpat1
    126           libffi6 libfontconfig1 libfreetype6 libglib2.0-0 libgnome-keyring0
    127           libgtk2.0-0 libpam0g libpango1.0-0 libpci3 libpcre3 libpixman-1-0
    128           libpng12-0 libspeechd2 libstdc++6 libsqlite3-0 libx11-6 libxau6
    129           libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxdmcp6 libxext6
    130           libxfixes3 libxi6 libxinerama1 libxrandr2 libxrender1 libxtst6
    131           zlib1g $chromeos_lib_list"
    132 
    133 # Debugging symbols for all of the run-time libraries
    134 dbg_list="libatk1.0-dbg libc6-dbg libcairo2-dbg libffi6-dbg libfontconfig1-dbg
    135           libglib2.0-0-dbg libgtk2.0-0-dbg libpango1.0-0-dbg libpcre3-dbg
    136           libpixman-1-0-dbg libsqlite3-0-dbg libx11-6-dbg libxau6-dbg
    137           libxcb1-dbg libxcomposite1-dbg libxcursor1-dbg libxdamage1-dbg
    138           libxdmcp6-dbg libxext6-dbg libxfixes3-dbg libxi6-dbg libxinerama1-dbg
    139           libxrandr2-dbg libxrender1-dbg libxtst6-dbg zlib1g-dbg"
    140 
    141 # Find the proper version of libstdc++6-4.x-dbg.
    142 if [ "x$lsb_release" = "xprecise" ]; then
    143   dbg_list="${dbg_list} libstdc++6-4.6-dbg"
    144 elif [ "x$lsb_release" = "xtrusty" ]; then
    145   dbg_list="${dbg_list} libstdc++6-4.8-dbg"
    146 else
    147   dbg_list="${dbg_list} libstdc++6-4.9-dbg"
    148 fi
    149 
    150 # 32-bit libraries needed e.g. to compile V8 snapshot for Android or armhf
    151 lib32_list="linux-libc-dev:i386"
    152 
    153 # arm cross toolchain packages needed to build chrome on armhf
    154 arm_list="libc6-dev-armhf-cross
    155           linux-libc-dev-armhf-cross
    156           g++-arm-linux-gnueabihf"
    157 
    158 # Work around for dependency issue Ubuntu/Trusty: http://crbug.com/435056
    159 case $lsb_release in
    160   trusty)
    161     arm_list+=" g++-4.8-multilib-arm-linux-gnueabihf
    162                 gcc-4.8-multilib-arm-linux-gnueabihf"
    163     ;;
    164   wily)
    165     arm_list+=" g++-5-multilib-arm-linux-gnueabihf
    166                 gcc-5-multilib-arm-linux-gnueabihf
    167                 gcc-arm-linux-gnueabihf"
    168     ;;
    169   xenial)
    170     arm_list+=" g++-5-multilib-arm-linux-gnueabihf
    171                 gcc-5-multilib-arm-linux-gnueabihf
    172                 gcc-arm-linux-gnueabihf"
    173     ;;
    174 esac
    175 
    176 # Packages to build NaCl, its toolchains, and its ports.
    177 naclports_list="ant autoconf bison cmake gawk intltool xutils-dev xsltproc"
    178 nacl_list="g++-mingw-w64-i686 lib32z1-dev
    179            libasound2:i386 libcap2:i386 libelf-dev:i386 libfontconfig1:i386
    180            libgconf-2-4:i386 libglib2.0-0:i386 libgpm2:i386 libgtk2.0-0:i386
    181            libncurses5:i386 lib32ncurses5-dev libnss3:i386 libpango1.0-0:i386
    182            libssl1.0.0:i386 libtinfo-dev libtinfo-dev:i386 libtool
    183            libxcomposite1:i386 libxcursor1:i386 libxdamage1:i386 libxi6:i386
    184            libxrandr2:i386 libxss1:i386 libxtst6:i386 texinfo xvfb
    185            ${naclports_list}"
    186 
    187 # Find the proper version of packages that depend on mesa. Only one -lts variant
    188 # of mesa can be installed and everything that depends on it must match.
    189 
    190 # Query for the name and status of all mesa LTS variants, filter for only
    191 # installed packages, extract just the name, and eliminate duplicates (there can
    192 # be more than one with the same name in the case of multiarch). Expand into an
    193 # array.
    194 mesa_packages=($(dpkg-query -Wf'${package} ${status}\n' \
    195                             libgl1-mesa-glx-lts-\* 2>/dev/null | \
    196                  grep " ok installed" | cut -d " " -f 1 | sort -u))
    197 if [ "${#mesa_packages[@]}" -eq 0 ]; then
    198   mesa_variant=""
    199 elif [ "${#mesa_packages[@]}" -eq 1 ]; then
    200   # Strip the base package name and leave just "-lts-whatever"
    201   mesa_variant="${mesa_packages[0]#libgl1-mesa-glx}"
    202 else
    203   echo "ERROR: unable to determine which libgl1-mesa-glx variant is installed."
    204   exit 1
    205 fi
    206 dev_list="${dev_list} libgbm-dev${mesa_variant}
    207           libgles2-mesa-dev${mesa_variant} libgl1-mesa-dev${mesa_variant}
    208           mesa-common-dev${mesa_variant}"
    209 nacl_list="${nacl_list} libgl1-mesa-glx${mesa_variant}:i386"
    210 
    211 # Some package names have changed over time
    212 if package_exists ttf-mscorefonts-installer; then
    213   dev_list="${dev_list} ttf-mscorefonts-installer"
    214 else
    215   dev_list="${dev_list} msttcorefonts"
    216 fi
    217 if package_exists libnspr4-dbg; then
    218   dbg_list="${dbg_list} libnspr4-dbg libnss3-dbg"
    219   lib_list="${lib_list} libnspr4 libnss3"
    220 else
    221   dbg_list="${dbg_list} libnspr4-0d-dbg libnss3-1d-dbg"
    222   lib_list="${lib_list} libnspr4-0d libnss3-1d"
    223 fi
    224 if package_exists libjpeg-dev; then
    225   dev_list="${dev_list} libjpeg-dev"
    226 else
    227   dev_list="${dev_list} libjpeg62-dev"
    228 fi
    229 if package_exists libudev1; then
    230   dev_list="${dev_list} libudev1"
    231   nacl_list="${nacl_list} libudev1:i386"
    232 else
    233   dev_list="${dev_list} libudev0"
    234   nacl_list="${nacl_list} libudev0:i386"
    235 fi
    236 if package_exists libbrlapi0.6; then
    237   dev_list="${dev_list} libbrlapi0.6"
    238 else
    239   dev_list="${dev_list} libbrlapi0.5"
    240 fi
    241 if package_exists apache2-bin; then
    242   dev_list="${dev_list} apache2-bin"
    243 else
    244   dev_list="${dev_list} apache2.2-bin"
    245 fi
    246 if package_exists fonts-stix; then
    247   dev_list="${dev_list} fonts-stix"
    248 else
    249   dev_list="${dev_list} xfonts-mathml"
    250 fi
    251 if package_exists fonts-indic; then
    252     dev_list="${dev_list} fonts-indic"
    253 else
    254     dev_list="${dev_list} ttf-indic-fonts"
    255 fi
    256 if package_exists php7.0-cgi; then
    257     dev_list="${dev_list} php7.0-cgi libapache2-mod-php7.0"
    258 else
    259     dev_list="${dev_list} php5-cgi libapache2-mod-php5"
    260 fi
    261 # Ubuntu 16.04 has this package deleted.
    262 if package_exists ttf-kochi-gothic; then
    263     dev_list="${dev_list} ttf-kochi-gothic"
    264 fi
    265 # Ubuntu 16.04 has this package deleted.
    266 if package_exists ttf-kochi-mincho; then
    267     dev_list="${dev_list} ttf-kochi-mincho"
    268 fi
    269 
    270 # Some packages are only needed if the distribution actually supports
    271 # installing them.
    272 if package_exists appmenu-gtk; then
    273   lib_list="$lib_list appmenu-gtk"
    274 fi
    275 
    276 # When cross building for arm/Android on 64-bit systems the host binaries
    277 # that are part of v8 need to be compiled with -m32 which means
    278 # that basic multilib support is needed.
    279 if file -L /sbin/init | grep -q 'ELF 64-bit'; then
    280   # gcc-multilib conflicts with the arm cross compiler (at least in trusty) but
    281   # g++-X.Y-multilib gives us the 32-bit support that we need. Find out the
    282   # appropriate value of X and Y by seeing what version the current
    283   # distribution's g++-multilib package depends on.
    284   multilib_package=$(apt-cache depends g++-multilib --important | \
    285       grep -E --color=never --only-matching '\bg\+\+-[0-9.]+-multilib\b')
    286   lib32_list="$lib32_list $multilib_package"
    287 fi
    288 
    289 # Waits for the user to press 'Y' or 'N'. Either uppercase of lowercase is
    290 # accepted. Returns 0 for 'Y' and 1 for 'N'. If an optional parameter has
    291 # been provided to yes_no(), the function also accepts RETURN as a user input.
    292 # The parameter specifies the exit code that should be returned in that case.
    293 # The function will echo the user's selection followed by a newline character.
    294 # Users can abort the function by pressing CTRL-C. This will call "exit 1".
    295 yes_no() {
    296   if [ 0 -ne "${do_default-0}" ] ; then
    297     [ $1 -eq 0 ] && echo "Y" || echo "N"
    298     return $1
    299   fi
    300   local c
    301   while :; do
    302     c="$(trap 'stty echo -iuclc icanon 2>/dev/null' EXIT INT TERM QUIT
    303          stty -echo iuclc -icanon 2>/dev/null
    304          dd count=1 bs=1 2>/dev/null | od -An -tx1)"
    305     case "$c" in
    306       " 0a") if [ -n "$1" ]; then
    307                [ $1 -eq 0 ] && echo "Y" || echo "N"
    308                return $1
    309              fi
    310              ;;
    311       " 79") echo "Y"
    312              return 0
    313              ;;
    314       " 6e") echo "N"
    315              return 1
    316              ;;
    317       "")    echo "Aborted" >&2
    318              exit 1
    319              ;;
    320       *)     # The user pressed an unrecognized key. As we are not echoing
    321              # any incorrect user input, alert the user by ringing the bell.
    322              (tput bel) 2>/dev/null
    323              ;;
    324     esac
    325   done
    326 }
    327 
    328 if test "$do_inst_syms" = "" && test 0 -eq ${do_quick_check-0}
    329 then
    330   echo "This script installs all tools and libraries needed to build Chromium."
    331   echo ""
    332   echo "For most of the libraries, it can also install debugging symbols, which"
    333   echo "will allow you to debug code in the system libraries. Most developers"
    334   echo "won't need these symbols."
    335   echo -n "Do you want me to install them for you (y/N) "
    336   if yes_no 1; then
    337     do_inst_syms=1
    338   fi
    339 fi
    340 if test "$do_inst_syms" = "1"; then
    341   echo "Including debugging symbols."
    342 else
    343   echo "Skipping debugging symbols."
    344   dbg_list=
    345 fi
    346 
    347 if test "$do_inst_lib32" = "1" ; then
    348   echo "Including 32-bit libraries for ARM/Android."
    349 else
    350   echo "Skipping 32-bit libraries for ARM/Android."
    351   lib32_list=
    352 fi
    353 
    354 if test "$do_inst_arm" = "1" ; then
    355   echo "Including ARM cross toolchain."
    356 else
    357   echo "Skipping ARM cross toolchain."
    358   arm_list=
    359 fi
    360 
    361 if test "$do_inst_nacl" = "1"; then
    362   echo "Including NaCl, NaCl toolchain, NaCl ports dependencies."
    363 else
    364   echo "Skipping NaCl, NaCl toolchain, NaCl ports dependencies."
    365   nacl_list=
    366 fi
    367 
    368 # The `sort -r -s -t: -k2` sorts all the :i386 packages to the front, to avoid
    369 # confusing dpkg-query (crbug.com/446172).
    370 packages="$(
    371   echo "${dev_list} ${lib_list} ${dbg_list} ${lib32_list} ${arm_list}"\
    372        "${nacl_list}" | tr " " "\n" | sort -u | sort -r -s -t: -k2 | tr "\n" " "
    373 )"
    374 
    375 if [ 1 -eq "${do_quick_check-0}" ] ; then
    376   failed_check="$(dpkg-query -W -f '${PackageSpec}:${Status}\n' \
    377     ${packages} 2>&1 | grep -v "ok installed" || :)"
    378   if [ -n "${failed_check}" ]; then
    379     echo
    380     nomatch="$(echo "${failed_check}" | \
    381       sed -e "s/^No packages found matching \(.*\).$/\1/;t;d")"
    382     missing="$(echo "${failed_check}" | \
    383       sed -e "/^No packages found matching/d;s/^\(.*\):.*$/\1/")"
    384     if [ "$nomatch" ]; then
    385       # Distinguish between packages that actually aren't available to the
    386       # system (i.e. not in any repo) and packages that just aren't known to
    387       # dpkg (i.e. managed by apt).
    388       unknown=""
    389       for p in ${nomatch}; do
    390         if apt-cache show ${p} > /dev/null 2>&1; then
    391           missing="${p}\n${missing}"
    392         else
    393           unknown="${p}\n${unknown}"
    394         fi
    395       done
    396       if [ -n "${unknown}" ]; then
    397         echo "WARNING: The following packages are unknown to your system"
    398         echo "(maybe missing a repo or need to 'sudo apt-get update'):"
    399         echo -e "${unknown}" | sed -e "s/^/  /"
    400       fi
    401     fi
    402     if [ -n "${missing}" ]; then
    403       echo "WARNING: The following packages are not installed:"
    404       echo -e "${missing}" | sed -e "s/^/  /"
    405     fi
    406     exit 1
    407   fi
    408   exit 0
    409 fi
    410 
    411 if test "$do_inst_lib32" = "1" || test "$do_inst_nacl" = "1"; then
    412   if [[ ! $lsb_release =~ (precise) ]]; then
    413     sudo dpkg --add-architecture i386
    414   fi
    415 fi
    416 sudo apt-get update
    417 
    418 # We initially run "apt-get" with the --reinstall option and parse its output.
    419 # This way, we can find all the packages that need to be newly installed
    420 # without accidentally promoting any packages from "auto" to "manual".
    421 # We then re-run "apt-get" with just the list of missing packages.
    422 echo "Finding missing packages..."
    423 # Intentionally leaving $packages unquoted so it's more readable.
    424 echo "Packages required: " $packages
    425 echo
    426 new_list_cmd="sudo apt-get install --reinstall $(echo $packages)"
    427 if new_list="$(yes n | LANGUAGE=en LANG=C $new_list_cmd)"; then
    428   # We probably never hit this following line.
    429   echo "No missing packages, and the packages are up-to-date."
    430 elif [ $? -eq 1 ]; then
    431   # We expect apt-get to have exit status of 1.
    432   # This indicates that we cancelled the install with "yes n|".
    433   new_list=$(echo "$new_list" |
    434     sed -e '1,/The following NEW packages will be installed:/d;s/^  //;t;d')
    435   new_list=$(echo "$new_list" | sed 's/ *$//')
    436   if [ -z "$new_list" ] ; then
    437     echo "No missing packages, and the packages are up-to-date."
    438   else
    439     echo "Installing missing packages: $new_list."
    440     sudo apt-get install ${do_quietly-} ${new_list}
    441   fi
    442   echo
    443 else
    444   # An apt-get exit status of 100 indicates that a real error has occurred.
    445 
    446   # I am intentionally leaving out the '"'s around new_list_cmd,
    447   # as this makes it easier to cut and paste the output
    448   echo "The following command failed: " ${new_list_cmd}
    449   echo
    450   echo "It produces the following output:"
    451   yes n | $new_list_cmd || true
    452   echo
    453   echo "You will have to install the above packages yourself."
    454   echo
    455   exit 100
    456 fi
    457 
    458 # Install the Chrome OS default fonts. This must go after running
    459 # apt-get, since install-chromeos-fonts depends on curl.
    460 if test "$do_inst_chromeos_fonts" != "0"; then
    461   echo
    462   echo "Installing Chrome OS fonts."
    463   dir=`echo $0 | sed -r -e 's/\/[^/]+$//'`
    464   if ! sudo $dir/linux/install-chromeos-fonts.py; then
    465     echo "ERROR: The installation of the Chrome OS default fonts failed."
    466     if [ `stat -f -c %T $dir` == "nfs" ]; then
    467       echo "The reason is that your repo is installed on a remote file system."
    468     else
    469       echo "This is expected if your repo is installed on a remote file system."
    470     fi
    471     echo "It is recommended to install your repo on a local file system."
    472     echo "You can skip the installation of the Chrome OS default founts with"
    473     echo "the command line option: --no-chromeos-fonts."
    474     exit 1
    475   fi
    476 else
    477   echo "Skipping installation of Chrome OS fonts."
    478 fi
    479 
    480 # $1 - target name
    481 # $2 - link name
    482 create_library_symlink() {
    483   target=$1
    484   linkname=$2
    485   if [ -L $linkname ]; then
    486     if [ "$(basename $(readlink $linkname))" != "$(basename $target)" ]; then
    487       sudo rm $linkname
    488     fi
    489   fi
    490   if [ ! -r $linkname ]; then
    491     echo "Creating link: $linkname"
    492     sudo ln -fs $target $linkname
    493   fi
    494 }
    495 
    496 if test "$do_inst_nacl" = "1"; then
    497   echo "Installing symbolic links for NaCl."
    498   # naclports needs to cross build python for i386, but libssl1.0.0:i386
    499   # only contains libcrypto.so.1.0.0 and not the symlink needed for
    500   # linking (libcrypto.so).
    501   create_library_symlink /lib/i386-linux-gnu/libcrypto.so.1.0.0 \
    502       /usr/lib/i386-linux-gnu/libcrypto.so
    503 
    504   create_library_symlink /lib/i386-linux-gnu/libssl.so.1.0.0 \
    505       /usr/lib/i386-linux-gnu/libssl.so
    506 else
    507   echo "Skipping symbolic links for NaCl."
    508 fi
    509