From c16c0c568140a7d363cea707d45e3e53c0fb07d2 Mon Sep 17 00:00:00 2001 From: LeiWang1999 Date: Tue, 11 Feb 2025 15:53:07 +0000 Subject: [PATCH 1/8] bump version into v0.1.0 --- VERSION | 2 +- setup.py | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/VERSION b/VERSION index 8a9ecc2ea..6c6aa7cb0 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.0.1 \ No newline at end of file +0.1.0 \ No newline at end of file diff --git a/setup.py b/setup.py index cef302bed..805becda2 100644 --- a/setup.py +++ b/setup.py @@ -292,7 +292,8 @@ def run(self): # Copy CUTLASS to the package directory CUTLASS_PREBUILD_ITEMS = [ - "3rdparty/cutlass", + "3rdparty/cutlass/include", + "3rdparty/cutlass/tools", ] for item in CUTLASS_PREBUILD_ITEMS: source_dir = os.path.join(ROOT_DIR, item) @@ -307,7 +308,8 @@ def run(self): shutil.copy2(source_dir, target_dir) # copy compoable kernel to the package directory CK_PREBUILD_ITEMS = [ - "3rdparty/composable_kernel", + "3rdparty/composable_kernel/include", + "3rdparty/composable_kernel/library", ] for item in CK_PREBUILD_ITEMS: source_dir = os.path.join(ROOT_DIR, item) From 94e05a16d84607738543b628ae50b24688fa2bae Mon Sep 17 00:00:00 2001 From: LeiWang1999 Date: Thu, 13 Feb 2025 06:19:11 +0000 Subject: [PATCH 2/8] [Enhancement] Add custom develop command for editable installs and update .gitignore --- .gitignore | 3 +++ setup.py | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index e5b5080d6..b2db65593 100644 --- a/.gitignore +++ b/.gitignore @@ -79,3 +79,6 @@ build_sdist/ # exclude debug testing folder !testing/python/debug + +# ignore lib with develop mode +tilelang/lib diff --git a/setup.py b/setup.py index 805becda2..7b0d6dffd 100644 --- a/setup.py +++ b/setup.py @@ -7,6 +7,7 @@ from setuptools import setup, find_packages, Extension from setuptools.command.build_py import build_py from setuptools.command.sdist import sdist +from setuptools.command.develop import develop import distutils.dir_util from typing import List import re @@ -204,9 +205,9 @@ def run(self): self.run_command("build_ext") build_ext_cmd = self.get_finalized_command("build_ext") build_temp_dir = build_ext_cmd.build_temp - ext_modules = build_ext_cmd.extensions # 列出所有扩展模块 + ext_modules = build_ext_cmd.extensions for ext in ext_modules: - extdir = build_ext_cmd.get_ext_fullpath(ext.name) # 获取扩展模块的完整路径 + extdir = build_ext_cmd.get_ext_fullpath(ext.name) print(f"Extension {ext.name} output directory: {extdir}") ext_output_dir = os.path.dirname(extdir) @@ -348,6 +349,52 @@ def make_distribution(self): super().make_distribution() +# ------------------------------------------------------------------------ +# NEW: Add a custom 'develop' command so that `pip install -e .` works. +# ------------------------------------------------------------------------ +class TileLangDevelopCommand(develop): + """ + Customized setuptools 'develop' command for an editable install. + Ensures the extension is built and all necessary assets are copied. + """ + + def run(self): + # 1. Build the C/C++ extension modules + self.run_command("build_ext") + + build_ext_cmd = self.get_finalized_command("build_ext") + ext_modules = build_ext_cmd.extensions + for ext in ext_modules: + extdir = build_ext_cmd.get_ext_fullpath(ext.name) + print(f"Extension {ext.name} output directory: {extdir}") + + ext_output_dir = os.path.dirname(extdir) + print(f"Extension output directory (parent): {ext_output_dir}") + + # Copy the built TVM to the package directory + TVM_PREBUILD_ITEMS = [ + f"{ext_output_dir}/libtvm_runtime.so", + f"{ext_output_dir}/libtvm.so", + f"{ext_output_dir}/libtilelang.so", + f"{ext_output_dir}/libtilelang_module.so", + ] + for item in TVM_PREBUILD_ITEMS: + source_lib_file = os.path.join(ROOT_DIR, item) + # only copy the file + file_name = os.path.basename(item) + target_dir = os.path.join(PACKAGE_NAME, file_name) + target_dir = os.path.dirname(target_dir) + target_dir = os.path.join(target_dir, "lib") + if not os.path.exists(target_dir): + os.makedirs(target_dir) + if os.path.exists(source_lib_file): + shutil.copy2(source_lib_file, target_dir) + # remove the original file + os.remove(source_lib_file) + else: + print(f"INFO: {source_lib_file} does not exist.") + + class CMakeExtension(Extension): """ A specialized setuptools Extension class for building a CMake project. @@ -466,5 +513,6 @@ def build_cmake(self, ext): "build_py": TileLangBuilPydCommand, "sdist": TileLangSdistCommand, "build_ext": CMakeBuild, + "develop": TileLangDevelopCommand, }, ) From 200bc527930a894b16436e5c507756d4358e9955 Mon Sep 17 00:00:00 2001 From: LeiWang1999 Date: Thu, 13 Feb 2025 08:33:40 +0000 Subject: [PATCH 3/8] [Documentation] Update README to include system dependencies installation instructions --- README.md | 4 +++ docs/get_started/Installation.rst | 3 ++- setup.py | 44 ++++++++++++++++++++----------- 3 files changed, 34 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 58faf9dbc..19cf2c1da 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,10 @@ pip install git+https://github.com/tile-ai/tilelang Or install locally: ```bash +# install required system dependencies +sudo apt-get update +sudo apt-get install -y python3-setuptools gcc libtinfo-dev zlib1g-dev build-essential cmake libedit-dev libxml2-dev + pip install . # with -e option if you want to install in editable mode ``` diff --git a/docs/get_started/Installation.rst b/docs/get_started/Installation.rst index 15b27f5f5..985ddc1a9 100644 --- a/docs/get_started/Installation.rst +++ b/docs/get_started/Installation.rst @@ -71,7 +71,8 @@ After installing the prerequisites, you can clone the TileLang repository and in If you want to install TileLang in development mode, you can run the following command: .. code:: bash - + sudo apt-get update + sudo apt-get install -y python3-setuptools gcc libtinfo-dev zlib1g-dev build-essential cmake libedit-dev libxml2-dev pip install -e . We currently provide three methods to install **TileLang**: diff --git a/setup.py b/setup.py index 7b0d6dffd..7e0c80ceb 100644 --- a/setup.py +++ b/setup.py @@ -212,6 +212,7 @@ def run(self): ext_output_dir = os.path.dirname(extdir) print(f"Extension output directory (parent): {ext_output_dir}") + print(f"Build temp directory: {build_temp_dir}") TILELANG_SRC = [ "src/tl_templates", @@ -227,28 +228,39 @@ def run(self): if not os.path.exists(target_dir): os.makedirs(target_dir) shutil.copy2(source_dir, target_dir) - # Copy the built TVM to the package directory + + + potential_dirs = [ + ext_output_dir, + self.build_lib, + build_temp_dir, + os.path.join(ROOT_DIR, "build"), + ] + TVM_PREBUILD_ITEMS = [ - f"{ext_output_dir}/libtvm_runtime.so", - f"{ext_output_dir}/libtvm.so", - f"{ext_output_dir}/libtilelang.so", - f"{ext_output_dir}/libtilelang_module.so", + "libtvm_runtime.so", + "libtvm.so", + "libtilelang.so", + "libtilelang_module.so", ] + for item in TVM_PREBUILD_ITEMS: - source_lib_file = os.path.join(ROOT_DIR, item) - # only copy the file - file_name = os.path.basename(item) - target_dir = os.path.join(self.build_lib, PACKAGE_NAME, file_name) - target_dir = os.path.dirname(target_dir) - target_dir = os.path.join(target_dir, "lib") - if not os.path.exists(target_dir): - os.makedirs(target_dir) - if os.path.exists(source_lib_file): + source_lib_file = None + for dir in potential_dirs: + candidate = os.path.join(dir, item) + if os.path.exists(candidate): + source_lib_file = candidate + break + + if source_lib_file: + target_dir = os.path.join(PACKAGE_NAME, "lib") + os.makedirs(target_dir, exist_ok=True) shutil.copy2(source_lib_file, target_dir) - # remove the original file + print(f"Copied {source_lib_file} to {target_dir}") + # remove old files os.remove(source_lib_file) else: - print(f"INFO: {source_lib_file} does not exist.") + print(f"WARNING: {item} not found in any expected directories!") TVM_CONFIG_ITEMS = [ f"{build_temp_dir}/config.cmake", From 1b302ea7cba5407c82c21b40e9c6da679ee3b371 Mon Sep 17 00:00:00 2001 From: LeiWang1999 Date: Thu, 13 Feb 2025 08:53:19 +0000 Subject: [PATCH 4/8] [Build] Update setup.py to support library file copying for both release and develop modes --- setup.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/setup.py b/setup.py index 7e0c80ceb..60eb32d63 100644 --- a/setup.py +++ b/setup.py @@ -253,11 +253,14 @@ def run(self): break if source_lib_file: - target_dir = os.path.join(PACKAGE_NAME, "lib") - os.makedirs(target_dir, exist_ok=True) - shutil.copy2(source_lib_file, target_dir) - print(f"Copied {source_lib_file} to {target_dir}") - # remove old files + target_dir_release = os.path.join(self.build_lib, PACKAGE_NAME, "lib") + target_dir_develop = os.path.join(PACKAGE_NAME, "lib") + os.makedirs(target_dir_release, exist_ok=True) + os.makedirs(target_dir_develop, exist_ok=True) + shutil.copy2(source_lib_file, target_dir_release) + print(f"Copied {source_lib_file} to {target_dir_release}") + shutil.copy2(source_lib_file, target_dir_develop) + print(f"Copied {source_lib_file} to {target_dir_develop}") os.remove(source_lib_file) else: print(f"WARNING: {item} not found in any expected directories!") From 927795fffa7d0f56ea139483fd15e2da6b16cbac Mon Sep 17 00:00:00 2001 From: LeiWang1999 Date: Thu, 13 Feb 2025 08:53:32 +0000 Subject: [PATCH 5/8] [Build] Refactor library file copying logic in setup.py --- setup.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 60eb32d63..369b8fbab 100644 --- a/setup.py +++ b/setup.py @@ -229,7 +229,6 @@ def run(self): os.makedirs(target_dir) shutil.copy2(source_dir, target_dir) - potential_dirs = [ ext_output_dir, self.build_lib, @@ -243,7 +242,7 @@ def run(self): "libtilelang.so", "libtilelang_module.so", ] - + for item in TVM_PREBUILD_ITEMS: source_lib_file = None for dir in potential_dirs: From 0b3cf60f6adcc29629441db8f42f24306912f53d Mon Sep 17 00:00:00 2001 From: LeiWang1999 Date: Thu, 13 Feb 2025 09:03:51 +0000 Subject: [PATCH 6/8] [Documentation] Remove unnecessary install section header in Installation.md --- docs/get_started/Installation.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/get_started/Installation.md b/docs/get_started/Installation.md index 9fc79210e..7e473de9b 100644 --- a/docs/get_started/Installation.md +++ b/docs/get_started/Installation.md @@ -1,5 +1,3 @@ -(install)= - # Installation Guide ## Installing with pip From e56befa26940d103287a0bb7f406d600822b6212 Mon Sep 17 00:00:00 2001 From: LeiWang1999 Date: Thu, 13 Feb 2025 15:04:44 +0000 Subject: [PATCH 7/8] [Build] Add tox configuration and local distribution script for multi-Python version support --- maint/scripts/local_distribution_tox.sh | 31 +++++++++++++++++++++++++ requirements-build.txt | 1 + setup.py | 14 ++++++++++- tox.ini | 25 ++++++++++++++++++++ 4 files changed, 70 insertions(+), 1 deletion(-) create mode 100755 maint/scripts/local_distribution_tox.sh create mode 100644 tox.ini diff --git a/maint/scripts/local_distribution_tox.sh b/maint/scripts/local_distribution_tox.sh new file mode 100755 index 000000000..aadb69c3a --- /dev/null +++ b/maint/scripts/local_distribution_tox.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +multi_python_version=("3.8","3.9","3.10" "3.11", "3.12") +for python_version in "${multi_python_version[@]}"; do + echo "Installing Python ${python_version}..." + apt-get install -y python${python_version} +done + +pip install -r requirements-build.txt + +# if dist and build directories exist, remove them +if [ -d dist ]; then + rm -r dist +fi + +# Build source distribution (disabled for now) +# python setup.py sdist --formats=gztar,zip + +# Build wheels for different Python versions +echo "Building wheels for multiple Python versions..." +tox -e py38,py39,py310,py311,py312 + +if [ $? -ne 0 ]; then + echo "Error: Failed to build the wheels." + exit 1 +else + echo "Wheels built successfully." +fi \ No newline at end of file diff --git a/requirements-build.txt b/requirements-build.txt index 0aa765d8a..ae680f6c5 100644 --- a/requirements-build.txt +++ b/requirements-build.txt @@ -4,3 +4,4 @@ packaging setuptools>=61 torch wheel +tox diff --git a/setup.py b/setup.py index 369b8fbab..21873a0cd 100644 --- a/setup.py +++ b/setup.py @@ -160,7 +160,19 @@ def download_and_extract_llvm(version, is_aarch64=False, extract_path="3rdparty" def update_submodules(): - """Updates git submodules.""" + """Updates git submodules if in a git repository.""" + def is_git_repo(): + try: + # Check if current directory is a git repository + subprocess.check_output(["git", "rev-parse", "--is-inside-work-tree"], stderr=subprocess.STDOUT) + return True + except (subprocess.CalledProcessError, FileNotFoundError): + return False + + if not is_git_repo(): + print("Info: Not a git repository, skipping submodule update.") + return + try: subprocess.check_call(["git", "submodule", "update", "--init", "--recursive"]) except subprocess.CalledProcessError as error: diff --git a/tox.ini b/tox.ini new file mode 100644 index 000000000..cdffacc16 --- /dev/null +++ b/tox.ini @@ -0,0 +1,25 @@ +[tox] +envlist = py38,py39,py310,py311,py312 +isolated_build = True + +[testenv] +deps = + wheel + build +commands = + python -m build --wheel -o {toxinidir}/dist + +[testenv:py38] +basepython = python3.8 + +[testenv:py39] +basepython = python3.9 + +[testenv:py310] +basepython = python3.10 + +[testenv:py311] +basepython = python3.11 + +[testenv:py312] +basepython = python3.12 From 02d80df62ec2a1aa01be9f26dab4d888cc938d8a Mon Sep 17 00:00:00 2001 From: LeiWang1999 Date: Thu, 13 Feb 2025 15:05:44 +0000 Subject: [PATCH 8/8] [Build] Improve git submodule update function with better error handling --- setup.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 21873a0cd..d6aa6b128 100644 --- a/setup.py +++ b/setup.py @@ -161,10 +161,12 @@ def download_and_extract_llvm(version, is_aarch64=False, extract_path="3rdparty" def update_submodules(): """Updates git submodules if in a git repository.""" + def is_git_repo(): try: # Check if current directory is a git repository - subprocess.check_output(["git", "rev-parse", "--is-inside-work-tree"], stderr=subprocess.STDOUT) + subprocess.check_output(["git", "rev-parse", "--is-inside-work-tree"], + stderr=subprocess.STDOUT) return True except (subprocess.CalledProcessError, FileNotFoundError): return False