Replaces cherry-picked upstream_ref with complete source trees. xllm/ — Iluvatar official C++ inference engine (15MB, 1470 files) Complete: kernels → layers → models → runtime → scheduler → api Excluded: .git, binary images, third_party submodule checkouts ds_vllm/ — Iluvatar official vllm fork (8MB, 703 files) Included: csrc/ (ALL CUDA kernels), fused_moe/, qwen3_5 model, _custom_ops Excluded: tests, benchmarks, docs, examples (not needed for reference) Critical call chains now fully traceable: MoE: moe_topk_softmax_kernels.cuh → ixformer.h → fused_moe.cpp → layer GDN: qwen3_gated_delta_net_base.cpp → qwen3_5_gated_delta_net.cpp Attention: ixformer.h → xllm_paged_attention → attention.cpp
671 lines
24 KiB
Python
671 lines
24 KiB
Python
import io
|
|
import os
|
|
import re
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
import argparse
|
|
from typing import Any, Optional
|
|
|
|
from distutils.core import Command
|
|
from setuptools import Extension, find_namespace_packages, setup
|
|
from setuptools.command.build_ext import build_ext
|
|
|
|
try:
|
|
from setuptools.command.bdist_wheel import bdist_wheel
|
|
except ModuleNotFoundError:
|
|
from wheel.bdist_wheel import bdist_wheel
|
|
|
|
from scripts.build_support.env import (
|
|
get_cxx_abi,
|
|
set_cuda_envs,
|
|
set_ilu_envs,
|
|
set_mlu_envs,
|
|
set_musa_envs,
|
|
set_npu_envs,
|
|
)
|
|
from scripts.build_support.utils import (
|
|
check_and_install_pre_commit,
|
|
get_base_dir,
|
|
get_cmake_dir,
|
|
get_cpu_arch,
|
|
get_device_type,
|
|
get_python_version,
|
|
get_torch_version,
|
|
get_version,
|
|
pre_build,
|
|
read_readme,
|
|
)
|
|
|
|
BUILD_TEST_FILE: bool = True
|
|
BUILD_EXPORT: bool = True
|
|
|
|
|
|
def _maybe_compile_tilelang_kernels(device: str) -> None:
|
|
if device != "npu":
|
|
return
|
|
|
|
output_root = os.path.join(get_cmake_dir(), "xllm", "compiler", "tilelang")
|
|
os.makedirs(output_root, exist_ok=True)
|
|
|
|
env = os.environ.copy()
|
|
base_dir = get_base_dir()
|
|
|
|
cmd = [
|
|
sys.executable,
|
|
os.path.join(base_dir, "xllm", "compiler", "tilelang_launcher.py"),
|
|
"compile-kernels",
|
|
"--target",
|
|
"ascend",
|
|
"--output-root",
|
|
output_root,
|
|
]
|
|
print("[INFO] compiling TileLang kernels via source-tree launcher")
|
|
subprocess.check_call(cmd, cwd=base_dir, env=env)
|
|
|
|
class CMakeExtension(Extension):
|
|
def __init__(self, name: str, path: str, sourcedir: str = "") -> None:
|
|
super().__init__(name, sources=[])
|
|
self.sourcedir = os.path.realpath(os.path.abspath(sourcedir))
|
|
self.path = path
|
|
|
|
class ExtBuild(build_ext):
|
|
user_options = build_ext.user_options + [
|
|
("base-dir=", None, "base directory of xLLM project"),
|
|
("device=", None, "target device type (npu or mlu or cuda or ilu or musa)"),
|
|
("arch=", None, "target arch type (x86 or arm)"),
|
|
("generate-so=", None, "generate so or binary"),
|
|
]
|
|
|
|
def initialize_options(self) -> None:
|
|
build_ext.initialize_options(self)
|
|
self.base_dir = get_base_dir()
|
|
self.device: Optional[str] = None
|
|
self.arch: Optional[str] = None
|
|
self.generate_so: bool = False
|
|
|
|
def finalize_options(self) -> None:
|
|
build_ext.finalize_options(self)
|
|
|
|
def run(self) -> None:
|
|
# check if cmake is installed
|
|
try:
|
|
out: bytes = subprocess.check_output(["cmake", "--version"])
|
|
except OSError:
|
|
raise RuntimeError(
|
|
"CMake must be installed to build the following extensions: "
|
|
+ ", ".join(e.name for e in self.extensions)
|
|
)
|
|
exit(1)
|
|
|
|
match = re.search(
|
|
r"version\s*(?P<major>\d+)\.(?P<minor>\d+)([\d.]+)?", out.decode()
|
|
)
|
|
if match is None:
|
|
raise RuntimeError(f"Failed to parse CMake version from: {out!r}")
|
|
cmake_major, cmake_minor = int(match.group("major")), int(match.group("minor"))
|
|
if (cmake_major, cmake_minor) < (3, 18):
|
|
raise RuntimeError("CMake >= 3.18.0 is required")
|
|
|
|
try:
|
|
# build extensions
|
|
for ext in self.extensions:
|
|
self.build_extension(ext)
|
|
except Exception as e:
|
|
print("ERROR: Build failed.")
|
|
print(f"Details: {e}")
|
|
exit(1)
|
|
|
|
def build_extension(self, ext: CMakeExtension) -> None:
|
|
ninja_dir = shutil.which("ninja")
|
|
# the output dir for the extension
|
|
extdir: str = os.path.abspath(os.path.dirname(self.get_ext_fullpath(ext.path)))
|
|
|
|
# create build directory
|
|
os.makedirs(self.build_temp, exist_ok=True)
|
|
|
|
# Using this requires trailing slash for auto-detection & inclusion of
|
|
# auxiliary "native" libs
|
|
|
|
debug: int = int(os.environ.get("DEBUG", 0)) if self.debug is None else int(self.debug)
|
|
build_type: str = "Debug" if debug else "Release"
|
|
|
|
default_jobs = os.cpu_count() or 1
|
|
max_jobs: str = os.getenv("MAX_JOBS", str(default_jobs))
|
|
max_jobs_int: int = int(max_jobs)
|
|
|
|
# Limit archive (ar/ranlib) concurrency to avoid file locking conflicts.
|
|
# The ar tool requires exclusive access to archive files (.a files) when
|
|
# creating or updating static libraries. When multiple ar processes attempt
|
|
# to modify the same archive file simultaneously, they compete for file locks,
|
|
# which can cause deadlocks and hang the build process.
|
|
archive_jobs: int = min(8, max(1, max_jobs_int // 4))
|
|
cmake_args: list[str] = [
|
|
"-G",
|
|
"Ninja",
|
|
f"-DCMAKE_MAKE_PROGRAM={ninja_dir}",
|
|
f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY={extdir}",
|
|
f"-DCMAKE_RUNTIME_OUTPUT_DIRECTORY={extdir}",
|
|
"-DUSE_CCACHE=ON",
|
|
f"-DPython_EXECUTABLE:FILEPATH={sys.executable}",
|
|
f"-DCMAKE_BUILD_TYPE={build_type}",
|
|
f"-DBUILD_SHARED_LIBS=OFF",
|
|
f"-DDEVICE_TYPE=USE_{self.device.upper()}",
|
|
f"-DDEVICE_ARCH={self.arch.upper()}",
|
|
f"-DXLLM_ATB_LAYERS_SOURCE_DIR={os.path.join(self.base_dir, 'third_party', 'xllm_atb_layers')}",
|
|
f"-DCMAKE_JOB_POOLS=archive={archive_jobs}",
|
|
]
|
|
|
|
if self.device is None:
|
|
raise ValueError("Please set --device to npu or mlu or cuda or ilu or musa.")
|
|
if self.arch is None:
|
|
raise ValueError("Please set --arch to x86 or arm.")
|
|
|
|
if self.device == "npu":
|
|
cmake_args += ["-DUSE_NPU=ON"]
|
|
set_npu_envs()
|
|
_maybe_compile_tilelang_kernels(self.device)
|
|
elif self.device == "mlu":
|
|
cmake_args += ["-DUSE_MLU=ON"]
|
|
set_mlu_envs()
|
|
elif self.device == "cuda":
|
|
torch_cuda_architectures = os.getenv("TORCH_CUDA_ARCH_LIST")
|
|
if not torch_cuda_architectures:
|
|
raise ValueError("Please set TORCH_CUDA_ARCH_LIST environment variable, e.g. export TORCH_CUDA_ARCH_LIST=\"8.0 8.9 9.0 10.0 12.0\"")
|
|
cmake_args += ["-DUSE_CUDA=ON",
|
|
f"-DTORCH_CUDA_ARCH_LIST={torch_cuda_architectures}"]
|
|
set_cuda_envs()
|
|
elif self.device == "ilu":
|
|
cmake_args += ["-DUSE_ILU=ON"]
|
|
set_ilu_envs()
|
|
elif self.device == "musa":
|
|
cmake_args += ["-DUSE_MUSA=ON"]
|
|
set_musa_envs()
|
|
global BUILD_TEST_FILE
|
|
BUILD_TEST_FILE = False
|
|
else:
|
|
raise ValueError("Please set --device to npu or mlu or cuda or ilu or musa.")
|
|
|
|
product: str = "xllm"
|
|
if self.generate_so:
|
|
product = "libxllm.so"
|
|
cmake_args += ["-DGENERATE_SO=ON"]
|
|
else:
|
|
cmake_args += ["-DGENERATE_SO=OFF"]
|
|
|
|
# Adding CMake arguments set as environment variable
|
|
# (needed e.g. to build for ARM OSx on conda-forge)
|
|
if "CMAKE_ARGS" in os.environ:
|
|
cmake_args += [item for item in os.environ["CMAKE_ARGS"].split(" ") if item]
|
|
|
|
# check if torch binary is built with cxx11 abi
|
|
if get_cxx_abi():
|
|
cmake_args += ["-DUSE_CXX11_ABI=ON", "-D_GLIBCXX_USE_CXX11_ABI=1"]
|
|
else:
|
|
cmake_args += ["-DUSE_CXX11_ABI=OFF", "-D_GLIBCXX_USE_CXX11_ABI=0"]
|
|
|
|
build_args = ["--config", build_type]
|
|
build_args += ["-j" + max_jobs]
|
|
|
|
env: dict[str, str] = os.environ.copy()
|
|
env["VCPKG_MAX_CONCURRENCY"] = str(max_jobs)
|
|
print("CMake Args: ", cmake_args)
|
|
print("Env: ", env)
|
|
|
|
self.build_cmake_targets(ext, cmake_args, build_args, env, extdir, product)
|
|
|
|
def build_cmake_targets(
|
|
self,
|
|
ext: CMakeExtension,
|
|
cmake_args: list[str],
|
|
build_args: list[str],
|
|
env: dict[str, str],
|
|
extdir: str,
|
|
product: str,
|
|
) -> None:
|
|
"""Build CMake targets"""
|
|
cmake_dir = get_cmake_dir()
|
|
subprocess.check_call(["cmake", self.base_dir] + cmake_args, cwd=cmake_dir, env=env)
|
|
|
|
base_build_args = build_args
|
|
# add build target to speed up the build process
|
|
build_args += ["--target", ext.name, "xllm"]
|
|
subprocess.check_call(["cmake", "--build", ".", "--verbose"] + build_args, cwd=cmake_dir)
|
|
|
|
os.makedirs(os.path.join(os.path.dirname(cmake_dir), "xllm/core/server/"), exist_ok=True)
|
|
shutil.copy(
|
|
os.path.join(extdir, product),
|
|
os.path.join(os.path.dirname(cmake_dir), "xllm/core/server/"),
|
|
)
|
|
|
|
if BUILD_EXPORT:
|
|
# build export module
|
|
build_args = base_build_args + ["--target export_module"]
|
|
subprocess.check_call(["cmake", "--build", ".", "--verbose"] + build_args, cwd=cmake_dir)
|
|
|
|
if BUILD_TEST_FILE:
|
|
# build tests target
|
|
build_args = base_build_args + ["--target all_tests"]
|
|
subprocess.check_call(["cmake", "--build", ".", "--verbose"] + build_args, cwd=cmake_dir)
|
|
|
|
class ExtBuildSingleTest(ExtBuild):
|
|
"""Inherit ExtBuild, used to build and run a single test"""
|
|
user_options = ExtBuild.user_options + [
|
|
("test-name=", None, "name of the test target to build and run"),
|
|
]
|
|
|
|
def initialize_options(self) -> None:
|
|
ExtBuild.initialize_options(self)
|
|
self.test_name: Optional[str] = None
|
|
|
|
def finalize_options(self) -> None:
|
|
ExtBuild.finalize_options(self)
|
|
if not self.test_name:
|
|
raise ValueError("--test-name is required for ExtBuildSingleTest")
|
|
|
|
def build_cmake_targets(
|
|
self,
|
|
ext: CMakeExtension,
|
|
cmake_args: list[str],
|
|
build_args: list[str],
|
|
env: dict[str, str],
|
|
extdir: str,
|
|
product: str,
|
|
) -> None:
|
|
"""Override method: only build the specified test target and run"""
|
|
cmake_dir = get_cmake_dir()
|
|
subprocess.check_call(["cmake", self.base_dir] + cmake_args, cwd=cmake_dir, env=env)
|
|
|
|
base_build_args = build_args
|
|
# Only build the specified test target
|
|
build_args += ["--target", self.test_name]
|
|
subprocess.check_call(["cmake", "--build", ".", "--verbose"] + build_args, cwd=cmake_dir)
|
|
|
|
# Find test executable
|
|
# CMake usually places executables in CMAKE_RUNTIME_OUTPUT_DIRECTORY or build directory
|
|
test_executable: Optional[str] = None
|
|
possible_paths: list[str] = [
|
|
os.path.join(cmake_dir, self.test_name),
|
|
os.path.join(extdir, self.test_name),
|
|
os.path.join(cmake_dir, "xllm", "core", self.test_name),
|
|
]
|
|
|
|
# Check possible paths first
|
|
for path in possible_paths:
|
|
if os.path.exists(path) and os.access(path, os.X_OK):
|
|
test_executable = path
|
|
break
|
|
|
|
# If not found, try recursive search in build directory
|
|
if not test_executable:
|
|
for root, dirs, files in os.walk(cmake_dir):
|
|
if self.test_name in files:
|
|
candidate = os.path.join(root, self.test_name)
|
|
if os.access(candidate, os.X_OK):
|
|
test_executable = candidate
|
|
break
|
|
|
|
if not test_executable:
|
|
# If not found, try using ctest to run
|
|
print(f"⚠️ Warning: Could not find test executable {self.test_name}, trying ctest...")
|
|
try:
|
|
subprocess.check_call(
|
|
["ctest", "-R", self.test_name, "--verbose"],
|
|
cwd=cmake_dir,
|
|
env=env
|
|
)
|
|
print(f"✅ Test {self.test_name} passed!")
|
|
except subprocess.CalledProcessError as e:
|
|
print(f"❌ Failed to run test {self.test_name}")
|
|
raise
|
|
else:
|
|
# Run test executable directly
|
|
print(f"🚀 Running test: {test_executable}")
|
|
try:
|
|
subprocess.check_call([test_executable], cwd=os.path.dirname(test_executable), env=env)
|
|
print(f"✅ Test {self.test_name} passed!")
|
|
except subprocess.CalledProcessError as e:
|
|
print(f"❌ Test {self.test_name} failed with exit code {e.returncode}")
|
|
raise
|
|
|
|
class BuildDistWheel(bdist_wheel):
|
|
user_options = bdist_wheel.user_options + [
|
|
("device=", None, "target device type (npu or mlu or cuda or ilu or musa)"),
|
|
("arch=", None, "target arch type (x86 or arm)"),
|
|
]
|
|
|
|
def initialize_options(self) -> None:
|
|
super().initialize_options()
|
|
self.device: Optional[str] = None
|
|
self.arch: Optional[str] = None
|
|
# Cache the original dist name early so finalize_options is idempotent
|
|
# and so name changes are visible to egg_info/metadata generation.
|
|
self._base_dist_name = self.distribution.metadata.name
|
|
|
|
def finalize_options(self) -> None:
|
|
# IMPORTANT: mutate distribution name BEFORE super().finalize_options().
|
|
# bdist_wheel finalization may finalize/cache egg_info metadata; if we
|
|
# change the name afterwards, the wheel filename and METADATA can diverge
|
|
# (pip will reject the wheel as "inconsistent name").
|
|
name = self._base_dist_name
|
|
|
|
# generate distribution name suffix
|
|
if self.device:
|
|
name += f"_{self.device}"
|
|
|
|
torch_version = get_torch_version(self.device)
|
|
if torch_version:
|
|
name += f"_torch{torch_version}"
|
|
|
|
if get_cxx_abi():
|
|
name += "_cxx11_abi"
|
|
else:
|
|
name += "_no_cxx11_abi"
|
|
|
|
self.distribution.metadata.name = name
|
|
super().finalize_options()
|
|
|
|
def run(self) -> None:
|
|
build_ext_cmd = self.get_finalized_command('build_ext')
|
|
build_ext_cmd.device = self.device
|
|
build_ext_cmd.arch = self.arch
|
|
|
|
print("🔨 build project...")
|
|
self.run_command('build')
|
|
|
|
print("🧪 testing UT...")
|
|
self.run_command('test')
|
|
|
|
if self.arch == 'arm':
|
|
ext_path = get_base_dir() + f"/build/lib.linux-aarch64-cpython-{get_python_version()}/"
|
|
else:
|
|
ext_path = get_base_dir() + f"/build/lib.linux-x86_64-cpython-{get_python_version()}/"
|
|
if len(ext_path) == 0:
|
|
print("❌ Build wheel failed, not found path.")
|
|
exit(1)
|
|
tmp_path = os.path.join(ext_path, 'xllm')
|
|
for root, dirs, files in os.walk(tmp_path):
|
|
for item in files:
|
|
path = os.path.join(root, item)
|
|
if '_test' in item and os.path.isfile(path):
|
|
os.remove(path)
|
|
global BUILD_TEST_FILE
|
|
BUILD_TEST_FILE = False
|
|
|
|
self.skip_build = True
|
|
super().run()
|
|
|
|
class TestUT(Command):
|
|
description = "Run all testing binary."
|
|
user_options = []
|
|
|
|
# Whitelist: tests that must run sequentially (not in parallel with others)
|
|
# Add test names here if they use fork() or have device initialization conflicts
|
|
# Note: Use test case name patterns (from gtest), not executable names
|
|
SEQUENTIAL_TESTS = [
|
|
'ReduceScatterMultiDeviceTest',
|
|
'DeepEPMultiDeviceTest',
|
|
'AttentionMultiDeviceTest',
|
|
'FusedMoEAll2AllMultiDeviceTest',
|
|
]
|
|
|
|
def initialize_options(self) -> None:
|
|
pass
|
|
|
|
def finalize_options(self) -> None:
|
|
pass
|
|
|
|
def run_ctest(self, cmake_dir: str) -> int:
|
|
def run_subprocess_with_streaming(
|
|
cmd: list[str],
|
|
error_message: str,
|
|
warn_if_no_tests: bool = False,
|
|
) -> None:
|
|
"""Helper function to run subprocess and stream output"""
|
|
process = subprocess.Popen(
|
|
cmd,
|
|
cwd=cmake_dir,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.STDOUT,
|
|
text=True,
|
|
bufsize=1,
|
|
)
|
|
|
|
if process.stdout is None:
|
|
raise RuntimeError("Failed to capture subprocess stdout for streaming.")
|
|
|
|
output_lines: list[str] = []
|
|
for line in iter(process.stdout.readline, ''):
|
|
print(line, end='')
|
|
output_lines.append(line)
|
|
|
|
return_code: int = process.wait()
|
|
|
|
# Warn if no tests were found, but don't fail (some backends may not compile certain tests)
|
|
if warn_if_no_tests and return_code == 0:
|
|
output_text: str = ''.join(output_lines)
|
|
if 'No tests were found' in output_text:
|
|
print(f"No tests matched the pattern (this is OK for some backends).")
|
|
return
|
|
|
|
if return_code != 0:
|
|
print(error_message)
|
|
exit(1)
|
|
|
|
try:
|
|
# Step 1: Run all tests EXCEPT sequential ones in parallel
|
|
if self.SEQUENTIAL_TESTS:
|
|
exclude_pattern = '|'.join(self.SEQUENTIAL_TESTS)
|
|
print("=" * 80)
|
|
print(f"Running tests in parallel (excluding: {', '.join(self.SEQUENTIAL_TESTS)})...")
|
|
print("=" * 80)
|
|
run_subprocess_with_streaming(
|
|
['ctest', '--parallel', '8', '--repeat', 'until-pass:5', '-E', exclude_pattern],
|
|
"Parallel tests failed."
|
|
)
|
|
else:
|
|
print("=" * 80)
|
|
print("Running all tests in parallel...")
|
|
print("=" * 80)
|
|
run_subprocess_with_streaming(
|
|
['ctest', '--parallel', '8', '--repeat', 'until-pass:5'],
|
|
"Parallel tests failed."
|
|
)
|
|
|
|
# Step 2: Run sequential tests one by one
|
|
for idx, test_name in enumerate(self.SEQUENTIAL_TESTS, start=2):
|
|
print("\n" + "=" * 80)
|
|
print(f"Step {idx}: Running {test_name} sequentially...")
|
|
print("=" * 80)
|
|
# Use pattern matching to include all test cases under the test class
|
|
# e.g., ReduceScatterMultiDeviceTest matches ReduceScatterMultiDeviceTest.BasicTest, etc.
|
|
run_subprocess_with_streaming(
|
|
['ctest', '--repeat', 'until-pass:5', '-R', test_name],
|
|
f"Sequential test {test_name} failed.",
|
|
warn_if_no_tests=True
|
|
)
|
|
|
|
print("\n" + "=" * 80)
|
|
print("All tests passed!")
|
|
print("=" * 80)
|
|
return 0
|
|
except subprocess.CalledProcessError as e:
|
|
print(e.stderr)
|
|
exit(1)
|
|
|
|
def run(self) -> None:
|
|
self.run_ctest(get_cmake_dir())
|
|
|
|
class SingleTest(Command):
|
|
"""Command to build and run a single test"""
|
|
description = "Build and run a single test target."
|
|
# test_name should match a CMake/CTest target name, for example:
|
|
# python setup.py test --test-name common_test
|
|
user_options = [
|
|
("test-name=", None, "name of the test target to build and run (e.g. platform_vmm_test)"),
|
|
("device=", None, "target device type (npu or mlu or cuda or ilu)"),
|
|
("arch=", None, "target arch type (x86 or arm)"),
|
|
("generate-so=", None, "generate so or binary"),
|
|
]
|
|
|
|
def initialize_options(self) -> None:
|
|
self.test_name: Optional[str] = None
|
|
self.device: Optional[str] = None
|
|
self.arch: Optional[str] = None
|
|
self.generate_so: bool = False
|
|
|
|
def finalize_options(self) -> None:
|
|
if not self.test_name:
|
|
raise ValueError("--test-name is required for single_test command")
|
|
|
|
def run(self) -> None:
|
|
# Create ExtBuildSingleTest instance and set parameters
|
|
build_ext = ExtBuildSingleTest(self.distribution)
|
|
build_ext.initialize_options()
|
|
build_ext.test_name = self.test_name
|
|
build_ext.device = self.device
|
|
build_ext.arch = self.arch
|
|
build_ext.generate_so = self.generate_so
|
|
build_ext.finalize_options()
|
|
|
|
# Ensure extension modules are set
|
|
if not hasattr(build_ext, 'extensions') or not build_ext.extensions:
|
|
build_ext.extensions = self.distribution.ext_modules
|
|
|
|
# Run build
|
|
build_ext.run()
|
|
|
|
def parse_arguments() -> dict[str, Any]:
|
|
parser = argparse.ArgumentParser(
|
|
description='Setup helper for building xllm',
|
|
epilog='Example: python setup.py build',
|
|
usage='%(prog)s [COMMAND] [OPTIONS]'
|
|
)
|
|
|
|
parser.add_argument(
|
|
'setup_args',
|
|
nargs='*',
|
|
metavar='argparse.REMAINDER',
|
|
help='setup command (build, test, bdist_wheel, etc.)'
|
|
)
|
|
|
|
parser.add_argument(
|
|
'--device',
|
|
type=str.lower,
|
|
choices=['auto', 'npu', 'mlu', 'cuda', 'ilu', 'musa'],
|
|
default='auto',
|
|
help='Device type: npu, mlu, ilu, cuda or musa (case-insensitive)'
|
|
)
|
|
parser.add_argument(
|
|
'--generate-so',
|
|
type=str.lower,
|
|
choices=['true', 'false', '1', '0', 'yes', 'no', 'y', 'n', 'on', 'off'],
|
|
default='false',
|
|
help='Whether to generate so or binary'
|
|
)
|
|
|
|
parser.add_argument(
|
|
'--test-name',
|
|
type=str,
|
|
default=None,
|
|
help='Name of the test target to build and run; when omitted, all tests run'
|
|
)
|
|
|
|
args = parser.parse_args()
|
|
|
|
sys.argv = [sys.argv[0]] + args.setup_args
|
|
|
|
generate_so = args.generate_so.lower() in ('true', '1', 'yes', 'y', 'on')
|
|
|
|
return {
|
|
'device': args.device,
|
|
'generate_so': generate_so,
|
|
'test_name': args.test_name,
|
|
}
|
|
|
|
if __name__ == "__main__":
|
|
config = parse_arguments()
|
|
|
|
arch = get_cpu_arch()
|
|
device = config['device']
|
|
if device == 'auto':
|
|
device = get_device_type()
|
|
print(f"🚀 Build xllm with CPU arch: {arch} and target device: {device}")
|
|
|
|
pre_build()
|
|
|
|
generate_so = config['generate_so']
|
|
test_name = config.get('test_name')
|
|
|
|
if "SKIP_TEST" in os.environ:
|
|
BUILD_TEST_FILE = False
|
|
if "SKIP_EXPORT" in os.environ:
|
|
BUILD_EXPORT = False
|
|
|
|
version = get_version()
|
|
|
|
# check and install git pre-commit
|
|
check_and_install_pre_commit()
|
|
|
|
test_cmd = SingleTest if test_name else TestUT
|
|
options = {
|
|
'build_ext': {
|
|
'device': device,
|
|
'arch': arch,
|
|
'generate_so': generate_so
|
|
},
|
|
'bdist_wheel': {
|
|
'device': device,
|
|
'arch': arch,
|
|
}
|
|
}
|
|
if test_name:
|
|
options['test'] = {
|
|
'device': device,
|
|
'arch': arch,
|
|
'generate_so': generate_so,
|
|
'test_name': test_name,
|
|
}
|
|
|
|
setup(
|
|
name="xllm",
|
|
version=version,
|
|
license="Apache 2.0",
|
|
author="xLLM Team",
|
|
author_email="infer@xllm.ai",
|
|
description="A high-performance inference system for large language models.",
|
|
long_description=read_readme(),
|
|
long_description_content_type="text/markdown",
|
|
url="https://github.com/jd-opensource/xllm",
|
|
project_urls={
|
|
"Homepage": "https://xllm.readthedocs.io/zh-cn/latest/",
|
|
"Documentation": "https://xllm.readthedocs.io/zh-cn/latest/",
|
|
},
|
|
classifiers=[
|
|
"Intended Audience :: Developers",
|
|
"Intended Audience :: Education",
|
|
"Programming Language :: C++",
|
|
"Programming Language :: Python :: 3 :: Only",
|
|
"Programming Language :: Python :: 3.10",
|
|
"Programming Language :: Python :: 3.11",
|
|
"Programming Language :: Python :: 3.12",
|
|
"Operating System :: POSIX",
|
|
"License :: OSI Approved :: Apache Software License",
|
|
"Topic :: Scientific/Engineering",
|
|
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
],
|
|
ext_modules=[CMakeExtension("xllm", "xllm/")],
|
|
cmdclass={"build_ext": ExtBuild,
|
|
"test": test_cmd,
|
|
'bdist_wheel': BuildDistWheel},
|
|
options=options,
|
|
packages=find_namespace_packages(include=["scripts.build_support"]),
|
|
zip_safe=False,
|
|
py_modules=["xllm/launch_xllm", "xllm/__init__",
|
|
"xllm/pybind/llm", "xllm/pybind/vlm",
|
|
"xllm/pybind/embedding", "xllm/pybind/util",
|
|
"xllm/pybind/args", "xllm/pybind/params",
|
|
"xllm/pybind/errors", "xllm/pybind/mm_utils"],
|
|
python_requires=">=3.10",
|
|
)
|