diff --git a/pyproject.toml b/pyproject.toml index bbac40a770..75c4141955 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,9 +28,6 @@ Homepage = "https://docs.xllm-ai.com/" Documentation = "https://docs.xllm-ai.com/" Repository = "https://github.com/jd-opensource/xllm" -[project.scripts] -xllm = "xllm.launch_server:main" - [tool.setuptools.dynamic] readme = { file = ["README.md"], content-type = "text/markdown" } version = { file = ["version.txt"] } diff --git a/setup.py b/setup.py index b120256a1b..92aed1c20f 100644 --- a/setup.py +++ b/setup.py @@ -125,6 +125,33 @@ def _stage_triton_npu_runtime_binaries(base_dir: str, extdir: str, device: str) ) logger.info(f"Staged {copied_count} Triton NPU runtime asset(s) into {dest_dir}") + +try: + from setuptools.command.build_scripts import build_scripts as _build_scripts +except ModuleNotFoundError: + from distutils.command.build_scripts import build_scripts as _build_scripts + + +class BuildBinaryScripts(_build_scripts): + """Ship the xllm cpp ELF as a wheel script verbatim. + + The default copy_scripts calls tokenize.open() to rewrite shebangs, which + raises SyntaxError on a raw ELF. Copy the file byte-for-byte instead so it + installs to bin/xllm and the cpp binary -- not a python wrapper -- owns the + `xllm` command. + """ + + def copy_scripts(self) -> tuple[list[str], list[str]]: + self.mkpath(self.build_dir) + outfiles: list[str] = [] + for script in self.scripts: + outfile = os.path.join(self.build_dir, os.path.basename(script)) + self.copy_file(script, outfile) + outfiles.append(outfile) + self._change_modes(outfiles) + return outfiles, [] + + class CMakeExtension(Extension): def __init__(self, name: str, path: str, sourcedir: str = "") -> None: super().__init__(name, sources=[]) @@ -478,6 +505,12 @@ def run(self) -> None: path = os.path.join(root, item) if '_test' in item and os.path.isfile(path): os.remove(path) + # The cpp ELF ships as a wheel script (bin/xllm) instead. Drop the + # in-package copy so the wheel carries a single binary and nothing + # shadows the `xllm` command on PATH. + in_pkg_binary = os.path.join(tmp_path, 'xllm') + if os.path.isfile(in_pkg_binary): + os.remove(in_pkg_binary) global BUILD_TEST_FILE BUILD_TEST_FILE = False @@ -753,7 +786,9 @@ def parse_arguments() -> dict[str, Any]: "Topic :: Scientific/Engineering :: Artificial Intelligence", ], ext_modules=[CMakeExtension("xllm", "xllm/")], + scripts=[os.path.join(get_base_dir(), "build", "xllm", "core", "server", "xllm")], cmdclass={"build_ext": ExtBuild, + "build_scripts": BuildBinaryScripts, "test": test_cmd, 'bdist_wheel': BuildDistWheel}, options=options,