# Copyright 2021 The IREE Authors # # Licensed under the Apache License v2.0 with LLVM Exceptions. # See https://llvm.org/LICENSE.txt for license information. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception """Builds the main distribution package. This script runs as the CIBW_BEFORE_BUILD command within cibuildwheel: - Main distribution .tar.bz2 file (the result of `ninja install`). - The python_packages/iree_compiler wheel, which is python version independent but platform specific. - Installable tests. It uses cibuildwheel for all of this as a convenience since it already knows how to arrange for the cross platform part of the build, including using an appropriate manylinux image, etc. This is expected to be run from the project directory, containing the following sub-directories: - c/ : Main IREE repository checkout. - bindist/ : Directory where binary distribution artifacts are written. - c/version_info.json : Version config information. Within the build environment (which may be the naked runner or a docker image): - iree-build/ : The build tree. - iree-install/ : The install tree. Environment variables: - BINDIST_DIR : If set, then this overrides the default bindist/ directory. Should be set if running in a mapped context like a docker container. Testing this script: It is not recommended to run cibuildwheel locally. However, this script can be executed as if running within such an environment. To do so, create a directory and: ln -s /path/to/iree c python -m venv .venv source .venv/bin/activate python ./c/build_tools/github_actions/build_dist.py main-dist python ./c/build_tools/github_actions/build_dist.py py-tflite-compiler-tools-pkg python ./c/build_tools/github_actions/build_dist.py py-tf-compiler-tools-pkg That is not a perfect approximation but is close. """ import json import os import platform import shutil import subprocess import sys import sysconfig import tarfile # Setup. WORK_DIR = os.path.realpath(os.path.curdir) BUILD_DIR = os.path.join(WORK_DIR, "iree-build") INSTALL_DIR = os.path.join(WORK_DIR, "iree-install") IREESRC_DIR = os.path.join(WORK_DIR, "c") TF_INTEGRATIONS_DIR = os.path.join(IREESRC_DIR, "integrations/tensorflow") BINDIST_DIR = os.environ.get("BINDIST_DIR") if BINDIST_DIR is None: BINDIST_DIR = os.path.join(WORK_DIR, "bindist") THIS_DIR = os.path.realpath(os.path.dirname(__file__)) CMAKE_CI_SCRIPT = os.path.join(THIS_DIR, "cmake_ci.py") BUILD_REQUIREMENTS_TXT = os.path.join( IREESRC_DIR, "runtime", "bindings", "python", "iree", "runtime", "build_requirements.txt", ) CI_REQUIREMENTS_TXT = os.path.join(THIS_DIR, "ci_requirements.txt") CONFIGURE_BAZEL_PY = os.path.join(IREESRC_DIR, "configure_bazel.py") # Load version info. def load_version_info(): with open(os.path.join(IREESRC_DIR, "version_info.json"), "rt") as f: return json.load(f) try: version_info = load_version_info() except FileNotFoundError: print("version_info.json not found. Using defaults") version_info = { "package-version": "0.1dev1", "package-suffix": "-dev", } def remove_cmake_cache(): cache_file = os.path.join(BUILD_DIR, "CMakeCache.txt") if os.path.exists(cache_file): print(f"Removing {cache_file}") os.remove(cache_file) else: print(f"Not removing cache file (does not exist): {cache_file}") def install_python_requirements(): print("Installing python requirements...") subprocess.check_call( [sys.executable, "-m", "pip", "install", "-r", BUILD_REQUIREMENTS_TXT] ) subprocess.check_call( [sys.executable, "-m", "pip", "install", "-r", CI_REQUIREMENTS_TXT] ) def configure_bazel(): print("Generating configured.bazelrc...") subprocess.check_call([sys.executable, CONFIGURE_BAZEL_PY]) def build_main_dist(): """Builds the main distribution binaries. Additional packages that are installable as part of a full build and do not benefit from a more restricted build can be added here. """ install_python_requirements() # Clean up install and build trees. shutil.rmtree(INSTALL_DIR, ignore_errors=True) remove_cmake_cache() # CMake configure. print("*** Configuring ***") subprocess.run( [ sys.executable, CMAKE_CI_SCRIPT, f"-B{BUILD_DIR}", "--log-level=VERBOSE", f"-DCMAKE_INSTALL_PREFIX={INSTALL_DIR}", # On some distributions, this will install to lib64. We would like # consistency in built packages, so hard-code it. "-DCMAKE_INSTALL_LIBDIR=lib", f"-DCMAKE_BUILD_TYPE=Release", f"-DIREE_BUILD_COMPILER=ON", f"-DIREE_BUILD_PYTHON_BINDINGS=OFF", f"-DIREE_BUILD_SAMPLES=OFF", # cpuinfo is set to be removed and is problematic from an # installed/bundled library perspective. f"-DIREE_ENABLE_CPUINFO=OFF", ], check=True, ) print("*** Building ***") subprocess.run( [ sys.executable, CMAKE_CI_SCRIPT, "--build", BUILD_DIR, "--target", "all", ], check=True, ) # TODO: Get proper dependency management on install targets so we don't # have to build all first. subprocess.run( [ sys.executable, CMAKE_CI_SCRIPT, "--build", BUILD_DIR, "--target", "iree-install-dist-stripped", ], check=True, ) print("*** Packaging ***") dist_entries = [ "bin", "lib", "include", ] dist_archive = os.path.join( BINDIST_DIR, f"iree-dist{version_info['package-suffix']}" f"-{version_info['package-version']}" f"-{sysconfig.get_platform()}.tar.xz", ) print(f"Creating archive {dist_archive}") os.makedirs(os.path.dirname(dist_archive), exist_ok=True) with tarfile.open(dist_archive, mode="w:xz") as tf: for entry in dist_entries: print(f"Adding entry: {entry}") tf.add(os.path.join(INSTALL_DIR, entry), arcname=entry, recursive=True) def build_py_tf_compiler_tools_pkg(): """Builds iree-install/python_packages/iree_tools_[tf, tflite] packages.""" install_python_requirements() configure_bazel() # Clean up install and build trees. shutil.rmtree(INSTALL_DIR, ignore_errors=True) remove_cmake_cache() os.makedirs(BINDIST_DIR, exist_ok=True) for project in ["iree_tflite", "iree_tf"]: print(f"*** Building wheel for {project} ***") subprocess.run( [ sys.executable, "-m", "pip", "wheel", os.path.join(TF_INTEGRATIONS_DIR, "python_projects", project), ], cwd=BINDIST_DIR, check=True, ) command = sys.argv[1] if command == "main-dist": build_main_dist() elif command == "py-tf-compiler-tools-pkg": build_py_tf_compiler_tools_pkg() else: print(f"Unrecognized command: {command}")