Skip to content

Commit

Permalink
[mpact][wheel] add setup.py for python wheel (#26)
Browse files Browse the repository at this point in the history
add setup.py for python wheel
  • Loading branch information
yinying-lisa-li authored Jun 10, 2024
1 parent 12f52e8 commit be71f44
Showing 1 changed file with 191 additions and 0 deletions.
191 changes: 191 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
# Part of the LLVM Project, 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
# Also available under a BSD-style license. See LICENSE.

# Script for generating the mpact wheel.
# ```
# $ python setup.py bdist_wheel
# ```
# Environment variables you are probably interested in:
#
# CMAKE_BUILD_TYPE:
# specify the build type: DEBUG/RelWithDebInfo/Release
#
# MPACT_CMAKE_ALREADY_BUILT:
# the `MPACT_CMAKE_BUILD_DIR` directory has already been compiled,
# and the CMake compilation process will not be executed again.
# On CIs, it is often advantageous to re-use/control the CMake build directory.
#
# It is recommended to build with Ninja and ccache. To do so, set environment
# variables by prefixing to above invocations:
# ```
# CMAKE_GENERATOR=Ninja CMAKE_C_COMPILER_LAUNCHER=ccache CMAKE_CXX_COMPILER_LAUNCHER=ccache
# ```
#
# Implementation notes:
# The contents of the wheel is just the contents of the `python_packages`
# directory that our CMake build produces. We go through quite a bit of effort
# on the CMake side to organize that directory already, so we avoid duplicating
# that here, and just package up its contents.
import os
import pathlib
import shutil
import subprocess
import sys

from datetime import date
from distutils.command.build import build as _build
from setuptools import setup, Extension
from setuptools.command.build_ext import build_ext
from setuptools.command.build_py import build_py


def _check_env_flag(name: str, default=None) -> bool:
return str(os.getenv(name, default)).upper() in ["ON", "1", "YES", "TRUE", "Y"]


PACKAGE_VERSION = "".join(str(date.today()).split("-"))
SRC_DIR = pathlib.Path(__file__).parent.absolute()
CMAKE_BUILD_TYPE = os.getenv("CMAKE_BUILD_TYPE", "Release")
MPACT_CMAKE_ALREADY_BUILT = _check_env_flag("MPACT_CMAKE_ALREADY_BUILT", False)
MPACT_CMAKE_BUILD_DIR = os.path.join(SRC_DIR, "build")


# Build phase discovery is unreliable. Just tell it what phases to run.
class CustomBuild(_build):
def initialize_options(self):
_build.initialize_options(self)
# Make setuptools not steal the build directory name,
# because the mlir c++ developers are quite
# used to having build/ be for cmake
self.build_base = "setup_build"

def run(self):
self.run_command("build_py")
self.run_command("build_ext")
self.run_command("build_scripts")


class CMakeBuild(build_py):
def cmake_build(self, cmake_build_dir):
llvm_dir = str(
SRC_DIR / "externals" / "torch-mlir" / "externals" / "llvm-project" / "llvm"
)
cmake_config_args = [
f"cmake",
f"-GNinja",
f"-DCMAKE_BUILD_TYPE=Release",
f"-DPython3_FIND_VIRTUALENV=ONLY",
f"-DLLVM_ENABLE_PROJECTS=mlir",
f"-DLLVM_EXTERNAL_PROJECTS='torch-mlir;mpact'",
f"-DLLVM_EXTERNAL_TORCH_MLIR_SOURCE_DIR='{SRC_DIR}/externals/torch-mlir'",
f"-DLLVM_EXTERNAL_MPACT_SOURCE_DIR='{SRC_DIR}'",
f"-DLLVM_TARGETS_TO_BUILD=host",
f"-DMLIR_ENABLE_BINDINGS_PYTHON=ON",
# Optimization options for building wheels.
f"-DCMAKE_VISIBILITY_INLINES_HIDDEN=ON",
f"-DCMAKE_C_VISIBILITY_PRESET=hidden",
f"-DCMAKE_CXX_VISIBILITY_PRESET=hidden",
f"{llvm_dir}",
]

cmake_build_args = [
f"cmake",
f"--build",
f".",
f"--target",
f"MPACTPythonModules",
f"MPACTBenchmarkPythonPythonModules",
]

try:
subprocess.check_call(cmake_config_args, cwd=cmake_build_dir)
subprocess.check_call(cmake_build_args, cwd=cmake_build_dir)
except subprocess.CalledProcessError as e:
print("cmake build failed with\n", e)
print("debug by follow cmake command:")
sys.exit(e.returncode)
finally:
print(f"cmake config: {' '.join(cmake_config_args)}")
print(f"cmake build: {' '.join(cmake_build_args)}")
print(f"cmake workspace: {cmake_build_dir}")
print(SRC_DIR)

def run(self):
target_dir = self.build_lib
cmake_build_dir = MPACT_CMAKE_BUILD_DIR
if not cmake_build_dir:
cmake_build_dir = os.path.abspath(os.path.join(target_dir, "..", "build"))

python_package_dir = os.path.join(
cmake_build_dir, "tools", "mpact", "python_packages", "mpact"
)
if not MPACT_CMAKE_ALREADY_BUILT:
os.makedirs(cmake_build_dir, exist_ok=True)
cmake_cache_file = os.path.join(cmake_build_dir, "CMakeCache.txt")
if os.path.exists(cmake_cache_file):
os.remove(cmake_cache_file)
# NOTE: With repeated builds for different Python versions, the
# prior version binaries will continue to accumulate. Here we just
# delete the directory where we build native extensions to keep
# this from happening but still take advantage of most of the
# build cache.
mlir_libs_dir = os.path.join(python_package_dir, "mpact", "_mlir_libs")
if os.path.exists(mlir_libs_dir):
print(f"Removing _mlir_mlibs dir to force rebuild: {mlir_libs_dir}")
shutil.rmtree(mlir_libs_dir)
else:
print(f"Not removing _mlir_libs dir (does not exist): {mlir_libs_dir}")
self.cmake_build(cmake_build_dir)

if os.path.exists(target_dir):
shutil.rmtree(target_dir, ignore_errors=False, onerror=None)

shutil.copytree(python_package_dir, target_dir, symlinks=False)


class CMakeExtension(Extension):
def __init__(self, name, sourcedir=""):
Extension.__init__(self, name, sources=[])
self.sourcedir = os.path.abspath(sourcedir)


class NoopBuildExtension(build_ext):
def build_extension(self, ext):
pass


with open("README.md", "r", encoding="utf-8") as fh:
long_description = fh.read()


# Requires and extension modules depend on whether building PyTorch
# extensions.
INSTALL_REQUIRES = [
"numpy",
"packaging",
]
EXT_MODULES = [
CMakeExtension("mpact._mlir_libs._mpact"),
]

setup(
name="mpact",
version=f"{PACKAGE_VERSION}",
author="Reid Tatge",
author_email="[email protected]",
description="MPACT retargetable ML compiler",
long_description=long_description,
long_description_content_type="text/markdown",
include_package_data=True,
cmdclass={
"build": CustomBuild,
"built_ext": NoopBuildExtension,
"build_py": CMakeBuild,
},
ext_modules=EXT_MODULES,
python_requires=">=3.8",
install_requires=INSTALL_REQUIRES,
zip_safe=False,
)

0 comments on commit be71f44

Please sign in to comment.