| #!/usr/bin/env python |
| # |
| # Copyright 2023 - The Android Open Source Project |
| # |
| # Licensed under the Apache License, Version 2.0 (the', help='License'); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an', help='AS IS' BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| import atexit |
| import glob |
| import logging |
| import os |
| import re |
| import shutil |
| import subprocess |
| import sys |
| from aemu.prebuilts.deps.common import EXE_SUFFIX |
| import aemu.prebuilts.deps.common as deps_common |
| import aemu.prebuilts.deps.mac as deps_mac |
| import aemu.prebuilts.deps.linux as deps_linux |
| import aemu.prebuilts.deps.windows as deps_win |
| from pathlib import Path |
| import platform |
| |
| AOSP_ROOT = Path(__file__).resolve().parents[7] |
| HOST_OS = platform.system().lower() |
| |
| QT_VERSION = "6.5.3" |
| QT_SUBMODULES = [ |
| "qtbase", |
| "qtdeclarative", |
| "qtpositioning", |
| "qtsvg", |
| "qtimageformats", |
| "qtwebchannel", |
| "qtwebsockets", |
| "qtwebengine" |
| ] |
| QT_NOWEBENGINE_SUBMODULES = [ |
| "qtbase", |
| "qtsvg", |
| "qtimageformats", |
| ] |
| AOSP_QT_SRC_PATH = os.path.join(AOSP_ROOT, "external", "qt5") |
| CMAKE_PATH = os.path.join(AOSP_ROOT, "prebuilts", "cmake", HOST_OS + "-x86", "bin") |
| NINJA_PATH = os.path.join(AOSP_ROOT, "prebuilts", "ninja", HOST_OS + "-x86") |
| |
| # We must move the source code from external/qt5 to a shorter path because of path too long issue. |
| # Symlinking to a shorter path will not work either. |
| WIN_QT_TMP_LOCATION = os.path.join("C:\\", "qttmp") |
| WIN_QT_SRC_SHORT_PATH = os.path.join(WIN_QT_TMP_LOCATION, "src") |
| WIN_QT_BUILD_PATH = os.path.join(WIN_QT_TMP_LOCATION, "bld") |
| |
| def addToSearchPath(searchDir): |
| os.environ["PATH"] = searchDir + os.pathsep + os.environ["PATH"] |
| |
| def checkDependencies(): |
| # Dependencies for Qt 6 w/ QtWebEngine listed in https://wiki.qt.io/Building_Qt_6_from_Git |
| logging.info("Checking for required build dependencies..") |
| # - Python >= 3.6.x |
| logging.info(">> Checking for Python >= 3.6.x (%s)", sys.version) |
| deps_common.checkPythonVersion(min_vers=(3, 6)) |
| |
| # Need perl to run qt5/init-repository |
| logging.info(">> Checking for perl") |
| deps_common.checkPerlVersion() |
| |
| # CMake >= 3.19 for Qt with QtWebEngine |
| logging.info(">> Checking CMake >= 3.19") |
| deps_common.checkCmakeVersion(min_vers=(3, 19)) |
| |
| # Ninja >= 1.7.2 for Qt with QtWebEngine |
| logging.info(">> Checking Ninja >= 1.7.2") |
| deps_common.checkNinjaVersion(min_vers=(1, 7, 2)) |
| |
| # Need node.js version 12 or later for QtWebEngine |
| logging.info(">> Checking for node.js version >= 12") |
| deps_common.checkNodeJsVersion(min_vers=(12, 0)) |
| |
| # QtWebEngine needs python html5lib package |
| logging.info(">> Checking for python package html5lib") |
| deps_common.checkPythonPackage("html5lib") |
| |
| # QtWebEngine requires GNUWin32 dependencies gperf, bison, flex |
| # TODO(joshuaduong): Locally I installed bison from https://gnuwin32.sourceforge.net/packages.html, but maybe we use chocolatey on the buildbot. |
| logging.info(">> Checking for gperf") |
| deps_common.checkGperfVersion() |
| logging.info(">> Checking for bison") |
| deps_common.checkBisonVersion() |
| logging.info(">> Checking for flex") |
| deps_common.checkFlexVersion() |
| |
| if HOST_OS == "windows": |
| # - Visual Studio 2019 v16.11+ |
| logging.info(">> Checking for Visual Studio 2019 v16.11+") |
| deps_win.checkVSVersion(min_vers=(16, 11)) |
| # Windows 10 SDK >= 10.0.20348.0 (documentation says >= 10.0.19041, but configure complains |
| # that it must be >= 10.0.20348.0). |
| logging.info(">> Checking for Windows 10 SDK >= 10.0.20348.0") |
| deps_win.checkWindowsSdk(min_vers=(10, 0, 20348, 0)) |
| elif HOST_OS == "darwin": |
| # MacOS sdk >= 13 |
| deps_mac.checkMacOsSDKVersion(min_vers=(12, 0)) |
| elif HOST_OS == "linux": |
| pkgconfig_libs = [ |
| ("xrender", [0, 9, 0]), |
| ("xcb-render", [1, 11]), |
| ("xcb-renderutil", [0, 3, 9]), |
| ("xcb-shape", [1, 11]), |
| ("xcb-randr", [1, 11]), |
| ("xcb-xfixes", [1, 11]), |
| ("xcb-xkb", [1, 11]), |
| ("xcb-sync", [1, 11]), |
| ("xcb-shm", [1, 11]), |
| ("xcb-icccm", [0, 3, 9]), |
| ("xcb-keysyms", [0, 3, 9]), |
| ("xcb-image", [0, 3, 9]), |
| ("xcb-util", [0, 3, 9]), |
| ("xcb-cursor", [0, 1, 1]), |
| ("xkbcommon", [0, 5, 0]), |
| ("xkbcommon-x11", [0, 5, 0]), |
| ("fontconfig", [2, 6]), |
| ("freetype2", [2, 3, 0]), |
| ("xext", None), |
| ("x11", None), |
| ("xcb", [1, 11]), |
| ("x11-xcb", [1, 3, 2]), |
| ("sm", None), |
| ("ice", None), |
| ("dbus-1", None), |
| ("xcomposite", None), |
| ("xcursor", None), |
| ("xrandr", None), |
| ("xshmfence", None), |
| ("libcupsfilters", None), |
| ] |
| for libname, vers in pkgconfig_libs: |
| if vers: |
| logging.info("Checking pkg-config for (%s >= %s)", libname, '.'.join(map(str, vers))) |
| else: |
| logging.info("Checking pkg-config for %s", libname) |
| deps_linux.checkPkgConfigLibraryExists(libname, vers) |
| # patchelf required to modify rpaths during installation |
| if not deps_common.checkExeIsOnPath("patchelf"): |
| return False |
| return True |
| |
| def flattenQtRepo(srcdir): |
| """Checks out the given git submodules in the Qt repository. |
| |
| The Qt git repository is using git submodules, and relies on a script, `init-repository` to check out |
| the git submodules. |
| |
| Args: |
| srcdir (StrOrBytesPath): Path to the Qt source code. |
| """ |
| perl_exe = "perl" + EXE_SUFFIX |
| logging.info(">> CMD: %s init-repostory", perl_exe) |
| try: |
| # We need to set this git config so init-repository pulls down the git submodules correctly. |
| # We might need to mirror these submodules as well. |
| subprocess.run(args=["git", "config", "remote.origin.url", "https://github.com/qt/"], |
| cwd=srcdir, env=os.environ.copy()) |
| res = subprocess.run(args=[perl_exe, "init-repository", "-f"], cwd=srcdir, env=os.environ.copy()) |
| if res.returncode != 0: |
| logging.critical("init-repository exited with non-zero code (%s)", res.returncode) |
| exit(res.returncode) |
| logging.debug(">> CMD: %s init-repostory succeeded", perl_exe) |
| finally: |
| subprocess.run(args=["git", "config", "--unset", "remote.origin.url"], |
| cwd=srcdir, env=os.environ.copy()) |
| |
| def configureQtBuild(srcdir, builddir, installdir, qtsubmodules, crosscompile_target=None, |
| qt_host_path=None): |
| """Runs the configure.bat script for Qt. |
| |
| Args: |
| srcdir (str): The location of the Qt source code. |
| builddir (str): The location of the Qt build directory. Must be outside of the `srcdir`. |
| This directory will be created in this function. |
| installdir (str): The location of the Qt installation directory. Must be outside of the `srcdir`. |
| This directory will be created in this function. |
| qtsubmodules (list(str)): The list of Qt submodules to build. |
| crosscompile_target (str): The target to cross-compile to. Defaults to None. This currently |
| only works for targeting linux_aarch64 target on linux_x86_64 host. |
| qt_host_path (str): The path to where Qt was installed on the host machine. This parameter |
| is only used in cross compilation builds. |
| """ |
| if os.path.exists(builddir): |
| shutil.rmtree(builddir) |
| old_umask = os.umask(0o027) |
| os.makedirs(builddir) |
| os.umask(old_umask) |
| |
| config_script = os.path.join(srcdir, |
| ("configure.bat" if HOST_OS == "windows" else "configure")) |
| conf_args = [config_script, |
| "-opensource", |
| "-confirm-license", |
| "-release", |
| "-force-debug-info", |
| "-shared", |
| "-no-rpath", |
| "-submodules", |
| ",".join(qtsubmodules), |
| "-nomake", "examples", |
| "-nomake", "tests", |
| "-nomake", "tools", |
| "-skip", "qtdoc", |
| "-skip", "qttranslations", |
| "-skip", "qttools", |
| "-no-feature-pdf", |
| "-no-feature-printdialog", |
| "-no-feature-printsupport", |
| "-no-feature-printer", |
| "-no-feature-printpreviewdialog", |
| "-no-feature-printpreviewwidget", |
| "-no-feature-webengine-pepper-plugins", |
| "-no-feature-webengine-printing-and-pdf", |
| "-no-feature-webengine-webrtc", |
| "-no-feature-webengine-spellchecker", |
| "-no-feature-cups", |
| "-no-strip", |
| "-no-framework", |
| "-qtlibinfix", "AndroidEmu", |
| "-prefix", installdir] |
| |
| if HOST_OS != "windows": |
| # qtwebengine build fails without opengl. |
| conf_args += ["-no-opengl"] |
| |
| if HOST_OS == "windows": |
| conf_args += ["-platform", "win32-msvc"] |
| elif HOST_OS == "linux": |
| if crosscompile_target == "linux_aarch64": |
| # Cross-compiling requires a host installation of Qt, so we must build Qt for |
| # linux-x86_64 prior to cross-compiling to linux_aarch64. |
| if not qt_host_path: |
| logging.fatal(f"No Qt host path was provided for {crosscompile_target} cross-compilation.") |
| conf_args += ["-platform", "linux-aarch64-gnu-g++", |
| "-device-option", "CROSS_COMPILE=aarch64-linux-gnu-", |
| "-no-glib", "-qt-host-path", qt_host_path, "-qt-pcre", "-qt-zlib", |
| "-qt-doubleconversion", "-qt-freetype", "-qt-harfbuzz", |
| "-no-feature-gssapi", "-no-feature-brotli", "-no-xcb", "-no-xkbcommon", |
| "-qt-webp", "-no-libudev", "-no-mtdev", "-no-linuxfb"] |
| os.environ["CC"] = "aarch64-linux-gnu-gcc" |
| os.environ["CXX"] = "aarch64-linux-gnu-g++" |
| extra_cflags = "-march=armv8-a" |
| extra_cxxflags = "-march=armv8-a" |
| os.environ["CFLAGS"] = extra_cflags |
| os.environ["CXXFLAGS"] = extra_cxxflags |
| conf_args += ["--", "-DCMAKE_SYSTEM_NAME=Linux", "-DCMAKE_SYSTEM_PROCESSOR=arm", |
| f"-DQT_HOST_PATH={qt_host_path}", "-DCMAKE_LINKER_FLAGS=-Wl,--as-needed"] |
| else: |
| conf_args += ["-linker", "lld", |
| "-platform", "linux-clang-libc++", |
| "-no-glib"] |
| |
| os.environ["CC"] = "clang" |
| os.environ["CXX"] = "clang++" |
| extra_cflags = "-m64 -fuse-ld=lld -fPIC" |
| extra_cxxflags = "-stdlib=libc++ -m64 -fuse-ld=lld -fPIC" |
| # Use libc++ instead of libstdc++ |
| conf_cmake_args = [ f"-DCMAKE_CXX_FLAGS={extra_cxxflags}", f"-DMAKE_C_FLAGS={extra_cflags}" ] |
| conf_args.append("--") |
| conf_args += conf_cmake_args |
| |
| # The QtWebEngine chromium build doesn't seem to pick up CXXFLAGS |
| # envrionment variables. So let's just create some clang wrappers |
| # to force use our flags. |
| os.environ["CFLAGS"] = extra_cflags |
| os.environ["CXXFLAGS"] = extra_cxxflags |
| toolchain_dir = Path(builddir) / "toolchain" |
| os.makedirs(Path(builddir) / "toolchain") |
| |
| clang_dir = deps_common.getClangDirectory() |
| with open(toolchain_dir / "clang", 'x') as f: |
| f.write(f"#!/bin/sh\n{clang_dir}/bin/clang {extra_cflags} $@") |
| os.chmod(toolchain_dir / "clang", 0o777) |
| |
| with open(toolchain_dir / "clang++", 'x') as f: |
| f.write(f"#!/bin/sh\n{clang_dir}/bin/clang++ {extra_cxxflags} $@") |
| os.chmod(toolchain_dir / "clang++", 0o777) |
| |
| with open(toolchain_dir / "ar", 'x') as f: |
| f.write(f"#!/bin/sh\n{clang_dir}/bin/llvm-ar $@") |
| os.chmod(toolchain_dir / "ar", 0o777) |
| |
| with open(toolchain_dir / "lld", 'x') as f: |
| f.write(f"#!/bin/sh\n{clang_dir}/bin/lld $@") |
| os.chmod(toolchain_dir / "lld", 0o777) |
| |
| # Add path to libc++.so.1 as some binaries (syncqt) that require it are ran during the |
| # configure step. |
| os.environ["LD_LIBRARY_PATH"] = str(deps_common.getClangDirectory() / "lib") |
| |
| addToSearchPath(str(toolchain_dir)) |
| |
| logging.info("[%s] Running %s", builddir, config_script) |
| logging.info(conf_args) |
| res = subprocess.run(args=conf_args, cwd=builddir, env=os.environ.copy()) |
| if res.returncode != 0: |
| logging.critical("%s exited with non-zero code (%s)", config_script, res.returncode) |
| exit(res.returncode) |
| logging.info("%s succeeded", config_script) |
| |
| |
| def buildQt(submodules, builddir): |
| """Builds the specified Qt submodules. |
| |
| Args: |
| submodules (tuple(str)): The Qt submodules to build. |
| builddir (str): The location of the Qt build directory. |
| """ |
| cmake_build_cmd = ["cmake" + EXE_SUFFIX, "--build", "."] |
| logging.info(cmake_build_cmd) |
| res = subprocess.run(args=cmake_build_cmd, cwd=builddir, env=os.environ.copy()) |
| if res.returncode != 0: |
| logging.critical("[%s] failed (%s)", cmake_build_cmd, res.returncode) |
| exit(res.returncode) |
| logging.info("Build succeeded") |
| |
| def installQt(submodules, builddir, installdir): |
| """Installs the specified Qt submodules to `installdir`. |
| |
| Args: |
| submodules (tuple(str)): The Qt submodules to install. |
| builddir (str): The location of the Qt build directory. |
| installdir (str): The location of the Qt install directory. |
| """ |
| logging.info("Installing Qt to %s", installdir) |
| cmake_install_cmd = ["cmake" + EXE_SUFFIX, "--install", ".", "--prefix", installdir] |
| logging.info(cmake_install_cmd) |
| res = subprocess.run(args=cmake_install_cmd, cwd=builddir, env=os.environ.copy()) |
| if res.returncode != 0: |
| logging.critical("[%s] failed (%s)", cmake_install_cmd, res.returncode) |
| exit(res.returncode) |
| logging.info("Installation succeeded") |
| |
| def cleanupQtTmpDirectory(): |
| if HOST_OS == "windows" and os.path.exists(WIN_QT_TMP_LOCATION): |
| # os.remove and shutils.rmtree may fail if any file in the tmp directory is read-only. |
| # So let's just use rmdir instead to destroy it. |
| subprocess.run(["rmdir", "/S", "/Q", WIN_QT_TMP_LOCATION], shell=True) |
| |
| def cleanup(): |
| cleanupQtTmpDirectory() |
| |
| def postInstall(installdir, target, is_webengine): |
| # Create include.system/QtCore/qconfig.h from include/QtCore/qconfig.h |
| src_qconfig = Path(installdir) / "include" / "QtCore" / "qconfig.h" |
| dst_qconfig = Path(installdir) / "include.system" / "QtCore" / "qconfig.h" |
| logging.info("Copy %s => %s", src_qconfig, dst_qconfig) |
| os.makedirs(dst_qconfig.parent, exist_ok=True) |
| shutil.copyfile(src_qconfig, dst_qconfig) |
| |
| if HOST_OS == "darwin": |
| mac_postInstall(installdir) |
| elif HOST_OS == "linux": |
| linux_postInstall(installdir, target, is_webengine) |
| |
| def mac_postInstall(installdir): |
| """Post-install steps specific for mac. |
| """ |
| def changeToQt6Rpaths(file): |
| libs = subprocess.check_output(["otool", "-LX", file], cwd=installdir, |
| env=os.environ.copy(), encoding="utf-8").split("\n") |
| qtlib_regex = ".*(libQt6.*AndroidEmu)\.6\.dylib" |
| for lib in libs: |
| s = re.search(qtlib_regex, lib) |
| if s: |
| old_lib = s.group(0).strip() |
| new_lib = f"@rpath/{s.group(1)}.{QT_VERSION}.dylib" |
| logging.info("%s: Changing %s => %s", os.path.basename(file), old_lib, new_lib) |
| subprocess.check_call( |
| ["install_name_tool", "-change", f"{old_lib}", f"{new_lib}", file], |
| cwd=installdir, env=os.environ.copy()) |
| |
| # Fix the rpaths. We want all libQt6 dependencies to point to @rpath/libQt6*.6.5.3.dylib instead |
| # of @rpath/libQt6*.6.dylib. This removes the need to set DYLD_LIBRARY_PATH properly. |
| for file in glob.iglob(os.path.join(installdir, "**", "*.dylib"), recursive=True): |
| if os.path.islink(file): |
| logging.info(">> Skipping symlink %s", file) |
| continue |
| else: |
| logging.info(">> Fixing rpath for %s", file) |
| basename = os.path.basename(file) |
| logging.info("%s: Changing install name to @rpath/%s", basename, basename) |
| subprocess.check_call(["install_name_tool", "-id", f"@rpath/{basename}", file], |
| cwd=installdir, env=os.environ.copy()) |
| changeToQt6Rpaths(file) |
| |
| |
| # Also need to fix the rpaths in the Qt executables we use. |
| fix_exes = [ |
| f"{installdir}/libexec/moc", |
| f"{installdir}/libexec/rcc", |
| f"{installdir}/libexec/uic", |
| f"{installdir}/libexec/QtWebEngineProcess"] |
| for exe in fix_exes: |
| if not os.path.isfile(exe): |
| logging.info(f"Skipping rpath fix for file {exe}") |
| continue |
| changeToQt6Rpaths(exe) |
| # Add the search path to the executables so we can use them without setting environment |
| # variables. |
| res = subprocess.run(args=["install_name_tool", "-add_rpath", "@loader_path/../lib", exe], |
| cwd=installdir, env=os.environ.copy(), encoding="utf-8") |
| if res.returncode != 0: |
| logging.critical("install_name_tool -add_rpath failed (%d)", res.returncode) |
| exit(res.returncode) |
| |
| def linux_postInstall(installdir, target, is_webengine): |
| # Install prebuilt clang's libc++.so.1 and libc++abi.so.1 to lib/ as Qt's compiler |
| # tools (moc, rcc, uic) depends on it. |
| clang_libs = ["libc++.so.1", "libc++abi.so.1"] |
| for lib in clang_libs: |
| src_lib = deps_common.getClangDirectory() / "lib" / lib |
| dst_lib = f"{installdir}/lib/{lib}" |
| logging.info(f"Copy {src_lib} ==> {dst_lib}") |
| shutil.copyfile(src_lib, dst_lib) |
| |
| # We also need additional libraries from the sysroot for linux |
| sysroot_dir = Path("/lib/x86_64-linux-gnu") |
| sysroot_libs = [ |
| "libpcre2-16.so.0", |
| "libfreetype.so.6", |
| "libxkbcommon.so.0", |
| "libXau.so.6", |
| "libXdmcp.so.6", |
| "libX11-xcb.so.1", |
| "libxcb-xkb.so.1", |
| "libxcb-cursor.so.0", |
| "libxcb-icccm.so.4", |
| "libxcb-image.so.0", |
| "libxcb-keysyms.so.1", |
| "libxcb-randr.so.0", |
| "libxcb-render-util.so.0", |
| "libxcb-render.so.0", |
| "libxcb-shape.so.0", |
| "libxcb-shm.so.0", |
| "libxcb-sync.so.1", |
| "libxcb-util.so.1", |
| "libxcb-xfixes.so.0", |
| "libxkbcommon-x11.so.0", |
| "libfontconfig.so.1"] |
| if target == "linux" and is_webengine: |
| sysroot_libs += ["libjpeg.so.8"] |
| for lib in sysroot_libs: |
| src_lib = sysroot_dir / lib |
| dst_lib = f"{installdir}/lib/{lib}" |
| logging.info(f"Copy {src_lib} ==> {dst_lib}") |
| shutil.copyfile(src_lib, dst_lib) |
| |
| if target != "linux_aarch64": |
| # need libunwind.so.1 for syncqt |
| src_libunwind = AOSP_ROOT / "prebuilts" / "android-emulator-build" / "common" / "libunwind" \ |
| / "linux-x86_64" / "lib" / "libunwind.so" |
| dst_libunwind = f"{installdir}/lib/libunwind.so.1" |
| logging.info(f"Copy {src_libunwind} ==> {dst_libunwind}") |
| shutil.copyfile(src_libunwind, dst_libunwind) |
| |
| # Need syncqt, qvkgen on linux-x86_64 for linux_aarch64 cross-compile build |
| fix_exes = [ |
| f"{installdir}/libexec/moc", |
| f"{installdir}/libexec/rcc", |
| f"{installdir}/libexec/uic", |
| f"{installdir}/libexec/syncqt", |
| f"{installdir}/libexec/qvkgen", |
| f"{installdir}/libexec/cmake_automoc_parser", |
| f"{installdir}/libexec/QtWebEngineProcess"] |
| # Add rpath to $ORIGIN/../lib so these executables can find libc++.so.1. |
| # You can verify the rpath with `objdump -x <exe> | grep PATH`. |
| # Also can check if libc++.so.1 is resolvable with `ldd <exe>`. |
| for exe in fix_exes: |
| if not os.path.isfile(exe): |
| logging.info(f"Skipping rpath fix for file {exe}") |
| continue |
| logging.info(f"Adding rpath $ORIGIN/../lib to {exe}") |
| # patchelf may use RUNPATH instead of RPATH. We can force RPATH by using --force-rpath. |
| subprocess.check_call( |
| ["patchelf", "--force-rpath", "--set-rpath", "$ORIGIN/../lib", exe], |
| cwd=installdir, env=os.environ.copy()) |
| |
| def buildPrebuilt(args, prebuilts_out_dir): |
| atexit.register(cleanup) |
| |
| if HOST_OS == "windows": |
| VS_INSTALL_PATH = os.environ["VS2022_INSTALL_PATH"] |
| if VS_INSTALL_PATH: |
| # The existence of the environment variable indicates we are on an old-style buildbot |
| # that does not have the docker configuration. |
| vcvarsall = os.path.join(VS_INSTALL_PATH, "VC", "Auxiliary", "Build", "vcvarsall.bat") |
| if not os.path.exists(vcvarsall): |
| logging.fatal(f"[{vcvarsall}] does not exist") |
| exit(-1) |
| deps_win.inheritSubprocessEnv([vcvarsall, "amd64", ">NUL", "2>&1"]) |
| # Use cmake from our prebuilts |
| addToSearchPath(CMAKE_PATH) |
| # Use ninja from our prebuilts |
| addToSearchPath(NINJA_PATH) |
| logging.info(os.environ) |
| |
| if not checkDependencies(): |
| logging.fatal("Build environment does not have the required dependencies to build. Exiting..") |
| exit(-1) |
| |
| # Qt source code is in external/qt5 |
| if not os.path.isdir(AOSP_QT_SRC_PATH): |
| logging.fatal("%s does not exist", AOSP_QT_SRC_PATH) |
| exit(-1) |
| logging.info("QT source: %s", AOSP_QT_SRC_PATH) |
| |
| # TODO(joshuaduong): If we decide to flatten the repository at check-in, then this step won't be necessary. |
| flattenQtRepo(AOSP_QT_SRC_PATH) |
| |
| if HOST_OS == "windows": |
| # On Windows, We must make sure Qt source code is in a very short directory, otherwise we |
| # may get a compiler error because of long paths issue. |
| cleanupQtTmpDirectory() |
| logging.info("Creating Qt temp directory [%s]", WIN_QT_TMP_LOCATION) |
| old_umask = os.umask(0o027) |
| os.makedirs(WIN_QT_TMP_LOCATION) |
| os.umask(old_umask) |
| logging.info("Moving source directory to shorter path [%s ==> %s]", |
| AOSP_QT_SRC_PATH, WIN_QT_SRC_SHORT_PATH) |
| os.rename(AOSP_QT_SRC_PATH, WIN_QT_SRC_SHORT_PATH) |
| qt_src_path = WIN_QT_SRC_SHORT_PATH |
| qt_build_path = WIN_QT_BUILD_PATH |
| else: |
| qt_src_path = AOSP_QT_SRC_PATH |
| qt_build_path = os.path.join(args.out, "build-qt") |
| |
| # Build the nowebengine variants as well for linux/mac |
| if HOST_OS == "linux" or HOST_OS == "darwin": |
| logging.info("Building Qt 6 (no QtWebEngine)") |
| qt_install_dir = os.path.join(prebuilts_out_dir, "qt-nowebengine") |
| configureQtBuild(qt_src_path, qt_build_path, qt_install_dir, QT_NOWEBENGINE_SUBMODULES) |
| buildQt(QT_NOWEBENGINE_SUBMODULES, qt_build_path) |
| installQt(QT_NOWEBENGINE_SUBMODULES, qt_build_path, qt_install_dir) |
| postInstall(qt_install_dir, args.target, False) |
| shutil.rmtree(qt_build_path) |
| |
| logging.info("Building Qt6 w/ QtWebEngine") |
| qt_install_dir = os.path.join(prebuilts_out_dir, "qt") |
| configureQtBuild(qt_src_path, qt_build_path, qt_install_dir, QT_SUBMODULES) |
| buildQt(QT_SUBMODULES, qt_build_path) |
| installQt(QT_SUBMODULES, qt_build_path, qt_install_dir) |
| postInstall(qt_install_dir, args.target, True) |
| |
| # Since linux_aarch64 cross-compilation requires having a host build of Qt, let's just build it |
| # in the linux x86_64 host instead of creating an additional linux_aarch64 build target. |
| if HOST_OS == "linux": |
| logging.info("Cross-compiling Qt 6 (no QtWebEngine) for linux_aarch64") |
| crosscompile_target = "linux_aarch64" |
| qt_install_dir = os.path.join(prebuilts_out_dir, "qt-nowebengine-linux_aarch64") |
| qt_host_path = os.path.join(prebuilts_out_dir, "qt-nowebengine") |
| configureQtBuild(qt_src_path, qt_build_path, qt_install_dir, QT_NOWEBENGINE_SUBMODULES, |
| crosscompile_target, qt_host_path) |
| buildQt(QT_NOWEBENGINE_SUBMODULES, qt_build_path) |
| installQt(QT_NOWEBENGINE_SUBMODULES, qt_build_path, qt_install_dir) |
| postInstall(qt_install_dir, "linux_aarch64", False) |
| shutil.rmtree(qt_build_path) |
| logging.info("Successfully built Qt!") |