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
10usage() {
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# Waits for the user to press 'Y' or 'N'. Either uppercase of lowercase is
30# accepted. Returns 0 for 'Y' and 1 for 'N'. If an optional parameter has
31# been provided to yes_no(), the function also accepts RETURN as a user input.
32# The parameter specifies the exit code that should be returned in that case.
33# The function will echo the user's selection followed by a newline character.
34# Users can abort the function by pressing CTRL-C. This will call "exit 1".
35yes_no() {
36  if [ 0 -ne "${do_default-0}" ] ; then
37    [ $1 -eq 0 ] && echo "Y" || echo "N"
38    return $1
39  fi
40  local c
41  while :; do
42    c="$(trap 'stty echo -iuclc icanon 2>/dev/null' EXIT INT TERM QUIT
43         stty -echo iuclc -icanon 2>/dev/null
44         dd count=1 bs=1 2>/dev/null | od -An -tx1)"
45    case "$c" in
46      " 0a") if [ -n "$1" ]; then
47               [ $1 -eq 0 ] && echo "Y" || echo "N"
48               return $1
49             fi
50             ;;
51      " 79") echo "Y"
52             return 0
53             ;;
54      " 6e") echo "N"
55             return 1
56             ;;
57      "")    echo "Aborted" >&2
58             exit 1
59             ;;
60      *)     # The user pressed an unrecognized key. As we are not echoing
61             # any incorrect user input, alert the user by ringing the bell.
62             (tput bel) 2>/dev/null
63             ;;
64    esac
65  done
66}
67
68# Checks whether a particular package is available in the repos.
69# USAGE: $ package_exists <package name>
70package_exists() {
71  [ ! -z "`apt-cache search --names-only "$1"`" ]
72}
73
74# These default to on because (some) bots need them and it keeps things
75# simple for the bot setup if all bots just run the script in its default
76# mode.  Developers who don't want stuff they don't need installed on their
77# own workstations can pass --no-arm --no-nacl when running the script.
78do_inst_arm=1
79do_inst_nacl=1
80
81while test "$1" != ""
82do
83  case "$1" in
84  --syms)                   do_inst_syms=1;;
85  --no-syms)                do_inst_syms=0;;
86  --lib32)                  do_inst_lib32=1;;
87  --arm)                    do_inst_arm=1;;
88  --no-arm)                 do_inst_arm=0;;
89  --chromeos-fonts)         do_inst_chromeos_fonts=1;;
90  --no-chromeos-fonts)      do_inst_chromeos_fonts=0;;
91  --nacl)                   do_inst_nacl=1;;
92  --no-nacl)                do_inst_nacl=0;;
93  --no-prompt)              do_default=1
94                            do_quietly="-qq --assume-yes"
95    ;;
96  --quick-check)            do_quick_check=1;;
97  --unsupported)            do_unsupported=1;;
98  *) usage;;
99  esac
100  shift
101done
102
103if test "$do_inst_arm" = "1"; then
104  do_inst_lib32=1
105fi
106
107# Check for lsb_release command in $PATH
108if ! which lsb_release > /dev/null; then
109  echo "ERROR: lsb_release not found in \$PATH" >&2
110  exit 1;
111fi
112
113distro_codename=$(lsb_release --codename --short)
114distro_id=$(lsb_release --id --short)
115supported_codenames="(trusty|xenial|yakkety)"
116supported_ids="(Debian)"
117if [ 0 -eq "${do_unsupported-0}" ] && [ 0 -eq "${do_quick_check-0}" ] ; then
118  if [[ ! $distro_codename =~ $supported_codenames &&
119        ! $distro_id =~ $supported_ids ]]; then
120    echo -e "ERROR: The only supported distros are\n" \
121      "\tUbuntu 14.04 (trusty)\n" \
122      "\tUbuntu 16.04 (xenial)\n" \
123      "\tUbuntu 16.10 (yakkety)\n" \
124      "\tDebian 8 (jessie) or later" >&2
125    exit 1
126  fi
127
128  if ! uname -m | egrep -q "i686|x86_64"; then
129    echo "Only x86 architectures are currently supported" >&2
130    exit
131  fi
132fi
133
134if [ "x$(id -u)" != x0 ] && [ 0 -eq "${do_quick_check-0}" ]; then
135  echo "Running as non-root user."
136  echo "You might have to enter your password one or more times for 'sudo'."
137  echo
138fi
139
140# Packages needed for chromeos only
141chromeos_dev_list="libbluetooth-dev libxkbcommon-dev realpath"
142
143# Packages needed for development
144dev_list="\
145  bison
146  cdbs
147  curl
148  dpkg-dev
149  elfutils
150  devscripts
151  fakeroot
152  flex
153  fonts-ipafont
154  fonts-thai-tlwg
155  g++
156  git-core
157  git-svn
158  gperf
159  libasound2-dev
160  libbrlapi-dev
161  libav-tools
162  libbz2-dev
163  libcairo2-dev
164  libcap-dev
165  libcups2-dev
166  libcurl4-gnutls-dev
167  libdrm-dev
168  libelf-dev
169  libffi-dev
170  libgconf2-dev
171  libglib2.0-dev
172  libglu1-mesa-dev
173  libgnome-keyring-dev
174  libgtk2.0-dev
175  libgtk-3-dev
176  libkrb5-dev
177  libnspr4-dev
178  libnss3-dev
179  libpam0g-dev
180  libpci-dev
181  libpulse-dev
182  libsctp-dev
183  libspeechd-dev
184  libsqlite3-dev
185  libssl-dev
186  libudev-dev
187  libwww-perl
188  libxslt1-dev
189  libxss-dev
190  libxt-dev
191  libxtst-dev
192  openbox
193  patch
194  perl
195  pkg-config
196  python
197  python-cherrypy3
198  python-crypto
199  python-dev
200  python-numpy
201  python-opencv
202  python-openssl
203  python-psutil
204  python-yaml
205  rpm
206  ruby
207  subversion
208  ttf-dejavu-core
209  wdiff
210  xcompmgr
211  zip
212  $chromeos_dev_list
213"
214
215# 64-bit systems need a minimum set of 32-bit compat packages for the pre-built
216# NaCl binaries.
217if file -L /sbin/init | grep -q 'ELF 64-bit'; then
218  dev_list="${dev_list} libc6-i386 lib32gcc1 lib32stdc++6"
219fi
220
221# Run-time libraries required by chromeos only
222chromeos_lib_list="libpulse0 libbz2-1.0"
223
224# Full list of required run-time libraries
225lib_list="\
226  libatk1.0-0
227  libc6
228  libasound2
229  libcairo2
230  libcap2
231  libcups2
232  libexpat1
233  libffi6
234  libfontconfig1
235  libfreetype6
236  libglib2.0-0
237  libgnome-keyring0
238  libgtk2.0-0
239  libgtk-3-0
240  libpam0g
241  libpango1.0-0
242  libpci3
243  libpcre3
244  libpixman-1-0
245  libspeechd2
246  libstdc++6
247  libsqlite3-0
248  libx11-6
249  libx11-xcb1
250  libxau6
251  libxcb1
252  libxcomposite1
253  libxcursor1
254  libxdamage1
255  libxdmcp6
256  libxext6
257  libxfixes3
258  libxi6
259  libxinerama1
260  libxrandr2
261  libxrender1
262  libxtst6
263  zlib1g
264  $chromeos_lib_list
265"
266
267# Debugging symbols for all of the run-time libraries
268dbg_list="\
269  libatk1.0-dbg
270  libc6-dbg
271  libcairo2-dbg
272  libffi6-dbg
273  libfontconfig1-dbg
274  libglib2.0-0-dbg
275  libgtk2.0-0-dbg
276  libgtk-3-0-dbg
277  libpango1.0-0-dbg
278  libpcre3-dbg
279  libpixman-1-0-dbg
280  libsqlite3-0-dbg
281  libx11-6-dbg
282  libx11-xcb1-dbg
283  libxau6-dbg
284  libxcb1-dbg
285  libxcomposite1-dbg
286  libxcursor1-dbg
287  libxdamage1-dbg
288  libxdmcp6-dbg
289  libxext6-dbg
290  libxi6-dbg
291  libxinerama1-dbg
292  libxrandr2-dbg
293  libxrender1-dbg
294  libxtst6-dbg
295  zlib1g-dbg
296"
297
298if [[ ! $distro_codename =~ "yakkety" ]]; then
299  dbg_list="${dbg_list} libxfixes3-dbg"
300fi
301
302# Find the proper version of libstdc++6-4.x-dbg.
303if [ "x$distro_codename" = "xtrusty" ]; then
304  dbg_list="${dbg_list} libstdc++6-4.8-dbg"
305else
306  dbg_list="${dbg_list} libstdc++6-4.9-dbg"
307fi
308
309# 32-bit libraries needed e.g. to compile V8 snapshot for Android or armhf
310lib32_list="linux-libc-dev:i386"
311
312# arm cross toolchain packages needed to build chrome on armhf
313EM_REPO="deb http://emdebian.org/tools/debian/ jessie main"
314EM_SOURCE=$(cat <<EOF
315# Repo added by Chromium $0
316${EM_REPO}
317# deb-src http://emdebian.org/tools/debian/ jessie main
318EOF
319)
320EM_ARCHIVE_KEY_FINGER="084C6C6F39159EDB67969AA87DE089671804772E"
321GPP_ARM_PACKAGE="g++-arm-linux-gnueabihf"
322case $distro_codename in
323  jessie)
324    eval $(apt-config shell APT_SOURCESDIR 'Dir::Etc::sourceparts/d')
325    CROSSTOOLS_LIST="${APT_SOURCESDIR}/crosstools.list"
326    arm_list="libc6-dev:armhf
327              linux-libc-dev:armhf"
328    if test "$do_inst_arm" = "1"; then
329      if $(dpkg-query -W ${GPP_ARM_PACKAGE} &>/dev/null); then
330        arm_list+=" ${GPP_ARM_PACKAGE}"
331      else
332        echo "The Debian Cross-toolchains repository is necessary to"
333        echo "cross-compile Chromium for arm."
334        echo -n "Do you want me to add it for you (y/N) "
335        if yes_no 1; then
336          gpg --keyserver pgp.mit.edu --recv-keys ${EM_ARCHIVE_KEY_FINGER}
337          gpg -a --export ${EM_ARCHIVE_KEY_FINGER} | sudo apt-key add -
338          if ! grep "^${EM_REPO}" "${CROSSTOOLS_LIST}" &>/dev/null; then
339            echo "${EM_SOURCE}" | sudo tee -a "${CROSSTOOLS_LIST}" >/dev/null
340          fi
341          arm_list+=" ${GPP_ARM_PACKAGE}"
342        fi
343      fi
344    fi
345    ;;
346  # All necessary ARM packages are available on the default repos on
347  # Debian 9 and later.
348  *)
349    arm_list="binutils-aarch64-linux-gnu
350              libc6-dev-armhf-cross
351              linux-libc-dev-armhf-cross
352              ${GPP_ARM_PACKAGE}"
353    ;;
354esac
355
356# Work around for dependency issue Ubuntu/Trusty: http://crbug.com/435056
357case $distro_codename in
358  trusty)
359    arm_list+=" g++-4.8-multilib-arm-linux-gnueabihf
360                gcc-4.8-multilib-arm-linux-gnueabihf"
361    ;;
362  xenial|yakkety)
363    arm_list+=" g++-5-multilib-arm-linux-gnueabihf
364                gcc-5-multilib-arm-linux-gnueabihf
365                gcc-arm-linux-gnueabihf"
366    ;;
367esac
368
369# Packages to build NaCl, its toolchains, and its ports.
370naclports_list="ant autoconf bison cmake gawk intltool xutils-dev xsltproc"
371nacl_list="\
372  g++-mingw-w64-i686
373  lib32z1-dev
374  libasound2:i386
375  libcap2:i386
376  libelf-dev:i386
377  libfontconfig1:i386
378  libgconf-2-4:i386
379  libglib2.0-0:i386
380  libgpm2:i386
381  libgtk2.0-0:i386
382  libgtk-3-0:i386
383  libncurses5:i386
384  lib32ncurses5-dev
385  libnss3:i386
386  libpango1.0-0:i386
387  libssl-dev:i386
388  libtinfo-dev
389  libtinfo-dev:i386
390  libtool
391  libxcomposite1:i386
392  libxcursor1:i386
393  libxdamage1:i386
394  libxi6:i386
395  libxrandr2:i386
396  libxss1:i386
397  libxtst6:i386
398  texinfo
399  xvfb
400  ${naclports_list}
401"
402
403if package_exists libssl1.0.0; then
404  nacl_list="${nacl_list} libssl1.0.0:i386"
405else
406  nacl_list="${nacl_list} libssl1.0.2:i386"
407fi
408
409# Find the proper version of packages that depend on mesa. Only one -lts variant
410# of mesa can be installed and everything that depends on it must match.
411
412# Query for the name and status of all mesa LTS variants, filter for only
413# installed packages, extract just the name, and eliminate duplicates (there can
414# be more than one with the same name in the case of multiarch). Expand into an
415# array.
416mesa_packages=($(dpkg-query -Wf'${package} ${status}\n' \
417                            libgl1-mesa-glx-lts-\* 2>/dev/null | \
418                 grep " ok installed" | cut -d " " -f 1 | sort -u))
419if [ "${#mesa_packages[@]}" -eq 0 ]; then
420  mesa_variant=""
421elif [ "${#mesa_packages[@]}" -eq 1 ]; then
422  # Strip the base package name and leave just "-lts-whatever"
423  mesa_variant="${mesa_packages[0]#libgl1-mesa-glx}"
424else
425  echo "ERROR: unable to determine which libgl1-mesa-glx variant is installed."
426  exit 1
427fi
428dev_list="${dev_list} libgbm-dev${mesa_variant}
429          libgles2-mesa-dev${mesa_variant} libgl1-mesa-dev${mesa_variant}
430          mesa-common-dev${mesa_variant}"
431nacl_list="${nacl_list} libgl1-mesa-glx${mesa_variant}:i386"
432
433# Some package names have changed over time
434if package_exists libpng12-0; then
435  lib_list="${lib_list} libpng12-0"
436else
437  lib_list="${lib_list} libpng16-16"
438fi
439if package_exists libnspr4-dbg; then
440  dbg_list="${dbg_list} libnspr4-dbg libnss3-dbg"
441  lib_list="${lib_list} libnspr4 libnss3"
442else
443  dbg_list="${dbg_list} libnspr4-0d-dbg libnss3-1d-dbg"
444  lib_list="${lib_list} libnspr4-0d libnss3-1d"
445fi
446if package_exists libjpeg-dev; then
447  dev_list="${dev_list} libjpeg-dev"
448else
449  dev_list="${dev_list} libjpeg62-dev"
450fi
451if package_exists libudev1; then
452  dev_list="${dev_list} libudev1"
453  nacl_list="${nacl_list} libudev1:i386"
454else
455  dev_list="${dev_list} libudev0"
456  nacl_list="${nacl_list} libudev0:i386"
457fi
458if package_exists libbrlapi0.6; then
459  dev_list="${dev_list} libbrlapi0.6"
460else
461  dev_list="${dev_list} libbrlapi0.5"
462fi
463if package_exists apache2-bin; then
464  dev_list="${dev_list} apache2-bin"
465else
466  dev_list="${dev_list} apache2.2-bin"
467fi
468if package_exists xfonts-mathml; then
469  dev_list="${dev_list} xfonts-mathml"
470fi
471if package_exists fonts-indic; then
472  dev_list="${dev_list} fonts-indic"
473else
474  dev_list="${dev_list} ttf-indic-fonts"
475fi
476if package_exists php7.0-cgi; then
477  dev_list="${dev_list} php7.0-cgi libapache2-mod-php7.0"
478else
479  dev_list="${dev_list} php5-cgi libapache2-mod-php5"
480fi
481# ttf-mscorefonts-installer is in the Debian contrib repo, which has
482# dependencies on non-free software.  Install it only if the user has already
483# enabled contrib.
484if package_exists ttf-mscorefonts-installer; then
485  dev_list="${dev_list} ttf-mscorefonts-installer"
486elif package_exists msttcorefonts; then
487  dev_list="${dev_list} msttcorefonts"
488fi
489# Ubuntu 16.04 has this package deleted.
490if package_exists ttf-kochi-gothic; then
491  dev_list="${dev_list} ttf-kochi-gothic"
492fi
493# Ubuntu 16.04 has this package deleted.
494if package_exists ttf-kochi-mincho; then
495  dev_list="${dev_list} ttf-kochi-mincho"
496fi
497
498# Some packages are only needed if the distribution actually supports
499# installing them.
500if package_exists appmenu-gtk; then
501  lib_list="$lib_list appmenu-gtk"
502fi
503
504# When cross building for arm/Android on 64-bit systems the host binaries
505# that are part of v8 need to be compiled with -m32 which means
506# that basic multilib support is needed.
507if file -L /sbin/init | grep -q 'ELF 64-bit'; then
508  # gcc-multilib conflicts with the arm cross compiler (at least in trusty) but
509  # g++-X.Y-multilib gives us the 32-bit support that we need. Find out the
510  # appropriate value of X and Y by seeing what version the current
511  # distribution's g++-multilib package depends on.
512  multilib_package=$(apt-cache depends g++-multilib --important | \
513      grep -E --color=never --only-matching '\bg\+\+-[0-9.]+-multilib\b')
514  lib32_list="$lib32_list $multilib_package"
515fi
516
517if test "$do_inst_syms" = "" && test 0 -eq ${do_quick_check-0}
518then
519  echo "This script installs all tools and libraries needed to build Chromium."
520  echo ""
521  echo "For most of the libraries, it can also install debugging symbols, which"
522  echo "will allow you to debug code in the system libraries. Most developers"
523  echo "won't need these symbols."
524  echo -n "Do you want me to install them for you (y/N) "
525  if yes_no 1; then
526    do_inst_syms=1
527  fi
528fi
529if test "$do_inst_syms" = "1"; then
530  echo "Including debugging symbols."
531  # Many debug packages are not available in Debian stretch,
532  # so exclude the ones that are missing.
533  available_dbg_packages=""
534  for package in ${dbg_list}; do
535    if package_exists ${package}; then
536      available_dbg_packages="${available_dbg_packages} ${package}"
537    fi
538  done
539  dbg_list="${available_dbg_packages}"
540else
541  echo "Skipping debugging symbols."
542  dbg_list=
543fi
544
545if test "$do_inst_lib32" = "1" ; then
546  echo "Including 32-bit libraries for ARM/Android."
547else
548  echo "Skipping 32-bit libraries for ARM/Android."
549  lib32_list=
550fi
551
552if test "$do_inst_arm" = "1" ; then
553  echo "Including ARM cross toolchain."
554else
555  echo "Skipping ARM cross toolchain."
556  arm_list=
557fi
558
559if test "$do_inst_nacl" = "1"; then
560  echo "Including NaCl, NaCl toolchain, NaCl ports dependencies."
561else
562  echo "Skipping NaCl, NaCl toolchain, NaCl ports dependencies."
563  nacl_list=
564fi
565
566# The `sort -r -s -t: -k2` sorts all the :i386 packages to the front, to avoid
567# confusing dpkg-query (crbug.com/446172).
568packages="$(
569  echo "${dev_list} ${lib_list} ${dbg_list} ${lib32_list} ${arm_list}"\
570       "${nacl_list}" | tr " " "\n" | sort -u | sort -r -s -t: -k2 | tr "\n" " "
571)"
572
573if [ 1 -eq "${do_quick_check-0}" ] ; then
574  if ! missing_packages="$(dpkg-query -W -f ' ' ${packages} 2>&1)"; then
575    # Distinguish between packages that actually aren't available to the
576    # system (i.e. not in any repo) and packages that just aren't known to
577    # dpkg (i.e. managed by apt).
578    missing_packages="$(echo "${missing_packages}" | awk '{print $NF}')"
579    not_installed=""
580    unknown=""
581    for p in ${missing_packages}; do
582      if apt-cache show ${p} > /dev/null 2>&1; then
583        not_installed="${p}\n${not_installed}"
584      else
585        unknown="${p}\n${unknown}"
586      fi
587    done
588    if [ -n "${not_installed}" ]; then
589      echo "WARNING: The following packages are not installed:"
590      echo -e "${not_installed}" | sed -e "s/^/  /"
591    fi
592    if [ -n "${unknown}" ]; then
593      echo "WARNING: The following packages are unknown to your system"
594      echo "(maybe missing a repo or need to 'sudo apt-get update'):"
595      echo -e "${unknown}" | sed -e "s/^/  /"
596    fi
597    exit 1
598  fi
599  exit 0
600fi
601
602if test "$do_inst_lib32" = "1" || test "$do_inst_nacl" = "1"; then
603  sudo dpkg --add-architecture i386
604fi
605sudo apt-get update
606
607# We initially run "apt-get" with the --reinstall option and parse its output.
608# This way, we can find all the packages that need to be newly installed
609# without accidentally promoting any packages from "auto" to "manual".
610# We then re-run "apt-get" with just the list of missing packages.
611echo "Finding missing packages..."
612# Intentionally leaving $packages unquoted so it's more readable.
613echo "Packages required: " $packages
614echo
615new_list_cmd="sudo apt-get install --reinstall $(echo $packages)"
616if new_list="$(yes n | LANGUAGE=en LANG=C $new_list_cmd)"; then
617  # We probably never hit this following line.
618  echo "No missing packages, and the packages are up to date."
619elif [ $? -eq 1 ]; then
620  # We expect apt-get to have exit status of 1.
621  # This indicates that we cancelled the install with "yes n|".
622  new_list=$(echo "$new_list" |
623    sed -e '1,/The following NEW packages will be installed:/d;s/^  //;t;d')
624  new_list=$(echo "$new_list" | sed 's/ *$//')
625  if [ -z "$new_list" ] ; then
626    echo "No missing packages, and the packages are up to date."
627  else
628    echo "Installing missing packages: $new_list."
629    sudo apt-get install ${do_quietly-} ${new_list}
630  fi
631  echo
632else
633  # An apt-get exit status of 100 indicates that a real error has occurred.
634
635  # I am intentionally leaving out the '"'s around new_list_cmd,
636  # as this makes it easier to cut and paste the output
637  echo "The following command failed: " ${new_list_cmd}
638  echo
639  echo "It produces the following output:"
640  yes n | $new_list_cmd || true
641  echo
642  echo "You will have to install the above packages yourself."
643  echo
644  exit 100
645fi
646
647# Install the Chrome OS default fonts. This must go after running
648# apt-get, since install-chromeos-fonts depends on curl.
649if test "$do_inst_chromeos_fonts" != "0"; then
650  echo
651  echo "Installing Chrome OS fonts."
652  dir=`echo $0 | sed -r -e 's/\/[^/]+$//'`
653  if ! sudo $dir/linux/install-chromeos-fonts.py; then
654    echo "ERROR: The installation of the Chrome OS default fonts failed."
655    if [ `stat -f -c %T $dir` == "nfs" ]; then
656      echo "The reason is that your repo is installed on a remote file system."
657    else
658      echo "This is expected if your repo is installed on a remote file system."
659    fi
660    echo "It is recommended to install your repo on a local file system."
661    echo "You can skip the installation of the Chrome OS default founts with"
662    echo "the command line option: --no-chromeos-fonts."
663    exit 1
664  fi
665else
666  echo "Skipping installation of Chrome OS fonts."
667fi
668
669echo "Installing locales."
670CHROMIUM_LOCALES="da_DK.UTF-8 fr_FR.UTF-8 he_IL.UTF-8 zh_TW.UTF-8"
671LOCALE_GEN=/etc/locale.gen
672if [ -e ${LOCALE_GEN} ]; then
673  OLD_LOCALE_GEN="$(cat /etc/locale.gen)"
674  for CHROMIUM_LOCALE in ${CHROMIUM_LOCALES}; do
675    sudo sed -i "s/^# ${CHROMIUM_LOCALE}/${CHROMIUM_LOCALE}/" ${LOCALE_GEN}
676  done
677  # Regenerating locales can take a while, so only do it if we need to.
678  if (echo "${OLD_LOCALE_GEN}" | cmp -s ${LOCALE_GEN}); then
679    echo "Locales already up-to-date."
680  else
681    sudo locale-gen
682  fi
683else
684  for CHROMIUM_LOCALE in ${CHROMIUM_LOCALES}; do
685    sudo locale-gen ${CHROMIUM_LOCALE}
686  done
687fi
688