init
commit
625bdee0ec
|
@ -0,0 +1,522 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright 2023 The Chromium Authors
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
# Script to install everything needed to build chromium on Arch Linux
|
||||
# including items requiring sudo privileges.
|
||||
|
||||
import argparse
|
||||
import functools
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
logging.basicConfig(stream=sys.stderr,
|
||||
level=logging.INFO,
|
||||
format='%(name)s [%(levelname)s]: %(message)s')
|
||||
logger = logging.getLogger(os.path.basename(sys.argv[0]))
|
||||
|
||||
|
||||
@functools.lru_cache(maxsize=1)
|
||||
def build_pacman_package_list():
|
||||
logger.info("Building pacman package list.")
|
||||
output = subprocess.check_output(["pacman", "-Q"]).decode()
|
||||
return set(line.split()[0] for line in output.strip().splitlines())
|
||||
|
||||
|
||||
def package_exists_in_repos(package_name: str) -> bool:
|
||||
"""Check if package exists in repositories"""
|
||||
result = subprocess.run(["pacman", "-Si", package_name],
|
||||
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
return result.returncode == 0
|
||||
|
||||
|
||||
def package_exists(package_name: str) -> bool:
|
||||
# Check if package is installed
|
||||
if package_name in build_pacman_package_list():
|
||||
return True
|
||||
# Check if package exists in repos
|
||||
return package_exists_in_repos(package_name)
|
||||
|
||||
|
||||
def parse_args(argv):
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Install Chromium build dependencies on Arch Linux.")
|
||||
parser.add_argument("--syms",
|
||||
action="store_true",
|
||||
help="Enable installation of debugging symbols")
|
||||
parser.add_argument(
|
||||
"--no-syms",
|
||||
action="store_false",
|
||||
dest="syms",
|
||||
help="Disable installation of debugging symbols",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--lib32",
|
||||
action="store_true",
|
||||
help="Enable installation of 32-bit libraries, e.g. for V8 snapshot",
|
||||
)
|
||||
parser.add_argument("--arm",
|
||||
action="store_true",
|
||||
help="Enable installation of arm cross toolchain")
|
||||
parser.add_argument(
|
||||
"--no-arm",
|
||||
action="store_false",
|
||||
dest="arm",
|
||||
help="Disable installation of arm cross toolchain",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--chromeos-fonts",
|
||||
action="store_true",
|
||||
help="Enable installation of Chrome OS fonts",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--no-chromeos-fonts",
|
||||
action="store_false",
|
||||
dest="chromeos_fonts",
|
||||
help="Disable installation of Chrome OS fonts",
|
||||
)
|
||||
parser.add_argument("--no-prompt",
|
||||
action="store_true",
|
||||
help="Automatic yes to prompts")
|
||||
parser.add_argument(
|
||||
"--quick-check",
|
||||
action="store_true",
|
||||
help="Quickly try to determine if dependencies are installed",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--aur-helper",
|
||||
default="yay",
|
||||
help="AUR helper to use (default: yay)",
|
||||
)
|
||||
|
||||
options = parser.parse_args(argv)
|
||||
|
||||
if options.arm:
|
||||
options.lib32 = True
|
||||
|
||||
return options
|
||||
|
||||
|
||||
def check_arch_linux():
|
||||
try:
|
||||
with open("/etc/os-release") as f:
|
||||
content = f.read()
|
||||
if "ID=arch" not in content and "ID_LIKE=arch" not in content:
|
||||
logger.error("This script is designed for Arch Linux and derivatives")
|
||||
sys.exit(1)
|
||||
except FileNotFoundError:
|
||||
logger.error("Cannot determine OS. This script is for Arch Linux.")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def check_architecture():
|
||||
architecture = subprocess.check_output(["uname", "-m"]).decode().strip()
|
||||
if architecture not in ["i686", "x86_64", 'aarch64']:
|
||||
logger.error("Only x86 and ARM64 architectures are currently supported")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def check_root():
|
||||
if os.geteuid() != 0:
|
||||
logger.info("Running as non-root user.")
|
||||
logger.info(
|
||||
"You might have to enter your password one or more times for 'sudo'.\n")
|
||||
|
||||
|
||||
def check_aur_helper(options):
|
||||
if not shutil.which(options.aur_helper):
|
||||
logger.error(f"AUR helper '{options.aur_helper}' not found.")
|
||||
logger.error("Please install an AUR helper like 'yay' or 'paru'.")
|
||||
logger.error("You can install yay with:")
|
||||
logger.error(" git clone https://aur.archlinux.org/yay.git")
|
||||
logger.error(" cd yay && makepkg -si")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def pacman_update(options):
|
||||
if options.lib32:
|
||||
# Enable multilib repository
|
||||
logger.info("Checking multilib repository...")
|
||||
with open("/etc/pacman.conf", "r") as f:
|
||||
config = f.read()
|
||||
|
||||
if "[multilib]" not in config or config.find("[multilib]") > config.find("#[multilib]"):
|
||||
logger.info("Enabling multilib repository...")
|
||||
subprocess.check_call([
|
||||
"sudo", "sed", "-i",
|
||||
"/^#\\[multilib\\]/,/^#Include = \\/etc\\/pacman.d\\/mirrorlist/ s/^#//",
|
||||
"/etc/pacman.conf"
|
||||
])
|
||||
|
||||
subprocess.check_call(["sudo", "pacman", "-Sy"])
|
||||
|
||||
|
||||
# Core packages needed for Chromium development - verified Arch package names only
|
||||
def get_core_packages():
|
||||
"""Return core packages that definitely exist in Arch repos"""
|
||||
return [
|
||||
# Build essentials
|
||||
"base-devel",
|
||||
"git",
|
||||
"python",
|
||||
"curl",
|
||||
"wget",
|
||||
"unzip",
|
||||
"zip",
|
||||
"p7zip",
|
||||
"bzip2",
|
||||
"xz",
|
||||
"patch",
|
||||
"perl",
|
||||
"ruby",
|
||||
"nodejs",
|
||||
"npm",
|
||||
"bison",
|
||||
"flex",
|
||||
"gperf",
|
||||
"pkgconf",
|
||||
"nasm",
|
||||
"yasm",
|
||||
|
||||
# Core libraries
|
||||
"alsa-lib",
|
||||
"at-spi2-core",
|
||||
"cairo",
|
||||
"cups",
|
||||
"dbus",
|
||||
"expat",
|
||||
"fontconfig",
|
||||
"freetype2",
|
||||
"glib2",
|
||||
"gtk3",
|
||||
"krb5",
|
||||
"libcap",
|
||||
"libdrm",
|
||||
"libelf",
|
||||
"libevdev",
|
||||
"libffi",
|
||||
"mesa",
|
||||
"libglvnd",
|
||||
"libice",
|
||||
"libinput",
|
||||
"libjpeg-turbo",
|
||||
"libpng",
|
||||
"libpulse",
|
||||
"libsm",
|
||||
"libx11",
|
||||
"libxau",
|
||||
"libxcb",
|
||||
"libxcomposite",
|
||||
"libxcursor",
|
||||
"libxdamage",
|
||||
"libxdmcp",
|
||||
"libxext",
|
||||
"libxfixes",
|
||||
"libxi",
|
||||
"libxinerama",
|
||||
"libxrandr",
|
||||
"libxrender",
|
||||
"libxshmfence",
|
||||
"libxt",
|
||||
"libxtst",
|
||||
"nspr",
|
||||
"nss",
|
||||
"pam",
|
||||
"pango",
|
||||
"sqlite",
|
||||
"systemd-libs",
|
||||
"util-linux",
|
||||
"vulkan-headers",
|
||||
"vulkan-icd-loader",
|
||||
"wayland",
|
||||
"xorg-server",
|
||||
"xorg-server-xvfb",
|
||||
"zlib",
|
||||
]
|
||||
|
||||
|
||||
def get_optional_packages():
|
||||
"""Return optional packages - only add if they exist"""
|
||||
candidates = [
|
||||
"bluez-libs",
|
||||
"speech-dispatcher",
|
||||
"libxss", # X11 screensaver
|
||||
"pciutils", # PCI utilities
|
||||
"xcompmgr", # Composite manager
|
||||
"fd", # Find alternative
|
||||
"ripgrep", # Fast grep
|
||||
"lighttpd", # Web server
|
||||
"openbox", # Window manager
|
||||
]
|
||||
|
||||
packages = []
|
||||
for pkg in candidates:
|
||||
if package_exists_in_repos(pkg):
|
||||
packages.append(pkg)
|
||||
else:
|
||||
logger.debug(f"Optional package '{pkg}' not found, skipping.")
|
||||
|
||||
return packages
|
||||
|
||||
|
||||
def dev_list():
|
||||
"""Get development packages"""
|
||||
packages = get_core_packages() + get_optional_packages()
|
||||
return packages
|
||||
|
||||
|
||||
def lib_list():
|
||||
"""Get runtime library packages"""
|
||||
packages = [
|
||||
"atk",
|
||||
"at-spi2-atk",
|
||||
"cairo",
|
||||
"cups",
|
||||
"dbus",
|
||||
"expat",
|
||||
"fontconfig",
|
||||
"freetype2",
|
||||
"glib2",
|
||||
"gtk3",
|
||||
"libdrm",
|
||||
"libglvnd",
|
||||
"libpulse",
|
||||
"libx11",
|
||||
"libxcb",
|
||||
"libxcomposite",
|
||||
"libxcursor",
|
||||
"libxdamage",
|
||||
"libxext",
|
||||
"libxfixes",
|
||||
"libxi",
|
||||
"libxinerama",
|
||||
"libxrandr",
|
||||
"libxrender",
|
||||
"libxtst",
|
||||
"mesa",
|
||||
"pango",
|
||||
"wayland",
|
||||
"zlib",
|
||||
]
|
||||
return packages
|
||||
|
||||
|
||||
def lib32_list(options):
|
||||
if not options.lib32:
|
||||
logger.info("Skipping 32-bit libraries.")
|
||||
return []
|
||||
logger.info("Including 32-bit libraries.")
|
||||
|
||||
packages = [
|
||||
"lib32-alsa-lib",
|
||||
"lib32-atk",
|
||||
"lib32-cairo",
|
||||
"lib32-dbus",
|
||||
"lib32-expat",
|
||||
"lib32-fontconfig",
|
||||
"lib32-freetype2",
|
||||
"lib32-gcc-libs",
|
||||
"lib32-glib2",
|
||||
"lib32-glibc",
|
||||
"lib32-gtk3",
|
||||
"lib32-libdrm",
|
||||
"lib32-libglvnd",
|
||||
"lib32-libx11",
|
||||
"lib32-libxcb",
|
||||
"lib32-libxcomposite",
|
||||
"lib32-libxcursor",
|
||||
"lib32-libxdamage",
|
||||
"lib32-libxext",
|
||||
"lib32-libxfixes",
|
||||
"lib32-libxi",
|
||||
"lib32-libxinerama",
|
||||
"lib32-libxrandr",
|
||||
"lib32-libxrender",
|
||||
"lib32-libxtst",
|
||||
"lib32-mesa",
|
||||
"lib32-nspr",
|
||||
"lib32-nss",
|
||||
"lib32-pango",
|
||||
"lib32-zlib",
|
||||
]
|
||||
|
||||
return packages
|
||||
|
||||
|
||||
def arm_list(options):
|
||||
if not options.arm:
|
||||
logger.info("Skipping ARM cross toolchain.")
|
||||
return []
|
||||
logger.info("Including ARM cross toolchain.")
|
||||
|
||||
# ARM cross toolchain packages (these are AUR packages)
|
||||
packages = [
|
||||
"arm-linux-gnueabihf-gcc",
|
||||
"arm-linux-gnueabihf-glibc",
|
||||
"arm-linux-gnueabihf-binutils",
|
||||
"arm-linux-gnueabihf-linux-api-headers",
|
||||
]
|
||||
|
||||
return packages
|
||||
|
||||
|
||||
def dbg_list(options):
|
||||
if not options.syms:
|
||||
logger.info("Skipping debugging symbols.")
|
||||
return []
|
||||
logger.info("Including debugging symbols.")
|
||||
|
||||
# Arch doesn't have separate debug packages like Debian/Ubuntu
|
||||
logger.info("Note: Debug symbols in Arch are typically included in packages")
|
||||
logger.info("or available through debug repositories. No additional packages needed.")
|
||||
|
||||
return []
|
||||
|
||||
|
||||
def package_list(options):
|
||||
packages = (dev_list() + lib_list() + dbg_list(options) +
|
||||
lib32_list(options))
|
||||
|
||||
# ARM packages are from AUR, handle separately
|
||||
arm_packages = arm_list(options) if options.arm else []
|
||||
|
||||
return list(set(packages)), arm_packages
|
||||
|
||||
|
||||
def missing_packages(packages):
|
||||
installed = build_pacman_package_list()
|
||||
missing = []
|
||||
for pkg in packages:
|
||||
if pkg not in installed:
|
||||
# Double-check that the package actually exists in repos
|
||||
if package_exists_in_repos(pkg):
|
||||
missing.append(pkg)
|
||||
else:
|
||||
logger.warning(f"Package '{pkg}' does not exist in repositories, skipping.")
|
||||
return missing
|
||||
|
||||
|
||||
def quick_check(options):
|
||||
if not options.quick_check:
|
||||
return
|
||||
|
||||
regular_packages, aur_packages = package_list(options)
|
||||
missing_regular = missing_packages(regular_packages)
|
||||
missing_aur = missing_packages(aur_packages)
|
||||
|
||||
if not missing_regular and not missing_aur:
|
||||
sys.exit(0)
|
||||
|
||||
if missing_regular:
|
||||
logger.warning("The following official packages are not installed:")
|
||||
logger.warning(" ".join(missing_regular))
|
||||
|
||||
if missing_aur:
|
||||
logger.warning("The following AUR packages are not installed:")
|
||||
logger.warning(" ".join(missing_aur))
|
||||
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def install_packages(options):
|
||||
regular_packages, aur_packages = package_list(options)
|
||||
|
||||
# Install regular packages with pacman
|
||||
missing_regular = missing_packages(regular_packages)
|
||||
if missing_regular:
|
||||
logger.info(f"Installing {len(missing_regular)} regular packages...")
|
||||
cmd = ["sudo", "pacman", "-S", "--needed"]
|
||||
if options.no_prompt:
|
||||
cmd.append("--noconfirm")
|
||||
subprocess.check_call(cmd + missing_regular)
|
||||
else:
|
||||
logger.info("All regular packages are already installed.")
|
||||
|
||||
# Install AUR packages
|
||||
missing_aur = missing_packages(aur_packages)
|
||||
if missing_aur:
|
||||
logger.info(f"Installing {len(missing_aur)} AUR packages...")
|
||||
cmd = [options.aur_helper, "-S", "--needed"]
|
||||
if options.no_prompt:
|
||||
cmd.append("--noconfirm")
|
||||
subprocess.check_call(cmd + missing_aur)
|
||||
else:
|
||||
if aur_packages:
|
||||
logger.info("All AUR packages are already installed.")
|
||||
|
||||
|
||||
def install_chromeos_fonts(options):
|
||||
if not options.chromeos_fonts:
|
||||
logger.info("Skipping installation of Chrome OS fonts.")
|
||||
return
|
||||
|
||||
logger.info("Installing Chrome OS fonts.")
|
||||
|
||||
# Check if we have the font installation script
|
||||
script_dir = os.path.abspath(os.path.dirname(__file__))
|
||||
font_script = os.path.join(script_dir, "linux", "install-chromeos-fonts.py")
|
||||
|
||||
if os.path.exists(font_script):
|
||||
try:
|
||||
subprocess.check_call(["sudo", font_script])
|
||||
except subprocess.CalledProcessError:
|
||||
logger.error("The installation of the Chrome OS default fonts failed.")
|
||||
logger.info("You can skip this with --no-chromeos-fonts.")
|
||||
else:
|
||||
logger.warning("Chrome OS font installation script not found.")
|
||||
logger.info("This is normal if you're not building from the full Chromium source tree.")
|
||||
|
||||
|
||||
def install_locales():
|
||||
logger.info("Installing locales.")
|
||||
|
||||
# Arch Linux locale setup is different from Debian/Ubuntu
|
||||
CHROMIUM_LOCALES = [
|
||||
"da_DK.UTF-8", "en_US.UTF-8", "fr_FR.UTF-8", "he_IL.UTF-8", "zh_TW.UTF-8"
|
||||
]
|
||||
|
||||
LOCALE_GEN = "/etc/locale.gen"
|
||||
if os.path.exists(LOCALE_GEN):
|
||||
with open(LOCALE_GEN, 'r') as f:
|
||||
current_config = f.read()
|
||||
|
||||
needs_update = False
|
||||
for locale in CHROMIUM_LOCALES:
|
||||
if f"#{locale}" in current_config and f"\n{locale}" not in current_config:
|
||||
subprocess.check_call([
|
||||
"sudo", "sed", "-i",
|
||||
f"s/^#{locale}/{locale}/",
|
||||
LOCALE_GEN
|
||||
])
|
||||
needs_update = True
|
||||
|
||||
if needs_update:
|
||||
subprocess.check_call(["sudo", "locale-gen"])
|
||||
else:
|
||||
logger.info("Locales already up-to-date.")
|
||||
else:
|
||||
logger.warning("locale.gen not found. Locales may need manual configuration.")
|
||||
|
||||
|
||||
def main():
|
||||
options = parse_args(sys.argv[1:])
|
||||
check_arch_linux()
|
||||
check_architecture()
|
||||
quick_check(options)
|
||||
check_root()
|
||||
check_aur_helper(options)
|
||||
pacman_update(options)
|
||||
install_packages(options)
|
||||
install_chromeos_fonts(options)
|
||||
install_locales()
|
||||
logger.info("Chromium build dependencies installation complete!")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
Loading…
Reference in New Issue