commit 625bdee0ec77fb5dd975a07f024d8b669db3b4a8 Author: Kar Date: Fri Sep 12 11:17:47 2025 +0000 init diff --git a/install-build-deps-arch.py b/install-build-deps-arch.py new file mode 100644 index 0000000..3797863 --- /dev/null +++ b/install-build-deps-arch.py @@ -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())